removed redundant deletion flag from CellRef

pull/22/head
Marc Zinnschlag 11 years ago
parent 18e7e83585
commit 43dd3b8ef2

@ -236,7 +236,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
// Loop through all the references // Loop through all the references
ESM::CellRef ref; ESM::CellRef ref;
if(!quiet) std::cout << " References:\n"; if(!quiet) std::cout << " References:\n";
while(cell.getNextRef(esm, ref))
bool deleted = false;
while(cell.getNextRef(esm, ref, deleted))
{ {
if (save) { if (save) {
info.data.mCellRefs[&cell].push_back(ref); info.data.mCellRefs[&cell].push_back(ref);
@ -251,6 +253,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Uses/health: '" << ref.mCharge << "'\n";
std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n";
std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl; std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl;
std::cout << " Deleted: " << deleted << std::endl;
} }
} }

@ -8,6 +8,5 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
mId = id; mId = id;
mCell = cell.mId; mCell = cell.mId;
if (!mDeleted) cell.addRef (mId);
cell.addRef (mId);
} }

@ -14,7 +14,8 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CellRef ref; CellRef ref;
while (cell2.getNextRef (reader, ref)) bool deleted = false;
while (cell2.getNextRef (reader, ref, deleted))
{ {
/// \todo handle deleted and moved references /// \todo handle deleted and moved references
ref.load (reader, cell2, getNewId()); ref.load (reader, cell2, getNewId());

@ -35,32 +35,30 @@ namespace MWWorld
{ {
template <typename X> template <typename X>
void CellRefList<X>::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) void CellRefList<X>::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore)
{ {
// Get existing reference, in case we need to overwrite it. const MWWorld::Store<X> &store = esmStore.get<X>();
typename std::list<LiveRef>::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum);
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)
liveCellRef.mData.setCount (0);
// Skip this when reference was deleted.
// TODO: Support respawning references, in this case, we need to track it somehow.
if (ref.mDeleted) {
if (iter != mList.end()) if (iter != mList.end())
mList.erase(iter); *iter = liveCellRef;
return; else
mList.push_back (liveCellRef);
} }
else
// for throwing exception on unhandled record type {
const MWWorld::Store<X> &store = esmStore.get<X>(); std::cerr
const X *ptr = store.search(ref.mRefID); << "Error: could not resolve cell reference " << ref.mRefID
<< " (dropping reference)" << std::endl;
/// \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) {
std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl;
} else {
if (iter != mList.end())
*iter = LiveRef(ref, ptr);
else
mList.push_back(LiveRef(ref, ptr));
} }
} }
@ -117,16 +115,13 @@ namespace MWWorld
ESM::CellRef ref; ESM::CellRef ref;
// Get each reference in turn // Get each reference in turn
while (mCell->getNextRef (esm[index], ref)) bool deleted = false;
while (mCell->getNextRef (esm[index], ref, deleted))
{ {
std::string lowerCase = Misc::StringUtils::lowerCase (ref.mRefID); if (deleted)
if (ref.mDeleted) {
// Right now, don't do anything. Where is "listRefs" actually used, anyway?
// Skipping for now...
continue; continue;
}
mIds.push_back (lowerCase); mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID));
} }
} }
@ -135,7 +130,7 @@ namespace MWWorld
void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm) void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
{ {
assert (mCell); assert (mCell);
if (mCell->mContextList.empty()) if (mCell->mContextList.empty())
return; // this is a dynamically generated cell -> skipping. return; // this is a dynamically generated cell -> skipping.
@ -150,102 +145,25 @@ namespace MWWorld
ESM::CellRef ref; ESM::CellRef ref;
// Get each reference in turn // Get each reference in turn
while(mCell->getNextRef(esm[index], ref)) bool deleted = false;
while(mCell->getNextRef(esm[index], ref, deleted))
{ {
// Don't load reference if it was moved to a different cell. // Don't load reference if it was moved to a different cell.
std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID);
ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum);
if (iter != mCell->mMovedRefs.end()) { if (iter != mCell->mMovedRefs.end()) {
continue; continue;
} }
int rec = store.find(ref.mRefID);
loadRef (ref, deleted, store);
ref.mRefID = lowerCase;
/* We can optimize this further by storing the pointer to the
record itself in store.all, so that we don't need to look it
up again here. However, never optimize. There are infinite
opportunities to do that later.
*/
switch(rec)
{
case ESM::REC_ACTI: mActivators.load(ref, store); break;
case ESM::REC_ALCH: mPotions.load(ref, store); break;
case ESM::REC_APPA: mAppas.load(ref, store); break;
case ESM::REC_ARMO: mArmors.load(ref, store); break;
case ESM::REC_BOOK: mBooks.load(ref, store); break;
case ESM::REC_CLOT: mClothes.load(ref, store); break;
case ESM::REC_CONT: mContainers.load(ref, store); break;
case ESM::REC_CREA: mCreatures.load(ref, store); break;
case ESM::REC_DOOR: mDoors.load(ref, store); break;
case ESM::REC_INGR: mIngreds.load(ref, store); break;
case ESM::REC_LEVC: mCreatureLists.load(ref, store); break;
case ESM::REC_LEVI: mItemLists.load(ref, store); break;
case ESM::REC_LIGH: mLights.load(ref, store); break;
case ESM::REC_LOCK: mLockpicks.load(ref, store); break;
case ESM::REC_MISC: mMiscItems.load(ref, store); break;
case ESM::REC_NPC_: mNpcs.load(ref, store); break;
case ESM::REC_PROB: mProbes.load(ref, store); break;
case ESM::REC_REPA: mRepairs.load(ref, store); break;
case ESM::REC_STAT: mStatics.load(ref, store); break;
case ESM::REC_WEAP: mWeapons.load(ref, store); break;
case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
default:
std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
}
} }
} }
// Load moved references, from separately tracked list. // Load moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it) for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{ {
// Doesn't seem to work in one line... huh? Too sleepy to check...
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it); ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
//ESM::CellRef &ref = const_cast<ESM::CellRef&>(it->second);
std::string lowerCase;
std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase),
(int(*)(int)) std::tolower);
int rec = store.find(ref.mRefID);
ref.mRefID = lowerCase;
/* We can optimize this further by storing the pointer to the
record itself in store.all, so that we don't need to look it
up again here. However, never optimize. There are infinite
opportunities to do that later.
*/
switch(rec)
{
case ESM::REC_ACTI: mActivators.load(ref, store); break;
case ESM::REC_ALCH: mPotions.load(ref, store); break;
case ESM::REC_APPA: mAppas.load(ref, store); break;
case ESM::REC_ARMO: mArmors.load(ref, store); break;
case ESM::REC_BOOK: mBooks.load(ref, store); break;
case ESM::REC_CLOT: mClothes.load(ref, store); break;
case ESM::REC_CONT: mContainers.load(ref, store); break;
case ESM::REC_CREA: mCreatures.load(ref, store); break;
case ESM::REC_DOOR: mDoors.load(ref, store); break;
case ESM::REC_INGR: mIngreds.load(ref, store); break;
case ESM::REC_LEVC: mCreatureLists.load(ref, store); break;
case ESM::REC_LEVI: mItemLists.load(ref, store); break;
case ESM::REC_LIGH: mLights.load(ref, store); break;
case ESM::REC_LOCK: mLockpicks.load(ref, store); break;
case ESM::REC_MISC: mMiscItems.load(ref, store); break;
case ESM::REC_NPC_: mNpcs.load(ref, store); break;
case ESM::REC_PROB: mProbes.load(ref, store); break;
case ESM::REC_REPA: mRepairs.load(ref, store); break;
case ESM::REC_STAT: mStatics.load(ref, store); break;
case ESM::REC_WEAP: mWeapons.load(ref, store); break;
case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break;
default:
std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
}
loadRef (ref, false, store);
} }
} }
@ -274,4 +192,39 @@ namespace MWWorld
return Ptr(); return Ptr();
} }
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store)
{
Misc::StringUtils::toLower (ref.mRefID);
switch (store.find (ref.mRefID))
{
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
case ESM::REC_ALCH: mPotions.load(ref, deleted, store); break;
case ESM::REC_APPA: mAppas.load(ref, deleted, store); break;
case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break;
case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break;
case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break;
case ESM::REC_CONT: mContainers.load(ref, deleted, store); break;
case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break;
case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break;
case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break;
case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break;
case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break;
case ESM::REC_LIGH: mLights.load(ref, deleted, store); break;
case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break;
case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break;
case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break;
case ESM::REC_PROB: mProbes.load(ref, deleted, store); break;
case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break;
case ESM::REC_STAT: mStatics.load(ref, deleted, store); break;
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break;
default:
std::cerr
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
}
}
} }

@ -25,7 +25,7 @@ namespace MWWorld
// and the build will fail with an ugly three-way cyclic header dependence // and the build will fail with an ugly three-way cyclic header dependence
// so we need to pass the instantiation of the method to the lnker, when // so we need to pass the instantiation of the method to the lnker, when
// all methods are known. // all methods are known.
void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); void load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore);
LiveRef *find (const std::string& name) LiveRef *find (const std::string& name)
{ {
@ -154,6 +154,11 @@ namespace MWWorld
void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store);
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.
}; };
} }

@ -108,7 +108,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
} }
// Insert the reference into the global lookup // Insert the reference into the global lookup
if (!id.empty() && isCacheableRecord(n.val)) { if (!id.empty() && isCacheableRecord(n.val)) {
mIds[id] = n.val; mIds[Misc::StringUtils::lowerCase (id)] = n.val;
} }
} }
listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);

@ -10,7 +10,7 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
// and we merge all this data into one Cell object. However, we can't simply search for the cell id, // and we merge all this data into one Cell object. However, we can't simply search for the cell id,
// as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they
// 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 = Misc::StringUtils::lowerCase(id); std::string idLower = Misc::StringUtils::lowerCase(id);
ESM::Cell *cell = new ESM::Cell; ESM::Cell *cell = new ESM::Cell;
@ -30,11 +30,10 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
// Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following
// implementation when the oher implementation works as well. // implementation when the oher implementation works as well.
cell->getNextRef(esm, ref); bool deleted = false;
std::string lowerCase; cell->getNextRef(esm, ref, deleted);
std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), Misc::StringUtils::toLower (ref.mRefID);
(int(*)(int)) std::tolower);
// Add data required to make reference appear in the correct cell. // Add data required to make reference appear in the correct cell.
// We should not need to test for duplicates, as this part of the code is pre-cell merge. // We should not need to test for duplicates, as this part of the code is pre-cell merge.

@ -71,9 +71,6 @@ namespace ESM
// -1 is not blocked, otherwise it is blocked. // -1 is not blocked, otherwise it is blocked.
signed char mReferenceBlocked; signed char mReferenceBlocked;
// Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn.
int mDeleted;
// Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza
// Brindisi Dorom", where it has the value 100. Also only for // Brindisi Dorom", where it has the value 100. Also only for
// activators. // activators.

@ -141,7 +141,7 @@ std::string Cell::getDescription() const
} }
} }
bool Cell::getNextRef(ESMReader &esm, CellRef &ref) bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted)
{ {
// TODO: Try and document reference numbering, I don't think this has been done anywhere else. // TODO: Try and document reference numbering, I don't think this has been done anywhere else.
if (!esm.hasMoreSubs()) if (!esm.hasMoreSubs())
@ -259,12 +259,13 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref)
//esm.getHNOT(NAM0, "NAM0"); //esm.getHNOT(NAM0, "NAM0");
} }
if (esm.isNextSub("DELE")) { if (esm.isNextSub("DELE"))
{
esm.skipHSub(); esm.skipHSub();
ref.mDeleted = 2; // Deleted, will not respawn. deleted = true;
// TODO: find out when references do respawn. }
} else else
ref.mDeleted = 0; deleted = false;
return true; return true;
} }

@ -141,7 +141,7 @@ struct Cell
All fields of the CellRef struct are overwritten. You can safely All fields of the CellRef struct are overwritten. You can safely
reuse one memory location without blanking it between calls. reuse one memory location without blanking it between calls.
*/ */
static bool getNextRef(ESMReader &esm, CellRef &ref); static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted);
/* This fetches an MVRF record, which is used to track moved references. /* This fetches an MVRF record, which is used to track moved references.
* Since they are comparably rare, we use a separate method for this. * Since they are comparably rare, we use a separate method for this.

Loading…
Cancel
Save