1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-21 20:11:34 +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 // for throwing exception on unhandled record type
const MWWorld::Store<X> &store = esmStore.get<X>(); 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) { if (ptr == NULL) {
throw std::runtime_error("Error resolving cell reference " + ref.mRefID); std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl;
} } else
mList[ref.mRefnum] = LiveRef(ref, ptr); mList[ref.mRefnum] = LiveRef(ref, ptr);
} }
LiveRef *find (const std::string& name) 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 // ... unless it got deleted! This means that the following record
// has been deleted, and trying to load it using standard assumptions // has been deleted, and trying to load it using standard assumptions
// on the structure will (probably) fail. // on the structure will (probably) fail.
/*
if (esm.isNextSub("DELE")) { if (esm.isNextSub("DELE")) {
esm.skipRecord(); esm.skipRecord();
all.erase(id); it->second->eraseStatic(id);
it->second->remove(id);
continue; continue;
} }
*/
it->second->load(esm, id); it->second->load(esm, id);
if (n.val==ESM::REC_DIAL) { if (n.val==ESM::REC_DIAL) {
// dirty hack, but it is better than non-const search() // dirty hack, but it is better than non-const search()
// or friends // or friends
dialogue = &mDialogs.mStatic.back(); //dialogue = &mDialogs.mStatic.back();
dialogue = const_cast<ESM::Dialogue*>(mDialogs.find(id));
assert (dialogue->mId == id); assert (dialogue->mId == id);
} else { } else {
dialogue = 0; dialogue = 0;
@ -140,12 +138,11 @@ void ESMStore::setUp()
ESM::NPC item; ESM::NPC item;
item.mId = "player"; item.mId = "player";
std::vector<ESM::NPC>::iterator pIt = const ESM::NPC *pIt = mNpcs.find("player");
std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp()); assert(pIt != NULL);
assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player");
mNpcs.insert(*pIt); mNpcs.insert(*pIt);
mNpcs.mStatic.erase(pIt); mNpcs.eraseStatic(pIt->mId);
} }
} // end namespace } // end namespace

View file

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