1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-25 06:35:30 +00:00

- Restore ability for plugins deleting records defined in parent files

- Don't throw a runtime_error when trying to load a reference based on a deleted record (just a warning for now, should be closer to MW)
This commit is contained in:
Mark Siewert 2012-12-26 10:34:59 +01:00
parent 049b0e66e0
commit 8ccec17481
3 changed files with 50 additions and 34 deletions

View File

@ -61,13 +61,14 @@ namespace MWWorld
{
// for throwing exception on unhandled record type
const MWWorld::Store<X> &store = esmStore.get<X>();
const X *ptr = store.find(ref.mRefID);
const X *ptr = store.search(ref.mRefID);
/// \note redundant because Store<X>::find() throws exception on miss
/// \note no longer redundant - changed to Store<X>::search(), don't throw
/// an exception on miss, try to continue (that's how MW does it, anyway)
if (ptr == NULL) {
throw std::runtime_error("Error resolving cell reference " + ref.mRefID);
}
mList[ref.mRefnum] = LiveRef(ref, ptr);
std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl;
} else
mList[ref.mRefnum] = LiveRef(ref, ptr);
}
LiveRef *find (const std::string& name)

View File

@ -87,20 +87,18 @@ void ESMStore::load(ESM::ESMReader &esm)
// ... unless it got deleted! This means that the following record
// has been deleted, and trying to load it using standard assumptions
// on the structure will (probably) fail.
/*
if (esm.isNextSub("DELE")) {
esm.skipRecord();
all.erase(id);
it->second->remove(id);
it->second->eraseStatic(id);
continue;
}
*/
it->second->load(esm, id);
if (n.val==ESM::REC_DIAL) {
// dirty hack, but it is better than non-const search()
// or friends
dialogue = &mDialogs.mStatic.back();
//dialogue = &mDialogs.mStatic.back();
dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
assert (dialogue->mId == id);
} else {
dialogue = 0;
@ -140,12 +138,11 @@ void ESMStore::setUp()
ESM::NPC item;
item.mId = "player";
std::vector<ESM::NPC>::iterator pIt =
std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp());
assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player");
const ESM::NPC *pIt = mNpcs.find("player");
assert(pIt != NULL);
mNpcs.insert(*pIt);
mNpcs.mStatic.erase(pIt);
mNpcs.eraseStatic(pIt->mId);
}
} // end namespace

View File

@ -19,6 +19,8 @@ namespace MWWorld
virtual int getSize() const = 0;
virtual void load(ESM::ESMReader &esm, const std::string &id) = 0;
virtual bool eraseStatic(const std::string &id) {return false;}
};
template <class T>
@ -85,7 +87,7 @@ namespace MWWorld
template <class T>
class Store : public StoreBase
{
std::vector<T> mStatic;
std::map<std::string, T> mStatic;
std::vector<T *> mShared;
std::map<std::string, T> mDynamic;
@ -107,11 +109,10 @@ namespace MWWorld
T item;
item.mId = StringUtils::lowerCase(id);
typename std::vector<T>::const_iterator it =
std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp());
if (it != mStatic.end() && StringUtils::ciEqual(it->mId, id)) {
return &(*it);
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) {
return &(it->second);
}
typename Dynamic::const_iterator dit = mDynamic.find(item.mId);
@ -133,18 +134,19 @@ namespace MWWorld
}
void load(ESM::ESMReader &esm, const std::string &id) {
mStatic.push_back(T());
mStatic.back().mId = StringUtils::lowerCase(id);
mStatic.back().load(esm);
std::string idLower = StringUtils::lowerCase(id);
mStatic[idLower] = T();
mStatic[idLower].mId = idLower;
mStatic[idLower].load(esm);
}
void setUp() {
std::sort(mStatic.begin(), mStatic.end(), RecordCmp());
//std::sort(mStatic.begin(), mStatic.end(), RecordCmp());
mShared.reserve(mStatic.size());
typename std::vector<T>::iterator it = mStatic.begin();
typename std::map<std::string, T>::iterator it = mStatic.begin();
for (; it != mStatic.end(); ++it) {
mShared.push_back(&(*it));
mShared.push_back(&(it->second));
}
}
@ -181,6 +183,19 @@ namespace MWWorld
return ptr;
}
bool eraseStatic(const std::string &id) {
T item;
item.mId = StringUtils::lowerCase(id);
typename std::map<std::string, T>::const_iterator it = mStatic.find(item.mId);
if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) {
mStatic.erase(it);
}
return true;
}
bool erase(const std::string &id) {
std::string key = StringUtils::lowerCase(id);
typename Dynamic::iterator it = mDynamic.find(key);
@ -204,16 +219,18 @@ namespace MWWorld
template <>
inline void Store<ESM::Dialogue>::load(ESM::ESMReader &esm, const std::string &id) {
mStatic.push_back(ESM::Dialogue());
mStatic.back().mId = id;
mStatic.back().load(esm);
std::string idLower = StringUtils::lowerCase(id);
mStatic[idLower] = ESM::Dialogue();
mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think
mStatic[idLower].load(esm);
}
template <>
inline void Store<ESM::Script>::load(ESM::ESMReader &esm, const std::string &id) {
mStatic.push_back(ESM::Script());
mStatic.back().load(esm);
StringUtils::toLower(mStatic.back().mId);
ESM::Script scpt;
scpt.load(esm);
StringUtils::toLower(scpt.mId);
mStatic[scpt.mId] = scpt;
}
template <>
@ -478,6 +495,7 @@ namespace MWWorld
// are not available until both cells have been loaded! So first, proceed as usual.
// All cells have a name record, even nameless exterior cells.
std::string idLower = StringUtils::lowerCase(id);
ESM::Cell *cell = new ESM::Cell;
cell->mName = id;
@ -487,7 +505,7 @@ namespace MWWorld
if(cell->mData.mFlags & ESM::Cell::Interior)
{
// Store interior cell by name, try to merge with existing parent data.
ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(id));
ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(idLower));
if (oldcell) {
// push the new references on the list of references to manage
oldcell->mContextList.push_back(cell->mContextList.at(0));
@ -496,7 +514,7 @@ namespace MWWorld
// have new cell replace old cell
*oldcell = *cell;
} else
mInt[cell->mName] = *cell;
mInt[idLower] = *cell;
delete cell;
}
else