1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-31 00:36:40 +00:00

ESM3 Cells have an Id.

Store<ESM::Cell> is updated to use it.
This commit is contained in:
florent.teppe 2023-02-18 22:32:27 +01:00
parent b04bcb9a9b
commit 36502eaf75
8 changed files with 71 additions and 36 deletions

View file

@ -20,6 +20,7 @@ namespace MWWorld
.mWorldspace{ Misc::StringUtils::lowerCase(cell.mEditorId) },
.mIndex{ cell.getGridX(), cell.getGridY() },
.mPaged = isExterior(),}
, mId(cell.mId)
,mMood{
.mAmbiantColor = cell.mLighting.ambient,
.mDirectionalColor = cell.mLighting.directional,
@ -41,6 +42,7 @@ namespace MWWorld
, mNameID(cell.mName)
, mRegion(cell.mRegion)
, mCellId(cell.getCellId())
, mId(cell.mId)
, mMood{
.mAmbiantColor = cell.mAmbi.mAmbient,
.mDirectionalColor = cell.mAmbi.mSunlight,

View file

@ -49,6 +49,7 @@ namespace MWWorld
std::string getDescription() const;
const MoodData& getMood() const { return mMood; }
float getWaterHeight() const { return mWaterHeight; }
const ESM::RefId& getId() const { return mId; };
private:
bool mIsExterior;
@ -61,6 +62,7 @@ namespace MWWorld
std::string mNameID; // The name that will be used by the script and console commands
ESM::RefId mRegion;
ESM::CellId mCellId;
ESM::RefId mId;
MoodData mMood;
float mWaterHeight;

View file

@ -468,13 +468,17 @@ namespace MWWorld
// Cell
//=========================================================================
const ESM::Cell* Store<ESM::Cell>::search(const ESM::RefId& cellId) const
{
auto foundCellIt = mCells.find(cellId);
if (foundCellIt == mCells.end())
return &foundCellIt->second;
return nullptr;
}
const ESM::Cell* Store<ESM::Cell>::search(const ESM::Cell& cell) const
{
if (cell.isExterior())
{
return search(cell.getGridX(), cell.getGridY());
}
return search(cell.mName);
return search(cell.mId);
}
// this method *must* be called right after esm3.loadCell()
@ -521,13 +525,13 @@ namespace MWWorld
DynamicInt::const_iterator it = mInt.find(name);
if (it != mInt.end())
{
return &(it->second);
return it->second;
}
DynamicInt::const_iterator dit = mDynamicInt.find(name);
if (dit != mDynamicInt.end())
{
return &dit->second;
return dit->second;
}
return nullptr;
@ -537,11 +541,11 @@ namespace MWWorld
std::pair<int, int> key(x, y);
DynamicExt::const_iterator it = mExt.find(key);
if (it != mExt.end())
return &(it->second);
return it->second;
DynamicExt::const_iterator dit = mDynamicExt.find(key);
if (dit != mDynamicExt.end())
return &dit->second;
return dit->second;
return nullptr;
}
@ -549,7 +553,7 @@ namespace MWWorld
{
DynamicExt::const_iterator it = mExt.find(std::make_pair(x, y));
if (it != mExt.end())
return &(it->second);
return (it->second);
return nullptr;
}
const ESM::Cell* Store<ESM::Cell>::searchOrCreate(int x, int y)
@ -557,11 +561,11 @@ namespace MWWorld
std::pair<int, int> key(x, y);
DynamicExt::const_iterator it = mExt.find(key);
if (it != mExt.end())
return &(it->second);
return (it->second);
DynamicExt::const_iterator dit = mDynamicExt.find(key);
if (dit != mDynamicExt.end())
return &dit->second;
return dit->second;
ESM::Cell newCell;
newCell.mData.mX = x;
@ -574,8 +578,11 @@ namespace MWWorld
newCell.mCellId.mPaged = true;
newCell.mCellId.mIndex.mX = x;
newCell.mCellId.mIndex.mY = y;
newCell.updateId();
return &mExt.insert(std::make_pair(key, newCell)).first->second;
ESM::Cell* newCellInserted = &mCells.insert(std::make_pair(newCell.mId, newCell)).first->second;
return mExt.insert(std::make_pair(key, newCellInserted)).first->second;
}
const ESM::Cell* Store<ESM::Cell>::find(std::string_view id) const
{
@ -607,12 +614,12 @@ namespace MWWorld
mSharedInt.clear();
mSharedInt.reserve(mInt.size());
for (auto& [_, cell] : mInt)
mSharedInt.push_back(&cell);
mSharedInt.push_back(cell);
mSharedExt.clear();
mSharedExt.reserve(mExt.size());
for (auto& [_, cell] : mExt)
mSharedExt.push_back(&cell);
mSharedExt.push_back(cell);
}
RecordId Store<ESM::Cell>::load(ESM::ESMReader& esm)
{
@ -622,13 +629,17 @@ namespace MWWorld
// are not available until both cells have been loaded at least partially!
// All cells have a name record, even nameless exterior cells.
ESM::Cell cell;
ESM::Cell* emplacedCell = nullptr;
bool isDeleted = false;
{
ESM::Cell cellToLoad;
cellToLoad.loadNameAndData(esm, isDeleted);
emplacedCell = &mCells.insert(std::make_pair(cellToLoad.mId, cellToLoad)).first->second;
}
ESM::Cell& cell = *emplacedCell;
// Load the (x,y) coordinates of the cell, if it is an exterior cell,
// so we can find the cell we need to merge with
cell.loadNameAndData(esm, isDeleted);
if (cell.mData.mFlags & ESM::Cell::Interior)
{
// Store interior cell by name, try to merge with existing parent data.
@ -647,7 +658,7 @@ namespace MWWorld
// spawn a new cell
cell.loadCell(esm, true);
mInt[cell.mName] = cell;
mInt[cell.mName] = &cell;
}
}
else
@ -700,19 +711,19 @@ namespace MWWorld
else
{
// spawn a new cell
cell.loadCell(esm, false);
emplacedCell->loadCell(esm, false);
// handle moved ref (MVRF) subrecords
handleMovedCellRefs(esm, &cell);
handleMovedCellRefs(esm, emplacedCell);
// push the new references on the list of references to manage
cell.postLoad(esm);
emplacedCell->postLoad(esm);
mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell;
mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = &cell;
}
}
return RecordId(ESM::RefId::stringRefId(cell.mName), isDeleted);
return RecordId(cell.mId, isDeleted);
}
Store<ESM::Cell>::iterator Store<ESM::Cell>::intBegin() const
{
@ -785,6 +796,7 @@ namespace MWWorld
}
ESM::Cell* Store<ESM::Cell>::insert(const ESM::Cell& cell)
{
ESM::Cell* insertedCell = &mCells.emplace(cell.mId, cell).first->second;
if (search(cell) != nullptr)
{
const std::string cellType = (cell.isExterior()) ? "exterior" : "interior";
@ -795,16 +807,16 @@ namespace MWWorld
std::pair<int, int> key(cell.getGridX(), cell.getGridY());
// duplicate insertions are avoided by search(ESM::Cell &)
DynamicExt::iterator result = mDynamicExt.emplace(key, cell).first;
mSharedExt.push_back(&result->second);
return &result->second;
DynamicExt::iterator result = mDynamicExt.emplace(key, insertedCell).first;
mSharedExt.push_back(result->second);
return result->second;
}
else
{
// duplicate insertions are avoided by search(ESM::Cell &)
DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, cell).first;
mSharedInt.push_back(&result->second);
return &result->second;
DynamicInt::iterator result = mDynamicInt.emplace(cell.mName, insertedCell).first;
mSharedInt.push_back(result->second);
return result->second;
}
}
bool Store<ESM::Cell>::erase(const ESM::Cell& cell)
@ -828,7 +840,7 @@ namespace MWWorld
for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it)
{
mSharedInt.push_back(&it->second);
mSharedInt.push_back(it->second);
}
return true;
@ -847,7 +859,7 @@ namespace MWWorld
for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it)
{
mSharedExt.push_back(&it->second);
mSharedExt.push_back(it->second);
}
return true;

