mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Merge branch 'cell-refId' into 'master'
Give ESM3 cells a RefId See merge request OpenMW/openmw!2752
This commit is contained in:
commit
a9c7354338
@ -220,7 +220,7 @@ namespace EsmTool
|
||||
{
|
||||
void CellState::load(ESM::ESMReader& reader, bool& deleted)
|
||||
{
|
||||
mCellState.mId.load(reader);
|
||||
mCellState.mId = reader.getCellId();
|
||||
mCellState.load(reader);
|
||||
if (mCellState.mHasFogOfWar)
|
||||
mFogState.load(reader);
|
||||
@ -1358,11 +1358,8 @@ namespace EsmTool
|
||||
void Record<CellState>::print()
|
||||
{
|
||||
std::cout << " Id:" << std::endl;
|
||||
std::cout << " Worldspace: " << mData.mCellState.mId.mWorldspace << std::endl;
|
||||
std::cout << " CellId: " << mData.mCellState.mId << std::endl;
|
||||
std::cout << " Index:" << std::endl;
|
||||
std::cout << " X: " << mData.mCellState.mId.mIndex.mX << std::endl;
|
||||
std::cout << " Y: " << mData.mCellState.mId.mIndex.mY << std::endl;
|
||||
std::cout << " Paged: " << mData.mCellState.mId.mPaged << std::endl;
|
||||
std::cout << " WaterLevel: " << mData.mCellState.mWaterLevel << std::endl;
|
||||
std::cout << " HasFogOfWar: " << mData.mCellState.mHasFogOfWar << std::endl;
|
||||
std::cout << " LastRespawn:" << std::endl;
|
||||
@ -1420,8 +1417,7 @@ namespace EsmTool
|
||||
std::string Record<CellState>::getId() const
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << mData.mCellState.mId.mWorldspace << " " << mData.mCellState.mId.mIndex.mX << " "
|
||||
<< mData.mCellState.mId.mIndex.mY << " " << mData.mCellState.mId.mPaged;
|
||||
stream << mData.mCellState.mId;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ namespace ESSImport
|
||||
// note if the player is in a nameless exterior cell, we will assign the cellId later based on player position
|
||||
if (Misc::StringUtils::ciEqual(cell.mName, mContext->mPlayerCellName))
|
||||
{
|
||||
mContext->mPlayer.mCellId = cell.getCellId();
|
||||
mContext->mPlayer.mCellId = cell.mId;
|
||||
}
|
||||
|
||||
Cell newcell;
|
||||
@ -301,7 +301,7 @@ namespace ESSImport
|
||||
marker.mWorldX = notepos[0];
|
||||
marker.mWorldY = notepos[1];
|
||||
marker.mNote = note;
|
||||
marker.mCell = cell.getCellId();
|
||||
marker.mCell = cell.mId;
|
||||
mMarkers.push_back(marker);
|
||||
}
|
||||
|
||||
@ -321,8 +321,9 @@ namespace ESSImport
|
||||
csta.mHasFogOfWar = 0;
|
||||
csta.mLastRespawn.mDay = 0;
|
||||
csta.mLastRespawn.mHour = 0;
|
||||
csta.mId = esmcell.getCellId();
|
||||
csta.mId.save(esm);
|
||||
csta.mId = esmcell.mId;
|
||||
csta.mIsInterior = !esmcell.isExterior();
|
||||
esm.writeCellId(csta.mId);
|
||||
// TODO csta.mLastRespawn;
|
||||
// shouldn't be needed if we respawn on global schedule like in original MW
|
||||
csta.mWaterLevel = esmcell.mWater;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/misc/constants.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
@ -60,19 +61,9 @@ namespace ESSImport
|
||||
|
||||
const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation;
|
||||
|
||||
ESM::CellId cell;
|
||||
cell.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
cell.mPaged = true;
|
||||
|
||||
cell.mIndex.mX = mark.mCellX;
|
||||
cell.mIndex.mY = mark.mCellY;
|
||||
|
||||
// TODO: Figure out a better way to detect interiors. (0, 0) is a valid exterior cell.
|
||||
if (mark.mCellX == 0 && mark.mCellY == 0)
|
||||
{
|
||||
cell.mWorldspace = pcdt.mMNAM;
|
||||
cell.mPaged = false;
|
||||
}
|
||||
bool interior = mark.mCellX == 0 && mark.mCellY == 0;
|
||||
ESM::RefId cell = ESM::Cell::generateIdForCell(!interior, pcdt.mMNAM, mark.mCellX, mark.mCellY);
|
||||
|
||||
out.mMarkedCell = cell;
|
||||
out.mMarkedPosition.pos[0] = mark.mX;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <components/esm3/player.hpp>
|
||||
#include <components/esm3/savedgame.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadarmo.hpp>
|
||||
#include <components/esm3/loadclot.hpp>
|
||||
@ -409,16 +410,11 @@ namespace ESSImport
|
||||
}
|
||||
|
||||
writer.startRecord(ESM::REC_PLAY);
|
||||
if (context.mPlayer.mCellId.mPaged)
|
||||
{
|
||||
// exterior cell -> determine cell coordinates based on position
|
||||
int cellX
|
||||
= static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits));
|
||||
int cellY
|
||||
= static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits));
|
||||
context.mPlayer.mCellId.mIndex.mX = cellX;
|
||||
context.mPlayer.mCellId.mIndex.mY = cellY;
|
||||
}
|
||||
ESM::CellId cellId = ESM::CellId::extractFromRefId(context.mPlayer.mCellId);
|
||||
int cellX = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[0] / Constants::CellSizeInUnits));
|
||||
int cellY = static_cast<int>(std::floor(context.mPlayer.mObject.mPosition.pos[1] / Constants::CellSizeInUnits));
|
||||
|
||||
context.mPlayer.mCellId = ESM::Cell::generateIdForCell(cellId.mPaged, cellId.mWorldspace, cellX, cellY);
|
||||
context.mPlayer.save(writer);
|
||||
writer.endRecord(ESM::REC_PLAY);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <components/esm3/controlsstate.hpp>
|
||||
#include <components/esm3/dialoguestate.hpp>
|
||||
#include <components/esm3/globalmap.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/loadcrea.hpp>
|
||||
#include <components/esm3/loadnpc.hpp>
|
||||
#include <components/esm3/player.hpp>
|
||||
@ -59,10 +60,7 @@ namespace ESSImport
|
||||
, mHour(0.f)
|
||||
, mNextActorId(0)
|
||||
{
|
||||
ESM::CellId playerCellId;
|
||||
playerCellId.mPaged = true;
|
||||
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||
mPlayer.mCellId = playerCellId;
|
||||
mPlayer.mCellId = ESM::RefId::esm3ExteriorCell(0, 0);
|
||||
mPlayer.mLastKnownExteriorPosition[0] = mPlayer.mLastKnownExteriorPosition[1]
|
||||
= mPlayer.mLastKnownExteriorPosition[2] = 0.0f;
|
||||
mPlayer.mHasMark = 0;
|
||||
|
@ -263,16 +263,18 @@ namespace NavMeshTool
|
||||
|
||||
const osg::Vec2i cellPosition(cell.mData.mX, cell.mData.mY);
|
||||
const std::size_t cellObjectsBegin = data.mObjects.size();
|
||||
const auto cellNameLowerCase = Misc::StringUtils::lowerCase(cell.mCellId.mWorldspace);
|
||||
const auto cellWorldspace = Misc::StringUtils::lowerCase(
|
||||
(cell.isExterior() ? ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace) : cell.mId)
|
||||
.serializeText());
|
||||
WorldspaceNavMeshInput& navMeshInput = [&]() -> WorldspaceNavMeshInput& {
|
||||
auto it = navMeshInputs.find(cellNameLowerCase);
|
||||
auto it = navMeshInputs.find(cellWorldspace);
|
||||
if (it == navMeshInputs.end())
|
||||
{
|
||||
it = navMeshInputs
|
||||
.emplace(cellNameLowerCase,
|
||||
std::make_unique<WorldspaceNavMeshInput>(cellNameLowerCase, settings.mRecast))
|
||||
.emplace(cellWorldspace,
|
||||
std::make_unique<WorldspaceNavMeshInput>(cellWorldspace, settings.mRecast))
|
||||
.first;
|
||||
it->second->mTileCachedRecastMeshManager.setWorldspace(cellNameLowerCase, nullptr);
|
||||
it->second->mTileCachedRecastMeshManager.setWorldspace(cellWorldspace, nullptr);
|
||||
}
|
||||
return *it->second;
|
||||
}();
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <apps/opencs/model/world/record.hpp>
|
||||
#include <apps/opencs/model/world/universalid.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
@ -337,7 +337,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view(int row) c
|
||||
return std::make_pair(UniversalId::Type_None, "");
|
||||
|
||||
if (id[0] == '#')
|
||||
id = ESM::CellId::sDefaultWorldspace;
|
||||
id = ESM::Cell::sDefaultWorldspace;
|
||||
|
||||
return std::make_pair(UniversalId(UniversalId::Type_Scene, id), hint);
|
||||
}
|
||||
|
@ -53,14 +53,17 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b
|
||||
|
||||
Cell& cell2 = base ? cell.mBase : cell.mModified;
|
||||
|
||||
CellRef ref;
|
||||
ref.mNew = false;
|
||||
ESM::MovedCellRef mref;
|
||||
bool isDeleted = false;
|
||||
bool isMoved = false;
|
||||
|
||||
while (ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved))
|
||||
while (true)
|
||||
{
|
||||
CellRef ref;
|
||||
ref.mNew = false;
|
||||
|
||||
if (!ESM::Cell::getNextRef(reader, ref, isDeleted, mref, isMoved))
|
||||
break;
|
||||
// Keep mOriginalCell empty when in modified (as an indicator that the
|
||||
// original cell will always be equal the current cell).
|
||||
ref.mOriginalCell = base ? cell2.mId : ESM::RefId();
|
||||
@ -70,7 +73,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b
|
||||
// Autocalculate the cell index from coordinates first
|
||||
std::pair<int, int> index = ref.getCellIndex();
|
||||
|
||||
ref.mCell = ESM::RefId::stringRefId("#" + std::to_string(index.first) + " " + std::to_string(index.second));
|
||||
ref.mCell = ESM::RefId::esm3ExteriorCell(index.first, index.second);
|
||||
|
||||
// Handle non-base moved references
|
||||
if (!base && isMoved)
|
||||
@ -86,12 +89,11 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b
|
||||
if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1])
|
||||
{
|
||||
ESM::RefId indexCell = ref.mCell;
|
||||
ref.mCell = ESM::RefId::stringRefId(
|
||||
"#" + std::to_string(mref.mTarget[0]) + " " + std::to_string(mref.mTarget[1]));
|
||||
ref.mCell = ESM::RefId::esm3ExteriorCell(mref.mTarget[0], mref.mTarget[1]);
|
||||
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Cell, mCells.getId(cellIndex));
|
||||
messages.add(id, "The position of the moved reference " + ref.mRefID.getRefIdString() + " (cell " + indexCell.getRefIdString() + ")"
|
||||
" does not match the target cell (" + ref.mCell.getRefIdString() + ")",
|
||||
messages.add(id, "The position of the moved reference " + ref.mRefID.toDebugString() + " (cell " + indexCell.toDebugString() + ")"
|
||||
" does not match the target cell (" + ref.mCell.toDebugString() + ")",
|
||||
std::string(), CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
}
|
||||
@ -118,7 +120,7 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b
|
||||
|
||||
messages.add(id,
|
||||
"Attempt to move a non-existent reference - RefNum index " + std::to_string(ref.mRefNum.mIndex)
|
||||
+ ", refID " + ref.mRefID.getRefIdString() + ", content file index "
|
||||
+ ", refID " + ref.mRefID.toDebugString() + ", content file index "
|
||||
+ std::to_string(ref.mRefNum.mContentFile),
|
||||
/*hint*/ "", CSMDoc::Message::Severity_Warning);
|
||||
continue;
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
#include <apps/opencs/view/world/dragrecordtable.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../../model/world/columns.hpp"
|
||||
@ -307,7 +305,7 @@ void CSVWorld::RegionMap::view()
|
||||
}
|
||||
|
||||
emit editRequest(
|
||||
CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::CellId::sDefaultWorldspace), hint.str());
|
||||
CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace), hint.str());
|
||||
}
|
||||
|
||||
void CSVWorld::RegionMap::viewInTable()
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include <apps/opencs/view/doc/subview.hpp>
|
||||
#include <apps/opencs/view/render/worldspacewidget.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../../model/world/cellselection.hpp"
|
||||
@ -49,7 +47,7 @@ CSVWorld::SceneSubView::SceneSubView(const CSMWorld::UniversalId& id, CSMDoc::Do
|
||||
CSVRender::WorldspaceWidget* worldspaceWidget = nullptr;
|
||||
widgetType whatWidget;
|
||||
|
||||
if (Misc::StringUtils::ciEqual(id.getId(), ESM::CellId::sDefaultWorldspace))
|
||||
if (Misc::StringUtils::ciEqual(id.getId(), ESM::Cell::sDefaultWorldspace))
|
||||
{
|
||||
whatWidget = widget_Paged;
|
||||
|
||||
@ -170,7 +168,7 @@ void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::UniversalId& i
|
||||
|
||||
void CSVWorld::SceneSubView::cellSelectionChanged(const CSMWorld::CellSelection& selection)
|
||||
{
|
||||
setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::CellId::sDefaultWorldspace));
|
||||
setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspace));
|
||||
int size = selection.getSize();
|
||||
|
||||
std::ostringstream stream;
|
||||
|
@ -40,7 +40,6 @@ namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <osg/Timer>
|
||||
@ -114,7 +113,7 @@ namespace MWBase
|
||||
{
|
||||
std::string name;
|
||||
float x, y; // world position
|
||||
ESM::CellId dest;
|
||||
ESM::RefId dest;
|
||||
};
|
||||
|
||||
World() {}
|
||||
@ -256,9 +255,8 @@ namespace MWBase
|
||||
= 0;
|
||||
///< Move to exterior cell.
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
virtual void changeToCell(
|
||||
const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)
|
||||
const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)
|
||||
= 0;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
@ -514,13 +512,16 @@ namespace MWBase
|
||||
virtual bool screenshot360(osg::Image* image) = 0;
|
||||
|
||||
/// Find default position inside exterior cell specified by name
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
virtual bool findExteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
/// \return empty RefId if exterior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findExteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
|
||||
/// Find default position inside interior cell specified by name
|
||||
/// \return false if interior with given name not exists, true otherwise
|
||||
virtual bool findInteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
/// \return empty RefId if interior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
|
||||
/// Find default position inside interior or exterior cell specified by name
|
||||
/// \return empty RefId if interior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) = 0;
|
||||
/// Enables or disables use of teleport spell effects (recall, intervention, etc).
|
||||
virtual void enableTeleporting(bool enable) = 0;
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/failedaction.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/worldmodel.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
#include "../mwgui/ustring.hpp"
|
||||
@ -298,16 +299,8 @@ namespace MWClass
|
||||
|
||||
std::string Door::getDestination(const MWWorld::LiveCellRef<ESM::Door>& door)
|
||||
{
|
||||
std::string_view dest = door.mRef.getDestCell();
|
||||
if (dest.empty())
|
||||
{
|
||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||
auto world = MWBase::Environment::get().getWorld();
|
||||
const osg::Vec2i index
|
||||
= MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]);
|
||||
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(index.x(), index.y());
|
||||
dest = world->getCellName(cell);
|
||||
}
|
||||
std::string_view dest
|
||||
= MWBase::Environment::get().getWorldModel()->getCell(door.mRef.getDestCell())->getCell()->getDisplayName();
|
||||
|
||||
return "#{sCell=" + std::string{ dest } + "}";
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ namespace MWGui
|
||||
return mMarkers.end();
|
||||
}
|
||||
|
||||
CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId& cellId) const
|
||||
CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::RefId& cellId) const
|
||||
{
|
||||
return mMarkers.equal_range(cellId);
|
||||
}
|
||||
@ -351,13 +351,9 @@ namespace MWGui
|
||||
{
|
||||
for (int dY = -mCellDistance; dY <= mCellDistance; ++dY)
|
||||
{
|
||||
ESM::CellId cellId;
|
||||
cellId.mPaged = !mInterior;
|
||||
cellId.mWorldspace = (mInterior ? mPrefix : ESM::CellId::sDefaultWorldspace);
|
||||
cellId.mIndex.mX = mCurX + dX;
|
||||
cellId.mIndex.mY = mCurY + dY;
|
||||
ESM::RefId cellRefId = ESM::Cell::generateIdForCell(!mInterior, mPrefix, mCurX + dX, mCurY + dY);
|
||||
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
|
||||
++it)
|
||||
{
|
||||
@ -885,16 +881,9 @@ namespace MWGui
|
||||
|
||||
mEditingMarker.mWorldX = worldPos.x();
|
||||
mEditingMarker.mWorldY = worldPos.y();
|
||||
ESM::RefId clickedId = ESM::Cell::generateIdForCell(!mInterior, LocalMapBase::mPrefix, x, y);
|
||||
|
||||
mEditingMarker.mCell.mPaged = !mInterior;
|
||||
if (mInterior)
|
||||
mEditingMarker.mCell.mWorldspace = LocalMapBase::mPrefix;
|
||||
else
|
||||
{
|
||||
mEditingMarker.mCell.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
mEditingMarker.mCell.mIndex.mX = x;
|
||||
mEditingMarker.mCell.mIndex.mY = y;
|
||||
}
|
||||
mEditingMarker.mCell = clickedId;
|
||||
|
||||
mEditNoteDialog.setVisible(true);
|
||||
mEditNoteDialog.showDeleteButton(false);
|
||||
@ -1120,12 +1109,8 @@ namespace MWGui
|
||||
|
||||
void MapWindow::setGlobalMapMarkerTooltip(MyGUI::Widget* markerWidget, int x, int y)
|
||||
{
|
||||
ESM::CellId cellId;
|
||||
cellId.mIndex.mX = x;
|
||||
cellId.mIndex.mY = y;
|
||||
cellId.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
cellId.mPaged = true;
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||
ESM::RefId cellRefId = ESM::RefId::esm3ExteriorCell(x, y);
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
||||
std::vector<std::string> destNotes;
|
||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it)
|
||||
destNotes.push_back(it->second.mNote);
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
#include "windowpinnablebase.hpp"
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
#include <components/esm3/custommarkerstate.hpp>
|
||||
#include <components/misc/constants.hpp>
|
||||
|
||||
@ -56,14 +54,14 @@ namespace MWGui
|
||||
|
||||
size_t size() const;
|
||||
|
||||
typedef std::multimap<ESM::CellId, ESM::CustomMarker> ContainerType;
|
||||
typedef std::multimap<ESM::RefId, ESM::CustomMarker> ContainerType;
|
||||
|
||||
typedef std::pair<ContainerType::const_iterator, ContainerType::const_iterator> RangeType;
|
||||
|
||||
ContainerType::const_iterator begin() const;
|
||||
ContainerType::const_iterator end() const;
|
||||
|
||||
RangeType getMarkers(const ESM::CellId& cellId) const;
|
||||
RangeType getMarkers(const ESM::RefId& cellId) const;
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
EventHandle_Void eventMarkersChanged;
|
||||
|
@ -195,9 +195,11 @@ namespace MWGui
|
||||
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(1);
|
||||
osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]);
|
||||
ESM::RefId cellId = ESM::Cell::generateIdForCell(!interior, cellname, posCell.x(), posCell.y());
|
||||
|
||||
// Teleports any followers, too.
|
||||
MWWorld::ActionTeleport action(interior ? cellname : "", pos, true);
|
||||
MWWorld::ActionTeleport action(cellId, pos, true);
|
||||
action.execute(player);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0);
|
||||
|
@ -36,8 +36,7 @@ namespace MWLua
|
||||
const MWWorld::CellRef& cellRef = doorPtr(o).getCellRef();
|
||||
if (!cellRef.getTeleport())
|
||||
return sol::nil;
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCellByPosition(
|
||||
cellRef.getDoorDest().asVec3(), cellRef.getDestCell());
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||
assert(cell);
|
||||
return o.getCell(lua, cell);
|
||||
};
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <components/esm3/aisequence.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/misc/algorithm.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
@ -78,7 +79,7 @@ namespace MWMechanics
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCellId.empty() && mCellId != actor.getCell()->getCell()->getCellId().mWorldspace)
|
||||
if (!mCellId.empty() && !Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->getNameId()))
|
||||
return false; // Not in the correct cell, pause and rely on the player to go back through a teleport door
|
||||
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState::Nothing);
|
||||
|
@ -174,8 +174,7 @@ namespace MWMechanics
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (Misc::StringUtils::ciEqual(
|
||||
mCellId, actor.getCell()->getCell()->getNameId())) // Cell to travel to
|
||||
else if (mCellId == actor.getCell()->getCell()->getWorldSpace()) // Cell to travel to
|
||||
{
|
||||
mRemainingDuration = mDuration;
|
||||
return true;
|
||||
|
@ -330,9 +330,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
|
||||
|
||||
const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore* cell)
|
||||
{
|
||||
const ESM::CellId& id = cell->getCell()->getCellId();
|
||||
const ESM::RefId id = cell->getCell()->getId();
|
||||
// static cache is OK for now, pathgrids can never change during runtime
|
||||
typedef std::map<ESM::CellId, std::unique_ptr<MWMechanics::PathgridGraph>> CacheMap;
|
||||
typedef std::map<ESM::RefId, std::unique_ptr<MWMechanics::PathgridGraph>> CacheMap;
|
||||
static CacheMap cache;
|
||||
CacheMap::iterator found = cache.find(id);
|
||||
if (found == cache.end())
|
||||
|
@ -487,9 +487,9 @@ namespace MWMechanics
|
||||
world->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||
if (markedCell)
|
||||
{
|
||||
std::string_view dest;
|
||||
ESM::RefId dest;
|
||||
if (!markedCell->isExterior())
|
||||
dest = markedCell->getCell()->getNameId();
|
||||
dest = markedCell->getCell()->getId();
|
||||
MWWorld::ActionTeleport action(dest, markedPosition, false);
|
||||
action.execute(target);
|
||||
if (!caster.isEmpty())
|
||||
|
@ -92,19 +92,9 @@ namespace MWScript
|
||||
ESM::Position pos;
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Ptr playerPtr = world->getPlayerPtr();
|
||||
|
||||
if (world->findExteriorPosition(cell, pos))
|
||||
{
|
||||
MWWorld::ActionTeleport({}, pos, false).execute(playerPtr);
|
||||
world->adjustPosition(playerPtr, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change to interior even if findInteriorPosition()
|
||||
// yields false. In this case position will be zero-point.
|
||||
world->findInteriorPosition(cell, pos);
|
||||
MWWorld::ActionTeleport(cell, pos, false).execute(playerPtr);
|
||||
}
|
||||
ESM::RefId cellId = world->findCellPosition(cell, pos);
|
||||
MWWorld::ActionTeleport(cellId, pos, false).execute(playerPtr);
|
||||
world->adjustPosition(playerPtr, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -87,8 +87,7 @@ namespace MWScript
|
||||
float distance;
|
||||
// If the objects are in different worldspaces, return a large value (just like vanilla)
|
||||
if (!to.isInCell() || !from.isInCell()
|
||||
|| to.getCell()->getCell()->getCellId().mWorldspace
|
||||
!= from.getCell()->getCell()->getCellId().mWorldspace)
|
||||
|| to.getCell()->getCell()->getWorldSpace() != from.getCell()->getCell()->getWorldSpace())
|
||||
distance = std::numeric_limits<float>::max();
|
||||
else
|
||||
{
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
@ -555,7 +554,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
|
||||
|
||||
if (ptr.isInCell())
|
||||
{
|
||||
const ESM::CellId& cellId = ptr.getCell()->getCell()->getCellId();
|
||||
const ESM::RefId cellId = ptr.getCell()->getCell()->getId();
|
||||
|
||||
// Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again
|
||||
MWBase::Environment::get().getWorld()->changeToCell(cellId, ptr.getRefData().getPosition(), false, false);
|
||||
@ -574,7 +573,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
MWBase::Environment::get().getWorld()->changeToCell(cell->getCell()->getCellId(), pos, true, false);
|
||||
MWBase::Environment::get().getWorld()->changeToCell(cell->getCell()->getId(), pos, true, false);
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld()->updateProjectilesCasters();
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
ActionTeleport::ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers)
|
||||
ActionTeleport::ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers)
|
||||
: Action(true)
|
||||
, mCellName(cellName)
|
||||
, mCellId(cellId)
|
||||
, mPosition(position)
|
||||
, mTeleportFollowers(teleportFollowers)
|
||||
{
|
||||
@ -33,7 +33,9 @@ namespace MWWorld
|
||||
{
|
||||
// Find any NPCs that are following the actor and teleport them with him
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
getFollowers(actor, followers, mCellName.empty(), true);
|
||||
|
||||
bool toExterior = MWBase::Environment::get().getWorldModel()->getCell(mCellId)->isExterior();
|
||||
getFollowers(actor, followers, toExterior, true);
|
||||
|
||||
for (std::set<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
|
||||
teleport(*it);
|
||||
@ -52,10 +54,7 @@ namespace MWWorld
|
||||
if (actor == world->getPlayerPtr())
|
||||
{
|
||||
world->getPlayer().setTeleported(true);
|
||||
if (mCellName.empty())
|
||||
world->changeToExteriorCell(mPosition, true);
|
||||
else
|
||||
world->changeToInteriorCell(mCellName, mPosition, true);
|
||||
world->changeToCell(mCellId, mPosition, true);
|
||||
teleported = world->getPlayerPtr();
|
||||
}
|
||||
else
|
||||
@ -65,15 +64,9 @@ namespace MWWorld
|
||||
actor.getClass().getCreatureStats(actor).getAiSequence().stopCombat();
|
||||
return;
|
||||
}
|
||||
else if (mCellName.empty())
|
||||
{
|
||||
const osg::Vec2i index = positionToCellIndex(mPosition.pos[0], mPosition.pos[1]);
|
||||
teleported = world->moveObject(
|
||||
actor, worldModel->getExterior(index.x(), index.y()), mPosition.asVec3(), true, true);
|
||||
}
|
||||
|
||||
else
|
||||
teleported
|
||||
= world->moveObject(actor, worldModel->getInterior(mCellName), mPosition.asVec3(), true, true);
|
||||
teleported = world->moveObject(actor, worldModel->getCell(mCellId), mPosition.asVec3(), true, true);
|
||||
}
|
||||
|
||||
if (!world->isWaterWalkingCastableOnTarget(teleported) && MWMechanics::hasWaterWalking(teleported))
|
||||
|
@ -13,7 +13,7 @@ namespace MWWorld
|
||||
{
|
||||
class ActionTeleport : public Action
|
||||
{
|
||||
std::string mCellName;
|
||||
ESM::RefId mCellId;
|
||||
ESM::Position mPosition;
|
||||
bool mTeleportFollowers;
|
||||
|
||||
@ -26,7 +26,7 @@ namespace MWWorld
|
||||
public:
|
||||
/// If cellName is empty, an exterior cell is assumed.
|
||||
/// @param teleportFollowers Whether to teleport any following actors of the target actor as well.
|
||||
ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers);
|
||||
ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers);
|
||||
|
||||
/// @param includeHostiles If true, include hostile followers (which won't actually be teleported) in the
|
||||
/// output,
|
||||
|
@ -16,10 +16,8 @@ namespace MWWorld
|
||||
, mDisplayname(cell.mFullName)
|
||||
, mNameID(cell.mEditorId)
|
||||
, mRegion(ESM::RefId()) // Unimplemented for now
|
||||
, mCellId{
|
||||
.mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) },
|
||||
.mIndex{ cell.getGridX(), cell.getGridY() },
|
||||
.mPaged = isExterior(),}
|
||||
, mId(cell.mId)
|
||||
, mParent(cell.mParent)
|
||||
,mMood{
|
||||
.mAmbiantColor = cell.mLighting.ambient,
|
||||
.mDirectionalColor = cell.mLighting.directional,
|
||||
@ -40,7 +38,8 @@ namespace MWWorld
|
||||
, mDisplayname(cell.mName)
|
||||
, mNameID(cell.mName)
|
||||
, mRegion(cell.mRegion)
|
||||
, mCellId(cell.getCellId())
|
||||
, mId(cell.mId)
|
||||
, mParent(ESM::RefId::stringRefId(ESM::Cell::sDefaultWorldspace))
|
||||
, mMood{
|
||||
.mAmbiantColor = cell.mAmbi.mAmbient,
|
||||
.mDirectionalColor = cell.mAmbi.mSunlight,
|
||||
@ -59,4 +58,11 @@ namespace MWWorld
|
||||
},
|
||||
*this);
|
||||
}
|
||||
ESM::RefId Cell::getWorldSpace() const
|
||||
{
|
||||
if (isExterior())
|
||||
return mParent;
|
||||
else
|
||||
return mId;
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,10 @@
|
||||
|
||||
#include <components/esm/esmbridge.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace ESM4
|
||||
@ -42,13 +40,14 @@ namespace MWWorld
|
||||
bool isQuasiExterior() const { return mIsQuasiExterior; }
|
||||
bool hasWater() const { return mHasWater; }
|
||||
bool noSleep() const { return mNoSleep; }
|
||||
const ESM::CellId& getCellId() const { return mCellId; }
|
||||
const ESM::RefId& getRegion() const { return mRegion; }
|
||||
std::string_view getNameId() const { return mNameID; }
|
||||
std::string_view getDisplayName() const { return mDisplayname; }
|
||||
std::string getDescription() const;
|
||||
const MoodData& getMood() const { return mMood; }
|
||||
float getWaterHeight() const { return mWaterHeight; }
|
||||
const ESM::RefId& getId() const { return mId; }
|
||||
ESM::RefId getWorldSpace() const;
|
||||
|
||||
private:
|
||||
bool mIsExterior;
|
||||
@ -60,7 +59,8 @@ namespace MWWorld
|
||||
std::string mDisplayname; // How the game displays it
|
||||
std::string mNameID; // The name that will be used by the script and console commands
|
||||
ESM::RefId mRegion;
|
||||
ESM::CellId mCellId;
|
||||
ESM::RefId mId;
|
||||
ESM::RefId mParent;
|
||||
MoodData mMood;
|
||||
|
||||
float mWaterHeight;
|
||||
|
@ -3,8 +3,11 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/objectstate.hpp>
|
||||
|
||||
#include <apps/openmw/mwworld/cellutils.hpp>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
CellRef::CellRef(const ESM::CellRef& ref)
|
||||
@ -67,15 +70,38 @@ namespace MWWorld
|
||||
|
||||
static const std::string emptyString = "";
|
||||
|
||||
const std::string& CellRef::getDestCell() const
|
||||
ESM::Position CellRef::getDoorDest() const
|
||||
{
|
||||
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; },
|
||||
[&](const ESM::CellRef& ref) -> const std::string& { return ref.mDestCell; },
|
||||
[&](const ESM4::Reference& ref) { return ref.mDoor.destPos; },
|
||||
[&](const ESM::CellRef& ref) -> ESM::Position { return ref.mDoorDest; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
ESM::RefId CellRef::getDestCell() const
|
||||
{
|
||||
auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::RefId {
|
||||
if (!ref.mDestCell.empty())
|
||||
{
|
||||
return ESM::RefId::stringRefId(ref.mDestCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]);
|
||||
return ESM::RefId::esm3ExteriorCell(index.x(), index.y());
|
||||
}
|
||||
};
|
||||
|
||||
return std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) -> ESM::RefId { return ESM::RefId::sEmpty; },
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
void CellRef::setScale(float scale)
|
||||
{
|
||||
if (scale != getScale())
|
||||
|
@ -61,18 +61,10 @@ namespace MWWorld
|
||||
}
|
||||
|
||||
// Teleport location for the door, if this is a teleporting door.
|
||||
const ESM::Position& getDoorDest() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::Position& operator()(const ESM::CellRef& ref) { return ref.mDoorDest; }
|
||||
const ESM::Position& operator()(const ESM4::Reference& ref) { return ref.mDoor.destPos; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
ESM::Position getDoorDest() const;
|
||||
|
||||
// Destination cell for doors (optional)
|
||||
const std::string& getDestCell() const;
|
||||
ESM::RefId getDestCell() const;
|
||||
|
||||
// Scale applied to mesh
|
||||
float getScale() const
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include <components/esm/format.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm3/cellstate.hpp>
|
||||
#include <components/esm3/containerstate.hpp>
|
||||
@ -988,11 +987,11 @@ namespace MWWorld
|
||||
|
||||
void CellStore::saveState(ESM::CellState& state) const
|
||||
{
|
||||
state.mId = mCellVariant.getCellId();
|
||||
state.mId = mCellVariant.getId();
|
||||
|
||||
if (!mCellVariant.isExterior() && mCellVariant.hasWater())
|
||||
state.mWaterLevel = mWaterLevel;
|
||||
|
||||
state.mIsInterior = !mCellVariant.isExterior();
|
||||
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
||||
state.mLastRespawn = mLastRespawn.toEsm();
|
||||
}
|
||||
@ -1019,10 +1018,10 @@ namespace MWWorld
|
||||
for (const auto& [base, store] : mMovedToAnotherCell)
|
||||
{
|
||||
ESM::RefNum refNum = base->mRef.getRefNum();
|
||||
ESM::CellId movedTo = store->getCell()->getCellId();
|
||||
ESM::RefId movedTo = store->getCell()->getId();
|
||||
|
||||
refNum.save(writer, true, "MVRF");
|
||||
movedTo.save(writer);
|
||||
writer.writeCellId(movedTo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1078,10 +1077,8 @@ namespace MWWorld
|
||||
{
|
||||
reader.cacheSubName();
|
||||
ESM::RefNum refnum;
|
||||
ESM::CellId movedTo;
|
||||
refnum.load(reader, true, "MVRF");
|
||||
movedTo.load(reader);
|
||||
|
||||
ESM::RefId movedToId = reader.getCellId();
|
||||
if (refnum.hasContentFile())
|
||||
{
|
||||
auto iter = contentFileMap.find(refnum.mContentFile);
|
||||
@ -1098,12 +1095,12 @@ namespace MWWorld
|
||||
continue;
|
||||
}
|
||||
|
||||
CellStore* otherCell = callback->getCellStore(movedTo);
|
||||
CellStore* otherCell = callback->getCellStore(movedToId);
|
||||
|
||||
if (otherCell == nullptr)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId()
|
||||
<< " (target cell " << movedTo.mWorldspace
|
||||
<< " (target cell " << movedToId
|
||||
<< " no longer exists). Reference moved back to its original location.";
|
||||
// Note by dropping tag the object will automatically re-appear in its original cell, though
|
||||
// potentially at inapproriate coordinates. Restore original coordinates:
|
||||
@ -1122,21 +1119,9 @@ namespace MWWorld
|
||||
}
|
||||
}
|
||||
|
||||
struct IsEqualVisitor
|
||||
{
|
||||
bool operator()(const ESM::Cell& a, const ESM::Cell& b) const { return a.getCellId() == b.getCellId(); }
|
||||
bool operator()(const ESM4::Cell& a, const ESM4::Cell& b) const { return a.mId == b.mId; }
|
||||
|
||||
template <class L, class R>
|
||||
bool operator()(const L&, const R&) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool CellStore::operator==(const CellStore& right) const
|
||||
{
|
||||
return ESM::visit(IsEqualVisitor(), this->mCellVariant, right.mCellVariant);
|
||||
return right.mCellVariant.getId() == mCellVariant.getId();
|
||||
}
|
||||
|
||||
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)
|
||||
|
@ -27,7 +27,6 @@ namespace ESM
|
||||
class ReadersCache;
|
||||
struct Cell;
|
||||
struct CellState;
|
||||
struct CellId;
|
||||
struct RefNum;
|
||||
struct Activator;
|
||||
struct Potion;
|
||||
@ -291,7 +290,7 @@ namespace MWWorld
|
||||
struct GetCellStoreCallback
|
||||
{
|
||||
///@note must return nullptr if the cell is not found
|
||||
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
|
||||
virtual CellStore* getCellStore(const ESM::RefId& cellId) = 0;
|
||||
virtual ~GetCellStoreCallback() = default;
|
||||
};
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace MWWorld
|
||||
{
|
||||
if (!cell.isExterior())
|
||||
continue;
|
||||
auto cellIndex = std::make_pair(cell.getCellId().mIndex.mX, cell.getCellId().mIndex.mY);
|
||||
auto cellIndex = std::make_pair(cell.getGridX(), cell.getGridY());
|
||||
mCellContexts[cellIndex] = std::move(cell.mContextList);
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ namespace MWWorld
|
||||
ESM::Player player;
|
||||
|
||||
mPlayer.save(player.mObject);
|
||||
player.mCellId = mCellStore->getCell()->getCellId();
|
||||
player.mCellId = mCellStore->getCell()->getId();
|
||||
|
||||
player.mCurrentCrimeId = mCurrentCrimeId;
|
||||
player.mPaidCrimeId = mPaidCrimeId;
|
||||
@ -298,7 +298,7 @@ namespace MWWorld
|
||||
{
|
||||
player.mHasMark = true;
|
||||
player.mMarkedPosition = mMarkedPosition;
|
||||
player.mMarkedCell = mMarkedCell->getCell()->getCellId();
|
||||
player.mMarkedCell = mMarkedCell->getCell()->getId();
|
||||
}
|
||||
else
|
||||
player.mHasMark = false;
|
||||
@ -371,7 +371,7 @@ namespace MWWorld
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId.mWorldspace << "' no longer exists";
|
||||
Log(Debug::Warning) << "Warning: Player cell '" << player.mCellId << "' no longer exists";
|
||||
// Cell no longer exists. The loader will have to choose a default cell.
|
||||
mCellStore = nullptr;
|
||||
}
|
||||
@ -392,12 +392,9 @@ namespace MWWorld
|
||||
mLastKnownExteriorPosition.y() = player.mLastKnownExteriorPosition[1];
|
||||
mLastKnownExteriorPosition.z() = player.mLastKnownExteriorPosition[2];
|
||||
|
||||
if (player.mHasMark && !player.mMarkedCell.mPaged)
|
||||
if (player.mHasMark)
|
||||
{
|
||||
// interior cell -> need to check if it exists (exterior cell will be
|
||||
// generated on the fly)
|
||||
|
||||
if (!world.getStore().get<ESM::Cell>().search(player.mMarkedCell.mWorldspace))
|
||||
if (!world.getStore().get<ESM::Cell>().search(player.mMarkedCell))
|
||||
player.mHasMark = false; // drop mark silently
|
||||
}
|
||||
|
||||
|
@ -552,9 +552,11 @@ namespace MWWorld
|
||||
unloadCell(cell, navigatorUpdateGuard.get());
|
||||
}
|
||||
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(
|
||||
mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace),
|
||||
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(mWorld.getWorldModel()
|
||||
.getExterior(playerCellX, playerCellY)
|
||||
->getCell()
|
||||
->getWorldSpace()
|
||||
.serializeText()),
|
||||
navigatorUpdateGuard.get());
|
||||
mNavigator.updateBounds(pos, navigatorUpdateGuard.get());
|
||||
|
||||
@ -675,8 +677,8 @@ namespace MWWorld
|
||||
"Testing exterior cells (" + std::to_string(i) + "/" + std::to_string(cells.getExtSize()) + ")...");
|
||||
|
||||
CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY);
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()),
|
||||
navigatorUpdateGuard.get());
|
||||
const osg::Vec3f position
|
||||
= osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits;
|
||||
mNavigator.updateBounds(position, navigatorUpdateGuard.get());
|
||||
@ -733,8 +735,8 @@ namespace MWWorld
|
||||
"Testing interior cells (" + std::to_string(i) + "/" + std::to_string(cells.getIntSize()) + ")...");
|
||||
|
||||
CellStore* cell = mWorld.getWorldModel().getInterior(it->mName);
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
mNavigator.setWorldspace(Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()),
|
||||
navigatorUpdateGuard.get());
|
||||
ESM::Position position;
|
||||
mWorld.findInteriorPosition(it->mName, position);
|
||||
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
||||
@ -890,7 +892,7 @@ namespace MWWorld
|
||||
loadingListener->setProgressRange(cell->count());
|
||||
|
||||
mNavigator.setWorldspace(
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get());
|
||||
Misc::StringUtils::lowerCase(cell->getCell()->getWorldSpace().serializeText()), navigatorUpdateGuard.get());
|
||||
mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get());
|
||||
|
||||
// Load cell.
|
||||
@ -920,16 +922,18 @@ namespace MWWorld
|
||||
MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->isQuasiExterior());
|
||||
}
|
||||
|
||||
void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
void Scene::changeToExteriorCell(
|
||||
const ESM::RefId& extCellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
{
|
||||
const osg::Vec2i cellIndex = positionToCellIndex(position.pos[0], position.pos[1]);
|
||||
|
||||
if (changeEvent)
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5);
|
||||
CellStore* current = mWorld.getWorldModel().getCell(extCellId);
|
||||
|
||||
const osg::Vec2i cellIndex(current->getCell()->getGridX(), current->getCell()->getGridY());
|
||||
|
||||
changeCellGrid(position.asVec3(), cellIndex.x(), cellIndex.y(), changeEvent);
|
||||
|
||||
CellStore* current = mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y());
|
||||
changePlayerCell(current, position, adjustPlayerPos);
|
||||
|
||||
if (changeEvent)
|
||||
@ -1129,15 +1133,7 @@ namespace MWWorld
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!door.getCellRef().getDestCell().empty())
|
||||
preloadCell(mWorld.getWorldModel().getInterior(door.getCellRef().getDestCell()));
|
||||
else
|
||||
{
|
||||
osg::Vec3f pos = door.getCellRef().getDoorDest().asVec3();
|
||||
const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y());
|
||||
preloadCell(mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y()), true);
|
||||
exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos)));
|
||||
}
|
||||
preloadCell(mWorld.getWorldModel().getCell(door.getCellRef().getDestCell()));
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
@ -167,7 +167,8 @@ namespace MWWorld
|
||||
///< Move to interior cell.
|
||||
/// @param changeEvent Set cellChanged flag?
|
||||
|
||||
void changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true);
|
||||
void changeToExteriorCell(
|
||||
const ESM::RefId& extCellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true);
|
||||
///< Move to exterior cell.
|
||||
/// @param changeEvent Set cellChanged flag?
|
||||
|
||||
|
@ -468,13 +468,17 @@ namespace MWWorld
|
||||
// Cell
|
||||
//=========================================================================
|
||||
|
||||
const ESM::Cell* Store<ESM::Cell>::search(const ESM::RefId& cellId) const
|
||||
{
|
||||
auto foundCellIt = mCells.find(cellId);
|
||||
if (foundCellIt != mCells.end())
|
||||
return &foundCellIt->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ESM::Cell* Store<ESM::Cell>::search(const ESM::Cell& cell) const
|
||||
{
|
||||
if (cell.isExterior())
|
||||
{
|
||||
return search(cell.getGridX(), cell.getGridY());
|
||||
}
|
||||
return search(cell.mName);
|
||||
return search(cell.mId);
|
||||
}
|
||||
|
||||
// this method *must* be called right after esm3.loadCell()
|
||||
@ -521,13 +525,13 @@ namespace MWWorld
|
||||
DynamicInt::const_iterator it = mInt.find(name);
|
||||
if (it != mInt.end())
|
||||
{
|
||||
return &(it->second);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
DynamicInt::const_iterator dit = mDynamicInt.find(name);
|
||||
if (dit != mDynamicInt.end())
|
||||
{
|
||||
return &dit->second;
|
||||
return dit->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -537,11 +541,11 @@ namespace MWWorld
|
||||
std::pair<int, int> key(x, y);
|
||||
DynamicExt::const_iterator it = mExt.find(key);
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
return it->second;
|
||||
|
||||
DynamicExt::const_iterator dit = mDynamicExt.find(key);
|
||||
if (dit != mDynamicExt.end())
|
||||
return &dit->second;
|
||||
return dit->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@ -549,7 +553,7 @@ namespace MWWorld
|
||||
{
|
||||
DynamicExt::const_iterator it = mExt.find(std::make_pair(x, y));
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
return (it->second);
|
||||
return nullptr;
|
||||
}
|
||||
const ESM::Cell* Store<ESM::Cell>::searchOrCreate(int x, int y)
|
||||
@ -557,11 +561,11 @@ namespace MWWorld
|
||||
std::pair<int, int> key(x, y);
|
||||
DynamicExt::const_iterator it = mExt.find(key);
|
||||
if (it != mExt.end())
|
||||
return &(it->second);
|
||||
return (it->second);
|
||||
|
||||
DynamicExt::const_iterator dit = mDynamicExt.find(key);
|
||||
if (dit != mDynamicExt.end())
|
||||
return &dit->second;
|
||||
return dit->second;
|
||||
|
||||
ESM::Cell newCell;
|
||||
newCell.mData.mX = x;
|
||||
@ -571,11 +575,11 @@ namespace MWWorld
|
||||
newCell.mAmbi.mSunlight = 0;
|
||||
newCell.mAmbi.mFog = 0;
|
||||
newCell.mAmbi.mFogDensity = 0;
|
||||
newCell.mCellId.mPaged = true;
|
||||
newCell.mCellId.mIndex.mX = x;
|
||||
newCell.mCellId.mIndex.mY = y;
|
||||
newCell.updateId();
|
||||
|
||||
return &mExt.insert(std::make_pair(key, newCell)).first->second;
|
||||
ESM::Cell* newCellInserted = &mCells.insert(std::make_pair(newCell.mId, newCell)).first->second;
|
||||
|
||||
return mExt.insert(std::make_pair(key, newCellInserted)).first->second;
|
||||
}
|
||||
const ESM::Cell* Store<ESM::Cell>::find(std::string_view id) const
|
||||
{
|
||||
@ -607,12 +611,12 @@ namespace MWWorld
|
||||
mSharedInt.clear();
|
||||
mSharedInt.reserve(mInt.size());
|
||||
for (auto& [_, cell] : mInt)
|
||||
mSharedInt.push_back(&cell);
|
||||
mSharedInt.push_back(cell);
|
||||
|
||||
mSharedExt.clear();
|
||||
mSharedExt.reserve(mExt.size());
|
||||
for (auto& [_, cell] : mExt)
|
||||
mSharedExt.push_back(&cell);
|
||||
mSharedExt.push_back(cell);
|
||||
}
|
||||
RecordId Store<ESM::Cell>::load(ESM::ESMReader& esm)
|
||||
{
|
||||
@ -622,13 +626,17 @@ namespace MWWorld
|
||||
// are not available until both cells have been loaded at least partially!
|
||||
|
||||
// All cells have a name record, even nameless exterior cells.
|
||||
ESM::Cell cell;
|
||||
ESM::Cell* emplacedCell = nullptr;
|
||||
bool isDeleted = false;
|
||||
|
||||
{
|
||||
ESM::Cell cellToLoad;
|
||||
cellToLoad.loadNameAndData(esm, isDeleted);
|
||||
emplacedCell = &mCells.insert(std::make_pair(cellToLoad.mId, cellToLoad)).first->second;
|
||||
}
|
||||
ESM::Cell& cell = *emplacedCell;
|
||||
// Load the (x,y) coordinates of the cell, if it is an exterior cell,
|
||||
// so we can find the cell we need to merge with
|
||||
cell.loadNameAndData(esm, isDeleted);
|
||||
|
||||
if (cell.mData.mFlags & ESM::Cell::Interior)
|
||||
{
|
||||
// Store interior cell by name, try to merge with existing parent data.
|
||||
@ -647,7 +655,7 @@ namespace MWWorld
|
||||
// spawn a new cell
|
||||
cell.loadCell(esm, true);
|
||||
|
||||
mInt[cell.mName] = cell;
|
||||
mInt[cell.mName] = &cell;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -700,19 +708,19 @@ namespace MWWorld
|
||||
else
|
||||
{
|
||||
// spawn a new cell
|
||||
cell.loadCell(esm, false);
|
||||
emplacedCell->loadCell(esm, false);
|
||||
|
||||
// handle moved ref (MVRF) subrecords
|
||||
handleMovedCellRefs(esm, &cell);
|
||||
handleMovedCellRefs(esm, emplacedCell);
|
||||
|
||||
// push the new references on the list of references to manage
|
||||
cell.postLoad(esm);
|
||||
emplacedCell->postLoad(esm);
|
||||
|
||||
mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell;
|
||||
mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = &cell;
|
||||
}
|
||||
}
|
||||
|
||||
return RecordId(ESM::RefId::stringRefId(cell.mName), isDeleted);
|
||||
return RecordId(cell.mId, isDeleted);
|
||||
}
|
||||
Store<ESM::Cell>::iterator Store<ESM::Cell>::intBegin() const
|
||||
{
|
||||
@ -790,21 +798,22 @@ namespace MWWorld
|
||||
const std::string cellType = (cell.isExterior()) ? "exterior" : "interior";
|
||||
throw std::runtime_error("Failed to create " + cellType + " cell");
|
||||
}
|
||||
ESM::Cell* insertedCell = &mCells.emplace(cell.mId, cell).first->second;
|
||||
if (cell.isExterior())
|
||||
{
|
||||
std::pair<int, int> key(cell.getGridX(), cell.getGridY());
|
||||
|
||||
// duplicate insertions are avoided by search(ESM::Cell &)
|
||||
DynamicExt::iterator result = mDynamicExt.emplace(key, cell).first;
|
||||
mSharedExt.push_back(&result->second);
|
||||
return &result->second;
|
||||
DynamicExt::iterator result = mDynamicExt.emplace(key, insertedCell).first;
|
||||
mSharedExt.push_back(result->second);
|
||||
return result->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// duplicate insertions are avoided by search(ESM::Cell &)
|
||||
DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, cell).first;
|
||||
mSharedInt.push_back(&result->second);
|
||||
return &result->second;
|
||||
DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, insertedCell).first;
|
||||
mSharedInt.push_back(result->second);
|
||||
return result->second;
|
||||
}
|
||||
}
|
||||
bool Store<ESM::Cell>::erase(const ESM::Cell& cell)
|
||||
@ -828,7 +837,7 @@ namespace MWWorld
|
||||
|
||||
for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it)
|
||||
{
|
||||
mSharedInt.push_back(&it->second);
|
||||
mSharedInt.push_back(it->second);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -847,7 +856,7 @@ namespace MWWorld
|
||||
|
||||
for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it)
|
||||
{
|
||||
mSharedExt.push_back(&it->second);
|
||||
mSharedExt.push_back(it->second);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -347,10 +347,12 @@ namespace MWWorld
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<std::string, ESM::Cell, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
|
||||
typedef std::unordered_map<std::string, ESM::Cell*, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
|
||||
DynamicInt;
|
||||
|
||||
typedef std::map<std::pair<int, int>, ESM::Cell, DynamicExtCmp> DynamicExt;
|
||||
typedef std::map<std::pair<int, int>, ESM::Cell*, DynamicExtCmp> DynamicExt;
|
||||
|
||||
std::unordered_map<ESM::RefId, ESM::Cell> mCells;
|
||||
|
||||
DynamicInt mInt;
|
||||
DynamicExt mExt;
|
||||
@ -367,6 +369,7 @@ namespace MWWorld
|
||||
public:
|
||||
typedef SharedIterator<ESM::Cell> iterator;
|
||||
|
||||
const ESM::Cell* search(const ESM::RefId& id) const;
|
||||
const ESM::Cell* search(std::string_view id) const;
|
||||
const ESM::Cell* search(int x, int y) const;
|
||||
const ESM::Cell* searchStatic(int x, int y) const;
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/esm3/esmwriter.hpp>
|
||||
@ -353,7 +352,7 @@ namespace MWWorld
|
||||
if (bypass && !mStartCell.empty())
|
||||
{
|
||||
ESM::Position pos;
|
||||
if (findExteriorPosition(mStartCell, pos))
|
||||
if (findExteriorPosition(mStartCell, pos).empty())
|
||||
{
|
||||
changeToExteriorCell(pos, true);
|
||||
adjustPosition(getPlayerPtr(), false);
|
||||
@ -378,7 +377,10 @@ namespace MWWorld
|
||||
pos.rot[0] = 0;
|
||||
pos.rot[1] = 0;
|
||||
pos.rot[2] = 0;
|
||||
mWorldScene->changeToExteriorCell(pos, true);
|
||||
|
||||
osg::Vec2i exteriorCellPos = positionToCellIndex(pos.pos[0], pos.pos[1]);
|
||||
ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y());
|
||||
mWorldScene->changeToExteriorCell(cellId, pos, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -974,30 +976,43 @@ namespace MWWorld
|
||||
mPhysics->clearQueuedMovement();
|
||||
mDiscardMovements = true;
|
||||
|
||||
if (changeEvent && mCurrentWorldSpace != ESM::CellId::sDefaultWorldspace)
|
||||
if (changeEvent && mCurrentWorldSpace != ESM::Cell::sDefaultWorldspace)
|
||||
{
|
||||
// changed worldspace
|
||||
mProjectileManager->clear();
|
||||
mRendering->notifyWorldSpaceChanged();
|
||||
}
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
||||
osg::Vec2i exteriorCellPos = positionToCellIndex(position.pos[0], position.pos[1]);
|
||||
ESM::RefId cellId = ESM::RefId::esm3ExteriorCell(exteriorCellPos.x(), exteriorCellPos.y());
|
||||
mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent);
|
||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||
mRendering->getCamera()->instantTransition();
|
||||
}
|
||||
|
||||
void World::changeToCell(
|
||||
const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
{
|
||||
if (!changeEvent)
|
||||
mCurrentWorldSpace = cellId.mWorldspace;
|
||||
const MWWorld::Cell* destinationCell = getWorldModel().getCell(cellId)->getCell();
|
||||
bool exteriorCell = destinationCell->isExterior();
|
||||
|
||||
if (cellId.mPaged)
|
||||
changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
||||
mPhysics->clearQueuedMovement();
|
||||
mDiscardMovements = true;
|
||||
|
||||
if (changeEvent && mCurrentWorldSpace != destinationCell->getNameId())
|
||||
{
|
||||
// changed worldspace
|
||||
mProjectileManager->clear();
|
||||
mRendering->notifyWorldSpaceChanged();
|
||||
mCurrentWorldSpace = destinationCell->getNameId();
|
||||
}
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
if (exteriorCell)
|
||||
mWorldScene->changeToExteriorCell(cellId, position, adjustPlayerPos, changeEvent);
|
||||
else
|
||||
changeToInteriorCell(cellId.mWorldspace, position, adjustPlayerPos, changeEvent);
|
||||
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
mWorldScene->changeToInteriorCell(destinationCell->getNameId(), position, adjustPlayerPos, changeEvent);
|
||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||
mRendering->getCamera()->instantTransition();
|
||||
}
|
||||
|
||||
float World::getMaxActivationDistance() const
|
||||
@ -1169,7 +1184,7 @@ namespace MWWorld
|
||||
if (mWorldScene->isCellActive(*newCell))
|
||||
mWorldScene->changePlayerCell(newCell, pos, false);
|
||||
else
|
||||
mWorldScene->changeToExteriorCell(pos, false);
|
||||
mWorldScene->changeToExteriorCell(newCell->getCell()->getId(), pos, false);
|
||||
}
|
||||
addContainerScripts(getPlayerPtr(), newCell);
|
||||
newPtr = getPlayerPtr();
|
||||
@ -1420,9 +1435,9 @@ namespace MWWorld
|
||||
esmPos.pos[0] = traced.x();
|
||||
esmPos.pos[1] = traced.y();
|
||||
esmPos.pos[2] = traced.z();
|
||||
std::string_view cell;
|
||||
ESM::RefId cell;
|
||||
if (!actor.getCell()->isExterior())
|
||||
cell = actor.getCell()->getCell()->getNameId();
|
||||
cell = actor.getCell()->getCell()->getId();
|
||||
MWWorld::ActionTeleport(cell, esmPos, false).execute(actor);
|
||||
}
|
||||
}
|
||||
@ -2060,24 +2075,7 @@ namespace MWWorld
|
||||
{
|
||||
World::DoorMarker newMarker;
|
||||
newMarker.name = MWClass::Door::getDestination(ref);
|
||||
|
||||
ESM::CellId cellid;
|
||||
if (!ref.mRef.getDestCell().empty())
|
||||
{
|
||||
cellid.mWorldspace = ref.mRef.getDestCell();
|
||||
cellid.mPaged = false;
|
||||
cellid.mIndex.mX = 0;
|
||||
cellid.mIndex.mY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellid.mPaged = true;
|
||||
const osg::Vec2i index
|
||||
= positionToCellIndex(ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1]);
|
||||
cellid.mIndex.mX = index.x();
|
||||
cellid.mIndex.mY = index.y();
|
||||
}
|
||||
newMarker.dest = cellid;
|
||||
newMarker.dest = ref.mRef.getDestCell();
|
||||
|
||||
ESM::Position pos = ref.mData.getPosition();
|
||||
|
||||
@ -2764,7 +2762,7 @@ namespace MWWorld
|
||||
physicActor->enableCollisionBody(enable);
|
||||
}
|
||||
|
||||
bool World::findInteriorPosition(std::string_view name, ESM::Position& pos)
|
||||
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;
|
||||
@ -2772,8 +2770,9 @@ namespace MWWorld
|
||||
MWWorld::CellStore* cellStore = mWorldModel.getInterior(name);
|
||||
|
||||
if (!cellStore)
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
|
||||
ESM::RefId cellId = cellStore->getCell()->getId();
|
||||
std::vector<const MWWorld::CellRef*> sortedDoors;
|
||||
for (const MWWorld::LiveCellRef<ESM::Door>& door : cellStore->getReadOnlyDoors().mList)
|
||||
{
|
||||
@ -2794,19 +2793,8 @@ namespace MWWorld
|
||||
for (const MWWorld::CellRef* door : sortedDoors)
|
||||
{
|
||||
MWWorld::CellStore* source = nullptr;
|
||||
source = mWorldModel.getCell(door->getDestCell());
|
||||
|
||||
// door to exterior
|
||||
if (door->getDestCell().empty())
|
||||
{
|
||||
ESM::Position doorDest = door->getDoorDest();
|
||||
const osg::Vec2i index = positionToCellIndex(doorDest.pos[0], doorDest.pos[1]);
|
||||
source = mWorldModel.getExterior(index.x(), index.y());
|
||||
}
|
||||
// door to interior
|
||||
else
|
||||
{
|
||||
source = mWorldModel.getInterior(door->getDestCell());
|
||||
}
|
||||
if (source)
|
||||
{
|
||||
// Find door leading to our current teleport door
|
||||
@ -2819,7 +2807,7 @@ namespace MWWorld
|
||||
/// not the one pointed to current door.
|
||||
pos = destDoor.mRef.getDoorDest();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2831,7 +2819,7 @@ namespace MWWorld
|
||||
// found the COC position?
|
||||
pos = stat4.mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
}
|
||||
// Fall back to the first static location.
|
||||
@ -2840,7 +2828,7 @@ namespace MWWorld
|
||||
{
|
||||
pos = statics4.begin()->mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
// Fall back to the first static location.
|
||||
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore->getReadOnlyStatics().mList;
|
||||
@ -2848,13 +2836,31 @@ namespace MWWorld
|
||||
{
|
||||
pos = statics.begin()->mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
}
|
||||
|
||||
bool World::findExteriorPosition(std::string_view nameId, ESM::Position& pos)
|
||||
ESM::RefId World::findCellPosition(std::string_view cellName, ESM::Position& pos)
|
||||
{
|
||||
ESM::RefId foundCell;
|
||||
try
|
||||
{
|
||||
foundCell = findInteriorPosition(cellName, pos);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
if (foundCell.empty())
|
||||
{
|
||||
return findExteriorPosition(cellName, pos);
|
||||
}
|
||||
|
||||
return foundCell;
|
||||
}
|
||||
|
||||
ESM::RefId World::findExteriorPosition(std::string_view nameId, ESM::Position& pos)
|
||||
{
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
|
||||
@ -2863,7 +2869,7 @@ namespace MWWorld
|
||||
{
|
||||
ext = mWorldModel.getCell(nameId)->getCell();
|
||||
if (!ext->isExterior())
|
||||
return false;
|
||||
return ESM::RefId();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
@ -2895,10 +2901,10 @@ namespace MWWorld
|
||||
// Note: Z pos will be adjusted by adjustPosition later
|
||||
pos.pos[2] = 0;
|
||||
|
||||
return true;
|
||||
return ext->getId();
|
||||
}
|
||||
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
}
|
||||
|
||||
void World::enableTeleporting(bool enable)
|
||||
@ -3289,10 +3295,10 @@ namespace MWWorld
|
||||
|
||||
// Search for a 'nearest' exterior, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. Will fail for isolated interiors.
|
||||
std::set<std::string_view> checkedCells;
|
||||
std::set<std::string_view> currentCells;
|
||||
std::set<std::string_view> nextCells;
|
||||
nextCells.insert(cell->getCell()->getNameId());
|
||||
std::set<ESM::RefId> checkedCells;
|
||||
std::set<ESM::RefId> currentCells;
|
||||
std::set<ESM::RefId> nextCells;
|
||||
nextCells.insert(cell->getCell()->getId());
|
||||
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
@ -3300,7 +3306,7 @@ namespace MWWorld
|
||||
nextCells.clear();
|
||||
for (const auto& currentCell : currentCells)
|
||||
{
|
||||
MWWorld::CellStore* next = mWorldModel.getInterior(currentCell);
|
||||
MWWorld::CellStore* next = mWorldModel.getCell(currentCell);
|
||||
if (!next)
|
||||
continue;
|
||||
|
||||
@ -3318,7 +3324,7 @@ namespace MWWorld
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string_view dest = ref.mRef.getDestCell();
|
||||
ESM::RefId dest = ref.mRef.getDestCell();
|
||||
if (!checkedCells.count(dest) && !currentCells.count(dest))
|
||||
nextCells.insert(dest);
|
||||
}
|
||||
@ -3342,19 +3348,19 @@ namespace MWWorld
|
||||
// Search for a 'nearest' marker, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. If an exterior is found, jump
|
||||
// to the nearest exterior marker, without further interior searching.
|
||||
std::set<std::string_view> checkedCells;
|
||||
std::set<std::string_view> currentCells;
|
||||
std::set<std::string_view> nextCells;
|
||||
std::set<ESM::RefId> checkedCells;
|
||||
std::set<ESM::RefId> currentCells;
|
||||
std::set<ESM::RefId> nextCells;
|
||||
MWWorld::ConstPtr closestMarker;
|
||||
|
||||
nextCells.insert(ptr.getCell()->getCell()->getNameId());
|
||||
nextCells.insert(ptr.getCell()->getCell()->getId());
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
currentCells = nextCells;
|
||||
nextCells.clear();
|
||||
for (const auto& cell : currentCells)
|
||||
{
|
||||
MWWorld::CellStore* next = mWorldModel.getInterior(cell);
|
||||
MWWorld::CellStore* next = mWorldModel.getCell(cell);
|
||||
checkedCells.insert(cell);
|
||||
if (!next)
|
||||
continue;
|
||||
@ -3440,11 +3446,11 @@ namespace MWWorld
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view cellName = "";
|
||||
ESM::RefId cellId;
|
||||
if (!closestMarker.mCell->isExterior())
|
||||
cellName = closestMarker.mCell->getCell()->getNameId();
|
||||
cellId = closestMarker.mCell->getCell()->getId();
|
||||
|
||||
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false);
|
||||
MWWorld::ActionTeleport action(cellId, closestMarker.getRefData().getPosition(), false);
|
||||
action.execute(ptr);
|
||||
}
|
||||
|
||||
@ -3646,13 +3652,13 @@ namespace MWWorld
|
||||
Log(Debug::Warning) << "Failed to confiscate items: no closest prison marker found.";
|
||||
return;
|
||||
}
|
||||
std::string_view prisonName = prisonMarker.getCellRef().getDestCell();
|
||||
ESM::RefId prisonName = prisonMarker.getCellRef().getDestCell();
|
||||
if (prisonName.empty())
|
||||
{
|
||||
Log(Debug::Warning) << "Failed to confiscate items: prison marker not linked to prison interior";
|
||||
return;
|
||||
}
|
||||
MWWorld::CellStore* prison = mWorldModel.getInterior(prisonName);
|
||||
MWWorld::CellStore* prison = mWorldModel.getCell(prisonName);
|
||||
if (!prison)
|
||||
{
|
||||
Log(Debug::Warning) << "Failed to confiscate items: failed to load cell " << prisonName;
|
||||
|
@ -349,7 +349,7 @@ namespace MWWorld
|
||||
///< Move to exterior cell.
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
void changeToCell(const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos,
|
||||
void changeToCell(const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos,
|
||||
bool changeEvent = true) override;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
@ -601,12 +601,12 @@ namespace MWWorld
|
||||
|
||||
/// Find center of exterior cell above land surface
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
bool findExteriorPosition(std::string_view nameId, ESM::Position& pos) override;
|
||||
ESM::RefId findExteriorPosition(std::string_view nameId, ESM::Position& pos) override;
|
||||
|
||||
/// Find position in interior cell near door entrance
|
||||
/// \return false if interior with given name not exists, true otherwise
|
||||
bool findInteriorPosition(std::string_view name, ESM::Position& pos) override;
|
||||
|
||||
ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) override;
|
||||
ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) override;
|
||||
/// Enables or disables use of teleport spell effects (recall, intervention, etc).
|
||||
void enableTeleporting(bool enable) override;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/cellref.hpp>
|
||||
#include <components/esm3/cellstate.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
@ -20,7 +21,8 @@
|
||||
namespace
|
||||
{
|
||||
template <class Visitor, class Key, class Comp>
|
||||
bool forEachInStore(const ESM::RefId& id, Visitor&& visitor, std::map<Key, MWWorld::CellStore, Comp>& cellStore)
|
||||
bool forEachInStore(
|
||||
const ESM::RefId& id, Visitor&& visitor, std::unordered_map<Key, MWWorld::CellStore, Comp>& cellStore)
|
||||
{
|
||||
for (auto& cell : cellStore)
|
||||
{
|
||||
@ -62,27 +64,25 @@ namespace
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
|
||||
{
|
||||
CellStore* cellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second;
|
||||
if (cell->mData.mFlags & ESM::Cell::Interior)
|
||||
{
|
||||
auto result = mInteriors.find(cell->mName);
|
||||
|
||||
if (result == mInteriors.end())
|
||||
result = mInteriors.emplace(cell->mName, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
result = mInteriors.emplace(cell->mName, cellStore).first;
|
||||
|
||||
return &result->second;
|
||||
return result->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::pair<int, int>, CellStore>::iterator result
|
||||
std::map<std::pair<int, int>, CellStore*>::iterator result
|
||||
= mExteriors.find(std::make_pair(cell->getGridX(), cell->getGridY()));
|
||||
|
||||
if (result == mExteriors.end())
|
||||
result = mExteriors
|
||||
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()),
|
||||
CellStore(MWWorld::Cell(*cell), mStore, mReaders))
|
||||
.first;
|
||||
result = mExteriors.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), cellStore).first;
|
||||
|
||||
return &result->second;
|
||||
return result->second;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +93,7 @@ void MWWorld::WorldModel::clear()
|
||||
mLastGeneratedRefnum = ESM::RefNum{};
|
||||
mInteriors.clear();
|
||||
mExteriors.clear();
|
||||
mCells.clear();
|
||||
std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair(ESM::RefId(), (MWWorld::CellStore*)nullptr));
|
||||
mIdCacheIndex = 0;
|
||||
}
|
||||
@ -143,7 +144,8 @@ void MWWorld::WorldModel::writeCell(ESM::ESMWriter& writer, CellStore& cell) con
|
||||
cell.saveState(cellState);
|
||||
|
||||
writer.startRecord(ESM::REC_CSTA);
|
||||
cellState.mId.save(writer);
|
||||
|
||||
writer.writeCellId(cellState.mId);
|
||||
cellState.save(writer);
|
||||
cell.writeFog(writer);
|
||||
cell.writeReferences(writer);
|
||||
@ -160,7 +162,7 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
|
||||
{
|
||||
std::map<std::pair<int, int>, CellStore>::iterator result = mExteriors.find(std::make_pair(x, y));
|
||||
std::map<std::pair<int, int>, CellStore*>::iterator result = mExteriors.find(std::make_pair(x, y));
|
||||
|
||||
if (result == mExteriors.end())
|
||||
{
|
||||
@ -170,29 +172,27 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
|
||||
{
|
||||
// Cell isn't predefined. Make one on the fly.
|
||||
ESM::Cell record;
|
||||
record.mCellId.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
record.mCellId.mPaged = true;
|
||||
record.mCellId.mIndex.mX = x;
|
||||
record.mCellId.mIndex.mY = y;
|
||||
|
||||
record.mData.mFlags = ESM::Cell::HasWater;
|
||||
record.mData.mX = x;
|
||||
record.mData.mY = y;
|
||||
record.mWater = 0;
|
||||
record.mMapColor = 0;
|
||||
record.updateId();
|
||||
|
||||
cell = MWBase::Environment::get().getWorld()->createRecord(record);
|
||||
}
|
||||
|
||||
result = mExteriors.emplace(std::make_pair(x, y), CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
CellStore* cellStore
|
||||
= &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second;
|
||||
result = mExteriors.emplace(std::make_pair(x, y), cellStore).first;
|
||||
}
|
||||
|
||||
if (result->second.getState() != CellStore::State_Loaded)
|
||||
if (result->second->getState() != CellStore::State_Loaded)
|
||||
{
|
||||
result->second.load();
|
||||
result->second->load();
|
||||
}
|
||||
|
||||
return &result->second;
|
||||
return result->second;
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
|
||||
@ -202,32 +202,85 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
|
||||
if (result == mInteriors.end())
|
||||
{
|
||||
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().searchCellName(name);
|
||||
|
||||
CellStore* newCellStore = nullptr;
|
||||
if (!cell4)
|
||||
{
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().find(name);
|
||||
result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first;
|
||||
newCellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mInteriors.emplace(name, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first;
|
||||
newCellStore
|
||||
= &mCells.emplace(cell4->mId, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first->second;
|
||||
}
|
||||
result = mInteriors.emplace(name, newCellStore).first;
|
||||
}
|
||||
|
||||
if (result->second.getState() != CellStore::State_Loaded)
|
||||
if (result->second->getState() != CellStore::State_Loaded)
|
||||
{
|
||||
result->second.load();
|
||||
result->second->load();
|
||||
}
|
||||
|
||||
return &result->second;
|
||||
return result->second;
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
||||
struct VisitorCellIdIsESM3Ext
|
||||
{
|
||||
if (id.mPaged)
|
||||
return getExterior(id.mIndex.mX, id.mIndex.mY);
|
||||
bool operator()(const ESM::ESM3ExteriorCellRefId& id)
|
||||
{
|
||||
coordOut = { id.getX(), id.getY() };
|
||||
return true;
|
||||
}
|
||||
|
||||
return getInterior(id.mWorldspace);
|
||||
template <typename T>
|
||||
bool operator()(const T&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::pair<int32_t, int32_t> coordOut = {};
|
||||
};
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id)
|
||||
{
|
||||
auto result = mCells.find(id);
|
||||
if (result != mCells.end())
|
||||
return &result->second;
|
||||
|
||||
VisitorCellIdIsESM3Ext isESM3ExteriorVisitor;
|
||||
|
||||
if (visit(isESM3ExteriorVisitor, id)) // That is an exterior cell Id
|
||||
{
|
||||
|
||||
return getExterior(isESM3ExteriorVisitor.coordOut.first, isESM3ExteriorVisitor.coordOut.second);
|
||||
}
|
||||
|
||||
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().search(id);
|
||||
CellStore* newCellStore = nullptr;
|
||||
if (!cell4)
|
||||
{
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().search(id);
|
||||
newCellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
newCellStore = &mCells.emplace(cell4->mId, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first->second;
|
||||
}
|
||||
if (newCellStore->getCell()->isExterior())
|
||||
{
|
||||
std::pair<int, int> coord
|
||||
= std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY());
|
||||
mExteriors.emplace(coord, newCellStore);
|
||||
}
|
||||
else
|
||||
{
|
||||
mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore);
|
||||
}
|
||||
if (newCellStore->getState() != CellStore::State_Loaded)
|
||||
{
|
||||
newCellStore->load();
|
||||
}
|
||||
return newCellStore;
|
||||
}
|
||||
|
||||
const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name)
|
||||
@ -329,17 +382,17 @@ MWWorld::Ptr MWWorld::WorldModel::getPtr(const ESM::RefId& name)
|
||||
// Then check cells that are already listed
|
||||
// Search in reverse, this is a workaround for an ambiguous chargen_plank reference in the vanilla game.
|
||||
// there is one at -22,16 and one at -2,-9, the latter should be used.
|
||||
for (std::map<std::pair<int, int>, CellStore>::reverse_iterator iter = mExteriors.rbegin();
|
||||
for (std::map<std::pair<int, int>, CellStore*>::reverse_iterator iter = mExteriors.rbegin();
|
||||
iter != mExteriors.rend(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache(name, iter->second);
|
||||
Ptr ptr = getPtrAndCache(name, *iter->second);
|
||||
if (!ptr.isEmpty())
|
||||
return ptr;
|
||||
}
|
||||
|
||||
for (auto iter = mInteriors.begin(); iter != mInteriors.end(); ++iter)
|
||||
{
|
||||
Ptr ptr = getPtrAndCache(name, iter->second);
|
||||
Ptr ptr = getPtrAndCache(name, *iter->second);
|
||||
if (!ptr.isEmpty())
|
||||
return ptr;
|
||||
}
|
||||
@ -389,8 +442,7 @@ void MWWorld::WorldModel::getExteriorPtrs(const ESM::RefId& name, std::vector<MW
|
||||
std::vector<MWWorld::Ptr> MWWorld::WorldModel::getAll(const ESM::RefId& id)
|
||||
{
|
||||
PtrCollector visitor;
|
||||
if (forEachInStore(id, visitor, mInteriors))
|
||||
forEachInStore(id, visitor, mExteriors);
|
||||
forEachInStore(id, visitor, mCells);
|
||||
return visitor.mPtrs;
|
||||
}
|
||||
|
||||
@ -398,12 +450,7 @@ int MWWorld::WorldModel::countSavedGameRecords() const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (auto iter(mInteriors.begin()); iter != mInteriors.end(); ++iter)
|
||||
if (iter->second.hasState())
|
||||
++count;
|
||||
|
||||
for (std::map<std::pair<int, int>, CellStore>::const_iterator iter(mExteriors.begin()); iter != mExteriors.end();
|
||||
++iter)
|
||||
for (auto iter(mCells.begin()); iter != mCells.end(); ++iter)
|
||||
if (iter->second.hasState())
|
||||
++count;
|
||||
|
||||
@ -412,14 +459,7 @@ int MWWorld::WorldModel::countSavedGameRecords() const
|
||||
|
||||
void MWWorld::WorldModel::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
{
|
||||
for (std::map<std::pair<int, int>, CellStore>::iterator iter(mExteriors.begin()); iter != mExteriors.end(); ++iter)
|
||||
if (iter->second.hasState())
|
||||
{
|
||||
writeCell(writer, iter->second);
|
||||
progress.increaseProgress();
|
||||
}
|
||||
|
||||
for (auto iter(mInteriors.begin()); iter != mInteriors.end(); ++iter)
|
||||
for (auto iter(mCells.begin()); iter != mCells.end(); ++iter)
|
||||
if (iter->second.hasState())
|
||||
{
|
||||
writeCell(writer, iter->second);
|
||||
@ -437,7 +477,7 @@ public:
|
||||
|
||||
MWWorld::WorldModel& mWorldModel;
|
||||
|
||||
MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) override
|
||||
MWWorld::CellStore* getCellStore(const ESM::RefId& cellId) override
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -455,7 +495,7 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, cons
|
||||
if (type == ESM::REC_CSTA)
|
||||
{
|
||||
ESM::CellState state;
|
||||
state.mId.load(reader);
|
||||
state.mId = reader.getCellId();
|
||||
|
||||
CellStore* cellStore = nullptr;
|
||||
|
||||
@ -466,8 +506,7 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, cons
|
||||
catch (...)
|
||||
{
|
||||
// silently drop cells that don't exist anymore
|
||||
Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId.mWorldspace
|
||||
<< " (cell no longer exists)";
|
||||
Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId << " (cell no longer exists)";
|
||||
reader.skipRecord();
|
||||
return true;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ namespace ESM
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
class ReadersCache;
|
||||
struct CellId;
|
||||
struct Cell;
|
||||
struct RefNum;
|
||||
}
|
||||
@ -42,8 +41,9 @@ namespace MWWorld
|
||||
typedef std::vector<std::pair<ESM::RefId, CellStore*>> IdCache;
|
||||
const MWWorld::ESMStore& mStore;
|
||||
ESM::ReadersCache& mReaders;
|
||||
mutable std::map<std::string, CellStore, Misc::StringUtils::CiComp> mInteriors;
|
||||
mutable std::map<std::pair<int, int>, CellStore> mExteriors;
|
||||
mutable std::unordered_map<ESM::RefId, CellStore> mCells;
|
||||
mutable std::map<std::string, CellStore*, Misc::StringUtils::CiComp> mInteriors;
|
||||
mutable std::map<std::pair<int, int>, CellStore*> mExteriors;
|
||||
IdCache mIdCache;
|
||||
std::size_t mIdCacheIndex = 0;
|
||||
std::unordered_map<ESM::RefNum, Ptr> mPtrIndex;
|
||||
@ -69,7 +69,7 @@ namespace MWWorld
|
||||
CellStore* getExterior(int x, int y);
|
||||
CellStore* getInterior(std::string_view name);
|
||||
CellStore* getCell(std::string_view name); // interior or named exterior
|
||||
CellStore* getCell(const ESM::CellId& Id);
|
||||
CellStore* getCell(const ESM::RefId& Id);
|
||||
|
||||
// If cellNameInSameWorldSpace is an interior - returns this interior.
|
||||
// Otherwise returns exterior cell for given position in the same world space.
|
||||
@ -91,9 +91,7 @@ namespace MWWorld
|
||||
template <typename Fn>
|
||||
void forEachLoadedCellStore(Fn&& fn)
|
||||
{
|
||||
for (auto& [_, store] : mInteriors)
|
||||
fn(store);
|
||||
for (auto& [_, store] : mExteriors)
|
||||
for (auto& [_, store] : mCells)
|
||||
fn(store);
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,12 @@ namespace ESM
|
||||
static RefId call() { return RefId::index(REC_BOOK, 7); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GenerateRefId<ESM3ExteriorCellRefId>
|
||||
{
|
||||
static RefId call() { return RefId::esm3ExteriorCell(-12, 7); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ESMRefIdTypesTest : Test
|
||||
{
|
||||
|
@ -248,16 +248,10 @@ namespace ESM
|
||||
record.mObject.mRef.mRefID = generateRandomRefId();
|
||||
std::generate_n(std::inserter(record.mPreviousItems, record.mPreviousItems.end()), 2,
|
||||
[&] { return std::make_pair(generateRandomRefId(), generateRandomRefId()); });
|
||||
record.mCellId.mWorldspace = "worldspace1";
|
||||
record.mCellId.mIndex.mX = 42;
|
||||
record.mCellId.mIndex.mY = 13;
|
||||
record.mCellId.mPaged = true;
|
||||
record.mCellId = ESM::RefId::esm3ExteriorCell(0, 0);
|
||||
generateArray(record.mLastKnownExteriorPosition);
|
||||
record.mHasMark = true;
|
||||
record.mMarkedCell.mWorldspace = "worldspace2";
|
||||
record.mMarkedCell.mIndex.mX = 0;
|
||||
record.mMarkedCell.mIndex.mY = 0;
|
||||
record.mMarkedCell.mPaged = false;
|
||||
record.mMarkedCell = ESM::RefId::esm3ExteriorCell(0, 0);
|
||||
generateArray(record.mMarkedPosition.pos);
|
||||
generateArray(record.mMarkedPosition.rot);
|
||||
record.mCurrentCrimeId = 42;
|
||||
@ -267,16 +261,11 @@ namespace ESM
|
||||
EXPECT_EQ(record.mBirthsign, result.mBirthsign);
|
||||
EXPECT_EQ(record.mPreviousItems, result.mPreviousItems);
|
||||
EXPECT_EQ(record.mPreviousItems, result.mPreviousItems);
|
||||
EXPECT_EQ(record.mCellId.mWorldspace, result.mCellId.mWorldspace);
|
||||
EXPECT_EQ(record.mCellId.mIndex.mX, result.mCellId.mIndex.mX);
|
||||
EXPECT_EQ(record.mCellId.mIndex.mY, result.mCellId.mIndex.mY);
|
||||
EXPECT_EQ(record.mCellId.mPaged, result.mCellId.mPaged);
|
||||
EXPECT_EQ(record.mCellId, result.mCellId);
|
||||
|
||||
EXPECT_THAT(record.mLastKnownExteriorPosition, ElementsAreArray(result.mLastKnownExteriorPosition));
|
||||
EXPECT_EQ(record.mHasMark, result.mHasMark);
|
||||
EXPECT_EQ(record.mMarkedCell.mWorldspace, result.mMarkedCell.mWorldspace);
|
||||
EXPECT_EQ(record.mMarkedCell.mIndex.mX, result.mMarkedCell.mIndex.mX);
|
||||
EXPECT_EQ(record.mMarkedCell.mIndex.mY, result.mMarkedCell.mIndex.mY);
|
||||
EXPECT_EQ(record.mMarkedCell.mPaged, result.mMarkedCell.mPaged);
|
||||
EXPECT_EQ(record.mMarkedCell, result.mMarkedCell);
|
||||
EXPECT_THAT(record.mMarkedPosition.pos, ElementsAreArray(result.mMarkedPosition.pos));
|
||||
EXPECT_THAT(record.mMarkedPosition.rot, ElementsAreArray(result.mMarkedPosition.rot));
|
||||
EXPECT_EQ(record.mCurrentCrimeId, result.mCurrentCrimeId);
|
||||
|
@ -285,6 +285,7 @@ namespace
|
||||
ESM::MaxOldSkillsAndAttributesFormatVersion,
|
||||
ESM::MaxOldCreatureStatsFormatVersion,
|
||||
ESM::MaxStringRefIdFormatVersion,
|
||||
ESM::MaxUseEsmCellIdFormatVersion,
|
||||
});
|
||||
for (ESM::FormatVersion v = result.back() + 1; v <= ESM::CurrentSaveGameFormatVersion; ++v)
|
||||
result.push_back(v);
|
||||
@ -445,6 +446,10 @@ namespace
|
||||
decltype(RecordType::mId) refId;
|
||||
if constexpr (ESM::hasIndex<RecordType> && !std::is_same_v<RecordType, ESM::LandTexture>)
|
||||
refId = RecordType::indexToRefId(index);
|
||||
else if constexpr (std::is_same_v<RecordType, ESM::Cell>)
|
||||
{
|
||||
refId = ESM::RefId::esm3ExteriorCell(0, 0);
|
||||
}
|
||||
else
|
||||
refId = ESM::StringRefId(stringId);
|
||||
|
||||
@ -562,7 +567,7 @@ namespace
|
||||
|
||||
REGISTER_TYPED_TEST_SUITE_P(StoreSaveLoadTest, shouldNotChangeRefId);
|
||||
|
||||
static_assert(std::tuple_size_v<RecordTypesWithSave> == 38);
|
||||
static_assert(std::tuple_size_v<RecordTypesWithSave> == 39);
|
||||
|
||||
INSTANTIATE_TYPED_TEST_SUITE_P(
|
||||
RecordTypesTest, StoreSaveLoadTest, typename AsTestingTypes<RecordTypesWithSave>::Type);
|
||||
|
@ -91,6 +91,7 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format
|
||||
generatedrefid
|
||||
indexrefid
|
||||
serializerefid
|
||||
esm3exteriorcellrefid
|
||||
)
|
||||
|
||||
add_component_dir(fx pass technique lexer widgets stateupdater)
|
||||
@ -391,7 +392,7 @@ if (USE_QT)
|
||||
)
|
||||
|
||||
add_component_qt_dir (misc
|
||||
helpviewer utf8qtextstream
|
||||
helpviewer utf8qtextstream hash
|
||||
)
|
||||
|
||||
add_component_qt_dir (files
|
||||
|
36
components/esm/esm3exteriorcellrefid.cpp
Normal file
36
components/esm/esm3exteriorcellrefid.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "esm3exteriorcellrefid.hpp"
|
||||
#include "serializerefid.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
std::string ESM3ExteriorCellRefId::toString() const
|
||||
{
|
||||
std::string result;
|
||||
std::size_t integralSizeX = getIntegralSize(mX);
|
||||
result.resize(integralSizeX + getIntegralSize(mY) + 3, '\0');
|
||||
serializeIntegral(mX, 0, result);
|
||||
result[integralSizeX] = ':';
|
||||
serializeIntegral(mY, integralSizeX + 1, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ESM3ExteriorCellRefId::toDebugString() const
|
||||
{
|
||||
std::string result;
|
||||
std::size_t integralSizeX = getIntegralSize(mX);
|
||||
|
||||
serializeRefIdPrefix(integralSizeX + getIntegralSize(mY) + 1, esm3ExteriorCellRefIdPrefix, result);
|
||||
serializeIntegral(mX, esm3ExteriorCellRefIdPrefix.size(), result);
|
||||
result[esm3ExteriorCellRefIdPrefix.size() + integralSizeX] = ':';
|
||||
serializeIntegral(mY, esm3ExteriorCellRefIdPrefix.size() + integralSizeX + 1, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, ESM3ExteriorCellRefId value)
|
||||
{
|
||||
return stream << "Vec2i{" << value.mX << "," << value.mY << '}';
|
||||
}
|
||||
}
|
57
components/esm/esm3exteriorcellrefid.hpp
Normal file
57
components/esm/esm3exteriorcellrefid.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef OPENMW_COMPONENTS_ESM_ESM3EXTERIORCELLREFID_HPP
|
||||
#define OPENMW_COMPONENTS_ESM_ESM3EXTERIORCELLREFID_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <components/misc/hash.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESM3ExteriorCellRefId
|
||||
{
|
||||
public:
|
||||
constexpr ESM3ExteriorCellRefId() = default;
|
||||
|
||||
constexpr explicit ESM3ExteriorCellRefId(int32_t x, int32_t y) noexcept
|
||||
: mX(x)
|
||||
, mY(y)
|
||||
{
|
||||
}
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
std::string toDebugString() const;
|
||||
|
||||
int32_t getX() const { return mX; }
|
||||
int32_t getY() const { return mY; }
|
||||
|
||||
constexpr bool operator==(ESM3ExteriorCellRefId rhs) const noexcept { return mX == rhs.mX && mY == rhs.mY; }
|
||||
|
||||
constexpr bool operator<(ESM3ExteriorCellRefId rhs) const noexcept { return mX < rhs.mX && mY < rhs.mY; }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, ESM3ExteriorCellRefId value);
|
||||
|
||||
friend struct std::hash<ESM3ExteriorCellRefId>;
|
||||
|
||||
private:
|
||||
int32_t mX = 0;
|
||||
int32_t mY = 0;
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<ESM::ESM3ExteriorCellRefId>
|
||||
{
|
||||
std::size_t operator()(ESM::ESM3ExteriorCellRefId value) const noexcept
|
||||
{
|
||||
return Misc::hash2dCoord(value.mX, value.mY);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -15,7 +15,6 @@ namespace ESM4
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
struct CellId;
|
||||
class RefId;
|
||||
|
||||
class CellVariant;
|
||||
|
@ -237,6 +237,13 @@ namespace ESM
|
||||
return ESM::RefId::index(recordType,
|
||||
deserializeIntegral<std::uint32_t>(indexRefIdPrefix.size() + sizeof(recordType) + 1, value));
|
||||
}
|
||||
if (value.starts_with(esm3ExteriorCellRefIdPrefix))
|
||||
{
|
||||
std::int32_t x = deserializeIntegral<std::int32_t>(esm3ExteriorCellRefIdPrefix.size(), value);
|
||||
std::int32_t y
|
||||
= deserializeIntegral<std::int32_t>(esm3ExteriorCellRefIdPrefix.size() + getIntegralSize(x) + 1, value);
|
||||
return ESM::ESM3ExteriorCellRefId(x, y);
|
||||
}
|
||||
|
||||
return ESM::RefId::stringRefId(value);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <components/misc/notnullptr.hpp>
|
||||
|
||||
#include "esm3exteriorcellrefid.hpp"
|
||||
#include "formidrefid.hpp"
|
||||
#include "generatedrefid.hpp"
|
||||
#include "indexrefid.hpp"
|
||||
@ -38,6 +39,7 @@ namespace ESM
|
||||
FormId = 3,
|
||||
Generated = 4,
|
||||
Index = 5,
|
||||
ESM3ExteriorCell = 6,
|
||||
};
|
||||
|
||||
// RefId is used to represent an Id that identifies an ESM record. These Ids can then be used in
|
||||
@ -48,7 +50,8 @@ namespace ESM
|
||||
public:
|
||||
const static RefId sEmpty;
|
||||
|
||||
using Value = std::variant<EmptyRefId, StringRefId, FormIdRefId, GeneratedRefId, IndexRefId>;
|
||||
using Value
|
||||
= std::variant<EmptyRefId, StringRefId, FormIdRefId, GeneratedRefId, IndexRefId, ESM3ExteriorCellRefId>;
|
||||
|
||||
// Constructs RefId from a serialized string containing byte by byte copy of RefId::mValue.
|
||||
static ESM::RefId deserialize(std::string_view value);
|
||||
@ -70,6 +73,8 @@ namespace ESM
|
||||
// identified by index (i.e. ESM3 SKIL).
|
||||
static RefId index(RecNameInts recordType, std::uint32_t value) { return RefId(IndexRefId(recordType, value)); }
|
||||
|
||||
static RefId esm3ExteriorCell(int32_t x, int32_t y) { return RefId(ESM3ExteriorCellRefId(x, y)); }
|
||||
|
||||
constexpr RefId() = default;
|
||||
|
||||
constexpr RefId(EmptyRefId value) noexcept
|
||||
@ -97,6 +102,11 @@ namespace ESM
|
||||
{
|
||||
}
|
||||
|
||||
constexpr RefId(ESM3ExteriorCellRefId value) noexcept
|
||||
: mValue(value)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns a reference to the value of StringRefId if it's the underlying value or throws an exception.
|
||||
const std::string& getRefIdString() const;
|
||||
|
||||
|
@ -12,6 +12,7 @@ namespace ESM
|
||||
constexpr std::string_view formIdRefIdPrefix = "FormId:";
|
||||
constexpr std::string_view generatedRefIdPrefix = "Generated:";
|
||||
constexpr std::string_view indexRefIdPrefix = "Index:";
|
||||
constexpr std::string_view esm3ExteriorCellRefIdPrefix = "Esm3ExteriorCell:";
|
||||
|
||||
template <class T>
|
||||
std::size_t getIntegralSize(T value)
|
||||
|
@ -2,12 +2,11 @@
|
||||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
#include <components/misc/algorithm.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
const std::string CellId::sDefaultWorldspace = "sys::default";
|
||||
|
||||
void CellId::load(ESMReader& esm)
|
||||
{
|
||||
mWorldspace = esm.getHNString("SPAC");
|
||||
@ -33,6 +32,46 @@ namespace ESM
|
||||
esm.writeHNT("CIDX", mIndex, 8);
|
||||
}
|
||||
|
||||
struct VisitCellRefId
|
||||
{
|
||||
CellId operator()(const ESM::EmptyRefId)
|
||||
{
|
||||
CellId out;
|
||||
out.mPaged = true;
|
||||
out.mIndex = {};
|
||||
return out;
|
||||
}
|
||||
|
||||
CellId operator()(const ESM::StringRefId& id)
|
||||
{
|
||||
CellId out;
|
||||
out.mPaged = false;
|
||||
out.mWorldspace = id.getValue();
|
||||
out.mIndex = { 0, 0 };
|
||||
return out;
|
||||
}
|
||||
CellId operator()(const ESM::ESM3ExteriorCellRefId& id)
|
||||
{
|
||||
CellId out;
|
||||
out.mPaged = true;
|
||||
out.mIndex = { id.getX(), id.getY() };
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
CellId operator()(const T& id)
|
||||
{
|
||||
throw std::runtime_error("cannot extract CellId from this Id type");
|
||||
}
|
||||
};
|
||||
|
||||
CellId CellId::extractFromRefId(const ESM::RefId& id)
|
||||
{
|
||||
// This is bad and that code should not be merged.
|
||||
|
||||
return visit(VisitCellRefId(), id);
|
||||
}
|
||||
|
||||
bool operator==(const CellId& left, const CellId& right)
|
||||
{
|
||||
return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged
|
||||
|
@ -21,10 +21,11 @@ namespace ESM
|
||||
CellIndex mIndex;
|
||||
bool mPaged;
|
||||
|
||||
static const std::string sDefaultWorldspace;
|
||||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
|
||||
// TODO tetramir: this probably shouldn't exist, needs it because some CellIds are saved on disk
|
||||
static CellId extractFromRefId(const ESM::RefId& id);
|
||||
};
|
||||
|
||||
bool operator==(const CellId& left, const CellId& right);
|
||||
|
@ -21,7 +21,7 @@ namespace ESM
|
||||
|
||||
void CellState::save(ESMWriter& esm) const
|
||||
{
|
||||
if (!mId.mPaged)
|
||||
if (mIsInterior)
|
||||
esm.writeHNT("WLVL", mWaterLevel);
|
||||
|
||||
esm.writeHNT("HFOW", mHasFogOfWar);
|
||||
|
@ -1,9 +1,8 @@
|
||||
#ifndef OPENMW_ESM_CELLSTATE_H
|
||||
#define OPENMW_ESM_CELLSTATE_H
|
||||
|
||||
#include "cellid.hpp"
|
||||
|
||||
#include "components/esm/defs.hpp"
|
||||
#include "components/esm/refid.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -15,8 +14,8 @@ namespace ESM
|
||||
/// \note Does not include references
|
||||
struct CellState
|
||||
{
|
||||
CellId mId;
|
||||
|
||||
RefId mId;
|
||||
bool mIsInterior;
|
||||
float mWaterLevel;
|
||||
|
||||
int mHasFogOfWar; // Do we have fog of war state (0 or 1)? (see fogstate.hpp)
|
||||
|
@ -10,7 +10,7 @@ namespace ESM
|
||||
{
|
||||
esm.writeHNT("POSX", mWorldX);
|
||||
esm.writeHNT("POSY", mWorldY);
|
||||
mCell.save(esm);
|
||||
esm.writeCellId(mCell);
|
||||
if (!mNote.empty())
|
||||
esm.writeHNString("NOTE", mNote);
|
||||
}
|
||||
@ -19,7 +19,7 @@ namespace ESM
|
||||
{
|
||||
esm.getHNT(mWorldX, "POSX");
|
||||
esm.getHNT(mWorldY, "POSY");
|
||||
mCell.load(esm);
|
||||
mCell = esm.getCellId();
|
||||
mNote = esm.getHNOString("NOTE");
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
#ifndef OPENMW_ESM_CUSTOMMARKERSTATE_H
|
||||
#define OPENMW_ESM_CUSTOMMARKERSTATE_H
|
||||
|
||||
#include "cellid.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
struct CustomMarker
|
||||
@ -12,7 +14,7 @@ namespace ESM
|
||||
float mWorldX;
|
||||
float mWorldY;
|
||||
|
||||
CellId mCell;
|
||||
RefId mCell;
|
||||
|
||||
std::string mNote;
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "readerscache.hpp"
|
||||
#include "savedgame.hpp"
|
||||
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/files/openfile.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
@ -86,6 +88,24 @@ namespace ESM
|
||||
}
|
||||
}
|
||||
|
||||
ESM::RefId ESMReader::getCellId()
|
||||
{
|
||||
if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellIdFormatVersion)
|
||||
{
|
||||
ESM::CellId cellId;
|
||||
cellId.load(*this);
|
||||
if (cellId.mPaged)
|
||||
{
|
||||
return ESM::RefId::esm3ExteriorCell(cellId.mIndex.mX, cellId.mIndex.mY);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESM::RefId::stringRefId(cellId.mWorldspace);
|
||||
}
|
||||
}
|
||||
return getHNRefId("NAME");
|
||||
}
|
||||
|
||||
void ESMReader::openRaw(std::unique_ptr<std::istream>&& stream, const std::filesystem::path& name)
|
||||
{
|
||||
close();
|
||||
@ -471,6 +491,13 @@ namespace ESM
|
||||
getExact(&index, sizeof(std::uint32_t));
|
||||
return RefId::index(recordType, index);
|
||||
}
|
||||
case RefIdType::ESM3ExteriorCell:
|
||||
{
|
||||
int32_t x, y;
|
||||
getExact(&x, sizeof(std::int32_t));
|
||||
getExact(&y, sizeof(std::int32_t));
|
||||
return RefId::esm3ExteriorCell(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
fail("Unsupported RefIdType: " + std::to_string(static_cast<unsigned>(refIdType)));
|
||||
|
@ -96,6 +96,9 @@ namespace ESM
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
// Because we want to get rid of CellId, we isolate it's uses.
|
||||
ESM::RefId getCellId();
|
||||
|
||||
// Read data of a given type, stored in a subrecord of a given name
|
||||
template <typename X>
|
||||
void getHNT(X& x, NAME name)
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/misc/notnullptr.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
|
||||
@ -60,6 +61,13 @@ namespace ESM
|
||||
mWriter.writeT(v.getRecordType());
|
||||
mWriter.writeT(v.getValue());
|
||||
}
|
||||
|
||||
void operator()(ESM3ExteriorCellRefId v) const
|
||||
{
|
||||
mWriter.writeT(RefIdType::ESM3ExteriorCell);
|
||||
mWriter.writeT(v.getX());
|
||||
mWriter.writeT(v.getY());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -236,6 +244,17 @@ namespace ESM
|
||||
writeHNRefId(name, value);
|
||||
}
|
||||
|
||||
void ESMWriter::writeCellId(const ESM::RefId& cellId)
|
||||
{
|
||||
if (mHeader.mFormatVersion <= ESM::MaxUseEsmCellIdFormatVersion)
|
||||
{
|
||||
ESM::CellId generatedCellid = ESM::CellId::extractFromRefId(cellId);
|
||||
generatedCellid.save(*this);
|
||||
}
|
||||
else
|
||||
writeHNRefId("NAME", cellId);
|
||||
}
|
||||
|
||||
void ESMWriter::writeMaybeFixedSizeString(const std::string& data, std::size_t size)
|
||||
{
|
||||
std::string string;
|
||||
|
@ -103,6 +103,8 @@ namespace ESM
|
||||
writeHNCRefId(name, value);
|
||||
}
|
||||
|
||||
void writeCellId(const ESM::RefId& cellId);
|
||||
|
||||
template <typename T>
|
||||
void writeHNT(NAME name, const T& data)
|
||||
{
|
||||
|
@ -23,7 +23,8 @@ namespace ESM
|
||||
inline constexpr FormatVersion MaxStringRefIdFormatVersion = 23;
|
||||
inline constexpr FormatVersion MaxSavedGameCellNameAsRefIdFormatVersion = 24;
|
||||
inline constexpr FormatVersion MaxNameIsRefIdOnlyFormatVersion = 25;
|
||||
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 26;
|
||||
inline constexpr FormatVersion MaxUseEsmCellIdFormatVersion = 26;
|
||||
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 27;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
#include "cellid.hpp"
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
@ -40,6 +39,8 @@ namespace ESM
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
const std::string Cell::sDefaultWorldspace = "sys::default";
|
||||
|
||||
// Some overloaded compare operators.
|
||||
bool operator==(const MovedCellRef& ref, const RefNum& refNum)
|
||||
{
|
||||
@ -57,6 +58,24 @@ namespace ESM
|
||||
loadCell(esm, saveContext);
|
||||
}
|
||||
|
||||
const ESM::RefId& Cell::updateId()
|
||||
{
|
||||
mId = generateIdForCell(isExterior(), mName, getGridX(), getGridY());
|
||||
return mId;
|
||||
}
|
||||
|
||||
ESM::RefId Cell::generateIdForCell(bool exterior, std::string_view cellName, int x, int y)
|
||||
{
|
||||
if (!exterior)
|
||||
{
|
||||
return ESM::RefId::stringRefId(cellName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESM::RefId::esm3ExteriorCell(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void Cell::loadNameAndData(ESMReader& esm, bool& isDeleted)
|
||||
{
|
||||
isDeleted = false;
|
||||
@ -91,20 +110,7 @@ namespace ESM
|
||||
if (!hasData)
|
||||
esm.fail("Missing DATA subrecord");
|
||||
|
||||
mCellId.mPaged = !(mData.mFlags & Interior);
|
||||
|
||||
if (mCellId.mPaged)
|
||||
{
|
||||
mCellId.mWorldspace = CellId::sDefaultWorldspace;
|
||||
mCellId.mIndex.mX = mData.mX;
|
||||
mCellId.mIndex.mY = mData.mY;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCellId.mWorldspace = Misc::StringUtils::lowerCase(mName);
|
||||
mCellId.mIndex.mX = 0;
|
||||
mCellId.mIndex.mY = 0;
|
||||
}
|
||||
updateId();
|
||||
}
|
||||
|
||||
void Cell::loadCell(ESMReader& esm, bool saveContext)
|
||||
@ -333,8 +339,4 @@ namespace ESM
|
||||
mAmbi.mFogDensity = 0;
|
||||
}
|
||||
|
||||
const CellId& Cell::getCellId() const
|
||||
{
|
||||
return mCellId;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cellid.hpp"
|
||||
#include "cellref.hpp"
|
||||
#include "components/esm/defs.hpp"
|
||||
#include "components/esm/esmcommon.hpp"
|
||||
@ -67,6 +66,8 @@ namespace ESM
|
||||
*/
|
||||
struct Cell
|
||||
{
|
||||
static const std::string sDefaultWorldspace;
|
||||
|
||||
constexpr static RecNameInts sRecordId = REC_CELL;
|
||||
|
||||
/// Return a string descriptor for this record type. Currently used for debugging / error logs only.
|
||||
@ -110,7 +111,7 @@ namespace ESM
|
||||
, mRefNumCounter(0)
|
||||
{
|
||||
}
|
||||
|
||||
ESM::RefId mId;
|
||||
// Interior cells are indexed by this (it's the 'id'), for exterior
|
||||
// cells it is optional.
|
||||
std::string mName;
|
||||
@ -120,7 +121,6 @@ namespace ESM
|
||||
|
||||
std::vector<ESM_Context> mContextList; // File position; multiple positions for multiple plugin support
|
||||
DATAstruct mData;
|
||||
CellId mCellId;
|
||||
|
||||
AMBIstruct mAmbi;
|
||||
bool mHasAmbi;
|
||||
@ -191,7 +191,9 @@ namespace ESM
|
||||
void blank();
|
||||
///< Set record to default state (does not touch the ID/index).
|
||||
|
||||
const CellId& getCellId() const;
|
||||
const ESM::RefId& updateId();
|
||||
|
||||
static ESM::RefId generateIdForCell(bool exterior, std::string_view cellName, int x, int y);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -11,7 +11,7 @@ namespace ESM
|
||||
mObject.mRef.loadId(esm, true);
|
||||
mObject.load(esm);
|
||||
|
||||
mCellId.load(esm);
|
||||
mCellId = esm.getCellId();
|
||||
|
||||
esm.getHNTSized<12>(mLastKnownExteriorPosition, "LKEP");
|
||||
|
||||
@ -19,7 +19,7 @@ namespace ESM
|
||||
{
|
||||
mHasMark = true;
|
||||
esm.getHTSized<24>(mMarkedPosition);
|
||||
mMarkedCell.load(esm);
|
||||
mMarkedCell = esm.getCellId();
|
||||
}
|
||||
else
|
||||
mHasMark = false;
|
||||
@ -92,14 +92,14 @@ namespace ESM
|
||||
{
|
||||
mObject.save(esm);
|
||||
|
||||
mCellId.save(esm);
|
||||
esm.writeCellId(mCellId);
|
||||
|
||||
esm.writeHNT("LKEP", mLastKnownExteriorPosition);
|
||||
|
||||
if (mHasMark)
|
||||
{
|
||||
esm.writeHNT("MARK", mMarkedPosition, 24);
|
||||
mMarkedCell.save(esm);
|
||||
esm.writeCellId(mMarkedCell);
|
||||
}
|
||||
|
||||
esm.writeHNRefId("SIGN", mBirthsign);
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cellid.hpp"
|
||||
#include "components/esm/defs.hpp"
|
||||
#include "npcstate.hpp"
|
||||
|
||||
@ -20,12 +19,12 @@ namespace ESM
|
||||
struct Player
|
||||
{
|
||||
NpcState mObject;
|
||||
CellId mCellId;
|
||||
RefId mCellId;
|
||||
float mLastKnownExteriorPosition[3];
|
||||
unsigned char mHasMark;
|
||||
bool mSetWerewolfAcrobatics;
|
||||
Position mMarkedPosition;
|
||||
CellId mMarkedCell;
|
||||
RefId mMarkedCell;
|
||||
ESM::RefId mBirthsign;
|
||||
|
||||
int mCurrentCrimeId;
|
||||
|
@ -53,7 +53,7 @@ void ESM4::Cell::load(ESM4::Reader& reader)
|
||||
reader.adjustFormId(mFormId);
|
||||
mId = ESM::RefId::formIdRefId(mFormId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
mParent = reader.currWorld();
|
||||
mParent = ESM::RefId::formIdRefId(reader.currWorld());
|
||||
|
||||
reader.clearCellGrid(); // clear until XCLC FIXME: somehow do this automatically?
|
||||
|
||||
|
@ -36,7 +36,6 @@
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm4/reader.hpp>
|
||||
|
||||
namespace ESM4
|
||||
@ -68,7 +67,7 @@ namespace ESM4
|
||||
ESM::RefId mId;
|
||||
std::uint32_t mFlags; // from the header, see enum type RecordFlag for details
|
||||
|
||||
FormId mParent; // world formId (for grouping cells), from the loading sequence
|
||||
ESM::RefId mParent; // world formId (for grouping cells), from the loading sequence
|
||||
|
||||
std::string mEditorId;
|
||||
std::string mFullName;
|
||||
|
@ -45,7 +45,7 @@ namespace EsmLoader
|
||||
return (v.mId);
|
||||
}
|
||||
|
||||
const ESM::CellId& operator()(const ESM::Cell& v) const { return v.mCellId; }
|
||||
const ESM::RefId& operator()(const ESM::Cell& v) const { return v.mId; }
|
||||
|
||||
std::pair<int, int> operator()(const ESM::Land& v) const { return std::pair(v.mX, v.mY); }
|
||||
|
||||
|
@ -15,6 +15,13 @@ namespace Misc
|
||||
std::hash<T> hasher;
|
||||
seed ^= static_cast<Seed>(hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||
}
|
||||
|
||||
// Comes from https://stackoverflow.com/questions/2634690/good-hash-function-for-a-2d-index
|
||||
// Effective Java (2nd edition) is cited as the source
|
||||
inline std::size_t hash2dCoord(int32_t x, int32_t y)
|
||||
{
|
||||
return (53 + std::hash<int32_t>{}(x)) * 53 + std::hash<int32_t>{}(y);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user