From bdb6896c3ff963219b86c13057603f24f755c1cc Mon Sep 17 00:00:00 2001 From: Nicolay Korslund Date: Thu, 20 May 2010 18:59:36 +0200 Subject: [PATCH] Created (a very slow) cell loader. Will optimize. --- CMakeLists.txt | 2 +- esm/loadcell.hpp | 12 +++-- game/cell_store.cpp | 63 ++++++++++++++++++++++++++ game/cell_store.hpp | 103 ++++++++++++++++++++++++++++++++++++++++++ game/esm_reclists.hpp | 26 ++++++++++- game/esm_store.hpp | 13 ++++++ game/main.cpp | 35 ++++---------- game/setup.cpp | 36 +++++++++++++++ 8 files changed, 257 insertions(+), 33 deletions(-) create mode 100644 game/cell_store.cpp create mode 100644 game/cell_store.hpp create mode 100644 game/setup.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4093e3387..7a4198a22 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) +set(GAME game/main.cpp game/esm_store.cpp game/cell_store.cpp game/setup.cpp) # Platform specific if (WIN32) diff --git a/esm/loadcell.hpp b/esm/loadcell.hpp index 3080dd50e..1a361580a 100644 --- a/esm/loadcell.hpp +++ b/esm/loadcell.hpp @@ -162,12 +162,16 @@ struct Cell // somewhere other than the file system, you need to pre-open the // ESMReader, and the filename must match the stored filename // exactly. - void restore(ESMReader &esm) + void restore(ESMReader &esm) const { esm.restoreContext(context); } - // Get the next reference in this cell, if any. Returns false when - // there are no more references in the cell. - bool getNextRef(ESMReader &esm, CellRef &ref) + /* Get the next reference in this cell, if any. Returns false when + there are no more references in the cell. + + All fields of the CellRef struct are overwritten. You can safely + reuse one memory location without blanking it between calls. + */ + static bool getNextRef(ESMReader &esm, CellRef &ref) { if(!esm.hasMoreSubs()) return false; diff --git a/game/cell_store.cpp b/game/cell_store.cpp new file mode 100644 index 000000000..a24ac6b8a --- /dev/null +++ b/game/cell_store.cpp @@ -0,0 +1,63 @@ +#include "cell_store.hpp" +#include +#include "mangle/tools/str_exception.h" + +using namespace ESMS; +using namespace std; + +void CellStore::loadInt(const std::string &name, const ESMStore &store, ESMReader &esm) +{ + cout << "loading cell '" << name << "'\n"; + + const Cell *ref = store.cells.findInt(name); + + if(ref == NULL) + throw str_exception("Cell not found - " + name); + + loadRefs(*ref, store, esm); +} + +void CellStore::loadExt(int X, int Y, const ESMStore &store, ESMReader &esm) +{ +} + +void CellStore::loadRefs(const Cell &cell, const ESMStore &store, ESMReader &esm) +{ + // 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)) + { + 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; + } +} diff --git a/game/cell_store.hpp b/game/cell_store.hpp new file mode 100644 index 000000000..d63fcf3da --- /dev/null +++ b/game/cell_store.hpp @@ -0,0 +1,103 @@ +#ifndef _GAME_CELL_STORE_H +#define _GAME_CELL_STORE_H + +/* + Cell storage. + + Used to load, look up and store all references in a single cell. + + Depends on esm/loadcell.hpp (loading from ESM) and esm_store.hpp + (looking up references.) Neither of these modules depend on us. + */ + +#include "esm_store.hpp" +#include "esm/records.hpp" +#include + +namespace ESMS +{ + using namespace ESM; + + /// A reference to one object (of any type) in a cell. + template + struct LiveCellRef + { + // The object that this instance is based on. + const X* base; + + /* Information about this instance, such as 3D location and + rotation and individual type-dependent data. + */ + CellRef ref; + + /* Pointer to any user-defined or engine-specific object. Eg. a + Sound object for sound sources. + */ + void *custom; + }; + + /// A list of cell references + template + struct CellRefList + { + typedef LiveCellRef LiveRef; + std::list list; + + // 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. + template + bool find(CellRef &ref, Y recList) + { + const X* obj = recList.find(ref.refID); + if(obj == NULL) return true; + + LiveRef lr; + lr.ref = ref; + lr.base = obj; + lr.custom = NULL; + + list.push_back(lr); + + return false; + } + }; + + /// A storage struct for one single cell reference. + struct CellStore + { + // Lists for each individual object type + CellRefList activators; + CellRefList potions; + CellRefList appas; + CellRefList armors; + CellRefList books; + CellRefList clothes; + CellRefList containers; + CellRefList creatures; + CellRefList doors; + CellRefList ingreds; + CellRefList creatureLists; + CellRefList itemLists; + CellRefList lights; + CellRefList lockpicks; + CellRefList miscItems; + CellRefList npcs; + CellRefList probes; + CellRefList repairs; + CellRefList statics; + CellRefList weapons; + + /** Look up and load an interior cell from the given ESM data + storage. */ + void loadInt(const std::string &name, const ESMStore &data, ESMReader &esm); + + /** Ditto for exterior cell. */ + void loadExt(int X, int Y, const ESMStore &data, ESMReader &esm); + + private: + void loadRefs(const Cell &cell, const ESMStore &data, ESMReader &esm); + }; +} + +#endif diff --git a/game/esm_reclists.hpp b/game/esm_reclists.hpp index 793478904..bf9ea639f 100644 --- a/game/esm_reclists.hpp +++ b/game/esm_reclists.hpp @@ -4,6 +4,7 @@ #include "esm/records.hpp" #include #include +#include namespace ESMS { @@ -24,6 +25,7 @@ namespace ESMS MapType list; + // Load one object of this type void load(ESMReader &esm) { std::string id = esm.getHNString("NAME"); @@ -32,6 +34,14 @@ namespace ESMS ref.load(esm); } + // Find the given object ID, or return NULL if not found. + const X* find(const std::string &id) const + { + if(list.find(id) == list.end()) + return NULL; + return &list.find(id)->second; + } + int getSize() { return list.size(); } }; @@ -67,10 +77,22 @@ namespace ESMS int getSize() { return count; } // List of interior cells. Indexed by cell name. - std::map intCells; + typedef std::map IntCells; + IntCells intCells; // List of exterior cells. Indexed as extCells[gridX][gridY]. - std::map > extCells; + typedef std::map > ExtCells; + ExtCells extCells; + + const Cell* findInt(const std::string &id) const + { + IntCells::const_iterator it = intCells.find(id); + + if(it == intCells.end()) + return NULL; + + return &it->second; + } void load(ESMReader &esm) { diff --git a/game/esm_store.hpp b/game/esm_store.hpp index 57c902d0a..1903eeca1 100644 --- a/game/esm_store.hpp +++ b/game/esm_store.hpp @@ -1,6 +1,19 @@ #ifndef _GAME_ESM_STORE_H #define _GAME_ESM_STORE_H +/* + The ESM storage module. + + This is separate from the ESM loader module, located in esm/. It is + also unaware of the cell loading and storage module. + + The advantage of this, as with all other modularizations, is that + you can replace the storage method later without touching the + loading code. Cutting down dependencies also help on the general + maintainability. + + */ + #include "esm/records.hpp" #include "esm_reclists.hpp" diff --git a/game/main.cpp b/game/main.cpp index d65d3305e..a05cc29cb 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,45 +1,28 @@ #include -#include "bsa/bsa_archive.h" #include "esm_store.hpp" - -#include "Ogre.h" +#include "cell_store.hpp" using namespace std; -// Absolute minimal OGRE setup -void ogre_setup() -{ - using namespace Ogre; - - // Disable Ogre logging - new LogManager; - Log *log = LogManager::getSingleton().createLog(""); - log->setDebugOutputEnabled(false); - - // Set up Root. - new Root(); -} +// See setup.cpp +void main_setup(const char* bsaFile); void maintest() { - const char* bsaFile = "data/Morrowind.bsa"; const char* esmFile = "data/Morrowind.esm"; + const char* bsaFile = "data/Morrowind.bsa"; - cout << "Hello, fellow traveler!\n"; - - cout << "Initializing OGRE\n"; - ogre_setup(); - - cout << "Adding " << bsaFile << endl; - addBSA(bsaFile); + main_setup(bsaFile); cout << "Loading ESM " << esmFile << "\n"; ESM::ESMReader esm; - esm.open(esmFile); ESMS::ESMStore store; + ESMS::CellStore cell; + + esm.open(esmFile); store.load(esm); - esm.close(); + cell.loadInt("Beshara", store, esm); cout << "\nThat's all for now!\n"; } diff --git a/game/setup.cpp b/game/setup.cpp new file mode 100644 index 000000000..448afa138 --- /dev/null +++ b/game/setup.cpp @@ -0,0 +1,36 @@ +/* Split off into a separate file just to increase compile + speed. Parsing Ogre.h takes a long time, and the Ogre-dependent + part doesn't change much. This entire layout will change later. + */ + +#include +#include "bsa/bsa_archive.h" +#include "Ogre.h" + +using namespace std; + +// Absolute minimal OGRE setup +void ogre_setup() +{ + using namespace Ogre; + + // Disable Ogre logging + new LogManager; + Log *log = LogManager::getSingleton().createLog(""); + log->setDebugOutputEnabled(false); + + // Set up Root. + new Root(); +} + +void main_setup(const char* bsaFile) +{ + cout << "Hello, fellow traveler!\n"; + + cout << "Initializing OGRE\n"; + ogre_setup(); + + cout << "Adding " << bsaFile << endl; + addBSA(bsaFile); +} +