2022-12-06 00:11:19 +01:00
|
|
|
#include "worldmodel.hpp"
|
2011-09-08 11:02:55 +02:00
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2014-01-23 11:29:40 +01:00
|
|
|
#include <components/esm/defs.hpp>
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/cellref.hpp>
|
|
|
|
#include <components/esm3/cellstate.hpp>
|
|
|
|
#include <components/esm3/esmreader.hpp>
|
|
|
|
#include <components/esm3/esmwriter.hpp>
|
2015-07-09 19:22:04 +02:00
|
|
|
#include <components/loadinglistener/loadinglistener.hpp>
|
2017-05-25 13:09:40 +04:00
|
|
|
#include <components/settings/settings.hpp>
|
2014-01-23 11:29:40 +01:00
|
|
|
|
2012-07-03 12:30:50 +02:00
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
#include "../mwbase/world.hpp"
|
|
|
|
|
2014-02-23 20:11:05 +01:00
|
|
|
#include "cellstore.hpp"
|
2012-10-01 19:17:04 +04:00
|
|
|
#include "esmstore.hpp"
|
2011-09-27 10:08:07 +02:00
|
|
|
|
2020-10-20 09:22:43 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
template <class Visitor, class Key>
|
|
|
|
bool forEachInStore(const std::string& id, Visitor&& visitor, std::map<Key, MWWorld::CellStore>& cellStore)
|
|
|
|
{
|
|
|
|
for (auto& cell : cellStore)
|
|
|
|
{
|
|
|
|
if (cell.second.getState() == MWWorld::CellStore::State_Unloaded)
|
|
|
|
cell.second.preload();
|
|
|
|
if (cell.second.getState() == MWWorld::CellStore::State_Preloaded)
|
|
|
|
{
|
|
|
|
if (cell.second.hasId(id))
|
|
|
|
{
|
|
|
|
cell.second.load();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bool cont = cell.second.forEach([&](MWWorld::Ptr ptr) {
|
2022-01-23 20:55:17 +01:00
|
|
|
if (ptr.getCellRef().getRefId() == id)
|
2020-10-20 09:22:43 +00:00
|
|
|
{
|
|
|
|
return visitor(ptr);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (!cont)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PtrCollector
|
|
|
|
{
|
|
|
|
std::vector<MWWorld::Ptr> mPtrs;
|
|
|
|
|
|
|
|
bool operator()(MWWorld::Ptr ptr)
|
|
|
|
{
|
|
|
|
mPtrs.emplace_back(ptr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2012-09-17 11:37:50 +04:00
|
|
|
if (cell->mData.mFlags & ESM::Cell::Interior)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2014-01-14 12:46:53 +04:00
|
|
|
std::string lowerName(Misc::StringUtils::lowerCase(cell->mName));
|
2014-01-24 18:21:52 +01:00
|
|
|
std::map<std::string, CellStore>::iterator result = mInteriors.find(lowerName);
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
if (result == mInteriors.end())
|
2022-06-01 22:53:18 +02:00
|
|
|
result = mInteriors.emplace(std::move(lowerName), CellStore(cell, mStore, mReaders)).first;
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
return &result->second;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-12-05 13:21:26 +01:00
|
|
|
std::map<std::pair<int, int>, CellStore>::iterator result
|
2012-11-05 16:07:59 +04:00
|
|
|
= mExteriors.find(std::make_pair(cell->getGridX(), cell->getGridY()));
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
if (result == mExteriors.end())
|
2022-06-01 22:53:18 +02:00
|
|
|
result = mExteriors
|
|
|
|
.emplace(std::make_pair(cell->getGridX(), cell->getGridY()), CellStore(cell, mStore, mReaders))
|
|
|
|
.first;
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
return &result->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::clear()
|
2013-05-15 17:54:18 +02:00
|
|
|
{
|
|
|
|
mInteriors.clear();
|
|
|
|
mExteriors.clear();
|
2020-11-13 11:39:47 +04:00
|
|
|
std::fill(mIdCache.begin(), mIdCache.end(), std::make_pair("", (MWWorld::CellStore*)nullptr));
|
2013-05-15 17:54:18 +02:00
|
|
|
mIdCacheIndex = 0;
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::Ptr MWWorld::WorldModel::getPtrAndCache(std::string_view name, CellStore& cellStore)
|
2012-06-21 11:43:18 +02:00
|
|
|
{
|
|
|
|
Ptr ptr = getPtr(name, cellStore);
|
|
|
|
|
2013-08-15 14:45:13 +02:00
|
|
|
if (!ptr.isEmpty() && ptr.isInCell())
|
2012-06-21 11:43:18 +02:00
|
|
|
{
|
|
|
|
mIdCache[mIdCacheIndex].first = name;
|
|
|
|
mIdCache[mIdCacheIndex].second = &cellStore;
|
|
|
|
if (++mIdCacheIndex >= mIdCache.size())
|
|
|
|
mIdCacheIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::writeCell(ESM::ESMWriter& writer, CellStore& cell) const
|
2014-01-23 11:29:40 +01:00
|
|
|
{
|
2014-02-24 10:03:04 +01:00
|
|
|
if (cell.getState() != CellStore::State_Loaded)
|
2015-12-06 18:03:55 +01:00
|
|
|
cell.load();
|
2014-02-24 10:03:04 +01:00
|
|
|
|
2014-01-23 11:29:40 +01:00
|
|
|
ESM::CellState cellState;
|
|
|
|
|
|
|
|
cell.saveState(cellState);
|
|
|
|
|
|
|
|
writer.startRecord(ESM::REC_CSTA);
|
|
|
|
cellState.mId.save(writer);
|
|
|
|
cellState.save(writer);
|
2014-05-11 02:07:28 +02:00
|
|
|
cell.writeFog(writer);
|
2014-01-23 12:51:42 +01:00
|
|
|
cell.writeReferences(writer);
|
2014-01-23 11:29:40 +01:00
|
|
|
writer.endRecord(ESM::REC_CSTA);
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCache& readers)
|
2022-06-01 22:53:18 +02:00
|
|
|
: mStore(store)
|
|
|
|
, mReaders(readers)
|
|
|
|
, mIdCacheIndex(0)
|
2021-04-10 11:20:12 +04:00
|
|
|
{
|
2021-04-16 08:10:31 +04:00
|
|
|
int cacheSize = std::clamp(Settings::Manager::getInt("pointers cache size", "Cells"), 40, 1000);
|
2021-04-10 11:20:12 +04:00
|
|
|
mIdCache = IdCache(cacheSize, std::pair<std::string, CellStore*>("", (CellStore*)nullptr));
|
|
|
|
}
|
2011-09-08 11:02:55 +02:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y)
|
2011-09-08 11:02:55 +02:00
|
|
|
{
|
2013-12-05 13:21:26 +01:00
|
|
|
std::map<std::pair<int, int>, CellStore>::iterator result = mExteriors.find(std::make_pair(x, y));
|
2011-09-08 11:02:55 +02:00
|
|
|
|
|
|
|
if (result == mExteriors.end())
|
|
|
|
{
|
2012-11-06 12:36:21 +04:00
|
|
|
const ESM::Cell* cell = mStore.get<ESM::Cell>().search(x, y);
|
2011-09-27 10:08:07 +02:00
|
|
|
|
|
|
|
if (!cell)
|
|
|
|
{
|
|
|
|
// Cell isn't predefined. Make one on the fly.
|
|
|
|
ESM::Cell record;
|
2016-07-02 19:48:11 +02:00
|
|
|
record.mCellId.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
2016-07-02 19:43:08 +02:00
|
|
|
record.mCellId.mPaged = true;
|
|
|
|
record.mCellId.mIndex.mX = x;
|
|
|
|
record.mCellId.mIndex.mY = y;
|
2011-09-27 10:08:07 +02:00
|
|
|
|
2014-01-07 20:43:08 +01:00
|
|
|
record.mData.mFlags = ESM::Cell::HasWater;
|
2012-09-17 11:37:50 +04:00
|
|
|
record.mData.mX = x;
|
|
|
|
record.mData.mY = y;
|
|
|
|
record.mWater = 0;
|
|
|
|
record.mMapColor = 0;
|
2011-09-27 10:08:07 +02:00
|
|
|
|
2012-07-03 12:30:50 +02:00
|
|
|
cell = MWBase::Environment::get().getWorld()->createRecord(record);
|
2011-09-27 10:08:07 +02:00
|
|
|
}
|
2011-09-08 11:02:55 +02:00
|
|
|
|
2022-06-01 22:53:18 +02:00
|
|
|
result = mExteriors.emplace(std::make_pair(x, y), CellStore(cell, mStore, mReaders)).first;
|
2012-02-12 12:35:29 +01:00
|
|
|
}
|
2011-09-10 11:22:32 +02:00
|
|
|
|
2014-02-23 14:26:36 +01:00
|
|
|
if (result->second.getState() != CellStore::State_Loaded)
|
2012-05-25 17:55:00 +02:00
|
|
|
{
|
2015-12-06 18:03:55 +01:00
|
|
|
result->second.load();
|
2012-05-25 17:55:00 +02:00
|
|
|
}
|
2012-03-10 12:36:29 +01:00
|
|
|
|
2011-09-08 11:02:55 +02:00
|
|
|
return &result->second;
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
|
2011-09-08 11:02:55 +02:00
|
|
|
{
|
2013-03-07 20:15:01 +01:00
|
|
|
std::string lowerName = Misc::StringUtils::lowerCase(name);
|
2013-12-05 13:21:26 +01:00
|
|
|
std::map<std::string, CellStore>::iterator result = mInteriors.find(lowerName);
|
2011-09-08 11:02:55 +02:00
|
|
|
|
|
|
|
if (result == mInteriors.end())
|
|
|
|
{
|
2013-03-07 20:15:01 +01:00
|
|
|
const ESM::Cell* cell = mStore.get<ESM::Cell>().find(lowerName);
|
2011-09-10 11:22:32 +02:00
|
|
|
|
2022-06-01 22:53:18 +02:00
|
|
|
result = mInteriors.emplace(std::move(lowerName), CellStore(cell, mStore, mReaders)).first;
|
2012-02-12 12:35:29 +01:00
|
|
|
}
|
2011-09-08 11:02:55 +02:00
|
|
|
|
2014-02-23 14:26:36 +01:00
|
|
|
if (result->second.getState() != CellStore::State_Loaded)
|
2012-05-25 17:55:00 +02:00
|
|
|
{
|
2015-12-06 18:03:55 +01:00
|
|
|
result->second.load();
|
2012-05-25 17:55:00 +02:00
|
|
|
}
|
2012-03-10 12:36:29 +01:00
|
|
|
|
2011-09-08 11:02:55 +02:00
|
|
|
return &result->second;
|
|
|
|
}
|
2011-09-22 11:54:08 +02:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::rest(double hours)
|
2018-09-23 22:03:43 +04:00
|
|
|
{
|
|
|
|
for (auto& interior : mInteriors)
|
|
|
|
{
|
2019-01-25 20:04:35 +04:00
|
|
|
interior.second.rest(hours);
|
2018-09-23 22:03:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& exterior : mExteriors)
|
|
|
|
{
|
2019-01-25 20:04:35 +04:00
|
|
|
exterior.second.rest(hours);
|
2018-09-23 22:03:43 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::recharge(float duration)
|
2018-12-15 10:23:50 +04:00
|
|
|
{
|
|
|
|
for (auto& interior : mInteriors)
|
|
|
|
{
|
|
|
|
interior.second.recharge(duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& exterior : mExteriors)
|
|
|
|
{
|
|
|
|
exterior.second.recharge(duration);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
2014-01-23 11:29:40 +01:00
|
|
|
{
|
|
|
|
if (id.mPaged)
|
|
|
|
return getExterior(id.mIndex.mX, id.mIndex.mY);
|
|
|
|
|
|
|
|
return getInterior(id.mWorldspace);
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::Ptr MWWorld::WorldModel::getPtr(std::string_view name, CellStore& cell, bool searchInContainers)
|
2011-09-22 11:54:08 +02:00
|
|
|
{
|
2014-02-23 14:26:36 +01:00
|
|
|
if (cell.getState() == CellStore::State_Unloaded)
|
2015-12-06 18:03:55 +01:00
|
|
|
cell.preload();
|
2011-09-24 11:45:59 +02:00
|
|
|
|
2014-02-23 14:26:36 +01:00
|
|
|
if (cell.getState() == CellStore::State_Preloaded)
|
2011-09-24 11:45:59 +02:00
|
|
|
{
|
2014-02-23 16:46:07 +01:00
|
|
|
if (cell.hasId(name))
|
2012-06-19 16:42:10 +02:00
|
|
|
{
|
2015-12-06 18:03:55 +01:00
|
|
|
cell.load();
|
2012-06-19 16:42:10 +02:00
|
|
|
}
|
2011-09-24 11:45:59 +02:00
|
|
|
else
|
|
|
|
return Ptr();
|
|
|
|
}
|
2013-04-14 17:37:39 +02:00
|
|
|
|
2014-02-23 16:46:07 +01:00
|
|
|
Ptr ptr = cell.search(name);
|
2011-09-22 11:54:08 +02:00
|
|
|
|
2015-12-17 20:34:50 +01:00
|
|
|
if (!ptr.isEmpty() && MWWorld::CellStore::isAccessible(ptr.getRefData(), ptr.getCellRef()))
|
2014-02-23 16:46:07 +01:00
|
|
|
return ptr;
|
2013-08-15 14:45:13 +02:00
|
|
|
|
|
|
|
if (searchInContainers)
|
|
|
|
return cell.searchInContainer(name);
|
2011-09-22 11:54:08 +02:00
|
|
|
|
|
|
|
return Ptr();
|
|
|
|
}
|
2011-09-22 12:44:17 +02:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::Ptr MWWorld::WorldModel::getPtr(const std::string& name)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2012-06-21 11:43:18 +02:00
|
|
|
// First check the cache
|
2021-04-10 11:20:12 +04:00
|
|
|
for (IdCache::iterator iter(mIdCache.begin()); iter != mIdCache.end(); ++iter)
|
2012-06-21 11:43:18 +02:00
|
|
|
if (iter->first == name && iter->second)
|
|
|
|
{
|
|
|
|
Ptr ptr = getPtr(name, *iter->second);
|
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then check cells that are already listed
|
2014-06-28 17:44:52 +02:00
|
|
|
// Search in reverse, this is a workaround for an ambiguous chargen_plank reference in the vanilla game.
|
|
|
|
// there is one at -22,16 and one at -2,-9, the latter should be used.
|
|
|
|
for (std::map<std::pair<int, int>, CellStore>::reverse_iterator iter = mExteriors.rbegin();
|
|
|
|
iter != mExteriors.rend(); ++iter)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2012-06-21 11:43:18 +02:00
|
|
|
Ptr ptr = getPtrAndCache(name, iter->second);
|
2011-09-22 12:44:17 +02:00
|
|
|
if (!ptr.isEmpty())
|
2013-04-14 17:37:39 +02:00
|
|
|
return ptr;
|
2011-09-22 12:44:17 +02:00
|
|
|
}
|
|
|
|
|
2013-12-05 13:21:26 +01:00
|
|
|
for (std::map<std::string, CellStore>::iterator iter = mInteriors.begin(); iter != mInteriors.end(); ++iter)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2012-06-21 11:43:18 +02:00
|
|
|
Ptr ptr = getPtrAndCache(name, iter->second);
|
2011-09-22 12:44:17 +02:00
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now try the other cells
|
2012-11-06 12:36:21 +04:00
|
|
|
const MWWorld::Store<ESM::Cell>& cells = mStore.get<ESM::Cell>();
|
|
|
|
MWWorld::Store<ESM::Cell>::iterator iter;
|
|
|
|
|
2013-04-14 17:37:39 +02:00
|
|
|
for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2013-12-05 13:21:26 +01:00
|
|
|
CellStore* cellStore = getCellStore(&(*iter));
|
2011-09-22 12:44:17 +02:00
|
|
|
|
2012-06-21 11:43:18 +02:00
|
|
|
Ptr ptr = getPtrAndCache(name, *cellStore);
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2013-04-14 17:37:39 +02:00
|
|
|
for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter)
|
2011-09-22 12:44:17 +02:00
|
|
|
{
|
2013-12-05 13:21:26 +01:00
|
|
|
CellStore* cellStore = getCellStore(&(*iter));
|
2011-09-22 12:44:17 +02:00
|
|
|
|
2012-06-21 11:43:18 +02:00
|
|
|
Ptr ptr = getPtrAndCache(name, *cellStore);
|
2011-09-22 12:44:17 +02:00
|
|
|
|
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// giving up
|
|
|
|
return Ptr();
|
|
|
|
}
|
2014-01-01 02:22:11 +01:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::Ptr MWWorld::WorldModel::getPtr(const std::string& id, const ESM::RefNum& refNum)
|
2020-05-10 14:57:06 +02:00
|
|
|
{
|
|
|
|
for (auto& pair : mInteriors)
|
|
|
|
{
|
|
|
|
Ptr ptr = getPtr(pair.second, id, refNum);
|
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
for (auto& pair : mExteriors)
|
|
|
|
{
|
|
|
|
Ptr ptr = getPtr(pair.second, id, refNum);
|
|
|
|
if (!ptr.isEmpty())
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
return Ptr();
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
MWWorld::Ptr MWWorld::WorldModel::getPtr(CellStore& cellStore, const std::string& id, const ESM::RefNum& refNum)
|
2020-05-10 14:57:06 +02:00
|
|
|
{
|
|
|
|
if (cellStore.getState() == CellStore::State_Unloaded)
|
|
|
|
cellStore.preload();
|
|
|
|
if (cellStore.getState() == CellStore::State_Preloaded)
|
|
|
|
{
|
|
|
|
if (cellStore.hasId(id))
|
|
|
|
cellStore.load();
|
|
|
|
else
|
|
|
|
return Ptr();
|
|
|
|
}
|
|
|
|
return cellStore.searchViaRefNum(refNum);
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::getExteriorPtrs(std::string_view name, std::vector<MWWorld::Ptr>& out)
|
2014-01-01 02:22:11 +01:00
|
|
|
{
|
2015-02-04 16:41:14 +01:00
|
|
|
const MWWorld::Store<ESM::Cell>& cells = mStore.get<ESM::Cell>();
|
|
|
|
for (MWWorld::Store<ESM::Cell>::iterator iter = cells.extBegin(); iter != cells.extEnd(); ++iter)
|
2014-01-01 02:22:11 +01:00
|
|
|
{
|
2015-02-04 16:41:14 +01:00
|
|
|
CellStore* cellStore = getCellStore(&(*iter));
|
|
|
|
|
|
|
|
Ptr ptr = getPtrAndCache(name, *cellStore);
|
|
|
|
|
2014-01-01 02:22:11 +01:00
|
|
|
if (!ptr.isEmpty())
|
|
|
|
out.push_back(ptr);
|
|
|
|
}
|
|
|
|
}
|
2014-01-23 11:29:40 +01:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::getInteriorPtrs(const std::string& name, std::vector<MWWorld::Ptr>& out)
|
2014-01-11 03:29:41 +01:00
|
|
|
{
|
2015-02-04 16:41:14 +01:00
|
|
|
const MWWorld::Store<ESM::Cell>& cells = mStore.get<ESM::Cell>();
|
|
|
|
for (MWWorld::Store<ESM::Cell>::iterator iter = cells.intBegin(); iter != cells.intEnd(); ++iter)
|
2014-01-11 03:29:41 +01:00
|
|
|
{
|
2015-02-04 16:41:14 +01:00
|
|
|
CellStore* cellStore = getCellStore(&(*iter));
|
|
|
|
|
|
|
|
Ptr ptr = getPtrAndCache(name, *cellStore);
|
|
|
|
|
2014-01-11 03:29:41 +01:00
|
|
|
if (!ptr.isEmpty())
|
|
|
|
out.push_back(ptr);
|
|
|
|
}
|
|
|
|
}
|
2014-01-24 18:21:52 +01:00
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
std::vector<MWWorld::Ptr> MWWorld::WorldModel::getAll(const std::string& id)
|
2020-10-20 09:22:43 +00:00
|
|
|
{
|
|
|
|
PtrCollector visitor;
|
|
|
|
if (forEachInStore(id, visitor, mInteriors))
|
|
|
|
forEachInStore(id, visitor, mExteriors);
|
|
|
|
return visitor.mPtrs;
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
int MWWorld::WorldModel::countSavedGameRecords() const
|
2014-01-23 11:29:40 +01:00
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
for (std::map<std::string, CellStore>::const_iterator iter(mInteriors.begin()); iter != mInteriors.end(); ++iter)
|
2014-02-24 10:03:04 +01:00
|
|
|
if (iter->second.hasState())
|
2014-01-23 11:29:40 +01:00
|
|
|
++count;
|
|
|
|
|
|
|
|
for (std::map<std::pair<int, int>, CellStore>::const_iterator iter(mExteriors.begin()); iter != mExteriors.end();
|
|
|
|
++iter)
|
2014-02-24 10:03:04 +01:00
|
|
|
if (iter->second.hasState())
|
2014-01-23 11:29:40 +01:00
|
|
|
++count;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
void MWWorld::WorldModel::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
2014-01-23 11:29:40 +01:00
|
|
|
{
|
2014-02-24 10:03:04 +01:00
|
|
|
for (std::map<std::pair<int, int>, CellStore>::iterator iter(mExteriors.begin()); iter != mExteriors.end(); ++iter)
|
|
|
|
if (iter->second.hasState())
|
2014-04-28 11:29:57 +02:00
|
|
|
{
|
2014-01-23 11:29:40 +01:00
|
|
|
writeCell(writer, iter->second);
|
2015-01-11 18:01:06 +01:00
|
|
|
progress.increaseProgress();
|
2014-04-28 11:29:57 +02:00
|
|
|
}
|
2014-01-23 11:29:40 +01:00
|
|
|
|
2014-02-24 10:03:04 +01:00
|
|
|
for (std::map<std::string, CellStore>::iterator iter(mInteriors.begin()); iter != mInteriors.end(); ++iter)
|
|
|
|
if (iter->second.hasState())
|
2014-04-28 11:29:57 +02:00
|
|
|
{
|
2014-01-23 11:29:40 +01:00
|
|
|
writeCell(writer, iter->second);
|
2015-01-11 18:01:06 +01:00
|
|
|
progress.increaseProgress();
|
2014-04-28 11:29:57 +02:00
|
|
|
}
|
2014-01-23 11:29:40 +01:00
|
|
|
}
|
|
|
|
|
2015-12-06 19:53:06 +01:00
|
|
|
struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback
|
|
|
|
{
|
|
|
|
public:
|
2022-12-15 20:56:17 +01:00
|
|
|
GetCellStoreCallback(MWWorld::WorldModel& worldModel)
|
|
|
|
: mWorldModel(worldModel)
|
2015-12-06 19:53:06 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-12-15 20:56:17 +01:00
|
|
|
MWWorld::WorldModel& mWorldModel;
|
2015-12-06 19:53:06 +01:00
|
|
|
|
2020-10-16 22:18:54 +04:00
|
|
|
MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) override
|
2015-12-06 19:53:06 +01:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2022-12-15 20:56:17 +01:00
|
|
|
return mWorldModel.getCell(cellId);
|
2015-12-06 19:53:06 +01:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2018-10-09 10:21:12 +04:00
|
|
|
return nullptr;
|
2015-12-06 19:53:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-12-06 00:11:19 +01:00
|
|
|
bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, const std::map<int, int>& contentFileMap)
|
2014-01-23 11:29:40 +01:00
|
|
|
{
|
|
|
|
if (type == ESM::REC_CSTA)
|
|
|
|
{
|
|
|
|
ESM::CellState state;
|
|
|
|
state.mId.load(reader);
|
|
|
|
|
2020-11-13 11:39:47 +04:00
|
|
|
CellStore* cellStore = nullptr;
|
2014-01-23 11:29:40 +01:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
cellStore = getCell(state.mId);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
// silently drop cells that don't exist anymore
|
2018-08-14 23:05:43 +04:00
|
|
|
Log(Debug::Warning) << "Warning: Dropping state for cell " << state.mId.mWorldspace
|
|
|
|
<< " (cell no longer exists)";
|
2014-06-01 23:11:38 +02:00
|
|
|
reader.skipRecord();
|
|
|
|
return true;
|
2014-01-23 11:29:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
state.load(reader);
|
|
|
|
cellStore->loadState(state);
|
2014-01-27 13:27:42 +01:00
|
|
|
|
2014-05-11 02:07:28 +02:00
|
|
|
if (state.mHasFogOfWar)
|
|
|
|
cellStore->readFog(reader);
|
|
|
|
|
2014-02-23 14:26:36 +01:00
|
|
|
if (cellStore->getState() != CellStore::State_Loaded)
|
2015-12-06 18:03:55 +01:00
|
|
|
cellStore->load();
|
2014-01-27 13:27:42 +01:00
|
|
|
|
2015-12-06 19:53:06 +01:00
|
|
|
GetCellStoreCallback callback(*this);
|
|
|
|
|
|
|
|
cellStore->readReferences(reader, contentFileMap, &callback);
|
2014-01-23 11:29:40 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2014-01-24 18:21:52 +01:00
|
|
|
}
|