diff --git a/components/misc/pathhelpers.hpp b/components/misc/pathhelpers.hpp index 5a6d3feb55..5dc814e20d 100644 --- a/components/misc/pathhelpers.hpp +++ b/components/misc/pathhelpers.hpp @@ -1,18 +1,18 @@ #ifndef OPENMW_COMPONENTS_MISC_PATHHELPERS_H #define OPENMW_COMPONENTS_MISC_PATHHELPERS_H -#include +#include namespace Misc { - inline size_t findExtension(std::string_view file) + inline constexpr std::size_t findExtension(std::string_view file) noexcept { return file.find_last_of('.'); } - inline std::string_view getFileExtension(std::string_view file) + inline constexpr std::string_view getFileExtension(std::string_view file) noexcept { - if (auto extPos = findExtension(file); extPos != std::string::npos) + if (auto extPos = findExtension(file); extPos != std::string_view::npos) { file.remove_prefix(extPos + 1); return file; @@ -20,9 +20,9 @@ namespace Misc return {}; } - inline std::string_view getFileName(std::string_view path) + inline constexpr std::string_view getFileName(std::string_view path) noexcept { - if (auto namePos = path.find_last_of("/\\"); namePos != std::string::npos) + if (auto namePos = path.find_last_of("/\\"); namePos != std::string_view::npos) { path.remove_prefix(namePos + 1); } @@ -30,11 +30,11 @@ namespace Misc return path; } - inline std::string_view stemFile(std::string_view path) + inline constexpr std::string_view stemFile(std::string_view path) noexcept { path = getFileName(path); - if (auto extPos = path.find_last_of("."); extPos != std::string::npos) + if (auto extPos = path.find_last_of('.'); extPos != std::string_view::npos) { path.remove_suffix(path.size() - extPos); } diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index c4d3da2938..a272d89dd1 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -23,16 +23,36 @@ namespace Resource { + namespace + { + std::string parseTextKey(const std::string& line) + { + const std::size_t spacePos = line.find_last_of(' '); + if (spacePos != std::string::npos) + return line.substr(0, spacePos); + return {}; + } + + double parseTimeSignature(std::string_view line) + { + const std::size_t spacePos = line.find_last_of(' '); + double time = 0.0; + if (spacePos != std::string_view::npos && spacePos + 1 < line.size()) + time = Misc::StringUtils::toNumeric(line.substr(spacePos + 1), time); + return time; + } + } RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, - osg::ref_ptr animationManager, const std::string& normalized, - const VFS::Manager* vfs) + osg::ref_ptr animationManager, VFS::Path::NormalizedView path, + const VFS::Manager& vfs) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) , mTarget(target) , mAnimationManager(std::move(animationManager)) - , mNormalized(normalized) - , mVFS(vfs) + , mPath(path) + , mVFS(&vfs) { + mPath.changeExtension("txt"); } bool RetrieveAnimationsVisitor::belongsToLeftUpperExtremity(const std::string& name) @@ -142,18 +162,22 @@ namespace Resource // InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow" osgAnimation formats // should have a .txt file with the same name, each line holding a textkey and whitespace separated time // value e.g. idle: start 0.0333 - try + if (const Files::IStreamPtr textKeysFile = mVFS->find(mPath)) { - Files::IStreamPtr textKeysFile = mVFS->get(changeFileExtension(mNormalized, "txt")); - std::string line; - while (getline(*textKeysFile, line)) + try { - mTarget.mTextKeys.emplace(parseTimeSignature(line), parseTextKey(line)); + std::string line; + while (getline(*textKeysFile, line)) + mTarget.mTextKeys.emplace(parseTimeSignature(line), parseTextKey(line)); + } + catch (const std::exception& e) + { + Log(Debug::Warning) << "Failed to read text key file \"" << mPath << "\": " << e.what(); } } - catch (const std::exception& e) + else { - Log(Debug::Warning) << "Failed to use textkey file " << mNormalized << ": " << e.what(); + Log(Debug::Warning) << "Text key file is not found: " << mPath; } callback->setEmulatedAnimations(emulatedAnimations); @@ -174,38 +198,6 @@ namespace Resource traverse(node); } - std::string RetrieveAnimationsVisitor::parseTextKey(const std::string& line) - { - size_t spacePos = line.find_last_of(' '); - if (spacePos != std::string::npos) - return line.substr(0, spacePos); - return ""; - } - - double RetrieveAnimationsVisitor::parseTimeSignature(const std::string& line) - { - size_t spacePos = line.find_last_of(' '); - double time = 0.0; - if (spacePos != std::string::npos && spacePos + 1 < line.size()) - time = Misc::StringUtils::toNumeric(line.substr(spacePos + 1), time); - return time; - } - - std::string RetrieveAnimationsVisitor::changeFileExtension(const std::string& file, const std::string& ext) - { - size_t extPos = file.find_last_of('.'); - if (extPos != std::string::npos && extPos + 1 < file.size()) - { - return file.substr(0, extPos + 1) + ext; - } - return file; - } - -} - -namespace Resource -{ - KeyframeManager::KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager, double expiryDelay, const ToUTF8::StatelessUtf8Encoder* encoder) : ResourceManager(vfs, expiryDelay) @@ -216,7 +208,7 @@ namespace Resource osg::ref_ptr KeyframeManager::get(const std::string& name) { - const std::string normalized = VFS::Path::normalizeFilename(name); + const VFS::Path::Normalized normalized(name); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) @@ -228,7 +220,7 @@ namespace Resource { auto file = std::make_shared(normalized); Nif::Reader reader(*file, mEncoder); - reader.parse(mVFS->getNormalized(normalized)); + reader.parse(mVFS->get(normalized)); NifOsg::Loader::loadKf(*file, *loaded.get()); } else @@ -238,7 +230,7 @@ namespace Resource = dynamic_cast(scene->getUpdateCallback()); if (bam) { - Resource::RetrieveAnimationsVisitor rav(*loaded.get(), std::move(bam), normalized, mVFS); + Resource::RetrieveAnimationsVisitor rav(*loaded.get(), std::move(bam), normalized, *mVFS); scene->accept(rav); } } diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index ed8d4a04ab..2f5aa875d0 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -1,9 +1,10 @@ #ifndef OPENMW_COMPONENTS_KEYFRAMEMANAGER_H #define OPENMW_COMPONENTS_KEYFRAMEMANAGER_H +#include + #include #include -#include #include @@ -20,9 +21,9 @@ namespace Resource class RetrieveAnimationsVisitor : public osg::NodeVisitor { public: - RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, - osg::ref_ptr animationManager, const std::string& normalized, - const VFS::Manager* vfs); + explicit RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, + osg::ref_ptr animationManager, VFS::Path::NormalizedView path, + const VFS::Manager& vfs); bool belongsToLeftUpperExtremity(const std::string& name); bool belongsToRightUpperExtremity(const std::string& name); @@ -32,13 +33,9 @@ namespace Resource virtual void apply(osg::Node& node) override; private: - std::string changeFileExtension(const std::string& file, const std::string& ext); - std::string parseTextKey(const std::string& line); - double parseTimeSignature(const std::string& line); - SceneUtil::KeyframeHolder& mTarget; osg::ref_ptr mAnimationManager; - std::string mNormalized; + VFS::Path::Normalized mPath; const VFS::Manager* mVFS; }; } diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index dfbde8299f..12ef378017 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,5 @@ #include "manager.hpp" -#include #include #include @@ -38,6 +37,11 @@ namespace VFS archive->listResources(mIndex); } + Files::IStreamPtr Manager::find(Path::NormalizedView name) const + { + return findNormalized(name.value()); + } + Files::IStreamPtr Manager::get(const Path::Normalized& name) const { return getNormalized(name); @@ -51,10 +55,10 @@ namespace VFS Files::IStreamPtr Manager::getNormalized(std::string_view normalizedName) const { assert(Path::isNormalized(normalizedName)); - const auto found = mIndex.find(normalizedName); - if (found == mIndex.end()) - throw std::runtime_error("Resource '" + std::string(normalizedName) + "' is not found"); - return found->second->open(); + auto ptr = findNormalized(normalizedName); + if (ptr == nullptr) + throw std::runtime_error("Resource '" + std::string(normalizedName) + "' not found"); + return ptr; } bool Manager::exists(const Path::Normalized& name) const @@ -116,4 +120,13 @@ namespace VFS { return { mIndex.begin(), mIndex.end() }; } + + Files::IStreamPtr Manager::findNormalized(std::string_view normalizedPath) const + { + assert(Path::isNormalized(normalizedPath)); + const auto it = mIndex.find(normalizedPath); + if (it == mIndex.end()) + return nullptr; + return it->second->open(); + } } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index d64be1d1d1..b6a9d796cc 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -45,6 +45,9 @@ namespace VFS bool exists(Path::NormalizedView name) const; + // Returns open file if exists or nullptr. + Files::IStreamPtr find(Path::NormalizedView name) const; + /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. /// @note May be called from any thread once the index has been built. @@ -78,6 +81,8 @@ namespace VFS std::vector> mArchives; FileMap mIndex; + + inline Files::IStreamPtr findNormalized(std::string_view normalizedPath) const; }; }