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:
parent
049b0e66e0
commit
8ccec17481
3 changed files with 50 additions and 34 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue