From 9c2145eda126cb05abe2f84213fce6fa242b92e5 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 29 Sep 2013 09:11:57 +0200 Subject: [PATCH] Issue #913: Merge --master and --plugin switches Merged master/plugin switches into content in openmw and mwiniimporter. Extension in content files is now required. Signed-off-by: Lukasz Gromanowski --- apps/mwiniimporter/importer.cpp | 25 ++----- apps/openmw/CMakeLists.txt | 1 + apps/openmw/engine.cpp | 40 +++-------- apps/openmw/engine.hpp | 15 ++-- apps/openmw/main.cpp | 36 +++------- apps/openmw/mwworld/contentloader.hpp | 35 +++++++++ apps/openmw/mwworld/esmloader.cpp | 31 ++++++++ apps/openmw/mwworld/esmloader.hpp | 34 +++++++++ apps/openmw/mwworld/omwloader.cpp | 17 +++++ apps/openmw/mwworld/omwloader.hpp | 21 ++++++ apps/openmw/mwworld/worldimp.cpp | 100 +++++++++++++++++--------- apps/openmw/mwworld/worldimp.hpp | 15 +++- 12 files changed, 254 insertions(+), 116 deletions(-) create mode 100644 apps/openmw/mwworld/contentloader.hpp create mode 100644 apps/openmw/mwworld/esmloader.cpp create mode 100644 apps/openmw/mwworld/esmloader.hpp create mode 100644 apps/openmw/mwworld/omwloader.cpp create mode 100644 apps/openmw/mwworld/omwloader.hpp diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 8732b3eab..b8b7e4c9d 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -813,8 +813,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector esmFiles; - std::vector espFiles; + std::vector contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); @@ -832,29 +831,19 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co std::string filetype(entry->substr(entry->length()-3)); Misc::StringUtils::toLower(filetype); - if(filetype.compare("esm") == 0) { - esmFiles.push_back(*entry); - } - else if(filetype.compare("esp") == 0) { - espFiles.push_back(*entry); + if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { + contentFiles.push_back(*entry); } } gameFile = ""; } - cfg.erase("master"); - cfg.insert( std::make_pair > ("master", std::vector() ) ); + cfg.erase("content"); + cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) { - cfg["master"].push_back(*it); - } - - cfg.erase("plugin"); - cfg.insert( std::make_pair > ("plugin", std::vector() ) ); - - for(std::vector::const_iterator it=espFiles.begin(); it!=espFiles.end(); ++it) { - cfg["plugin"].push_back(*it); + for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(*it); } } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b367e2a1e..807b1b5ff 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -58,6 +58,7 @@ add_openmw_dir (mwworld cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor + contentloader esmloader omwloader ) add_openmw_dir (mwclass diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a2eccbaf9..d29301ed3 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -261,34 +261,14 @@ void OMW::Engine::setCell (const std::string& cellName) mCellName = cellName; } -// Set master file (esm) -// - If the given name does not have an extension, ".esm" is added automatically - -void OMW::Engine::addMaster (const std::string& master) +void OMW::Engine::addContentFile(const std::string& file) { - mMaster.push_back(master); - std::string &str = mMaster.back(); + if (file.find_last_of(".") == std::string::npos) + { + throw std::runtime_error("Missing extension in content file!"); + } - // Append .esm if not already there - std::string::size_type sep = str.find_last_of ("."); - if (sep == std::string::npos) - { - str += ".esm"; - } -} - -// Add plugin file (esp) -void OMW::Engine::addPlugin (const std::string& plugin) -{ - mPlugins.push_back(plugin); - std::string &str = mPlugins.back(); - - // Append .esp if not already there - std::string::size_type sep = str.find_last_of ("."); - if (sep == std::string::npos) - { - str += ".esp"; - } + mContentFiles.push_back(file); } void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) @@ -403,7 +383,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.getWindowManager()->setNewGame(true); // Create the world - mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, + mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, mActivationDistanceOverride)); MWBase::Environment::get().getWorld()->setupPlayer(); @@ -414,8 +394,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //Load translation data mTranslationDataStorage.setEncoder(mEncoder); - for (size_t i = 0; i < mMaster.size(); i++) - mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]); + for (size_t i = 0; i < mContentFiles.size(); i++) + mTranslationDataStorage.loadTranslationData(mFileCollections, mContentFiles[i]); Compiler::registerExtensions (mExtensions); @@ -480,7 +460,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::go() { assert (!mCellName.empty()); - assert (!mMaster.empty()); + assert (!mContentFiles.empty()); assert (!mOgre); Settings::Manager settings; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 665b0094c..553d29068 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -68,8 +68,7 @@ namespace OMW boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; std::string mCellName; - std::vector mMaster; - std::vector mPlugins; + std::vector mContentFiles; int mFpsLevel; bool mVerboseScripts; bool mNewGame; @@ -135,13 +134,11 @@ namespace OMW /// Set start cell name (only interiors for now) void setCell(const std::string& cellName); - /// Set master file (esm) - /// - If the given name does not have an extension, ".esm" is added automatically - void addMaster(const std::string& master); - - /// Same as "addMaster", but for plugin files (esp) - /// - If the given name does not have an extension, ".esp" is added automatically - void addPlugin(const std::string& plugin); + /** + * @brief addContentFile - Adds content file (ie. esm/esp, or omwgame/omwaddon) to the content files container. + * @param file - filename (extension is required) + */ + void addContentFile(const std::string& file); /// Enable fps counter void showFPS(int level); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 27afd734a..33f740b31 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -110,11 +110,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("start", bpo::value()->default_value("Beshara"), "set initial cell") - ("master", bpo::value()->default_value(StringsVector(), "") - ->multitoken(), "master file(s)") - - ("plugin", bpo::value()->default_value(StringsVector(), "") - ->multitoken(), "plugin file(s)") + ("content", bpo::value()->default_value(StringsVector(), "") + ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ("anim-verbose", bpo::value()->implicit_value(true) ->default_value(false), "output animation indices files") @@ -152,8 +149,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("activate-dist", bpo::value ()->default_value (-1), "activation distance override"); - ; - bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) .options(desc).allow_unregistered().run(); @@ -211,29 +206,18 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setResourceDir(variables["resources"].as()); - // master and plugin - StringsVector master = variables["master"].as(); - if (master.empty()) + StringsVector content = variables["content"].as(); + if (content.empty()) { - std::cout << "No master file given. Aborting...\n"; - return false; + std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl; + return false; } - StringsVector plugin = variables["plugin"].as(); - // Removed check for 255 files, which would be the hard-coded limit in Morrowind. - // I'll keep the following variable in, maybe we can use it for something different. - // Say, a feedback like "loading file x/cnt". - // Commenting this out for now to silence compiler warning. - //int cnt = master.size() + plugin.size(); - - // Prepare loading master/plugin files (i.e. send filenames to engine) - for (std::vector::size_type i = 0; i < master.size(); i++) + StringsVector::const_iterator it(content.begin()); + StringsVector::const_iterator end(content.end()); + for (; it != end; ++it) { - engine.addMaster(master[i]); - } - for (std::vector::size_type i = 0; i < plugin.size(); i++) - { - engine.addPlugin(plugin[i]); + engine.addContentFile(*it); } // startup-settings diff --git a/apps/openmw/mwworld/contentloader.hpp b/apps/openmw/mwworld/contentloader.hpp new file mode 100644 index 000000000..c57935c90 --- /dev/null +++ b/apps/openmw/mwworld/contentloader.hpp @@ -0,0 +1,35 @@ +#ifndef CONTENTLOADER_HPP +#define CONTENTLOADER_HPP + +#include +#include + +#include "components/loadinglistener/loadinglistener.hpp" + +namespace MWWorld +{ + +struct ContentLoader +{ + ContentLoader(Loading::Listener& listener) + : mListener(listener) + { + } + + virtual ~ContentLoader() + { + } + + virtual void load(const boost::filesystem::path& filepath, int& index) + { + std::cout << "Loading content file " << filepath.string() << std::endl; + mListener.setLabel(filepath.string()); + } + + protected: + Loading::Listener& mListener; +}; + +} /* namespace MWWorld */ + +#endif /* CONTENTLOADER_HPP */ diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp new file mode 100644 index 000000000..1b8880d37 --- /dev/null +++ b/apps/openmw/mwworld/esmloader.cpp @@ -0,0 +1,31 @@ +#include "esmloader.hpp" +#include "esmstore.hpp" + +#include "components/to_utf8/to_utf8.hpp" + +namespace MWWorld +{ + +EsmLoader::EsmLoader(MWWorld::ESMStore& store, std::vector& readers, + ToUTF8::Utf8Encoder* encoder, Loading::Listener& listener) + : ContentLoader(listener) + , mStore(store) + , mEsm(readers) + , mEncoder(encoder) +{ +} + +void EsmLoader::load(const boost::filesystem::path& filepath, int& index) +{ + ContentLoader::load(filepath.filename(), index); + + ESM::ESMReader lEsm; + lEsm.setEncoder(mEncoder); + lEsm.setIndex(index); + lEsm.setGlobalReaderList(&mEsm); + lEsm.open(filepath.string()); + mEsm[index] = lEsm; + mStore.load(mEsm[index], &mListener); +} + +} /* namespace MWWorld */ diff --git a/apps/openmw/mwworld/esmloader.hpp b/apps/openmw/mwworld/esmloader.hpp new file mode 100644 index 000000000..d799c3f15 --- /dev/null +++ b/apps/openmw/mwworld/esmloader.hpp @@ -0,0 +1,34 @@ +#ifndef ESMLOADER_HPP +#define ESMLOADER_HPP + +#include + +#include "contentloader.hpp" +#include "components/esm/esmreader.hpp" + +namespace ToUTF8 +{ + class Utf8Encoder; +} + +namespace MWWorld +{ + +class ESMStore; + +struct EsmLoader : public ContentLoader +{ + EsmLoader(MWWorld::ESMStore& store, std::vector& readers, + ToUTF8::Utf8Encoder* encoder, Loading::Listener& listener); + + void load(const boost::filesystem::path& filepath, int& index); + + private: + std::vector& mEsm; + MWWorld::ESMStore& mStore; + ToUTF8::Utf8Encoder* mEncoder; +}; + +} /* namespace MWWorld */ + +#endif // ESMLOADER_HPP diff --git a/apps/openmw/mwworld/omwloader.cpp b/apps/openmw/mwworld/omwloader.cpp new file mode 100644 index 000000000..8562a4fe0 --- /dev/null +++ b/apps/openmw/mwworld/omwloader.cpp @@ -0,0 +1,17 @@ +#include "omwloader.hpp" + +namespace MWWorld +{ + +OmwLoader::OmwLoader(Loading::Listener& listener) + : ContentLoader(listener) +{ +} + +void OmwLoader::load(const boost::filesystem::path& filepath, int& index) +{ + ContentLoader::load(filepath.filename(), index); +} + +} /* namespace MWWorld */ + diff --git a/apps/openmw/mwworld/omwloader.hpp b/apps/openmw/mwworld/omwloader.hpp new file mode 100644 index 000000000..cb9faa430 --- /dev/null +++ b/apps/openmw/mwworld/omwloader.hpp @@ -0,0 +1,21 @@ +#ifndef OMWLOADER_HPP +#define OMWLOADER_HPP + +#include "contentloader.hpp" + +namespace MWWorld +{ + +/** + * @brief Placeholder for real OpenMW content loader + */ +struct OmwLoader : public ContentLoader +{ + OmwLoader(Loading::Listener& listener); + + void load(const boost::filesystem::path& filepath, int& index); +}; + +} /* namespace MWWorld */ + +#endif /* OMWLOADER_HPP */ diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f3d4c81b7..b7b23e5c1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,4 +1,11 @@ #include "worldimp.hpp" +#ifdef _WIN32 +#include +#elif defined HAVE_UNORDERED_MAP +#include +#else +#include +#endif #include @@ -31,6 +38,10 @@ #include "containerstore.hpp" #include "inventorystore.hpp" +#include "contentloader.hpp" +#include "esmloader.hpp" +#include "omwloader.hpp" + using namespace Ogre; namespace @@ -80,6 +91,38 @@ namespace namespace MWWorld { + struct GameContentLoader : public ContentLoader + { + GameContentLoader(Loading::Listener& listener) + : ContentLoader(listener) + { + } + + bool addLoader(const std::string& extension, ContentLoader* loader) + { + return mLoaders.insert(std::make_pair(extension, loader)).second; + } + + void load(const boost::filesystem::path& filepath, int& index) + { + LoadersContainer::iterator it(mLoaders.find(filepath.extension().string())); + if (it != mLoaders.end()) + { + it->second->load(filepath, index); + } + else + { + std::string msg("Cannot load file: "); + msg += filepath.string(); + throw std::runtime_error(msg.c_str()); + } + } + + private: + typedef std::tr1::unordered_map LoadersContainer; + LoadersContainer mLoaders; + }; + Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) { if (MWWorld::LiveCellRef *ref = @@ -163,7 +206,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::vector& master, const std::vector& plugins, + const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), @@ -181,44 +224,22 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - int idx = 0; // NOTE: We might need to reserve one more for the running game / save. - mEsm.resize(master.size() + plugins.size()); + mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener->loadingOn(); - for (std::vector::size_type i = 0; i < master.size(); i++, idx++) - { - boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); - std::cout << "Loading ESM " << masterPath.string() << "\n"; - listener->setLabel(masterPath.filename().string()); + GameContentLoader gameContentLoader(*listener); + EsmLoader esmLoader(mStore, mEsm, encoder, *listener); + OmwLoader omwLoader(*listener); - // This parses the ESM file - ESM::ESMReader lEsm; - lEsm.setEncoder(encoder); - lEsm.setIndex(idx); - lEsm.setGlobalReaderList(&mEsm); - lEsm.open (masterPath.string()); - mEsm[idx] = lEsm; - mStore.load (mEsm[idx], listener); - } + gameContentLoader.addLoader(".esm", &esmLoader); + gameContentLoader.addLoader(".esp", &esmLoader); + gameContentLoader.addLoader(".omwgame", &omwLoader); + gameContentLoader.addLoader(".omwaddon", &omwLoader); - for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) - { - boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); + loadContentFiles(fileCollections, contentFiles, gameContentLoader); - std::cout << "Loading ESP " << pluginPath.string() << "\n"; - listener->setLabel(pluginPath.filename().string()); - - // This parses the ESP file - ESM::ESMReader lEsm; - lEsm.setEncoder(encoder); - lEsm.setIndex(idx); - lEsm.setGlobalReaderList(&mEsm); - lEsm.open (pluginPath.string()); - mEsm[idx] = lEsm; - mStore.load (mEsm[idx], listener); - } listener->loadingOff(); // insert records that may not be present in all versions of MW @@ -1960,4 +1981,19 @@ namespace MWWorld return mGodMode; } + void World::loadContentFiles(const Files::Collections& fileCollections, + const std::vector& content, ContentLoader& contentLoader) + { + std::vector::const_iterator it(content.begin()); + std::vector::const_iterator end(content.end()); + for (int idx = 0; it != end; ++it, ++idx) + { + boost::filesystem::path filename(*it); + const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); + if (col.doesExist(*it)) + { + contentLoader.load(col.getPath(*it), idx); + } + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 53b01f1ab..d39189282 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" +#include "contentloader.hpp" + namespace Ogre { class Vector3; @@ -41,6 +43,8 @@ namespace MWRender class Animation; } +struct ContentLoader; + namespace MWWorld { class WeatherManager; @@ -113,6 +117,15 @@ namespace MWWorld void ensureNeededRecords(); + /** + * @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon) + * @param fileCollections- Container which holds content file names and their paths + * @param content - Container which holds content file names + * @param contentLoader - + */ + void loadContentFiles(const Files::Collections& fileCollections, + const std::vector& content, ContentLoader& contentLoader); + int mPlayIntro; bool mTeleportEnabled; @@ -121,7 +134,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::vector& master, const std::vector& plugins, + const std::vector& contentFiles, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride);