OpenMW
|
00001 #ifndef OPENMW_MWWORLD_ESMSTORE_H 00002 #define OPENMW_MWWORLD_ESMSTORE_H 00003 00004 #include <stdexcept> 00005 00006 #include <components/esm/records.hpp> 00007 #include "store.hpp" 00008 00009 namespace Loading 00010 { 00011 class Listener; 00012 } 00013 00014 namespace MWWorld 00015 { 00016 class ESMStore 00017 { 00018 Store<ESM::Activator> mActivators; 00019 Store<ESM::Potion> mPotions; 00020 Store<ESM::Apparatus> mAppas; 00021 Store<ESM::Armor> mArmors; 00022 Store<ESM::BodyPart> mBodyParts; 00023 Store<ESM::Book> mBooks; 00024 Store<ESM::BirthSign> mBirthSigns; 00025 Store<ESM::Class> mClasses; 00026 Store<ESM::Clothing> mClothes; 00027 Store<ESM::LoadCNTC> mContChange; 00028 Store<ESM::Container> mContainers; 00029 Store<ESM::Creature> mCreatures; 00030 Store<ESM::LoadCREC> mCreaChange; 00031 Store<ESM::Dialogue> mDialogs; 00032 Store<ESM::Door> mDoors; 00033 Store<ESM::Enchantment> mEnchants; 00034 Store<ESM::Faction> mFactions; 00035 Store<ESM::Global> mGlobals; 00036 Store<ESM::Ingredient> mIngreds; 00037 Store<ESM::CreatureLevList> mCreatureLists; 00038 Store<ESM::ItemLevList> mItemLists; 00039 Store<ESM::Light> mLights; 00040 Store<ESM::Lockpick> mLockpicks; 00041 Store<ESM::Miscellaneous> mMiscItems; 00042 Store<ESM::NPC> mNpcs; 00043 Store<ESM::LoadNPCC> mNpcChange; 00044 Store<ESM::Probe> mProbes; 00045 Store<ESM::Race> mRaces; 00046 Store<ESM::Region> mRegions; 00047 Store<ESM::Repair> mRepairs; 00048 Store<ESM::SoundGenerator> mSoundGens; 00049 Store<ESM::Sound> mSounds; 00050 Store<ESM::Spell> mSpells; 00051 Store<ESM::StartScript> mStartScripts; 00052 Store<ESM::Static> mStatics; 00053 Store<ESM::Weapon> mWeapons; 00054 00055 Store<ESM::GameSetting> mGameSettings; 00056 Store<ESM::Script> mScripts; 00057 00058 // Lists that need special rules 00059 Store<ESM::Cell> mCells; 00060 Store<ESM::Land> mLands; 00061 Store<ESM::LandTexture> mLandTextures; 00062 Store<ESM::Pathgrid> mPathgrids; 00063 00064 Store<ESM::MagicEffect> mMagicEffects; 00065 Store<ESM::Skill> mSkills; 00066 00067 // Special entry which is hardcoded and not loaded from an ESM 00068 Store<ESM::Attribute> mAttributes; 00069 00070 // Lookup of all IDs. Makes looking up references faster. Just 00071 // maps the id name to the record type. 00072 std::map<std::string, int> mIds; 00073 std::map<int, StoreBase *> mStores; 00074 00075 ESM::NPC mPlayerTemplate; 00076 00077 unsigned int mDynamicCount; 00078 00079 public: 00081 typedef std::map<int, StoreBase *>::const_iterator iterator; 00082 00083 iterator begin() const { 00084 return mStores.begin(); 00085 } 00086 00087 iterator end() const { 00088 return mStores.end(); 00089 } 00090 00091 // Look up the given ID in 'all'. Returns 0 if not found. 00092 int find(const std::string &id) const 00093 { 00094 std::map<std::string, int>::const_iterator it = mIds.find(id); 00095 if (it == mIds.end()) { 00096 return 0; 00097 } 00098 return it->second; 00099 } 00100 00101 ESMStore() 00102 : mDynamicCount(0) 00103 { 00104 // Cell store needs access to this for tracking moved references 00105 mCells.mEsmStore = this; 00106 00107 mStores[ESM::REC_ACTI] = &mActivators; 00108 mStores[ESM::REC_ALCH] = &mPotions; 00109 mStores[ESM::REC_APPA] = &mAppas; 00110 mStores[ESM::REC_ARMO] = &mArmors; 00111 mStores[ESM::REC_BODY] = &mBodyParts; 00112 mStores[ESM::REC_BOOK] = &mBooks; 00113 mStores[ESM::REC_BSGN] = &mBirthSigns; 00114 mStores[ESM::REC_CELL] = &mCells; 00115 mStores[ESM::REC_CLAS] = &mClasses; 00116 mStores[ESM::REC_CLOT] = &mClothes; 00117 mStores[ESM::REC_CNTC] = &mContChange; 00118 mStores[ESM::REC_CONT] = &mContainers; 00119 mStores[ESM::REC_CREA] = &mCreatures; 00120 mStores[ESM::REC_CREC] = &mCreaChange; 00121 mStores[ESM::REC_DIAL] = &mDialogs; 00122 mStores[ESM::REC_DOOR] = &mDoors; 00123 mStores[ESM::REC_ENCH] = &mEnchants; 00124 mStores[ESM::REC_FACT] = &mFactions; 00125 mStores[ESM::REC_GLOB] = &mGlobals; 00126 mStores[ESM::REC_GMST] = &mGameSettings; 00127 mStores[ESM::REC_INGR] = &mIngreds; 00128 mStores[ESM::REC_LAND] = &mLands; 00129 mStores[ESM::REC_LEVC] = &mCreatureLists; 00130 mStores[ESM::REC_LEVI] = &mItemLists; 00131 mStores[ESM::REC_LIGH] = &mLights; 00132 mStores[ESM::REC_LOCK] = &mLockpicks; 00133 mStores[ESM::REC_LTEX] = &mLandTextures; 00134 mStores[ESM::REC_MISC] = &mMiscItems; 00135 mStores[ESM::REC_NPC_] = &mNpcs; 00136 mStores[ESM::REC_NPCC] = &mNpcChange; 00137 mStores[ESM::REC_PGRD] = &mPathgrids; 00138 mStores[ESM::REC_PROB] = &mProbes; 00139 mStores[ESM::REC_RACE] = &mRaces; 00140 mStores[ESM::REC_REGN] = &mRegions; 00141 mStores[ESM::REC_REPA] = &mRepairs; 00142 mStores[ESM::REC_SCPT] = &mScripts; 00143 mStores[ESM::REC_SNDG] = &mSoundGens; 00144 mStores[ESM::REC_SOUN] = &mSounds; 00145 mStores[ESM::REC_SPEL] = &mSpells; 00146 mStores[ESM::REC_SSCR] = &mStartScripts; 00147 mStores[ESM::REC_STAT] = &mStatics; 00148 mStores[ESM::REC_WEAP] = &mWeapons; 00149 } 00150 00151 void clearDynamic () 00152 { 00153 for (std::map<int, StoreBase *>::iterator it = mStores.begin(); it != mStores.end(); ++it) 00154 it->second->clearDynamic(); 00155 00156 mNpcs.insert(mPlayerTemplate); 00157 } 00158 00159 void movePlayerRecord () 00160 { 00161 mPlayerTemplate = *mNpcs.find("player"); 00162 mNpcs.eraseStatic(mPlayerTemplate.mId); 00163 mNpcs.insert(mPlayerTemplate); 00164 } 00165 00166 void load(ESM::ESMReader &esm, Loading::Listener* listener); 00167 00168 template <class T> 00169 const Store<T> &get() const { 00170 throw std::runtime_error("Storage for this type not exist"); 00171 } 00172 00173 template <class T> 00174 const T *insert(const T &x) { 00175 Store<T> &store = const_cast<Store<T> &>(get<T>()); 00176 if (store.search(x.mId) != 0) { 00177 std::ostringstream msg; 00178 msg << "Try to override existing record '" << x.mId << "'"; 00179 throw std::runtime_error(msg.str()); 00180 } 00181 T record = x; 00182 00183 std::ostringstream id; 00184 id << "$dynamic" << mDynamicCount++; 00185 record.mId = id.str(); 00186 00187 T *ptr = store.insert(record); 00188 for (iterator it = mStores.begin(); it != mStores.end(); ++it) { 00189 if (it->second == &store) { 00190 mIds[ptr->mId] = it->first; 00191 } 00192 } 00193 return ptr; 00194 } 00195 00196 template <class T> 00197 const T *insertStatic(const T &x) { 00198 Store<T> &store = const_cast<Store<T> &>(get<T>()); 00199 if (store.search(x.mId) != 0) { 00200 std::ostringstream msg; 00201 msg << "Try to override existing record '" << x.mId << "'"; 00202 throw std::runtime_error(msg.str()); 00203 } 00204 T record = x; 00205 00206 T *ptr = store.insertStatic(record); 00207 for (iterator it = mStores.begin(); it != mStores.end(); ++it) { 00208 if (it->second == &store) { 00209 mIds[ptr->mId] = it->first; 00210 } 00211 } 00212 return ptr; 00213 } 00214 00215 // This method must be called once, after loading all master/plugin files. This can only be done 00216 // from the outside, so it must be public. 00217 void setUp(); 00218 }; 00219 00220 template <> 00221 inline const ESM::Cell *ESMStore::insert<ESM::Cell>(const ESM::Cell &cell) { 00222 return mCells.insert(cell); 00223 } 00224 00225 template <> 00226 inline const ESM::NPC *ESMStore::insert<ESM::NPC>(const ESM::NPC &npc) { 00227 if (Misc::StringUtils::ciEqual(npc.mId, "player")) { 00228 return mNpcs.insert(npc); 00229 } else if (mNpcs.search(npc.mId) != 0) { 00230 std::ostringstream msg; 00231 msg << "Try to override existing record '" << npc.mId << "'"; 00232 throw std::runtime_error(msg.str()); 00233 } 00234 ESM::NPC record = npc; 00235 00236 std::ostringstream id; 00237 id << "$dynamic" << mDynamicCount++; 00238 record.mId = id.str(); 00239 00240 ESM::NPC *ptr = mNpcs.insert(record); 00241 mIds[ptr->mId] = ESM::REC_NPC_; 00242 return ptr; 00243 } 00244 00245 template <> 00246 inline const Store<ESM::Activator> &ESMStore::get<ESM::Activator>() const { 00247 return mActivators; 00248 } 00249 00250 template <> 00251 inline const Store<ESM::Potion> &ESMStore::get<ESM::Potion>() const { 00252 return mPotions; 00253 } 00254 00255 template <> 00256 inline const Store<ESM::Apparatus> &ESMStore::get<ESM::Apparatus>() const { 00257 return mAppas; 00258 } 00259 00260 template <> 00261 inline const Store<ESM::Armor> &ESMStore::get<ESM::Armor>() const { 00262 return mArmors; 00263 } 00264 00265 template <> 00266 inline const Store<ESM::BodyPart> &ESMStore::get<ESM::BodyPart>() const { 00267 return mBodyParts; 00268 } 00269 00270 template <> 00271 inline const Store<ESM::Book> &ESMStore::get<ESM::Book>() const { 00272 return mBooks; 00273 } 00274 00275 template <> 00276 inline const Store<ESM::BirthSign> &ESMStore::get<ESM::BirthSign>() const { 00277 return mBirthSigns; 00278 } 00279 00280 template <> 00281 inline const Store<ESM::Class> &ESMStore::get<ESM::Class>() const { 00282 return mClasses; 00283 } 00284 00285 template <> 00286 inline const Store<ESM::Clothing> &ESMStore::get<ESM::Clothing>() const { 00287 return mClothes; 00288 } 00289 00290 template <> 00291 inline const Store<ESM::LoadCNTC> &ESMStore::get<ESM::LoadCNTC>() const { 00292 return mContChange; 00293 } 00294 00295 template <> 00296 inline const Store<ESM::Container> &ESMStore::get<ESM::Container>() const { 00297 return mContainers; 00298 } 00299 00300 template <> 00301 inline const Store<ESM::Creature> &ESMStore::get<ESM::Creature>() const { 00302 return mCreatures; 00303 } 00304 00305 template <> 00306 inline const Store<ESM::LoadCREC> &ESMStore::get<ESM::LoadCREC>() const { 00307 return mCreaChange; 00308 } 00309 00310 template <> 00311 inline const Store<ESM::Dialogue> &ESMStore::get<ESM::Dialogue>() const { 00312 return mDialogs; 00313 } 00314 00315 template <> 00316 inline const Store<ESM::Door> &ESMStore::get<ESM::Door>() const { 00317 return mDoors; 00318 } 00319 00320 template <> 00321 inline const Store<ESM::Enchantment> &ESMStore::get<ESM::Enchantment>() const { 00322 return mEnchants; 00323 } 00324 00325 template <> 00326 inline const Store<ESM::Faction> &ESMStore::get<ESM::Faction>() const { 00327 return mFactions; 00328 } 00329 00330 template <> 00331 inline const Store<ESM::Global> &ESMStore::get<ESM::Global>() const { 00332 return mGlobals; 00333 } 00334 00335 template <> 00336 inline const Store<ESM::Ingredient> &ESMStore::get<ESM::Ingredient>() const { 00337 return mIngreds; 00338 } 00339 00340 template <> 00341 inline const Store<ESM::CreatureLevList> &ESMStore::get<ESM::CreatureLevList>() const { 00342 return mCreatureLists; 00343 } 00344 00345 template <> 00346 inline const Store<ESM::ItemLevList> &ESMStore::get<ESM::ItemLevList>() const { 00347 return mItemLists; 00348 } 00349 00350 template <> 00351 inline const Store<ESM::Light> &ESMStore::get<ESM::Light>() const { 00352 return mLights; 00353 } 00354 00355 template <> 00356 inline const Store<ESM::Lockpick> &ESMStore::get<ESM::Lockpick>() const { 00357 return mLockpicks; 00358 } 00359 00360 template <> 00361 inline const Store<ESM::Miscellaneous> &ESMStore::get<ESM::Miscellaneous>() const { 00362 return mMiscItems; 00363 } 00364 00365 template <> 00366 inline const Store<ESM::NPC> &ESMStore::get<ESM::NPC>() const { 00367 return mNpcs; 00368 } 00369 00370 template <> 00371 inline const Store<ESM::LoadNPCC> &ESMStore::get<ESM::LoadNPCC>() const { 00372 return mNpcChange; 00373 } 00374 00375 template <> 00376 inline const Store<ESM::Probe> &ESMStore::get<ESM::Probe>() const { 00377 return mProbes; 00378 } 00379 00380 template <> 00381 inline const Store<ESM::Race> &ESMStore::get<ESM::Race>() const { 00382 return mRaces; 00383 } 00384 00385 template <> 00386 inline const Store<ESM::Region> &ESMStore::get<ESM::Region>() const { 00387 return mRegions; 00388 } 00389 00390 template <> 00391 inline const Store<ESM::Repair> &ESMStore::get<ESM::Repair>() const { 00392 return mRepairs; 00393 } 00394 00395 template <> 00396 inline const Store<ESM::SoundGenerator> &ESMStore::get<ESM::SoundGenerator>() const { 00397 return mSoundGens; 00398 } 00399 00400 template <> 00401 inline const Store<ESM::Sound> &ESMStore::get<ESM::Sound>() const { 00402 return mSounds; 00403 } 00404 00405 template <> 00406 inline const Store<ESM::Spell> &ESMStore::get<ESM::Spell>() const { 00407 return mSpells; 00408 } 00409 00410 template <> 00411 inline const Store<ESM::StartScript> &ESMStore::get<ESM::StartScript>() const { 00412 return mStartScripts; 00413 } 00414 00415 template <> 00416 inline const Store<ESM::Static> &ESMStore::get<ESM::Static>() const { 00417 return mStatics; 00418 } 00419 00420 template <> 00421 inline const Store<ESM::Weapon> &ESMStore::get<ESM::Weapon>() const { 00422 return mWeapons; 00423 } 00424 00425 template <> 00426 inline const Store<ESM::GameSetting> &ESMStore::get<ESM::GameSetting>() const { 00427 return mGameSettings; 00428 } 00429 00430 template <> 00431 inline const Store<ESM::Script> &ESMStore::get<ESM::Script>() const { 00432 return mScripts; 00433 } 00434 00435 template <> 00436 inline const Store<ESM::Cell> &ESMStore::get<ESM::Cell>() const { 00437 return mCells; 00438 } 00439 00440 template <> 00441 inline const Store<ESM::Land> &ESMStore::get<ESM::Land>() const { 00442 return mLands; 00443 } 00444 00445 template <> 00446 inline const Store<ESM::LandTexture> &ESMStore::get<ESM::LandTexture>() const { 00447 return mLandTextures; 00448 } 00449 00450 template <> 00451 inline const Store<ESM::Pathgrid> &ESMStore::get<ESM::Pathgrid>() const { 00452 return mPathgrids; 00453 } 00454 00455 template <> 00456 inline const Store<ESM::MagicEffect> &ESMStore::get<ESM::MagicEffect>() const { 00457 return mMagicEffects; 00458 } 00459 00460 template <> 00461 inline const Store<ESM::Skill> &ESMStore::get<ESM::Skill>() const { 00462 return mSkills; 00463 } 00464 00465 template <> 00466 inline const Store<ESM::Attribute> &ESMStore::get<ESM::Attribute>() const { 00467 return mAttributes; 00468 } 00469 } 00470 00471 #endif