void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) { bool quiet = (info.quiet_given || info.mode == "clone"); bool save = (info.mode == "clone"); // Skip back to the beginning of the reference list // FIXME: Changes to the references backend required to support multiple plugins have // almost certainly broken this following line. I'll leave it as is for now, so that // the compiler does not complain. cell.restore(esm, 0); // Loop through all the references ESM::CellRef ref; if(!quiet) std::cout << " References:\n"; while(cell.getNextRef(esm, ref)) { if (save) { info.data.mCellRefs[&cell].push_back(ref); } if(quiet) continue; std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Blocked: '" << static_cast<int>(ref.mReferenceBlocked) << "'" << std::endl; } }
/// Run through references and store IDs void listRefs(const ESMStore &store, ESMReader &esm) { assert (cell); if (cell->context.filename.empty()) return; // this is a dynamically generated cell -> skipping. // Reopen the ESM reader and seek to the right position. cell->restore (esm); CellRef ref; // Get each reference in turn while (cell->getNextRef (esm, ref)) { std::string lowerCase; std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); mIds.push_back (lowerCase); } std::sort (mIds.begin(), mIds.end()); }
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader) { ESM::Cell cell; bool isDeleted = false; cell.loadNameAndData(esmReader, isDeleted); return QString::fromStdString(cell.mName); }
void loadRefs(const ESMStore &store, ESMReader &esm) { assert (cell); if (cell->context.filename.empty()) return; // this is a dynamically generated cell -> skipping. // Reopen the ESM reader and seek to the right position. cell->restore(esm); CellRef ref; // Get each reference in turn while(cell->getNextRef(esm, ref)) { std::string lowerCase; std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); int rec = store.find(ref.refID); ref.refID = 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 REC_ACTI: activators.find(ref, store.activators); break; case REC_ALCH: potions.find(ref, store.potions); break; case REC_APPA: appas.find(ref, store.appas); break; case REC_ARMO: armors.find(ref, store.armors); break; case REC_BOOK: books.find(ref, store.books); break; case REC_CLOT: clothes.find(ref, store.clothes); break; case REC_CONT: containers.find(ref, store.containers); break; case REC_CREA: creatures.find(ref, store.creatures); break; case REC_DOOR: doors.find(ref, store.doors); break; case REC_INGR: ingreds.find(ref, store.ingreds); break; case REC_LEVC: creatureLists.find(ref, store.creatureLists); break; case REC_LEVI: itemLists.find(ref, store.itemLists); break; case REC_LIGH: lights.find(ref, store.lights); break; case REC_LOCK: lockpicks.find(ref, store.lockpicks); break; case REC_MISC: miscItems.find(ref, store.miscItems); break; case REC_NPC_: npcs.find(ref, store.npcs); break; case REC_PROB: probes.find(ref, store.probes); break; case REC_REPA: repairs.find(ref, store.repairs); break; case REC_STAT: statics.find(ref, store.statics); break; case REC_WEAP: weapons.find(ref, store.weapons); break; case 0: std::cout << "Cell reference " + ref.refID + " not found!\n"; break; default: std::cout << "WARNING: Ignoring reference '" << ref.refID << "' of unhandled type\n"; } } }
void load(ESMReader &esm, const std::string &id) { count++; // All cells have a name record, even nameless exterior cells. ESM::Cell *cell = new ESM::Cell; cell->name = id; // The cell itself takes care of all the hairy details cell->load(esm); if(cell->data.flags & ESM::Cell::Interior) { // Store interior cell by name intCells[id] = cell; } else { // Store exterior cells by grid position extCells[std::make_pair (cell->data.gridX, cell->data.gridY)] = cell; } }
void load (const ESMStore &store, ESMReader &esm) { if (mState!=State_Loaded) { if (mState==State_Preloaded) mIds.clear(); std::cout << "loading cell " << cell->getDescription() << std::endl; loadRefs (store, esm); mState = State_Loaded; } }
bool isExterior() const { return mCell->isExterior(); }
void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // 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 // are not available until both cells have been loaded at least partially! // All cells have a name record, even nameless exterior cells. std::string idLower = Misc::StringUtils::lowerCase(id); ESM::Cell cell; cell.mName = id; // Load the (x,y) coordinates of the cell, if it is an exterior cell, // so we can find the cell we need to merge with cell.loadData(esm); 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(idLower)); if (oldcell) { // merge new cell into old cell // push the new references on the list of references to manage (saveContext = true) oldcell->mData = cell.mData; oldcell->loadCell(esm, true); } else { // spawn a new cell cell.loadCell(esm, true); mInt[idLower] = cell; } } else { // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(cell.getGridX(), cell.getGridY())); if (oldcell) { // merge new cell into old cell oldcell->mData = cell.mData; oldcell->loadCell(esm, false); // handle moved ref (MVRF) subrecords handleMovedCellRefs (esm, &cell); // push the new references on the list of references to manage oldcell->postLoad(esm); // merge lists of leased references, use newer data in case of conflict for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { // remove reference from current leased ref tracker and add it to new cell ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); if (itold != oldcell->mMovedRefs.end()) { ESM::MovedCellRef target0 = *itold; ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1])); ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); wipecell->mLeasedRefs.erase(it_lease); *itold = *it; } } // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a // reference to this cell, so the list for the new cell should be empty. The list for oldcell, // however, could have leased refs in it and so should be kept. } else { // spawn a new cell cell.loadCell(esm, false); // handle moved ref (MVRF) subrecords handleMovedCellRefs (esm, &cell); // push the new references on the list of references to manage cell.postLoad(esm); mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; } } }
void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id) { // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, // 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 // 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 = Misc::StringUtils::lowerCase(id); ESM::Cell *cell = new ESM::Cell; cell->mName = id; //First part of cell loading cell->preLoad(esm); //Handling MovedCellRefs, there is no way to do it inside loadcell while (esm.isNextSub("MVRF")) { ESM::CellRef ref; ESM::MovedCellRef cMRef; cell->getNextMVRF(esm, cMRef); MWWorld::Store<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(mEsmStore->get<ESM::Cell>()); ESM::Cell *cellAlt = const_cast<ESM::Cell*>(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. cell->getNextRef(esm, ref); std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); // 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. cell->mMovedRefs.push_back(cMRef); // But there may be duplicates here! ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); if (iter == cellAlt->mLeasedRefs.end()) cellAlt->mLeasedRefs.push_back(ref); else *iter = ref; } //Second part of cell loading cell->postLoad(esm); 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(idLower)); if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); // copy list into new cell cell->mContextList = oldcell->mContextList; // have new cell replace old cell *oldcell = *cell; } else mInt[idLower] = *cell; } else { // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast<ESM::Cell*>(search(cell->getGridX(), cell->getGridY())); if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); // copy list into new cell cell->mContextList = oldcell->mContextList; // merge lists of leased references, use newer data in case of conflict for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { // remove reference from current leased ref tracker and add it to new cell ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); if (itold != oldcell->mMovedRefs.end()) { ESM::MovedCellRef target0 = *itold; ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1])); ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); wipecell->mLeasedRefs.erase(it_lease); *itold = *it; } } cell->mMovedRefs = oldcell->mMovedRefs; // have new cell replace old cell *oldcell = *cell; } else mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; } delete cell; }