mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 20:56:42 +00:00 
			
		
		
		
	accessing references via their ID now also works for references in containers in active cells
This commit is contained in:
		
							parent
							
								
									aee0336780
								
							
						
					
					
						commit
						e94fcce622
					
				
					 6 changed files with 111 additions and 37 deletions
				
			
		|  | @ -48,7 +48,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS | |||
| { | ||||
|     Ptr ptr = getPtr (name, cellStore); | ||||
| 
 | ||||
|     if (!ptr.isEmpty()) | ||||
|     if (!ptr.isEmpty() && ptr.isInCell()) | ||||
|     { | ||||
|         mIdCache[mIdCacheIndex].first = name; | ||||
|         mIdCache[mIdCacheIndex].second = &cellStore; | ||||
|  | @ -121,7 +121,8 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) | |||
|     return &result->second; | ||||
| } | ||||
| 
 | ||||
| MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& cell) | ||||
| MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& cell, | ||||
|     bool searchInContainers) | ||||
| { | ||||
|     if (cell.mState==Ptr::CellStore::State_Unloaded) | ||||
|         cell.preload (mStore, mReader); | ||||
|  | @ -138,71 +139,69 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce | |||
|             return Ptr(); | ||||
|     } | ||||
| 
 | ||||
|     MWWorld::Ptr ptr; | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Activator> *ref = cell.mActivators.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Potion> *ref = cell.mPotions.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Apparatus> *ref = cell.mAppas.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Armor> *ref = cell.mArmors.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Book> *ref = cell.mBooks.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Clothing> *ref = cell.mClothes.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Container> *ref = cell.mContainers.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Creature> *ref = cell.mCreatures.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Door> *ref = cell.mDoors.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Ingredient> *ref = cell.mIngreds.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::CreatureLevList> *ref = cell.mCreatureLists.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::ItemLevList> *ref = cell.mItemLists.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Light> *ref = cell.mLights.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Lockpick> *ref = cell.mLockpicks.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = cell.mMiscItems.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::NPC> *ref = cell.mNpcs.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Probe> *ref = cell.mProbes.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Repair> *ref = cell.mRepairs.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Static> *ref = cell.mStatics.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (MWWorld::LiveCellRef<ESM::Weapon> *ref = cell.mWeapons.find (name)) | ||||
|         ptr = Ptr (ref, &cell); | ||||
|         return Ptr (ref, &cell); | ||||
| 
 | ||||
|     if (searchInContainers) | ||||
|         return cell.searchInContainer (name); | ||||
| 
 | ||||
|     if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) { | ||||
|         return ptr; | ||||
|     } | ||||
|     return Ptr(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,7 +45,8 @@ namespace MWWorld | |||
| 
 | ||||
|             CellStore *getInterior (const std::string& name); | ||||
| 
 | ||||
|             Ptr getPtr (const std::string& name, CellStore& cellStore); | ||||
|             Ptr getPtr (const std::string& name, CellStore& cellStore, bool searchInContainers = false); | ||||
|             ///< \param searchInContainers Only affect loaded cells.
 | ||||
| 
 | ||||
|             Ptr getPtr (const std::string& name); | ||||
|     }; | ||||
|  |  | |||
|  | @ -7,6 +7,29 @@ | |||
| 
 | ||||
| #include "ptr.hpp" | ||||
| #include "esmstore.hpp" | ||||
| #include "class.hpp" | ||||
| #include "containerstore.hpp" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     template<typename T> | ||||
|     MWWorld::Ptr searchInContainerList (MWWorld::CellRefList<T>& containerList, const std::string& id) | ||||
|     { | ||||
|         for (typename MWWorld::CellRefList<T>::List::iterator iter (containerList.mList.begin()); | ||||
|              iter!=containerList.mList.end(); ++iter) | ||||
|         { | ||||
|             MWWorld::Ptr container (&*iter, 0); | ||||
| 
 | ||||
|             MWWorld::Ptr ptr = | ||||
|                 MWWorld::Class::get (container).getContainerStore (container).search (id); | ||||
| 
 | ||||
|             if (!ptr.isEmpty()) | ||||
|                 return ptr; | ||||
|         } | ||||
| 
 | ||||
|         return MWWorld::Ptr(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|  | @ -16,14 +39,14 @@ namespace MWWorld | |||
|     { | ||||
|         // Get existing reference, in case we need to overwrite it.
 | ||||
|         typename std::list<LiveRef>::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum); | ||||
|          | ||||
| 
 | ||||
|         // Skip this when reference was deleted.
 | ||||
|         // TODO: Support respawning references, in this case, we need to track it somehow.
 | ||||
|         if (ref.mDeleted) { | ||||
|             mList.erase(iter); | ||||
|             return; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         // for throwing exception on unhandled record type
 | ||||
|         const MWWorld::Store<X> &store = esmStore.get<X>(); | ||||
|         const X *ptr = store.search(ref.mRefID); | ||||
|  | @ -39,7 +62,7 @@ namespace MWWorld | |||
|             mList.push_back(LiveRef(ref, ptr)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     template<typename X> bool operator==(const LiveCellRef<X>& ref, int pRefnum) | ||||
|     { | ||||
|         return (ref.mRef.mRefnum == pRefnum); | ||||
|  | @ -133,7 +156,7 @@ namespace MWWorld | |||
|                 ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); | ||||
|                 if (iter != mCell->mMovedRefs.end()) { | ||||
|                     continue; | ||||
|                 }                     | ||||
|                 } | ||||
|                 int rec = store.find(ref.mRefID); | ||||
| 
 | ||||
|                 ref.mRefID = lowerCase; | ||||
|  | @ -186,7 +209,7 @@ namespace MWWorld | |||
|                 (int(*)(int)) std::tolower); | ||||
| 
 | ||||
|             int rec = store.find(ref.mRefID); | ||||
|              | ||||
| 
 | ||||
|             ref.mRefID = lowerCase; | ||||
| 
 | ||||
|             /* We can optimize this further by storing the pointer to the
 | ||||
|  | @ -221,7 +244,33 @@ namespace MWWorld | |||
|                 default: | ||||
|                 std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; | ||||
|                 } | ||||
|              | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ptr CellStore::searchInContainer (const std::string& id) | ||||
|     { | ||||
|         { | ||||
|             Ptr ptr = searchInContainerList (mContainers, id); | ||||
| 
 | ||||
|             if (!ptr.isEmpty()) | ||||
|                 return ptr; | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             Ptr ptr = searchInContainerList (mCreatures, id); | ||||
| 
 | ||||
|             if (!ptr.isEmpty()) | ||||
|                 return ptr; | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             Ptr ptr = searchInContainerList (mNpcs, id); | ||||
| 
 | ||||
|             if (!ptr.isEmpty()) | ||||
|                 return ptr; | ||||
|         } | ||||
| 
 | ||||
|         return Ptr(); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -131,6 +131,8 @@ namespace MWWorld | |||
|         return mCell->isExterior(); | ||||
|     } | ||||
| 
 | ||||
|     Ptr searchInContainer (const std::string& id); | ||||
| 
 | ||||
|   private: | ||||
| 
 | ||||
|     template<class Functor, class List> | ||||
|  | @ -148,6 +150,7 @@ namespace MWWorld | |||
|     void listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); | ||||
| 
 | ||||
|     void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); | ||||
| 
 | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| 
 | ||||
| #include <components/esm/loadcont.hpp> | ||||
| #include <components/compiler/locals.hpp> | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
|  | @ -85,12 +86,12 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr | |||
|         CellStore *cell; | ||||
| 
 | ||||
|         Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); | ||||
|          | ||||
| 
 | ||||
|         if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) | ||||
|         { | ||||
|             cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed
 | ||||
|             | ||||
|             // Set OnPCAdd special variable, if it is declared 
 | ||||
| 
 | ||||
|             // Set OnPCAdd special variable, if it is declared
 | ||||
|             item.mRefData->getLocals().setVarByInt(script, "onpcadd", 1); | ||||
|         } | ||||
|         else | ||||
|  | @ -347,6 +348,25 @@ int MWWorld::ContainerStore::getType (const Ptr& ptr) | |||
|         "Object of type " + ptr.getTypeName() + " can not be placed into a container"); | ||||
| } | ||||
| 
 | ||||
| MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id) | ||||
| { | ||||
|     /// \todo Since we have direct access to the CellRefList here, the performance of this function
 | ||||
|     /// could be improved notably by iterating directly over the CellRefLists instead of using
 | ||||
|     /// a ContainerStoreIterator.
 | ||||
| 
 | ||||
|     std::string id2 = Misc::StringUtils::lowerCase (id); | ||||
| 
 | ||||
|     for (ContainerStoreIterator iter (this); iter!=end(); ++iter) | ||||
|     { | ||||
|         Ptr ptr = *iter; | ||||
| 
 | ||||
|         if (Misc::StringUtils::lowerCase (Class::get (ptr).getId (ptr))==id2) | ||||
|             return ptr; | ||||
|     } | ||||
| 
 | ||||
|     return Ptr(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container) | ||||
| : mType (-1), mMask (0), mContainer (container) | ||||
|  |  | |||
|  | @ -106,6 +106,8 @@ namespace MWWorld | |||
|             ///< This function throws an exception, if ptr does not point to an object, that can be
 | ||||
|             /// put into a container.
 | ||||
| 
 | ||||
|             Ptr search (const std::string& id); | ||||
| 
 | ||||
|         friend class ContainerStoreIterator; | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue