1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00
OpenMW/apps/openmw/mwworld/cellstore.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1311 lines
44 KiB
C++
Raw Normal View History

#include "cellstore.hpp"
#include "magiceffects.hpp"
2014-02-23 16:46:07 +01:00
#include <algorithm>
2018-08-14 23:05:43 +04:00
#include <components/debug/debuglog.hpp>
#include <components/esm3/cellid.hpp>
#include <components/esm3/cellref.hpp>
#include <components/esm3/cellstate.hpp>
#include <components/esm3/containerstate.hpp>
#include <components/esm3/creaturelevliststate.hpp>
#include <components/esm3/creaturestate.hpp>
#include <components/esm3/doorstate.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm3/fogstate.hpp>
#include <components/esm3/loadacti.hpp>
#include <components/esm3/loadalch.hpp>
#include <components/esm3/loadappa.hpp>
#include <components/esm3/loadarmo.hpp>
#include <components/esm3/loadbody.hpp>
#include <components/esm3/loadbook.hpp>
#include <components/esm3/loadclot.hpp>
#include <components/esm3/loadcont.hpp>
#include <components/esm3/loadcrea.hpp>
#include <components/esm3/loaddoor.hpp>
#include <components/esm3/loadench.hpp>
#include <components/esm3/loadingr.hpp>
#include <components/esm3/loadlevlist.hpp>
#include <components/esm3/loadligh.hpp>
#include <components/esm3/loadlock.hpp>
#include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadnpc.hpp>
#include <components/esm3/loadprob.hpp>
#include <components/esm3/loadrepa.hpp>
#include <components/esm3/loadstat.hpp>
#include <components/esm3/loadweap.hpp>
#include <components/esm3/npcstate.hpp>
#include <components/esm3/objectstate.hpp>
#include <components/esm3/readerscache.hpp>
#include <components/esm4/loadligh.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/misc/tuplehelpers.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
2014-04-29 15:27:49 +02:00
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/recharge.hpp"
2014-04-29 15:27:49 +02:00
#include "class.hpp"
#include "containerstore.hpp"
2012-10-01 19:17:04 +04:00
#include "esmstore.hpp"
#include "inventorystore.hpp"
#include "ptr.hpp"
#include "worldmodel.hpp"
namespace
{
2022-09-09 18:28:48 +02:00
template <typename Record>
struct RecordToState
{
using StateType = ESM::ObjectState;
};
template <>
struct RecordToState<ESM::NPC>
{
using StateType = ESM::NpcState;
};
template <>
struct RecordToState<ESM::Creature>
{
using StateType = ESM::CreatureState;
};
template <>
struct RecordToState<ESM::Door>
{
using StateType = ESM::DoorState;
};
template <>
struct RecordToState<ESM::Container>
{
using StateType = ESM::ContainerState;
};
template <>
struct RecordToState<ESM::CreatureLevList>
{
using StateType = ESM::CreatureLevListState;
};
template <typename T>
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
MWWorld::Ptr searchInContainerList(MWWorld::CellRefList<T>& containerList, const ESM::RefId& id)
{
for (auto iter(containerList.mList.begin()); iter != containerList.mList.end(); ++iter)
{
2020-11-13 11:39:47 +04:00
MWWorld::Ptr container(&*iter, nullptr);
if (container.getRefData().getCustomData() == nullptr)
continue;
MWWorld::Ptr ptr = container.getClass().getContainerStore(container).search(id);
if (!ptr.isEmpty())
return ptr;
}
return MWWorld::Ptr();
}
2014-04-29 15:27:49 +02:00
template <typename T>
MWWorld::Ptr searchViaActorId(MWWorld::CellRefList<T>& actorList, int actorId, MWWorld::CellStore* cell,
const std::map<MWWorld::LiveCellRefBase*, MWWorld::CellStore*>& toIgnore)
2014-04-29 15:27:49 +02:00
{
for (typename MWWorld::CellRefList<T>::List::iterator iter(actorList.mList.begin());
iter != actorList.mList.end(); ++iter)
{
MWWorld::Ptr actor(&*iter, cell);
if (toIgnore.find(&*iter) != toIgnore.end())
continue;
if (actor.getClass().getCreatureStats(actor).matchesActorId(actorId) && actor.getRefData().getCount() > 0)
2014-04-29 15:27:49 +02:00
return actor;
}
return MWWorld::Ptr();
}
template <typename T>
void writeReferenceCollection(ESM::ESMWriter& writer, const MWWorld::CellRefList<T>& collection)
{
if (!collection.mList.empty())
{
// references
for (typename MWWorld::CellRefList<T>::List::const_iterator iter(collection.mList.begin());
iter != collection.mList.end(); ++iter)
{
if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.hasContentFile())
{
// Reference that came from a content file and has not been changed -> ignore
continue;
}
if (iter->mData.getCount() == 0 && !iter->mRef.hasContentFile())
{
// Deleted reference that did not come from a content file -> ignore
continue;
}
using StateType = typename RecordToState<T>::StateType;
StateType state;
iter->save(state);
// recordId currently unused
writer.writeHNT("OBJE", collection.mList.front().mBase->sRecordId);
state.save(writer);
}
}
}
template <class RecordType, class T>
void fixRestockingImpl(const T* base, RecordType& state)
{
// Workaround for old saves not containing negative quantities
for (const auto& baseItem : base->mInventory.mList)
{
if (baseItem.mCount < 0)
{
for (auto& item : state.mInventory.mItems)
{
if (item.mCount > 0 && baseItem.mItem == item.mRef.mRefID)
item.mCount = -item.mCount;
}
}
}
}
template <class RecordType, class T>
void fixRestocking(const T* base, RecordType& state)
{
}
template <>
void fixRestocking<>(const ESM::Creature* base, ESM::CreatureState& state)
{
fixRestockingImpl(base, state);
}
template <>
void fixRestocking<>(const ESM::NPC* base, ESM::NpcState& state)
{
fixRestockingImpl(base, state);
}
template <>
void fixRestocking<>(const ESM::Container* base, ESM::ContainerState& state)
{
fixRestockingImpl(base, state);
}
template <typename T>
void readReferenceCollection(ESM::ESMReader& reader, MWWorld::CellRefList<T>& collection, const ESM::CellRef& cref,
const std::map<int, int>& contentFileMap, MWWorld::CellStore* cellstore)
{
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
using StateType = typename RecordToState<T>::StateType;
StateType state;
state.mRef = cref;
state.load(reader);
// If the reference came from a content file, make sure this content file is loaded
if (state.mRef.mRefNum.hasContentFile())
{
std::map<int, int>::const_iterator iter = contentFileMap.find(state.mRef.mRefNum.mContentFile);
if (iter == contentFileMap.end())
return; // content file has been removed -> skip
state.mRef.mRefNum.mContentFile = iter->second;
}
if (!MWWorld::LiveCellRef<T>::checkState(state))
return; // not valid anymore with current content files -> skip
const T* record = esmStore.get<T>().search(state.mRef.mRefID);
if (!record)
return;
if (state.mVersion < 15)
fixRestocking(record, state);
if (state.mVersion < 17)
{
if constexpr (std::is_same_v<T, ESM::Creature>)
MWWorld::convertMagicEffects(state.mCreatureStats, state.mInventory);
else if constexpr (std::is_same_v<T, ESM::NPC>)
MWWorld::convertMagicEffects(state.mCreatureStats, state.mInventory, &state.mNpcStats);
}
else if (state.mVersion < 20)
{
if constexpr (std::is_same_v<T, ESM::Creature> || std::is_same_v<T, ESM::NPC>)
MWWorld::convertStats(state.mCreatureStats);
}
if (state.mRef.mRefNum.hasContentFile())
{
for (typename MWWorld::CellRefList<T>::List::iterator iter(collection.mList.begin());
iter != collection.mList.end(); ++iter)
if (iter->mRef.getRefNum() == state.mRef.mRefNum && iter->mRef.getRefId() == state.mRef.mRefID)
{
// overwrite existing reference
float oldscale = iter->mRef.getScale();
iter->load(state);
const ESM::Position& oldpos = iter->mRef.getPosition();
const ESM::Position& newpos = iter->mData.getPosition();
const MWWorld::Ptr ptr(&*iter, cellstore);
if ((oldscale != iter->mRef.getScale() || oldpos.asVec3() != newpos.asVec3()
|| oldpos.rot[0] != newpos.rot[0] || oldpos.rot[1] != newpos.rot[1]
|| oldpos.rot[2] != newpos.rot[2])
&& !ptr.getClass().isActor())
MWBase::Environment::get().getWorld()->moveObject(ptr, newpos.asVec3());
if (!iter->mData.isEnabled())
{
iter->mData.enable();
MWBase::Environment::get().getWorld()->disable(ptr);
}
MWBase::Environment::get().getWorldModel()->registerPtr(ptr);
return;
}
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Warning: Dropping reference to " << state.mRef.mRefID
<< " (invalid content file link)";
return;
}
// new reference
MWWorld::LiveCellRef<T> ref(record);
ref.load(state);
collection.mList.push_back(ref);
MWWorld::LiveCellRefBase* base = &collection.mList.back();
MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(base, cellstore));
}
// this function allows us to link a CellRefList<T> to the associated recNameInt, and apply a function
template <typename RecordType, typename Callable>
static void recNameSwitcher(MWWorld::CellRefList<RecordType>& store, ESM::RecNameInts recnNameInt, Callable&& f)
{
if (RecordType::sRecordId == recnNameInt)
{
f(store);
}
}
// helper function for forEachInternal
template <class Visitor, class List>
bool forEachImp(Visitor& visitor, List& list, MWWorld::CellStore* cellStore)
{
for (typename List::List::iterator iter(list.mList.begin()); iter != list.mList.end(); ++iter)
{
if (!MWWorld::CellStore::isAccessible(iter->mData, iter->mRef))
continue;
if (!visitor(MWWorld::Ptr(&*iter, cellStore)))
return false;
}
return true;
}
}
namespace MWWorld
{
struct CellStoreImp
{
CellStoreTuple mRefLists;
template <typename T>
static void assignStoreToIndex(CellStore& stores, CellRefList<T>& refList)
{
const std::size_t storeIndex = CellStore::getTypeIndex<T>();
if (stores.mCellRefLists.size() <= storeIndex)
stores.mCellRefLists.resize(storeIndex + 1);
2022-09-09 18:28:48 +02:00
assert(&refList == &std::get<CellRefList<T>>(stores.mCellStoreImp->mRefLists));
stores.mCellRefLists[storeIndex] = &refList;
}
// listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved
// objects are accounted for.
template <class Visitor>
static bool forEachInternal(Visitor& visitor, MWWorld::CellStore& cellStore)
{
bool returnValue = true;
Misc::tupleForEach(cellStore.mCellStoreImp->mRefLists, [&visitor, &returnValue, &cellStore](auto& store) {
returnValue = returnValue && forEachImp(visitor, store, &cellStore);
});
return returnValue;
}
};
2021-01-12 12:39:19 +04:00
template <typename X>
void CellRefList<X>::load(ESM::CellRef& ref, bool deleted, const MWWorld::ESMStore& esmStore)
{
const MWWorld::Store<X>& store = esmStore.get<X>();
if (const X* ptr = store.search(ref.mRefID))
{
typename std::list<LiveRef>::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefNum);
LiveRef liveCellRef(ref, ptr);
if (deleted)
2015-12-12 22:37:23 +01:00
liveCellRef.mData.setDeletedByContentFile(true);
if (iter != mList.end())
*iter = liveCellRef;
else
mList.push_back(liveCellRef);
}
else
{
Log(Debug::Warning) << "Warning: could not resolve cell reference '" << ref.mRefID << "'"
2018-08-14 23:05:43 +04:00
<< " (dropping reference)";
}
}
template <typename X>
void CellRefList<X>::load(const ESM4::Reference& ref, bool deleted, const MWWorld::ESMStore& esmStore)
{
if constexpr (!ESM::isESM4Rec(X::sRecordId))
return;
const MWWorld::Store<X>& store = esmStore.get<X>();
if (const X* ptr = store.search(ref.mBaseObj))
{
LiveRef liveCellRef(ref, ptr);
if (deleted)
liveCellRef.mData.setDeletedByContentFile(true);
mList.push_back(liveCellRef);
}
else
{
Log(Debug::Warning) << "Warning: could not resolve cell reference '" << ref.mId << "'"
<< " (dropping reference)";
}
}
template <typename X>
bool operator==(const LiveCellRef<X>& ref, int pRefnum)
{
return (ref.mRef.mRefnum == pRefnum);
}
Ptr CellStore::getCurrentPtr(LiveCellRefBase* ref)
{
MovedRefTracker::iterator found = mMovedToAnotherCell.find(ref);
if (found != mMovedToAnotherCell.end())
return Ptr(ref, found->second);
return Ptr(ref, this);
}
2015-11-14 17:44:16 +01:00
void CellStore::moveFrom(const Ptr& object, CellStore* from)
{
if (mState != State_Loaded)
load();
mHasState = true;
2015-11-14 17:44:16 +01:00
MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase());
if (found != mMovedToAnotherCell.end())
{
// A cell we had previously moved an object to is returning it to us.
assert(found->second == from);
mMovedToAnotherCell.erase(found);
}
else
{
mMovedHere.insert(std::make_pair(object.getBase(), from));
}
updateMergedRefs();
2015-11-14 17:44:16 +01:00
}
MWWorld::Ptr CellStore::moveTo(const Ptr& object, CellStore* cellToMoveTo)
2015-11-14 17:44:16 +01:00
{
if (cellToMoveTo == this)
throw std::runtime_error("moveTo: object is already in this cell");
// We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise.
if (mState != State_Loaded)
throw std::runtime_error(
"moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)");
// Ensure that the object actually exists in the cell
if (searchViaRefNum(object.getCellRef().getRefNum()).isEmpty())
throw std::runtime_error("moveTo: object is not in this cell");
MWBase::Environment::get().getWorldModel()->registerPtr(MWWorld::Ptr(object.getBase(), cellToMoveTo));
2015-12-06 18:43:52 +01:00
2015-11-14 17:44:16 +01:00
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())
{
// Special case - object didn't originate in this cell
// Move it back to its original cell first
CellStore* originalCell = found->second;
assert(originalCell != this);
originalCell->moveFrom(object, this);
mMovedHere.erase(found);
// Now that object is back to its rightful owner, we can move it
if (cellToMoveTo != originalCell)
{
originalCell->moveTo(object, cellToMoveTo);
}
2015-11-14 17:44:16 +01:00
updateMergedRefs();
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
2015-11-14 17:44:16 +01:00
}
cellToMoveTo->moveFrom(object, this);
mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo));
updateMergedRefs();
MWWorld::Ptr ptr(object.getBase(), cellToMoveTo);
const Class& cls = ptr.getClass();
if (cls.hasInventoryStore(ptr))
cls.getInventoryStore(ptr).setActor(ptr);
return ptr;
2015-11-14 17:44:16 +01:00
}
2015-12-06 18:13:04 +01:00
struct MergeVisitor
2015-11-14 17:44:16 +01:00
{
2015-12-06 18:13:04 +01:00
MergeVisitor(std::vector<LiveCellRefBase*>& mergeTo,
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedToAnotherCell)
: mMergeTo(mergeTo)
, mMovedHere(movedHere)
, mMovedToAnotherCell(movedToAnotherCell)
{
}
2015-11-14 17:44:16 +01:00
bool operator()(const MWWorld::Ptr& ptr)
{
if (mMovedToAnotherCell.find(ptr.getBase()) != mMovedToAnotherCell.end())
return true;
mMergeTo.push_back(ptr.getBase());
return true;
}
void merge()
{
for (const auto& [base, _] : mMovedHere)
mMergeTo.push_back(base);
}
private:
std::vector<LiveCellRefBase*>& mMergeTo;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedHere;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedToAnotherCell;
};
void CellStore::updateMergedRefs()
{
mMergedRefs.clear();
mRechargingItemsUpToDate = false;
2015-12-06 18:13:04 +01:00
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
CellStoreImp::forEachInternal(visitor, *this);
2015-12-06 18:13:04 +01:00
visitor.merge();
2015-11-14 17:44:16 +01:00
}
bool CellStore::movedHere(const MWWorld::Ptr& ptr) const
{
if (ptr.isEmpty())
return false;
if (mMovedHere.find(ptr.getBase()) != mMovedHere.end())
return true;
return false;
}
CellStore::CellStore(MWWorld::Cell cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers)
: mStore(esmStore)
, mReaders(readers)
, mCellVariant(std::move(cell))
, mState(State_Unloaded)
, mHasState(false)
, mLastRespawn(0, 0)
, mCellStoreImp(std::make_unique<CellStoreImp>())
2022-09-09 18:28:48 +02:00
, mRechargingItemsUpToDate(false)
{
std::apply([this](auto&... x) { (CellStoreImp::assignStoreToIndex(*this, x), ...); }, mCellStoreImp->mRefLists);
mWaterLevel = mCellVariant.getWaterHeight();
}
CellStore::~CellStore() = default;
CellStore::CellStore(CellStore&&) = default;
const MWWorld::Cell* CellStore::getCell() const
{
return &mCellVariant;
}
2014-02-23 14:26:36 +01:00
CellStore::State CellStore::getState() const
{
return mState;
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const std::vector<ESM::RefId>& CellStore::getPreloadedIds() const
{
return mIds;
}
bool CellStore::hasState() const
{
return mHasState;
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
bool CellStore::hasId(const ESM::RefId& id) const
2014-02-23 16:46:07 +01:00
{
if (mState == State_Unloaded)
return false;
if (mState == State_Preloaded)
return std::binary_search(mIds.begin(), mIds.end(), id);
return searchConst(id).isEmpty();
2014-02-23 16:46:07 +01:00
}
2015-12-17 23:59:18 +01:00
template <typename PtrType>
2015-12-06 18:13:04 +01:00
struct SearchVisitor
{
2015-12-17 23:59:18 +01:00
PtrType mFound;
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& mIdToFind;
SearchVisitor(const ESM::RefId& id)
: mIdToFind(id)
{
}
2015-12-17 23:59:18 +01:00
bool operator()(const PtrType& ptr)
{
2022-08-27 13:07:59 +02:00
if (ptr.getCellRef().getRefId() == mIdToFind)
{
mFound = ptr;
return false;
}
return true;
}
};
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
Ptr CellStore::search(const ESM::RefId& id)
2014-02-23 16:46:07 +01:00
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
SearchVisitor<MWWorld::Ptr> searchVisitor(id);
2015-12-06 18:13:04 +01:00
forEach(searchVisitor);
return searchVisitor.mFound;
2014-02-23 16:46:07 +01:00
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
ConstPtr CellStore::searchConst(const ESM::RefId& id) const
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
SearchVisitor<MWWorld::ConstPtr> searchVisitor(id);
2015-12-17 23:59:18 +01:00
forEachConst(searchVisitor);
return searchVisitor.mFound;
}
2014-04-29 15:27:49 +02:00
Ptr CellStore::searchViaActorId(int id)
{
if (Ptr ptr = ::searchViaActorId(get<ESM::NPC>(), id, this, mMovedToAnotherCell); !ptr.isEmpty())
2014-04-29 15:27:49 +02:00
return ptr;
if (Ptr ptr = ::searchViaActorId(get<ESM::Creature>(), id, this, mMovedToAnotherCell); !ptr.isEmpty())
2014-04-29 15:27:49 +02:00
return ptr;
for (const auto& [base, _] : mMovedHere)
{
MWWorld::Ptr actor(base, this);
if (!actor.getClass().isActor())
continue;
if (actor.getClass().getCreatureStats(actor).matchesActorId(id) && actor.getRefData().getCount() > 0)
return actor;
}
2014-04-29 15:27:49 +02:00
return Ptr();
}
class RefNumSearchVisitor
{
const ESM::RefNum& mRefNum;
2022-09-22 21:26:05 +03:00
public:
RefNumSearchVisitor(const ESM::RefNum& refNum)
: mRefNum(refNum)
{
}
Ptr mFound;
bool operator()(const Ptr& ptr)
{
if (ptr.getCellRef().getRefNum() == mRefNum)
{
mFound = ptr;
return false;
}
return true;
}
};
Ptr CellStore::searchViaRefNum(const ESM::RefNum& refNum)
{
RefNumSearchVisitor searchVisitor(refNum);
forEach(searchVisitor);
return searchVisitor.mFound;
}
2014-02-23 17:34:18 +01:00
float CellStore::getWaterLevel() const
{
if (isExterior())
return -1;
2014-02-23 17:34:18 +01:00
return mWaterLevel;
}
void CellStore::setWaterLevel(float level)
{
mWaterLevel = level;
mHasState = true;
2014-02-23 17:34:18 +01:00
}
std::size_t CellStore::count() const
2014-02-23 21:21:27 +01:00
{
2015-12-04 20:03:14 +01:00
return mMergedRefs.size();
2014-02-23 21:21:27 +01:00
}
void CellStore::load()
{
if (mState != State_Loaded)
{
if (mState == State_Preloaded)
mIds.clear();
loadRefs();
mState = State_Loaded;
}
}
void CellStore::preload()
{
if (mState == State_Unloaded)
{
listRefs();
mState = State_Preloaded;
}
}
void CellStore::listRefs(const ESM::Cell& cell)
{
if (cell.mContextList.empty())
return; // this is a dynamically generated cell -> skipping.
// Load references from all plugins that do something with this cell.
for (size_t i = 0; i < cell.mContextList.size(); i++)
{
try
{
// Reopen the ESM reader and seek to the right position.
const std::size_t index = static_cast<std::size_t>(cell.mContextList[i].index);
const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
cell.restore(*reader, i);
ESM::CellRef ref;
// Get each reference in turn
ESM::MovedCellRef cMRef;
bool deleted = false;
bool moved = false;
while (ESM::Cell::getNextRef(
*reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved))
{
if (deleted || moved)
continue;
// Don't list reference if it was moved to a different cell.
ESM::MovedCellRefTracker::const_iterator iter
= std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum);
if (iter != cell.mMovedRefs.end())
{
continue;
}
mIds.push_back(std::move(ref.mRefID));
}
}
catch (std::exception& e)
{
2018-08-14 23:05:43 +04:00
Log(Debug::Error) << "An error occurred listing references for cell " << getCell()->getDescription()
<< ": " << e.what();
}
}
// List moved references, from separately tracked list.
for (const auto& [ref, deleted] : cell.mLeasedRefs)
{
if (!deleted)
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
mIds.push_back(ref.mRefID);
}
}
void CellStore::listRefs(const ESM4::Cell& cell)
{
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
for (const auto& ref : refs)
{
if (ref.mParent == cell.mId)
{
mIds.push_back(ref.mBaseObj);
}
}
}
void CellStore::listRefs()
{
ESM::visit([&](auto&& cell) { listRefs(cell); }, mCellVariant);
std::sort(mIds.begin(), mIds.end());
}
void CellStore::loadRefs(const ESM::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
{
if (cell.mContextList.empty())
return; // this is a dynamically generated cell -> skipping.
// Load references from all plugins that do something with this cell.
for (size_t i = 0; i < cell.mContextList.size(); i++)
{
try
{
// Reopen the ESM reader and seek to the right position.
const std::size_t index = static_cast<std::size_t>(cell.mContextList[i].index);
const ESM::ReadersCache::BusyItem reader = mReaders.get(index);
cell.restore(*reader, i);
ESM::CellRef ref;
// Get each reference in turn
ESM::MovedCellRef cMRef;
bool deleted = false;
bool moved = false;
while (ESM::Cell::getNextRef(
*reader, ref, deleted, cMRef, moved, ESM::Cell::GetNextRefMode::LoadOnlyNotMoved))
{
if (moved)
continue;
// Don't load reference if it was moved to a different cell.
ESM::MovedCellRefTracker::const_iterator iter
= std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum);
if (iter != cell.mMovedRefs.end())
{
continue;
}
loadRef(ref, deleted, refNumToID);
}
}
catch (std::exception& e)
{
Log(Debug::Error) << "An error occurred loading references for cell " << getCell()->getDescription()
<< ": " << e.what();
}
}
// Load moved references, from separately tracked list.
for (const auto& leasedRef : cell.mLeasedRefs)
{
ESM::CellRef& ref = const_cast<ESM::CellRef&>(leasedRef.first);
bool deleted = leasedRef.second;
loadRef(ref, deleted, refNumToID);
}
}
void CellStore::loadRefs(const ESM4::Cell& cell, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
{
auto& refs = MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>();
for (const auto& ref : refs)
{
if (ref.mParent == cell.mId)
{
loadRef(ref, false);
}
}
}
void CellStore::loadRefs()
{
std::map<ESM::RefNum, ESM::RefId> refNumToID; // used to detect refID modifications
ESM::visit([&](auto&& cell) { loadRefs(cell, refNumToID); }, mCellVariant);
updateMergedRefs();
}
2014-02-23 21:39:18 +01:00
bool CellStore::isExterior() const
{
return mCellVariant.isExterior();
2014-02-23 21:39:18 +01:00
}
2022-08-19 14:51:52 +00:00
bool CellStore::isQuasiExterior() const
{
return mCellVariant.isQuasiExterior();
2022-08-19 14:51:52 +00:00
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
Ptr CellStore::searchInContainer(const ESM::RefId& id)
{
bool oldState = mHasState;
mHasState = true;
if (Ptr ptr = searchInContainerList(get<ESM::Container>(), id); !ptr.isEmpty())
2014-02-23 18:17:41 +01:00
return ptr;
if (Ptr ptr = searchInContainerList(get<ESM::Creature>(), id); !ptr.isEmpty())
2014-02-23 18:17:41 +01:00
return ptr;
if (Ptr ptr = searchInContainerList(get<ESM::NPC>(), id); !ptr.isEmpty())
2014-02-23 18:17:41 +01:00
return ptr;
mHasState = oldState;
return Ptr();
}
void CellStore::loadRef(const ESM4::Reference& ref, bool deleted)
{
const MWWorld::ESMStore& store = mStore;
ESM::RecNameInts foundType = static_cast<ESM::RecNameInts>(store.find(ref.mBaseObj));
Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType](auto& x) {
recNameSwitcher(
x, foundType, [&ref, &deleted, &store](auto& storeIn) { storeIn.load(ref, deleted, store); });
});
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
void CellStore::loadRef(ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, ESM::RefId>& refNumToID)
{
const MWWorld::ESMStore& store = mStore;
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
auto it = refNumToID.find(ref.mRefNum);
if (it != refNumToID.end())
{
if (it->second != ref.mRefID)
{
// refID was modified, make sure we don't end up with duplicated refs
ESM::RecNameInts foundType = static_cast<ESM::RecNameInts>(store.find(it->second));
if (foundType != 0)
{
Misc::tupleForEach(this->mCellStoreImp->mRefLists, [&ref, foundType](auto& x) {
recNameSwitcher(x, foundType, [&ref](auto& storeIn) { storeIn.remove(ref.mRefNum); });
});
}
}
}
ESM::RecNameInts foundType = static_cast<ESM::RecNameInts>(store.find(ref.mRefID));
2022-09-09 18:28:48 +02:00
bool handledType = false;
if (foundType != 0)
{
Misc::tupleForEach(
this->mCellStoreImp->mRefLists, [&ref, &deleted, &store, foundType, &handledType](auto& x) {
recNameSwitcher(x, foundType, [&ref, &deleted, &store, &handledType](auto& storeIn) {
2022-09-09 18:28:48 +02:00
handledType = true;
storeIn.load(ref, deleted, store);
2022-09-22 21:26:05 +03:00
});
});
2022-09-09 18:28:48 +02:00
}
else
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
Log(Debug::Error) << "Cell reference '" + ref.mRefID.getRefIdString() + "' not found!";
2022-09-09 18:28:48 +02:00
return;
}
if (!handledType)
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
Log(Debug::Error) << "Error: Ignoring reference '" << ref.mRefID.getRefIdString() << "' of unhandled type";
2022-09-09 18:28:48 +02:00
return;
}
refNumToID[ref.mRefNum] = ref.mRefID;
}
void CellStore::loadState(const ESM::CellState& state)
{
mHasState = true;
if (!mCellVariant.isExterior() && mCellVariant.hasWater())
mWaterLevel = state.mWaterLevel;
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
}
void CellStore::saveState(ESM::CellState& state) const
{
state.mId = mCellVariant.getCellId();
if (!mCellVariant.isExterior() && mCellVariant.hasWater())
state.mWaterLevel = mWaterLevel;
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
state.mLastRespawn = mLastRespawn.toEsm();
}
void CellStore::writeFog(ESM::ESMWriter& writer) const
{
if (mFogState.get())
{
mFogState->save(writer, !mCellVariant.isExterior());
}
}
void CellStore::readFog(ESM::ESMReader& reader)
{
2022-05-29 13:24:48 +02:00
mFogState = std::make_unique<ESM::FogState>();
mFogState->load(reader);
}
void CellStore::writeReferences(ESM::ESMWriter& writer) const
{
Misc::tupleForEach(this->mCellStoreImp->mRefLists,
[&writer](auto& cellRefList) { writeReferenceCollection(writer, cellRefList); });
for (const auto& [base, store] : mMovedToAnotherCell)
{
ESM::RefNum refNum = base->mRef.getRefNum();
ESM::CellId movedTo = store->getCell()->getCellId();
refNum.save(writer, true, "MVRF");
movedTo.save(writer);
}
}
void CellStore::readReferences(
ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback)
{
mHasState = true;
while (reader.isNextSub("OBJE"))
{
unsigned int unused;
reader.getHT(unused);
// load the RefID first so we know what type of object it is
ESM::CellRef cref;
cref.loadId(reader, true);
int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID);
if (type == 0)
{
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)";
2021-07-12 20:51:13 +02:00
// Skip until the next OBJE or MVRF
while (reader.hasMoreSubs() && !reader.peekNextSub("OBJE") && !reader.peekNextSub("MVRF"))
{
reader.getSubName();
reader.skipHSub();
}
continue;
}
if (type != 0)
{
bool foundCorrespondingStore = false;
Misc::tupleForEach(this->mCellStoreImp->mRefLists,
[&reader, this, &cref, &contentFileMap, &foundCorrespondingStore, type](auto&& x) {
recNameSwitcher(x, static_cast<ESM::RecNameInts>(type),
[&reader, this, &cref, &contentFileMap, &foundCorrespondingStore](auto& store) {
foundCorrespondingStore = true;
readReferenceCollection(reader, store, cref, contentFileMap, this);
});
2022-09-09 18:28:48 +02:00
});
if (!foundCorrespondingStore)
throw std::runtime_error("unknown type in cell reference section");
}
}
// Do another update here to make sure objects referred to by MVRF tags can be found
// This update is only needed for old saves that used the old copy&delete way of moving objects
updateMergedRefs();
while (reader.isNextSub("MVRF"))
{
reader.cacheSubName();
ESM::RefNum refnum;
ESM::CellId movedTo;
refnum.load(reader, true, "MVRF");
movedTo.load(reader);
if (refnum.hasContentFile())
{
auto iter = contentFileMap.find(refnum.mContentFile);
if (iter != contentFileMap.end())
refnum.mContentFile = iter->second;
}
// Search for the reference. It might no longer exist if its content file was removed.
Ptr movedRef = searchViaRefNum(refnum);
if (movedRef.isEmpty())
{
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << refnum.mIndex
<< " (moved object no longer exists)";
continue;
}
CellStore* otherCell = callback->getCellStore(movedTo);
2018-10-09 10:21:12 +04:00
if (otherCell == nullptr)
{
Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId()
2018-08-14 23:05:43 +04:00
<< " (target cell " << movedTo.mWorldspace
<< " no longer exists). Reference moved back to its original location.";
// Note by dropping tag the object will automatically re-appear in its original cell, though
// potentially at inapproriate coordinates. Restore original coordinates:
movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition());
continue;
}
if (otherCell == this)
{
// Should never happen unless someone's tampering with files.
2018-08-14 23:05:43 +04:00
Log(Debug::Warning) << "Found invalid moved ref, ignoring";
continue;
}
moveTo(movedRef, otherCell);
}
}
2014-02-23 21:39:18 +01:00
struct IsEqualVisitor
2014-02-23 21:39:18 +01:00
{
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; }
2014-02-23 21:39:18 +01:00
template <class L, class R>
bool operator()(const L&, const R&) const
{
return false;
}
};
bool CellStore::operator==(const CellStore& right) const
{
return ESM::visit(IsEqualVisitor(), this->mCellVariant, right.mCellVariant);
2014-02-23 21:39:18 +01:00
}
2022-04-08 22:04:32 +02:00
void CellStore::setFog(std::unique_ptr<ESM::FogState>&& fog)
{
2022-04-08 22:04:32 +02:00
mFogState = std::move(fog);
}
ESM::FogState* CellStore::getFog() const
{
return mFogState.get();
}
void clearCorpse(const MWWorld::Ptr& ptr)
{
const MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
2018-08-29 18:38:12 +03:00
static const float fCorpseClearDelay = MWBase::Environment::get()
.getWorld()
->getStore()
.get<ESM::GameSetting>()
.find("fCorpseClearDelay")
->mValue.getFloat();
if (creatureStats.isDead() && creatureStats.isDeathAnimationFinished() && !ptr.getClass().isPersistent(ptr)
&& creatureStats.getTimeOfDeath() + fCorpseClearDelay
<= MWBase::Environment::get().getWorld()->getTimeStamp())
{
MWBase::Environment::get().getWorld()->deleteObject(ptr);
}
}
void CellStore::rest(double hours)
{
if (mState == State_Loaded)
{
for (CellRefList<ESM::Creature>::List::iterator it(get<ESM::Creature>().mList.begin());
it != get<ESM::Creature>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
{
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
}
}
for (CellRefList<ESM::NPC>::List::iterator it(get<ESM::NPC>().mList.begin());
it != get<ESM::NPC>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
{
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
}
}
}
}
void CellStore::recharge(float duration)
{
if (duration <= 0)
return;
if (mState == State_Loaded)
{
for (CellRefList<ESM::Creature>::List::iterator it(get<ESM::Creature>().mList.begin());
it != get<ESM::Creature>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
}
}
for (CellRefList<ESM::NPC>::List::iterator it(get<ESM::NPC>().mList.begin());
it != get<ESM::NPC>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
}
}
for (CellRefList<ESM::Container>::List::iterator it(get<ESM::Container>().mList.begin());
it != get<ESM::Container>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getRefData().getCount() > 0
&& ptr.getClass().getContainerStore(ptr).isResolved())
{
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
}
}
rechargeItems(duration);
}
}
void CellStore::respawn()
{
if (mState == State_Loaded)
{
2018-08-29 18:38:12 +03:00
static const int iMonthsToRespawn = MWBase::Environment::get()
.getWorld()
->getStore()
.get<ESM::GameSetting>()
.find("iMonthsToRespawn")
->mValue.getInteger();
if (MWBase::Environment::get().getWorld()->getTimeStamp() - mLastRespawn > 24 * 30 * iMonthsToRespawn)
{
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
for (CellRefList<ESM::Container>::List::iterator it(get<ESM::Container>().mList.begin());
it != get<ESM::Container>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
ptr.getClass().respawn(ptr);
}
}
for (CellRefList<ESM::Creature>::List::iterator it(get<ESM::Creature>().mList.begin());
it != get<ESM::Creature>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr);
ptr.getClass().respawn(ptr);
}
for (CellRefList<ESM::NPC>::List::iterator it(get<ESM::NPC>().mList.begin());
it != get<ESM::NPC>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr);
ptr.getClass().respawn(ptr);
}
for (CellRefList<ESM::CreatureLevList>::List::iterator it(get<ESM::CreatureLevList>().mList.begin());
it != get<ESM::CreatureLevList>().mList.end(); ++it)
{
Ptr ptr = getCurrentPtr(&*it);
// no need to clearCorpse, handled as part of get<ESM::Creature>()
ptr.getClass().respawn(ptr);
}
}
}
void MWWorld::CellStore::rechargeItems(float duration)
{
if (!mRechargingItemsUpToDate)
{
updateRechargingItems();
mRechargingItemsUpToDate = true;
}
for (const auto& [item, charge] : mRechargingItems)
{
MWMechanics::rechargeItem(item, charge, duration);
}
}
void MWWorld::CellStore::updateRechargingItems()
{
mRechargingItems.clear();
const auto update = [this](auto& list) {
for (auto& item : list)
{
Ptr ptr = getCurrentPtr(&item);
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
{
checkItem(ptr);
}
}
};
update(get<ESM::Weapon>().mList);
update(get<ESM::Armor>().mList);
update(get<ESM::Clothing>().mList);
update(get<ESM::Book>().mList);
}
2021-06-23 23:13:59 +02:00
void MWWorld::CellStore::checkItem(const Ptr& ptr)
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& enchantmentId = ptr.getClass().getEnchantment(ptr);
2022-08-22 16:55:53 +02:00
if (enchantmentId.empty())
return;
const ESM::Enchantment* enchantment
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
if (!enchantment)
{
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item "
<< ptr.getCellRef().getRefId();
return;
}
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
mRechargingItems.emplace_back(ptr.getBase(), static_cast<float>(enchantment->mData.mCharge));
}
Ptr MWWorld::CellStore::getMovedActor(int actorId) const
{
for (const auto& [cellRef, cell] : mMovedToAnotherCell)
{
if (cellRef->mClass->isActor() && cellRef->mData.getCustomData())
{
Ptr actor(cellRef, cell);
if (actor.getClass().getCreatureStats(actor).getActorId() == actorId)
return actor;
}
}
return {};
}
}