diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a4198a22..ff461fc43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ set(BSA bsa/bsa_archive.cpp bsa/bsa_file.cpp) set(NIF nif/nif_file.cpp nifogre/ogre_nif_loader.cpp) set(TOOLS tools/stringops.cpp) set(MANGLE_VFS mangle/vfs/servers/ogre_vfs.cpp) -set(GAME game/main.cpp game/esm_store.cpp game/cell_store.cpp game/setup.cpp) +set(GAME game/main.cpp game/esm_store/store.cpp game/cell_store.cpp game/setup.cpp) # Platform specific if (WIN32) diff --git a/esm/loadcell.hpp b/esm/loadcell.hpp index 1a361580a..dcb255949 100644 --- a/esm/loadcell.hpp +++ b/esm/loadcell.hpp @@ -118,9 +118,6 @@ struct Cell void load(ESMReader &esm) { - // All cells have a name record, even nameless exterior cells. - name = esm.getHNString("NAME"); - // Ignore this for now, it might mean we should delete the entire // cell? if(esm.isNextSub("DELE")) esm.skipHSub(); diff --git a/game/cell_store.cpp b/game/cell_store.cpp index a24ac6b8a..d07007ad2 100644 --- a/game/cell_store.cpp +++ b/game/cell_store.cpp @@ -31,33 +31,41 @@ void CellStore::loadRefs(const Cell &cell, const ESMStore &store, ESMReader &esm // Get each reference in turn while(cell.getNextRef(esm, ref)) { - cout << "Reference: " << ref.refID; - - // Check each list in turn. Potential for optimization. - if( - activators .find(ref, store.activators) && - potions .find(ref, store.potions) && - appas .find(ref, store.appas) && - armors .find(ref, store.armors) && - books .find(ref, store.books) && - clothes .find(ref, store.clothes) && - containers .find(ref, store.containers) && - creatures .find(ref, store.creatures) && - doors .find(ref, store.doors) && - ingreds .find(ref, store.ingreds) && - creatureLists .find(ref, store.creatureLists) && - itemLists .find(ref, store.itemLists) && - lights .find(ref, store.lights) && - lockpicks .find(ref, store.lockpicks) && - miscItems .find(ref, store.miscItems) && - npcs .find(ref, store.npcs) && - probes .find(ref, store.probes) && - repairs .find(ref, store.repairs) && - statics .find(ref, store.statics) && - weapons .find(ref, store.weapons) - - ) cout << " (NOT FOUND)"; - - cout << endl; + int rec = store.find(ref.refID); + + /* 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: cout << "Cell reference " + ref.refID + " not found!\n"; break; + default: + assert(0); + } } + + cout << "Statics in cell: " << statics.list.size() << endl; } diff --git a/game/cell_store.hpp b/game/cell_store.hpp index d63fcf3da..56fe0fb37 100644 --- a/game/cell_store.hpp +++ b/game/cell_store.hpp @@ -10,8 +10,9 @@ (looking up references.) Neither of these modules depend on us. */ -#include "esm_store.hpp" +#include "esm_store/store.hpp" #include "esm/records.hpp" +#include "mangle/tools/str_exception.h" #include namespace ESMS @@ -45,12 +46,13 @@ namespace ESMS // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is - // found, and returns false. Returns true if no match is found. + // found. If not, throw an exception. template - bool find(CellRef &ref, Y recList) + void find(CellRef &ref, Y recList) { const X* obj = recList.find(ref.refID); - if(obj == NULL) return true; + if(obj == NULL) + throw str_exception("Error resolving cell reference " + ref.refID); LiveRef lr; lr.ref = ref; @@ -58,8 +60,6 @@ namespace ESMS lr.custom = NULL; list.push_back(lr); - - return false; } }; diff --git a/game/esm_reclists.hpp b/game/esm_store/reclists.hpp similarity index 87% rename from game/esm_reclists.hpp rename to game/esm_store/reclists.hpp index bf9ea639f..e02bc95b6 100644 --- a/game/esm_reclists.hpp +++ b/game/esm_store/reclists.hpp @@ -12,7 +12,7 @@ namespace ESMS struct RecList { - virtual void load(ESMReader &esm) = 0; + virtual void load(ESMReader &esm, const std::string &id) = 0; virtual int getSize() = 0; }; @@ -26,10 +26,8 @@ namespace ESMS MapType list; // Load one object of this type - void load(ESMReader &esm) + void load(ESMReader &esm, const std::string &id) { - std::string id = esm.getHNString("NAME"); - X &ref = list[id]; ref.load(esm); } @@ -55,10 +53,8 @@ namespace ESMS MapType list; - void load(ESMReader &esm) + void load(ESMReader &esm, const std::string &id) { - std::string id = esm.getHNString("NAME"); - X &ref = list[id]; ref.id = id; ref.load(esm); @@ -94,20 +90,23 @@ namespace ESMS return &it->second; } - void load(ESMReader &esm) + void load(ESMReader &esm, const std::string &id) { using namespace std; count++; - // The cell itself takes care of all the hairy details + // All cells have a name record, even nameless exterior cells. Cell cell; + cell.name = id; + + // The cell itself takes care of all the hairy details cell.load(esm); if(cell.data.flags & Cell::Interior) { // Store interior cell by name - intCells[cell.name] = cell; + intCells[id] = cell; } else { diff --git a/game/esm_store.cpp b/game/esm_store/store.cpp similarity index 84% rename from game/esm_store.cpp rename to game/esm_store/store.cpp index a532fa542..b5a24f532 100644 --- a/game/esm_store.cpp +++ b/game/esm_store/store.cpp @@ -1,6 +1,6 @@ #include #include -#include "esm_store.hpp" +#include "store.hpp" using namespace std; using namespace ESM; @@ -36,7 +36,12 @@ void ESMStore::load(ESMReader &esm) } // Load it - it->second->load(esm); + std::string id = esm.getHNOString("NAME"); + it->second->load(esm, id); + + // Insert the reference into the global lookup + if(!id.empty()) + all[id] = n.val; } cout << "\n" << recLists.size() << " record types:\n"; diff --git a/game/esm_store.hpp b/game/esm_store/store.hpp similarity index 91% rename from game/esm_store.hpp rename to game/esm_store/store.hpp index 1903eeca1..a09891e6a 100644 --- a/game/esm_store.hpp +++ b/game/esm_store/store.hpp @@ -15,7 +15,7 @@ */ #include "esm/records.hpp" -#include "esm_reclists.hpp" +#include "reclists.hpp" namespace ESMS { @@ -78,6 +78,19 @@ namespace ESMS //RecListT skills; //RecListT pathgrids; + // Lookup of all IDs. Makes looking up references faster. Just + // maps the id name to the record type. + typedef std::map AllMap; + AllMap all; + + // Look up the given ID in 'all'. Returns 0 if not found. + int find(const std::string &id) const + { + AllMap::const_iterator it = all.find(id); + if(it == all.end()) return 0; + return it->second; + } + ESMStore() { recLists[REC_ACTI] = &activators; diff --git a/game/main.cpp b/game/main.cpp index a05cc29cb..1d7ec097b 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,6 +1,5 @@ #include -#include "esm_store.hpp" #include "cell_store.hpp" using namespace std;