Issue #133 Handle resources across multiple data directories - WIP

Work In Progress - added support for multiple paths in SoundManager.

Signed-off-by: Lukasz Gromanowski <lgromanowski@gmail.com>
actorid
Lukasz Gromanowski 13 years ago
parent 86f88bedae
commit b004e2479c

@ -200,12 +200,12 @@ void OMW::Engine::loadBSA()
for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter) for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter)
{ {
std::cout << "Adding " << iter->second.string() << std::endl; std::cout << "Adding " << iter->second.string() << std::endl;
Bsa::addBSA (iter->second.string()); Bsa::addBSA (iter->second.string());
} }
std::cout << "Data dir " << mDataDir.string() << std::endl; //std::cout << "Data dir " << mDataDir.string() << std::endl;
Bsa::addDir(mDataDir.string(), mFSStrict); //Bsa::addDir(mDataDir.string(), mFSStrict);
} }
// add resources directory // add resources directory
@ -228,7 +228,7 @@ void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs)
{ {
/// \todo remove mDataDir, once resources system can handle multiple directories /// \todo remove mDataDir, once resources system can handle multiple directories
assert (!dataDirs.empty()); assert (!dataDirs.empty());
mDataDir = dataDirs.back(); mDataDirs = dataDirs;
mFileCollections = Files::Collections (dataDirs, !mFSStrict); mFileCollections = Files::Collections (dataDirs, !mFSStrict);
} }
@ -339,7 +339,7 @@ void OMW::Engine::go()
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(), mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
mOgre->getCamera(), mOgre->getCamera(),
mEnvironment.mWorld->getStore(), mEnvironment.mWorld->getStore(),
(mDataDir), mDataDirs,
mUseSound, mFSStrict, mEnvironment); mUseSound, mFSStrict, mEnvironment);
// Create script system // Create script system

@ -64,7 +64,7 @@ namespace OMW
class Engine : private Ogre::FrameListener class Engine : private Ogre::FrameListener
{ {
std::string mEncoding; std::string mEncoding;
boost::filesystem::path mDataDir; Files::PathContainer mDataDirs;
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre; OEngine::Render::OgreRenderer *mOgre;
OEngine::Physic::PhysicEngine* mPhysicEngine; OEngine::Physic::PhysicEngine* mPhysicEngine;

@ -4,8 +4,6 @@
#include <algorithm> #include <algorithm>
#include <map> #include <map>
using namespace std;
#include <OgreRoot.h> #include <OgreRoot.h>
#include <openengine/sound/sndmanager.hpp> #include <openengine/sound/sndmanager.hpp>
@ -15,6 +13,7 @@ using namespace std;
#include <components/file_finder/file_finder.hpp> #include <components/file_finder/file_finder.hpp>
#include <components/esm_store/store.hpp> #include <components/esm_store/store.hpp>
#include "../mwworld/environment.hpp" #include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp" #include "../mwworld/world.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
@ -90,24 +89,28 @@ namespace MWSound
// relative to the sound dir, and translates them into full paths // relative to the sound dir, and translates them into full paths
// of existing files in the filesystem, if they exist. // of existing files in the filesystem, if they exist.
bool FSstrict; bool FSstrict;
FileFinder::FileFinder files; FileFinder::LessTreeFileFinder files;
FileFinder::FileFinderStrict strict; FileFinder::StrictTreeFileFinder strict;
FileFinder::FileFinder musicpath; FileFinder::LessTreeFileFinder musicpath;
FileFinder::FileFinderStrict musicpathStrict; FileFinder::StrictTreeFileFinder musicpathStrict;
SoundImpl(Ogre::Root *root, Ogre::Camera *camera, SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str,
const ESMS::ESMStore &str, const Files::PathContainer& soundDir,
const std::string &soundDir, const std::string &musicDir, bool fsstrict) const Files::PathContainer& musicDir,
bool fsstrict)
: mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) : mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
, updater(mgr) , updater(mgr)
, cameraTracker(mgr) , cameraTracker(mgr)
, store(str) , store(str)
, files(soundDir), strict(soundDir) , FSstrict(fsstrict)
,musicpath(musicDir), musicpathStrict(musicDir) , files(soundDir)
, strict(soundDir)
, musicpath(musicDir)
, musicpathStrict(musicDir)
{ {
FSstrict = fsstrict;
cout << "Sound output: " << SOUND_OUT << endl; std::cout << "Sound output: " << SOUND_OUT << std::endl;
cout << "Sound decoder: " << SOUND_IN << endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl;
// Attach the camera to the camera tracker // Attach the camera to the camera tracker
cameraTracker.followCamera(camera); cameraTracker.followCamera(camera);
@ -136,36 +139,49 @@ namespace MWSound
bool hasFile(const std::string &str, bool music = false) bool hasFile(const std::string &str, bool music = false)
{ {
if(FSstrict == false) bool found = false;
if(!FSstrict)
{ {
if(music) if(music)
{ {
if(musicpath.has(str)) return true; found = musicpath.has(str);
// Not found? Try with .mp3 // Not found? Try with .mp3
return musicpath.has(toMp3(str)); if (!found)
{
found = musicpath.has(toMp3(str));
}
} }
else else
{ {
if(files.has(str)) return true; found = files.has(str);
return files.has(toMp3(str)); if (!found)
{
found = files.has(toMp3(str));
}
} }
} }
else else
{ {
if(music) if(music)
{ {
if(musicpathStrict.has(str)) return true; found = musicpathStrict.has(str);
// Not found? Try with .mp3 // Not found? Try with .mp3
return musicpathStrict.has(toMp3(str)); if (!found)
{
found = musicpathStrict.has(toMp3(str));
}
} }
else else
{ {
if(strict.has(str)) return true; found = strict.has(str);
return strict.has(toMp3(str)); if (!found)
{
found = strict.has(toMp3(str));
}
} }
} }
return found;
} }
// Convert a Morrowind sound path (eg. Fx\funny.wav) to full path // Convert a Morrowind sound path (eg. Fx\funny.wav) to full path
@ -258,13 +274,13 @@ namespace MWSound
} }
catch(...) catch(...)
{ {
cout << "Error loading " << file << ", skipping.\n"; std::cout << "Error loading " << file << ", skipping.\n";
} }
} }
// Clears all the sub-elements of a given iterator, and then // Clears all the sub-elements of a given iterator, and then
// removes it from 'sounds'. // removes it from 'sounds'.
void clearAll(PtrMap::iterator it) void clearAll(PtrMap::iterator& it)
{ {
IDMap::iterator sit = it->second.begin(); IDMap::iterator sit = it->second.begin();
@ -362,9 +378,9 @@ namespace MWSound
} }
} }
} }
}; }; /* SoundImpl */
void SoundManager::streamMusicFull (const std::string& filename) void SoundManager::streamMusicFull(const std::string& filename)
{ {
if(!mData) return; if(!mData) return;
@ -381,20 +397,24 @@ namespace MWSound
} }
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
const ESMS::ESMStore &store, const ESMS::ESMStore &store, const Files::PathContainer& dataDirs,
boost::filesystem::path dataDir, bool useSound, bool fsstrict, MWWorld::Environment& environment)
bool useSound, bool fsstrict, MWWorld::Environment& environment) : mData(NULL)
: mData(NULL), fsStrict (fsstrict), mEnvironment (environment) , fsStrict(fsstrict)
, mEnvironment(environment)
{ {
MP3Lookup(dataDir / "Music/Explore/"); for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
if(useSound) {
mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict); MP3Lookup((*it) / "Music/Explore/");
}
if(useSound)
{
mData = new SoundImpl(root, camera, store, dataDirs /* Sound */, dataDirs /* Music */, fsstrict);
}
test.name = ""; test.name = "";
total = 0; total = 0;
} }
SoundManager::~SoundManager() SoundManager::~SoundManager()
@ -407,14 +427,12 @@ namespace MWSound
{ {
if(mData->hasFile(filename, true)) if(mData->hasFile(filename, true))
{ {
std::string fullpath = mData->convertPath(filename, true); streamMusicFull(mData->convertPath(filename, true));
streamMusicFull(fullpath);
} }
} }
void SoundManager::MP3Lookup(const boost::filesystem::path& dir)
void SoundManager::MP3Lookup(boost::filesystem::path dir) {
{
boost::filesystem::directory_iterator dir_iter(dir), dir_end; boost::filesystem::directory_iterator dir_iter(dir), dir_end;
std::string mp3extension = ".mp3"; std::string mp3extension = ".mp3";
@ -425,35 +443,30 @@ namespace MWSound
files.push_back(*dir_iter); files.push_back(*dir_iter);
} }
} }
} }
void SoundManager::startRandomTitle() void SoundManager::startRandomTitle()
{ {
std::vector<boost::filesystem::path>::iterator fileIter; if(!files.empty())
if(files.size() > 0)
{ {
fileIter = files.begin(); Files::PathContainer::iterator fileIter = files.begin();
srand ( time(NULL) ); srand( time(NULL) );
int r = rand() % files.size() + 1; //old random code int r = rand() % files.size() + 1; //old random code
for(int i = 1; i < r; i++) std::advance(fileIter, r - 1);
{
fileIter++;
}
std::string music = fileIter->string(); std::string music = fileIter->string();
std::cout << "Playing " << music << "\n";
try try
{ {
std::cout << "Playing " << music << "\n";
streamMusicFull(music); streamMusicFull(music);
} }
catch(std::exception &e) catch (std::exception &e)
{ {
std::cout << " Music Error: " << e.what() << "\n"; std::cout << " Music Error: " << e.what() << "\n";
} }
} }
} }
bool SoundManager::isMusicPlaying() bool SoundManager::isMusicPlaying()
{ {
@ -465,14 +478,12 @@ namespace MWSound
return test; return test;
} }
SoundManager::SoundImpl SoundManager::getMData() SoundManager::SoundImpl SoundManager::getMData()
{ {
// bool test = mData->music->isPlaying(); // bool test = mData->music->isPlaying();
return *mData; return *mData;
} }
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
{ {
// The range values are not tested // The range values are not tested
@ -480,7 +491,7 @@ namespace MWSound
if(mData->hasFile(filename)) if(mData->hasFile(filename))
mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false); mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false);
else else
cout << "Sound file " << filename << " not found, skipping.\n"; std::cout << "Sound file " << filename << " not found, skipping.\n";
} }
bool SoundManager::sayDone (MWWorld::Ptr ptr) const bool SoundManager::sayDone (MWWorld::Ptr ptr) const
@ -490,20 +501,20 @@ namespace MWSound
} }
void SoundManager::playSound (const std::string& soundId, float volume, float pitch) void SoundManager::playSound(const std::string& soundId, float volume, float pitch)
{ {
if(!mData) return; if(!mData) return;
// Play and forget // Play and forget
float min, max; float min, max;
const std::string &file = mData->lookup(soundId, volume, min, max); const std::string &file = mData->lookup(soundId, volume, min, max);
if(file != "") if (file != "")
{ {
SoundPtr snd = mData->mgr->load(file); SoundPtr snd = mData->mgr->load(file);
snd->setVolume(volume); snd->setVolume(volume);
snd->setRange(min,max); snd->setRange(min,max);
snd->setPitch(pitch); snd->setPitch(pitch);
snd->play(); snd->play();
} }
} }
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId, void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
@ -514,7 +525,7 @@ namespace MWSound
// Look up the sound in the ESM data // Look up the sound in the ESM data
float min, max; float min, max;
const std::string &file = mData->lookup(soundId, volume, min, max); const std::string &file = mData->lookup(soundId, volume, min, max);
if(file != "") if (file != "")
mData->add(file, ptr, soundId, volume, pitch, min, max, loop); mData->add(file, ptr, soundId, volume, pitch, min, max, loop);
} }
@ -541,18 +552,19 @@ namespace MWSound
void SoundManager::updateObject(MWWorld::Ptr ptr) void SoundManager::updateObject(MWWorld::Ptr ptr)
{ {
if(!mData) return; if (mData != NULL)
mData->updatePositions(ptr); {
mData->updatePositions(ptr);
}
} }
void SoundManager::update (float duration) void SoundManager::update (float duration)
{ {
std::string effect;
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
//If the region has changed //If the region has changed
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){ if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10)
{
timer.restart(); timer.restart();
if (test.name != current->cell->region) if (test.name != current->cell->region)
{ {
@ -564,11 +576,12 @@ namespace MWSound
{ {
std::vector<ESM::Region::SoundRef>::iterator soundIter = test.soundList.begin(); std::vector<ESM::Region::SoundRef>::iterator soundIter = test.soundList.begin();
//mEnvironment.mSoundManager //mEnvironment.mSoundManager
if(total == 0){ if(total == 0)
while (!(soundIter == test.soundList.end())) {
while (soundIter != test.soundList.end())
{ {
ESM::NAME32 go = soundIter->sound;
int chance = (int) soundIter->chance; int chance = (int) soundIter->chance;
//ESM::NAME32 go = soundIter->sound;
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
soundIter++; soundIter++;
total += chance; total += chance;
@ -578,7 +591,7 @@ namespace MWSound
int r = rand() % total; //old random code int r = rand() % total; //old random code
int pos = 0; int pos = 0;
soundIter = test.soundList.begin(); soundIter = test.soundList.begin();
while (!(soundIter == test.soundList.end())) while (soundIter != test.soundList.end())
{ {
const ESM::NAME32 go = soundIter->sound; const ESM::NAME32 go = soundIter->sound;
int chance = (int) soundIter->chance; int chance = (int) soundIter->chance;
@ -586,13 +599,11 @@ namespace MWSound
soundIter++; soundIter++;
if( r - pos < chance) if( r - pos < chance)
{ {
effect = go.name;
//play sound //play sound
std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0); mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0);
break; break;
} }
pos += chance; pos += chance;
} }

@ -2,14 +2,15 @@
#define GAME_SOUND_SOUNDMANAGER_H #define GAME_SOUND_SOUNDMANAGER_H
#include <string> #include <string>
#include <map>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/timer.hpp>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include <openengine/sound/sndmanager.hpp> #include <openengine/sound/sndmanager.hpp>
#include <components/files/multidircollection.hpp>
#include <boost/timer.hpp>
namespace Ogre namespace Ogre
{ {
@ -37,7 +38,7 @@ namespace MWSound
struct SoundImpl; struct SoundImpl;
SoundImpl *mData; SoundImpl *mData;
std::vector<boost::filesystem::path> files; Files::PathContainer files;
bool fsStrict; bool fsStrict;
MWWorld::Environment& mEnvironment; MWWorld::Environment& mEnvironment;
@ -52,7 +53,7 @@ namespace MWSound
public: public:
SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store,
boost::filesystem::path dataDir, bool useSound, bool fsstrict, const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
MWWorld::Environment& environment); MWWorld::Environment& environment);
~SoundManager(); ~SoundManager();
@ -61,7 +62,7 @@ namespace MWSound
/// \param filename name of a sound file in "Music/" in the data directory. /// \param filename name of a sound file in "Music/" in the data directory.
void startRandomTitle(); void startRandomTitle();
void MP3Lookup(boost::filesystem::path dir); void MP3Lookup(const boost::filesystem::path& dir);
bool isMusicPlaying(); bool isMusicPlaying();

@ -1,9 +1,11 @@
#ifndef FILE_FINDER_MAIN_H #ifndef FILE_FINDER_MAIN_H
#define FILE_FINDER_MAIN_H #define FILE_FINDER_MAIN_H
#include <map>
#include "search.hpp" #include "search.hpp"
#include "filename_less.hpp" #include "filename_less.hpp"
#include <map> #include <components/files/multidircollection.hpp>
namespace FileFinder namespace FileFinder
{ {
@ -11,7 +13,8 @@ namespace FileFinder
template <typename LESS> template <typename LESS>
class FileFinderT class FileFinderT
{ {
std::map<std::string, std::string, LESS> table; typedef std::map<std::string, std::string, LESS> TableContainer;
TableContainer table;
struct Inserter : ReturnPath struct Inserter : ReturnPath
{ {
@ -35,12 +38,12 @@ public:
// Remember the original path length, so we can cut it away from // Remember the original path length, so we can cut it away from
// the relative paths used as keys // the relative paths used as keys
std::string pstring = path.string(); const std::string& pstring = path.string();
inserter.cut = pstring.size(); inserter.cut = pstring.size();
// If the path does not end in a slash, then boost will add one // If the path does not end in a slash, then boost will add one
// later, which means one more character we have to remove. // later, which means one more character we have to remove.
char last = pstring[pstring.size()-1]; char last = *pstring.rbegin();
if(last != '\\' && last != '/') if(last != '\\' && last != '/')
inserter.cut++; inserter.cut++;
@ -56,12 +59,84 @@ public:
// Find the full path from a relative path. // Find the full path from a relative path.
const std::string &lookup(const std::string& file) const const std::string &lookup(const std::string& file) const
{ {
return table.find(file)->second; static std::string empty;
typename TableContainer::const_iterator it = table.find(file);
return (it != table.end()) ? it->second : empty;
} }
}; };
template
<
class LESS
>
struct TreeFileFinder
{
typedef TreeFileFinder<LESS> finder_t;
TreeFileFinder(const Files::PathContainer& paths, bool recurse = true)
{
struct : ReturnPath
{
finder_t *owner;
int cut;
void add(const boost::filesystem::path &pth)
{
std::string file = pth.string();
std::string key = file.substr(cut);
owner->mTable[key] = file;
}
} inserter;
inserter.owner = this;
for (Files::PathContainer::const_iterator it = paths.begin(); it != paths.end(); ++it)
{
// Remember the original path length, so we can cut it away from
// the relative paths used as keys
const std::string& pstring = it->string();
inserter.cut = pstring.size();
// If the path does not end in a slash, then boost will add one
// later, which means one more character we have to remove.
char last = *pstring.rbegin();
if (last != '\\' && last != '/')
{
inserter.cut++;
}
// Fill the map
find(*it, inserter, recurse);
}
}
bool has(const std::string& file) const
{
return mTable.find(file) != mTable.end();
}
const std::string& lookup(const std::string& file) const
{
static std::string empty;
typename TableContainer::const_iterator it = mTable.find(file);
return (it != mTable.end()) ? it->second : empty;
}
private:
typedef std::map<std::string, std::string, LESS> TableContainer;
TableContainer mTable;
// Inserter inserter;
};
// The default is to use path_less for equality checks // The default is to use path_less for equality checks
typedef FileFinderT<path_less> FileFinder; typedef FileFinderT<path_less> FileFinder;
typedef FileFinderT<path_slash> FileFinderStrict; typedef FileFinderT<path_slash> FileFinderStrict;
}
#endif typedef TreeFileFinder<path_less> LessTreeFileFinder;
typedef TreeFileFinder<path_slash> StrictTreeFileFinder;
} /* namespace FileFinder */
#endif /* FILE_FINDER_MAIN_H */

@ -2,27 +2,27 @@
#include <iostream> #include <iostream>
using namespace std; void FileFinder::find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse)
using namespace boost::filesystem;
void FileFinder::find(const path & dir_path, ReturnPath &ret, bool recurse)
{ {
if ( !exists( dir_path ) ) if ( !boost::filesystem::exists( dir_path ) )
{ {
cout << "Path " << dir_path << " not found\n"; std::cout << "Path " << dir_path << " not found" << std::endl;
return; return;
} }
directory_iterator end_itr; // default construction yields past-the-end boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr(dir_path); for (boost::filesystem::directory_iterator itr(dir_path); itr != end_itr; ++itr)
itr != end_itr;
++itr )
{ {
if ( is_directory( *itr ) ) if (boost::filesystem::is_directory( *itr ))
{
if (recurse)
{
find(*itr, ret);
}
}
else
{ {
if(recurse) find(*itr, ret); ret.add(*itr);
} }
else
ret.add(*itr);
} }
} }

@ -68,7 +68,7 @@ namespace Files
/// \param foldCase Ignore filename case /// \param foldCase Ignore filename case
boost::filesystem::path getPath (const std::string& file) const; boost::filesystem::path getPath (const std::string& file) const;
///< Return full path (including filename) of \æ file. ///< Return full path (including filename) of \a file.
/// ///
/// If the file does not exist, an exception is thrown. \a file must include /// If the file does not exist, an exception is thrown. \a file must include
/// the extension. /// the extension.

Loading…
Cancel
Save