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