mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-08-03 15:27:13 -04:00
Fix path handling for files in BSAs
This commit is contained in:
parent
53feb29a5b
commit
206d38f3d7
@ -155,7 +155,7 @@ namespace
|
|||||||
|
|
||||||
VFS::Manager vfs;
|
VFS::Manager vfs;
|
||||||
|
|
||||||
VFS::registerArchives(&vfs, fileCollections, archives, true);
|
VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder());
|
||||||
|
|
||||||
Settings::Manager::load(config);
|
Settings::Manager::load(config);
|
||||||
|
|
||||||
|
@ -113,7 +113,8 @@ namespace
|
|||||||
|
|
||||||
void compile(const std::string& name)
|
void compile(const std::string& name)
|
||||||
{
|
{
|
||||||
mTechnique = std::make_unique<Technique>(*mVFS.get(), mImageManager, name, 1, 1, true, true);
|
mTechnique = std::make_unique<Technique>(
|
||||||
|
*mVFS.get(), mImageManager, Technique::makeFileName(name), name, 1, 1, true, true);
|
||||||
mTechnique->compile();
|
mTechnique->compile();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -189,7 +189,7 @@ namespace NavMeshTool
|
|||||||
|
|
||||||
VFS::Manager vfs;
|
VFS::Manager vfs;
|
||||||
|
|
||||||
VFS::registerArchives(&vfs, fileCollections, archives, true);
|
VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder());
|
||||||
|
|
||||||
Settings::Manager::load(config);
|
Settings::Manager::load(config);
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ bool isBSA(const std::filesystem::path& path)
|
|||||||
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
if (isBSA(path))
|
if (isBSA(path))
|
||||||
return VFS::makeBsaArchive(path);
|
return VFS::makeBsaArchive(path, nullptr);
|
||||||
if (std::filesystem::is_directory(path))
|
if (std::filesystem::is_directory(path))
|
||||||
return std::make_unique<VFS::FileSystemArchive>(path);
|
return std::make_unique<VFS::FileSystemArchive>(path);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -198,7 +198,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
readVFS(VFS::makeBsaArchive(file.second), file.second, quiet);
|
readVFS(VFS::makeBsaArchive(file.second, nullptr), file.second, quiet);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +143,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
|||||||
, mArchives(archives)
|
, mArchives(archives)
|
||||||
, mVFS(std::make_unique<VFS::Manager>())
|
, mVFS(std::make_unique<VFS::Manager>())
|
||||||
{
|
{
|
||||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true);
|
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder());
|
||||||
|
|
||||||
mResourcesManager.setVFS(mVFS.get());
|
mResourcesManager.setVFS(mVFS.get());
|
||||||
|
|
||||||
@ -1465,7 +1465,7 @@ std::vector<ESM::RefId> CSMWorld::Data::getIds(bool listDeleted) const
|
|||||||
void CSMWorld::Data::assetsChanged()
|
void CSMWorld::Data::assetsChanged()
|
||||||
{
|
{
|
||||||
mVFS.get()->reset();
|
mVFS.get()->reset();
|
||||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true);
|
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder());
|
||||||
|
|
||||||
const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics,
|
const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics,
|
||||||
UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos };
|
UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos };
|
||||||
|
@ -729,7 +729,7 @@ void OMW::Engine::prepareEngine()
|
|||||||
|
|
||||||
mVFS = std::make_unique<VFS::Manager>();
|
mVFS = std::make_unique<VFS::Manager>();
|
||||||
|
|
||||||
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);
|
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true, &mEncoder.get()->getStatelessEncoder());
|
||||||
|
|
||||||
mResourceSystem = std::make_unique<Resource::ResourceSystem>(
|
mResourceSystem = std::make_unique<Resource::ResourceSystem>(
|
||||||
mVFS.get(), Settings::cells().mCacheExpiryDelay, &mEncoder.get()->getStatelessEncoder());
|
mVFS.get(), Settings::cells().mCacheExpiryDelay, &mEncoder.get()->getStatelessEncoder());
|
||||||
|
@ -33,6 +33,14 @@
|
|||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::shared_ptr<fx::Technique>& getTechnique(const MyGUI::ListBox& list, size_t selected)
|
||||||
|
{
|
||||||
|
return *list.getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PostProcessorHud::ListWrapper::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char ch)
|
void PostProcessorHud::ListWrapper::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char ch)
|
||||||
{
|
{
|
||||||
if (MyGUI::InputManager::getInstance().isShiftPressed()
|
if (MyGUI::InputManager::getInstance().isShiftPressed()
|
||||||
@ -117,7 +125,7 @@ namespace MWGui
|
|||||||
if (index >= sender->getItemCount())
|
if (index >= sender->getItemCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateConfigView(sender->getItemNameAt(index));
|
updateConfigView(getTechnique(*sender, index)->getFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessorHud::toggleTechnique(bool enabled)
|
void PostProcessorHud::toggleTechnique(bool enabled)
|
||||||
@ -131,7 +139,7 @@ namespace MWGui
|
|||||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||||
mOverrideHint = list->getItemNameAt(selected);
|
mOverrideHint = list->getItemNameAt(selected);
|
||||||
|
|
||||||
auto technique = *list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
auto technique = getTechnique(*list, selected);
|
||||||
if (technique->getDynamic())
|
if (technique->getDynamic())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -167,7 +175,7 @@ namespace MWGui
|
|||||||
|
|
||||||
if (static_cast<size_t>(index) != selected)
|
if (static_cast<size_t>(index) != selected)
|
||||||
{
|
{
|
||||||
auto technique = *mActiveList->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
auto technique = getTechnique(*mActiveList, selected);
|
||||||
if (technique->getDynamic() || technique->getInternal())
|
if (technique->getDynamic() || technique->getInternal())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -290,16 +298,16 @@ namespace MWGui
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (mInactiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
if (mInactiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
||||||
updateConfigView(mInactiveList->getItemNameAt(mInactiveList->getIndexSelected()));
|
updateConfigView(getTechnique(*mInactiveList, mInactiveList->getIndexSelected())->getFileName());
|
||||||
else if (mActiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
else if (mActiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
||||||
updateConfigView(mActiveList->getItemNameAt(mActiveList->getIndexSelected()));
|
updateConfigView(getTechnique(*mActiveList, mActiveList->getIndexSelected())->getFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessorHud::updateConfigView(const std::string& name)
|
void PostProcessorHud::updateConfigView(VFS::Path::NormalizedView path)
|
||||||
{
|
{
|
||||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||||
|
|
||||||
auto technique = processor->loadTechnique(name);
|
auto technique = processor->loadTechnique(path);
|
||||||
|
|
||||||
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
||||||
return;
|
return;
|
||||||
@ -423,22 +431,22 @@ namespace MWGui
|
|||||||
|
|
||||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||||
|
|
||||||
std::vector<std::string> techniques;
|
std::vector<VFS::Path::NormalizedView> techniques;
|
||||||
for (const auto& [name, _] : processor->getTechniqueMap())
|
for (const auto& vfsPath : processor->getTechniqueFiles())
|
||||||
techniques.push_back(name);
|
techniques.emplace_back(vfsPath);
|
||||||
std::sort(techniques.begin(), techniques.end(), Misc::StringUtils::ciLess);
|
std::sort(techniques.begin(), techniques.end());
|
||||||
|
|
||||||
for (const std::string& name : techniques)
|
for (VFS::Path::NormalizedView path : techniques)
|
||||||
{
|
{
|
||||||
auto technique = processor->loadTechnique(name);
|
auto technique = processor->loadTechnique(path);
|
||||||
|
|
||||||
if (!technique->getHidden() && !processor->isTechniqueEnabled(technique))
|
if (!technique->getHidden() && !processor->isTechniqueEnabled(technique))
|
||||||
{
|
{
|
||||||
std::string lowerName = Utf8Stream::lowerCaseUtf8(name);
|
std::string lowerName = Utf8Stream::lowerCaseUtf8(technique->getName());
|
||||||
std::string lowerCaption = mFilter->getCaption();
|
std::string lowerCaption = mFilter->getCaption();
|
||||||
lowerCaption = Utf8Stream::lowerCaseUtf8(lowerCaption);
|
lowerCaption = Utf8Stream::lowerCaseUtf8(lowerCaption);
|
||||||
if (lowerName.find(lowerCaption) != std::string::npos)
|
if (lowerName.find(lowerCaption) != std::string::npos)
|
||||||
mInactiveList->addItem(name, technique);
|
mInactiveList->addItem(technique->getName(), technique);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <MyGUI_ListBox.h>
|
#include <MyGUI_ListBox.h>
|
||||||
|
|
||||||
#include <components/settings/shadermanager.hpp>
|
#include <components/settings/shadermanager.hpp>
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
namespace MyGUI
|
namespace MyGUI
|
||||||
{
|
{
|
||||||
@ -48,7 +49,7 @@ namespace MWGui
|
|||||||
|
|
||||||
void notifyFilterChanged(MyGUI::EditBox* sender);
|
void notifyFilterChanged(MyGUI::EditBox* sender);
|
||||||
|
|
||||||
void updateConfigView(const std::string& name);
|
void updateConfigView(VFS::Path::NormalizedView path);
|
||||||
|
|
||||||
void notifyResetButtonClicked(MyGUI::Widget* sender);
|
void notifyResetButtonClicked(MyGUI::Widget* sender);
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <osg/Texture3D>
|
#include <osg/Texture3D>
|
||||||
|
|
||||||
#include <components/files/conversion.hpp>
|
#include <components/files/conversion.hpp>
|
||||||
|
#include <components/misc/pathhelpers.hpp>
|
||||||
#include <components/misc/strings/algorithm.hpp>
|
#include <components/misc/strings/algorithm.hpp>
|
||||||
#include <components/misc/strings/lower.hpp>
|
#include <components/misc/strings/lower.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
@ -250,14 +251,12 @@ namespace MWRender
|
|||||||
|
|
||||||
void PostProcessor::populateTechniqueFiles()
|
void PostProcessor::populateTechniqueFiles()
|
||||||
{
|
{
|
||||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
|
for (const auto& path : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
|
||||||
{
|
{
|
||||||
std::filesystem::path path = Files::pathFromUnicodeString(name);
|
std::string_view fileExt = Misc::getFileExtension(path);
|
||||||
std::string fileExt = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(path.extension()));
|
if (path.parent().parent().empty() && fileExt == fx::Technique::sExt)
|
||||||
if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
|
|
||||||
{
|
{
|
||||||
const auto absolutePath = mVFS->getAbsoluteFileName(path);
|
mTechniqueFiles.emplace(path);
|
||||||
mTechniqueFileMap[Files::pathToUnicodeString(absolutePath.stem())] = absolutePath;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,7 +350,7 @@ namespace MWRender
|
|||||||
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto lastWriteTime = std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]);
|
const auto lastWriteTime = mVFS->getLastModified(technique->getFileName());
|
||||||
const bool isDirty = technique->setLastModificationTime(lastWriteTime);
|
const bool isDirty = technique->setLastModificationTime(lastWriteTime);
|
||||||
|
|
||||||
if (!isDirty)
|
if (!isDirty)
|
||||||
@ -363,7 +362,7 @@ namespace MWRender
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
|
||||||
if (technique->compile())
|
if (technique->compile())
|
||||||
Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()];
|
Log(Debug::Info) << "Reloaded technique : " << technique->getFileName();
|
||||||
|
|
||||||
mReload = technique->isValid();
|
mReload = technique->isValid();
|
||||||
}
|
}
|
||||||
@ -750,27 +749,31 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
||||||
|
{
|
||||||
|
VFS::Path::Normalized path = fx::Technique::makeFileName(name);
|
||||||
|
return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame)
|
||||||
{
|
{
|
||||||
for (const auto& technique : mTemplates)
|
for (const auto& technique : mTemplates)
|
||||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
if (technique->getFileName() == path)
|
||||||
return technique;
|
return technique;
|
||||||
|
|
||||||
for (const auto& technique : mQueuedTemplates)
|
for (const auto& technique : mQueuedTemplates)
|
||||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
if (technique->getFileName() == path)
|
||||||
return technique;
|
return technique;
|
||||||
|
|
||||||
std::string realName = name;
|
if (!mTechniqueFiles.contains(path))
|
||||||
auto fileIter = mTechniqueFileMap.find(name);
|
return {};
|
||||||
if (fileIter != mTechniqueFileMap.end())
|
|
||||||
realName = fileIter->first;
|
|
||||||
|
|
||||||
auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(),
|
auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(),
|
||||||
std::move(realName), renderWidth(), renderHeight(), mUBO, mNormalsSupported);
|
path, mVFS->getStem(path), renderWidth(), renderHeight(), mUBO, mNormalsSupported);
|
||||||
|
|
||||||
technique->compile();
|
technique->compile();
|
||||||
|
|
||||||
if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
|
if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
|
||||||
technique->setLastModificationTime(std::filesystem::last_write_time(fileIter->second));
|
technique->setLastModificationTime(mVFS->getLastModified(path));
|
||||||
|
|
||||||
if (loadNextFrame)
|
if (loadNextFrame)
|
||||||
{
|
{
|
||||||
@ -802,7 +805,10 @@ namespace MWRender
|
|||||||
if (techniqueName.empty())
|
if (techniqueName.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mTechniques.push_back(loadTechnique(techniqueName));
|
auto technique = loadTechnique(techniqueName);
|
||||||
|
if (!technique)
|
||||||
|
continue;
|
||||||
|
mTechniques.push_back(std::move(technique));
|
||||||
}
|
}
|
||||||
|
|
||||||
dirtyTechniques();
|
dirtyTechniques();
|
||||||
|
@ -128,7 +128,7 @@ namespace MWRender
|
|||||||
|
|
||||||
const TechniqueList& getTemplates() const { return mTemplates; }
|
const TechniqueList& getTemplates() const { return mTemplates; }
|
||||||
|
|
||||||
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
const auto& getTechniqueFiles() const { return mTechniqueFiles; }
|
||||||
|
|
||||||
void resize();
|
void resize();
|
||||||
|
|
||||||
@ -176,6 +176,7 @@ namespace MWRender
|
|||||||
|
|
||||||
void toggleMode();
|
void toggleMode();
|
||||||
|
|
||||||
|
std::shared_ptr<fx::Technique> loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false);
|
||||||
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
||||||
|
|
||||||
TechniqueList getChain();
|
TechniqueList getChain();
|
||||||
@ -232,8 +233,7 @@ namespace MWRender
|
|||||||
TechniqueList mQueuedTemplates;
|
TechniqueList mQueuedTemplates;
|
||||||
TechniqueList mInternalTechniques;
|
TechniqueList mInternalTechniques;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::filesystem::path, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
|
std::unordered_set<VFS::Path::Normalized, VFS::Path::Hash, std::equal_to<>> mTechniqueFiles;
|
||||||
mTechniqueFileMap;
|
|
||||||
|
|
||||||
RenderingManager& mRendering;
|
RenderingManager& mRendering;
|
||||||
osgViewer::Viewer* mViewer;
|
osgViewer::Viewer* mViewer;
|
||||||
|
@ -50,6 +50,7 @@ namespace Bsa
|
|||||||
public:
|
public:
|
||||||
using BSAFile::getFilename;
|
using BSAFile::getFilename;
|
||||||
using BSAFile::getList;
|
using BSAFile::getList;
|
||||||
|
using BSAFile::getPath;
|
||||||
using BSAFile::open;
|
using BSAFile::open;
|
||||||
|
|
||||||
BA2DX10File();
|
BA2DX10File();
|
||||||
|
@ -38,6 +38,7 @@ namespace Bsa
|
|||||||
public:
|
public:
|
||||||
using BSAFile::getFilename;
|
using BSAFile::getFilename;
|
||||||
using BSAFile::getList;
|
using BSAFile::getList;
|
||||||
|
using BSAFile::getPath;
|
||||||
using BSAFile::open;
|
using BSAFile::open;
|
||||||
|
|
||||||
BA2GNRLFile();
|
BA2GNRLFile();
|
||||||
|
@ -84,15 +84,15 @@ namespace Bsa
|
|||||||
protected:
|
protected:
|
||||||
bool mHasChanged = false;
|
bool mHasChanged = false;
|
||||||
|
|
||||||
|
/// True when an archive has been loaded
|
||||||
|
bool mIsLoaded = false;
|
||||||
|
|
||||||
/// Table of files in this archive
|
/// Table of files in this archive
|
||||||
FileList mFiles;
|
FileList mFiles;
|
||||||
|
|
||||||
/// Filename string buffer
|
/// Filename string buffer
|
||||||
std::vector<char> mStringBuf;
|
std::vector<char> mStringBuf;
|
||||||
|
|
||||||
/// True when an archive has been loaded
|
|
||||||
bool mIsLoaded;
|
|
||||||
|
|
||||||
/// Used for error messages
|
/// Used for error messages
|
||||||
std::filesystem::path mFilepath;
|
std::filesystem::path mFilepath;
|
||||||
|
|
||||||
@ -109,11 +109,6 @@ namespace Bsa
|
|||||||
* -----------------------------------
|
* -----------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BSAFile()
|
|
||||||
: mIsLoaded(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~BSAFile()
|
virtual ~BSAFile()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
@ -148,6 +143,11 @@ namespace Bsa
|
|||||||
return Files::pathToUnicodeString(mFilepath);
|
return Files::pathToUnicodeString(mFilepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& getPath() const
|
||||||
|
{
|
||||||
|
return mFilepath;
|
||||||
|
}
|
||||||
|
|
||||||
// checks version of BSA from file header
|
// checks version of BSA from file header
|
||||||
static BsaVersion detectVersion(const std::filesystem::path& filePath);
|
static BsaVersion detectVersion(const std::filesystem::path& filePath);
|
||||||
};
|
};
|
||||||
|
@ -117,6 +117,7 @@ namespace Bsa
|
|||||||
public:
|
public:
|
||||||
using BSAFile::getFilename;
|
using BSAFile::getFilename;
|
||||||
using BSAFile::getList;
|
using BSAFile::getList;
|
||||||
|
using BSAFile::getPath;
|
||||||
using BSAFile::open;
|
using BSAFile::open;
|
||||||
|
|
||||||
CompressedBSAFile() = default;
|
CompressedBSAFile() = default;
|
||||||
|
@ -37,22 +37,20 @@ namespace
|
|||||||
|
|
||||||
namespace fx
|
namespace fx
|
||||||
{
|
{
|
||||||
namespace
|
VFS::Path::Normalized Technique::makeFileName(std::string_view name)
|
||||||
{
|
|
||||||
VFS::Path::Normalized makeFilePath(std::string_view name)
|
|
||||||
{
|
{
|
||||||
std::string fileName(name);
|
std::string fileName(name);
|
||||||
|
fileName += '.';
|
||||||
fileName += Technique::sExt;
|
fileName += Technique::sExt;
|
||||||
VFS::Path::Normalized result(Technique::sSubdir);
|
VFS::Path::Normalized result(Technique::sSubdir);
|
||||||
result /= fileName;
|
result /= fileName;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width,
|
Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager,
|
||||||
int height, bool ubo, bool supportsNormals)
|
VFS::Path::NormalizedView fileName, std::string name, int width, int height, bool ubo, bool supportsNormals)
|
||||||
: mName(std::move(name))
|
: mName(std::move(name))
|
||||||
, mFilePath(makeFilePath(mName))
|
, mFilePath(fileName)
|
||||||
, mLastModificationTime(std::filesystem::file_time_type::clock::now())
|
, mLastModificationTime(std::filesystem::file_time_type::clock::now())
|
||||||
, mWidth(width)
|
, mWidth(width)
|
||||||
, mHeight(height)
|
, mHeight(height)
|
||||||
|
@ -105,8 +105,8 @@ namespace fx
|
|||||||
using UniformMap = std::vector<std::shared_ptr<Types::UniformBase>>;
|
using UniformMap = std::vector<std::shared_ptr<Types::UniformBase>>;
|
||||||
using RenderTargetMap = std::unordered_map<std::string_view, Types::RenderTarget>;
|
using RenderTargetMap = std::unordered_map<std::string_view, Types::RenderTarget>;
|
||||||
|
|
||||||
static constexpr std::string_view sExt = ".omwfx";
|
static constexpr std::string_view sExt = "omwfx";
|
||||||
static constexpr std::string_view sSubdir = "shaders";
|
static constexpr VFS::Path::NormalizedView sSubdir{ "shaders" };
|
||||||
|
|
||||||
enum class Status
|
enum class Status
|
||||||
{
|
{
|
||||||
@ -123,8 +123,10 @@ namespace fx
|
|||||||
static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4);
|
static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4);
|
||||||
static constexpr FlagsType Flag_Hidden = (1 << 5);
|
static constexpr FlagsType Flag_Hidden = (1 << 5);
|
||||||
|
|
||||||
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width,
|
static VFS::Path::Normalized makeFileName(std::string_view name);
|
||||||
int height, bool ubo, bool supportsNormals);
|
|
||||||
|
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, VFS::Path::NormalizedView fileName,
|
||||||
|
std::string name, int width, int height, bool ubo, bool supportsNormals);
|
||||||
|
|
||||||
bool compile();
|
bool compile();
|
||||||
|
|
||||||
|
@ -56,7 +56,9 @@ namespace TestingOpenMW
|
|||||||
|
|
||||||
Files::IStreamPtr open() override { return std::make_unique<std::stringstream>(mContent, std::ios_base::in); }
|
Files::IStreamPtr open() override { return std::make_unique<std::stringstream>(mContent, std::ios_base::in); }
|
||||||
|
|
||||||
std::filesystem::path getPath() override { return "TestFile"; }
|
std::filesystem::file_time_type getLastModified() const override { return {}; }
|
||||||
|
|
||||||
|
std::string getStem() const override { return "TestFile"; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string mContent;
|
const std::string mContent;
|
||||||
|
@ -10,45 +10,72 @@
|
|||||||
#include <components/bsa/bsafile.hpp>
|
#include <components/bsa/bsafile.hpp>
|
||||||
#include <components/bsa/compressedbsafile.hpp>
|
#include <components/bsa/compressedbsafile.hpp>
|
||||||
|
|
||||||
|
#include <components/toutf8/toutf8.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
{
|
{
|
||||||
|
template <typename BSAFileType>
|
||||||
|
class BsaArchive;
|
||||||
|
|
||||||
template <typename FileType>
|
template <typename FileType>
|
||||||
class BsaArchiveFile : public File
|
class BsaArchiveFile : public File
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, FileType* bsa)
|
BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, const BsaArchive<FileType>* bsa)
|
||||||
: mInfo(info)
|
: mInfo(info)
|
||||||
, mFile(bsa)
|
, mFile(bsa)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Files::IStreamPtr open() override { return mFile->getFile(mInfo); }
|
Files::IStreamPtr open() override { return mFile->getFile()->getFile(mInfo); }
|
||||||
|
|
||||||
std::filesystem::path getPath() override { return mInfo->name(); }
|
std::filesystem::file_time_type getLastModified() const override
|
||||||
|
{
|
||||||
|
return std::filesystem::last_write_time(mFile->getFile()->getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getStem() const override
|
||||||
|
{
|
||||||
|
std::string_view name = mInfo->name();
|
||||||
|
auto index = name.find_last_of("\\/");
|
||||||
|
if (index != std::string_view::npos)
|
||||||
|
name = name.substr(index + 1);
|
||||||
|
index = name.find_last_of('.');
|
||||||
|
if (index != std::string_view::npos && index != 0)
|
||||||
|
name = name.substr(0, index);
|
||||||
|
std::string out;
|
||||||
|
std::string_view utf8 = mFile->getUtf8(name, out);
|
||||||
|
if (out.data() == utf8.data())
|
||||||
|
out.resize(utf8.size());
|
||||||
|
else
|
||||||
|
out = utf8;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
const Bsa::BSAFile::FileStruct* mInfo;
|
const Bsa::BSAFile::FileStruct* mInfo;
|
||||||
FileType* mFile;
|
const BsaArchive<FileType>* mFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename BSAFileType>
|
template <typename BSAFileType>
|
||||||
class BsaArchive : public Archive
|
class BsaArchive : public Archive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BsaArchive(const std::filesystem::path& filename)
|
BsaArchive(const std::filesystem::path& filename, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||||
: Archive()
|
: Archive()
|
||||||
|
, mEncoder(encoder)
|
||||||
{
|
{
|
||||||
mFile = std::make_unique<BSAFileType>();
|
mFile = std::make_unique<BSAFileType>();
|
||||||
mFile->open(filename);
|
mFile->open(filename);
|
||||||
|
|
||||||
const Bsa::BSAFile::FileList& filelist = mFile->getList();
|
std::string buffer;
|
||||||
for (Bsa::BSAFile::FileList::const_iterator it = filelist.begin(); it != filelist.end(); ++it)
|
for (const Bsa::BSAFile::FileStruct& file : mFile->getList())
|
||||||
{
|
{
|
||||||
mResources.emplace_back(&*it, mFile.get());
|
mResources.emplace_back(&file, this);
|
||||||
mFiles.emplace_back(it->name());
|
mFiles.emplace_back(getUtf8(file.name(), buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(mFiles.begin(), mFiles.end());
|
std::sort(mFiles.begin(), mFiles.end());
|
||||||
@ -56,8 +83,12 @@ namespace VFS
|
|||||||
|
|
||||||
void listResources(FileMap& out) override
|
void listResources(FileMap& out) override
|
||||||
{
|
{
|
||||||
|
std::string buffer;
|
||||||
for (auto& resource : mResources)
|
for (auto& resource : mResources)
|
||||||
out[VFS::Path::Normalized(resource.mInfo->name())] = &resource;
|
{
|
||||||
|
std::string_view path = getUtf8(resource.mInfo->name(), buffer);
|
||||||
|
out[VFS::Path::Normalized(path)] = &resource;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(Path::NormalizedView file) const override
|
bool contains(Path::NormalizedView file) const override
|
||||||
@ -67,26 +98,37 @@ namespace VFS
|
|||||||
|
|
||||||
std::string getDescription() const override { return std::string{ "BSA: " } + mFile->getFilename(); }
|
std::string getDescription() const override { return std::string{ "BSA: " } + mFile->getFilename(); }
|
||||||
|
|
||||||
|
BSAFileType* getFile() const { return mFile.get(); }
|
||||||
|
|
||||||
|
std::string_view getUtf8(std::string_view input, std::string& buffer) const
|
||||||
|
{
|
||||||
|
if (mEncoder == nullptr)
|
||||||
|
return input;
|
||||||
|
return mEncoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::UseGrowFactor, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<BSAFileType> mFile;
|
std::unique_ptr<BSAFileType> mFile;
|
||||||
std::vector<BsaArchiveFile<BSAFileType>> mResources;
|
std::vector<BsaArchiveFile<BSAFileType>> mResources;
|
||||||
std::vector<VFS::Path::Normalized> mFiles;
|
std::vector<VFS::Path::Normalized> mFiles;
|
||||||
|
const ToUTF8::StatelessUtf8Encoder* mEncoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<VFS::Archive> makeBsaArchive(const std::filesystem::path& path)
|
inline std::unique_ptr<VFS::Archive> makeBsaArchive(
|
||||||
|
const std::filesystem::path& path, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||||
{
|
{
|
||||||
switch (Bsa::BSAFile::detectVersion(path))
|
switch (Bsa::BSAFile::detectVersion(path))
|
||||||
{
|
{
|
||||||
case Bsa::BsaVersion::Unknown:
|
case Bsa::BsaVersion::Unknown:
|
||||||
break;
|
break;
|
||||||
case Bsa::BsaVersion::Uncompressed:
|
case Bsa::BsaVersion::Uncompressed:
|
||||||
return std::make_unique<BsaArchive<Bsa::BSAFile>>(path);
|
return std::make_unique<BsaArchive<Bsa::BSAFile>>(path, encoder);
|
||||||
case Bsa::BsaVersion::Compressed:
|
case Bsa::BsaVersion::Compressed:
|
||||||
return std::make_unique<BsaArchive<Bsa::CompressedBSAFile>>(path);
|
return std::make_unique<BsaArchive<Bsa::CompressedBSAFile>>(path, encoder);
|
||||||
case Bsa::BsaVersion::BA2GNRL:
|
case Bsa::BsaVersion::BA2GNRL:
|
||||||
return std::make_unique<BsaArchive<Bsa::BA2GNRLFile>>(path);
|
return std::make_unique<BsaArchive<Bsa::BA2GNRLFile>>(path, encoder);
|
||||||
case Bsa::BsaVersion::BA2DX10:
|
case Bsa::BsaVersion::BA2DX10:
|
||||||
return std::make_unique<BsaArchive<Bsa::BA2DX10File>>(path);
|
return std::make_unique<BsaArchive<Bsa::BA2DX10File>>(path, encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Unknown archive type '" + Files::pathToUnicodeString(path) + "'");
|
throw std::runtime_error("Unknown archive type '" + Files::pathToUnicodeString(path) + "'");
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define OPENMW_COMPONENTS_VFS_FILE_H
|
#define OPENMW_COMPONENTS_VFS_FILE_H
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <components/files/istreamptr.hpp>
|
#include <components/files/istreamptr.hpp>
|
||||||
|
|
||||||
@ -14,7 +15,9 @@ namespace VFS
|
|||||||
|
|
||||||
virtual Files::IStreamPtr open() = 0;
|
virtual Files::IStreamPtr open() = 0;
|
||||||
|
|
||||||
virtual std::filesystem::path getPath() = 0;
|
virtual std::filesystem::file_time_type getLastModified() const = 0;
|
||||||
|
|
||||||
|
virtual std::string getStem() const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,4 +81,14 @@ namespace VFS
|
|||||||
return Files::openConstrainedFileStream(mPath);
|
return Files::openConstrainedFileStream(mPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::file_time_type FileSystemArchiveFile::getLastModified() const
|
||||||
|
{
|
||||||
|
return std::filesystem::last_write_time(mPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileSystemArchiveFile::getStem() const
|
||||||
|
{
|
||||||
|
return Files::pathToUnicodeString(mPath.stem());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ namespace VFS
|
|||||||
|
|
||||||
Files::IStreamPtr open() override;
|
Files::IStreamPtr open() override;
|
||||||
|
|
||||||
std::filesystem::path getPath() override { return mPath; }
|
std::filesystem::file_time_type getLastModified() const override;
|
||||||
|
|
||||||
|
std::string getStem() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::filesystem::path mPath;
|
std::filesystem::path mPath;
|
||||||
|
@ -81,15 +81,20 @@ namespace VFS
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const
|
std::filesystem::file_time_type Manager::getLastModified(VFS::Path::NormalizedView name) const
|
||||||
{
|
{
|
||||||
std::string normalized = Files::pathToUnicodeString(name);
|
const auto found = mIndex.find(name);
|
||||||
Path::normalizeFilenameInPlace(normalized);
|
|
||||||
|
|
||||||
const auto found = mIndex.find(normalized);
|
|
||||||
if (found == mIndex.end())
|
if (found == mIndex.end())
|
||||||
throw std::runtime_error("Resource '" + normalized + "' is not found");
|
throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found");
|
||||||
return found->second->getPath();
|
return found->second->getLastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Manager::getStem(VFS::Path::NormalizedView name) const
|
||||||
|
{
|
||||||
|
const auto found = mIndex.find(name);
|
||||||
|
if (found == mIndex.end())
|
||||||
|
throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found");
|
||||||
|
return found->second->getStem();
|
||||||
}
|
}
|
||||||
|
|
||||||
RecursiveDirectoryRange Manager::getRecursiveDirectoryIterator(std::string_view path) const
|
RecursiveDirectoryRange Manager::getRecursiveDirectoryIterator(std::string_view path) const
|
||||||
|
@ -72,10 +72,9 @@ namespace VFS
|
|||||||
|
|
||||||
RecursiveDirectoryRange getRecursiveDirectoryIterator() const;
|
RecursiveDirectoryRange getRecursiveDirectoryIterator() const;
|
||||||
|
|
||||||
/// Retrieve the absolute path to the file
|
std::filesystem::file_time_type getLastModified(VFS::Path::NormalizedView name) const;
|
||||||
/// @note Throws an exception if the file can not be found.
|
// Equivalent to std::filesystem::path::stem. The result isn't normalized.
|
||||||
/// @note May be called from any thread once the index has been built.
|
std::string getStem(VFS::Path::NormalizedView name) const;
|
||||||
std::filesystem::path getAbsoluteFileName(const std::filesystem::path& name) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<Archive>> mArchives;
|
std::vector<std::unique_ptr<Archive>> mArchives;
|
||||||
|
@ -127,6 +127,15 @@ namespace VFS::Path
|
|||||||
return stream << value.mValue;
|
return stream << value.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NormalizedView parent() const
|
||||||
|
{
|
||||||
|
NormalizedView p;
|
||||||
|
const std::size_t pos = mValue.find_last_of(separator);
|
||||||
|
if (pos != std::string_view::npos)
|
||||||
|
p.mValue = mValue.substr(0, pos);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string_view mValue;
|
std::string_view mValue;
|
||||||
};
|
};
|
||||||
@ -259,6 +268,11 @@ namespace VFS::Path
|
|||||||
return stream << value.mValue;
|
return stream << value.mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NormalizedView parent() const
|
||||||
|
{
|
||||||
|
return NormalizedView(*this).parent();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mValue;
|
std::string mValue;
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,7 @@ namespace VFS
|
|||||||
{
|
{
|
||||||
|
|
||||||
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
||||||
const std::vector<std::string>& archives, bool useLooseFiles)
|
const std::vector<std::string>& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||||
{
|
{
|
||||||
const Files::PathContainer& dataDirs = collections.getPaths();
|
const Files::PathContainer& dataDirs = collections.getPaths();
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ namespace VFS
|
|||||||
// Last BSA has the highest priority
|
// Last BSA has the highest priority
|
||||||
const auto archivePath = collections.getPath(*archive);
|
const auto archivePath = collections.getPath(*archive);
|
||||||
Log(Debug::Info) << "Adding BSA archive " << archivePath;
|
Log(Debug::Info) << "Adding BSA archive " << archivePath;
|
||||||
vfs->addArchive(makeBsaArchive(archivePath));
|
vfs->addArchive(makeBsaArchive(archivePath, encoder));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3,13 +3,18 @@
|
|||||||
|
|
||||||
#include <components/files/collections.hpp>
|
#include <components/files/collections.hpp>
|
||||||
|
|
||||||
|
namespace ToUTF8
|
||||||
|
{
|
||||||
|
class StatelessUtf8Encoder;
|
||||||
|
}
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
{
|
{
|
||||||
class Manager;
|
class Manager;
|
||||||
|
|
||||||
/// @brief Register BSA and file system archives based on the given OpenMW configuration.
|
/// @brief Register BSA and file system archives based on the given OpenMW configuration.
|
||||||
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
||||||
const std::vector<std::string>& archives, bool useLooseFiles);
|
const std::vector<std::string>& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user