View file

@ -347,10 +347,12 @@ namespace MWWorld
}
};
typedef std::unordered_map<std::string, ESM::Cell, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
typedef std::unordered_map<std::string, ESM::Cell*, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
DynamicInt;
typedef std::map<std::pair<int, int>, ESM::Cell, DynamicExtCmp> DynamicExt;
typedef std::map<std::pair<int, int>, ESM::Cell*, DynamicExtCmp> DynamicExt;
std::unordered_map<ESM::RefId, ESM::Cell> mCells;
DynamicInt mInt;
DynamicExt mExt;
@ -367,6 +369,7 @@ namespace MWWorld
public:
typedef SharedIterator<ESM::Cell> iterator;
const ESM::Cell* search(const ESM::RefId& id) const;
const ESM::Cell* search(std::string_view id) const;
const ESM::Cell* search(int x, int y) const;
const ESM::Cell* searchStatic(int x, int y) const;

View file

@ -180,6 +180,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
record.mData.mY = y;
record.mWater = 0;
record.mMapColor = 0;
record.updateId();
cell = MWBase::Environment::get().getWorld()->createRecord(record);
}

View file

@ -562,7 +562,7 @@ namespace
REGISTER_TYPED_TEST_SUITE_P(StoreSaveLoadTest, shouldNotChangeRefId);
static_assert(std::tuple_size_v<RecordTypesWithSave> == 38);
static_assert(std::tuple_size_v<RecordTypesWithSave> == 39);
INSTANTIATE_TYPED_TEST_SUITE_P(
RecordTypesTest, StoreSaveLoadTest, typename AsTestingTypes<RecordTypesWithSave>::Type);

View file

@ -57,6 +57,19 @@ namespace ESM
loadCell(esm, saveContext);
}
const ESM::RefId& Cell::updateId()
{
if (isExterior())
{
mId = ESM::RefId::stringRefId("#" + std::to_string(mData.mX) + "," + std::to_string(mData.mY));
}
else
{
mId = ESM::RefId::stringRefId(mName);
}
return mId;
}
void Cell::loadNameAndData(ESMReader& esm, bool& isDeleted)
{
isDeleted = false;
@ -105,6 +118,7 @@ namespace ESM
mCellId.mIndex.mX = 0;
mCellId.mIndex.mY = 0;
}
updateId();
}
void Cell::loadCell(ESMReader& esm, bool saveContext)

View file

@ -110,7 +110,7 @@ namespace ESM
, mRefNumCounter(0)
{
}
ESM::RefId mId;
// Interior cells are indexed by this (it's the 'id'), for exterior
// cells it is optional.
std::string mName;
@ -192,6 +192,7 @@ namespace ESM
///< Set record to default state (does not touch the ID/index).
const CellId& getCellId() const;
const ESM::RefId& updateId();
};
}
#endif