From 9fb639a00e1a809a9ea9b5e68777ec46f534761c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 13:27:40 +0200 Subject: Update ModInfo to use a single file tree for all content-related operations. --- src/modinforegular.cpp | 94 +++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index d89716da..3c1d49ea 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -38,7 +38,6 @@ ModInfoRegular::ModInfoRegular(PluginContainer *pluginContainer, const IPluginGa , m_TrackedState(TRACKED_UNKNOWN) , m_NexusBridge(pluginContainer) { - testValid(); m_CreationTime = QFileInfo(path.absolutePath()).birthTime(); // read out the meta-file for information readMeta(); @@ -656,58 +655,59 @@ std::vector ModInfoRegular::getFlags() const std::vector ModInfoRegular::getContents() const { - QTime now = QTime::currentTime(); - if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) { - m_CachedContent.clear(); - QDir dir(absolutePath()); - if (dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl").size() > 0) { - m_CachedContent.push_back(CONTENT_PLUGIN); - } - if (dir.entryList(QStringList() << "*.bsa" << "*.ba2").size() > 0) { - m_CachedContent.push_back(CONTENT_BSA); - } - //use >1 for ini files since there is meta.ini in all mods already. - if (dir.entryList(QStringList() << "*.ini").size() > 1) { - m_CachedContent.push_back(CONTENT_INI); - } + auto tree = contentFileTree(); + std::vector contents; - if (dir.entryList(QStringList() << "*.modgroups").size() > 0) { - m_CachedContent.push_back(CONTENT_MODGROUP); + for (auto e : *tree) { + if (e->isFile()) { + auto suffix = e->suffix(); + if (suffix == "esp" || suffix == "esm" || suffix == "esl") { + contents.push_back(CONTENT_PLUGIN); + } + else if (suffix == "bsa" || suffix == "ba2") { + contents.push_back(CONTENT_BSA); + } + //use >1 for ini files since there is meta.ini in all mods already. + else if (suffix == "ini" && e->compare("meta.ini") != 0) { + contents.push_back(CONTENT_INI); + } + else if (suffix == "modgroups") { + contents.push_back(CONTENT_MODGROUP); + } + } + else { + if (e->compare("textures") == 0 || e->compare("icons") == 0 || e->compare("bookart") == 0) + contents.push_back(CONTENT_TEXTURE); + if (e->compare("meshes") == 0) + contents.push_back(CONTENT_MESH); + if (e->compare("interface") == 0 || e->compare("menus") == 0) + contents.push_back(CONTENT_INTERFACE); + if (e->compare("music") == 0 || e->compare("sound") == 0) + contents.push_back(CONTENT_SOUND); + if (e->compare("scripts") == 0) + contents.push_back(CONTENT_SCRIPT); + if (e->compare("SkyProc Patchers") == 0) + contents.push_back(CONTENT_SKYPROC); + if (e->compare("MCM") == 0) + contents.push_back(CONTENT_MCM); } + } - ScriptExtender *extender = qApp->property("managed_game") - .value() - ->feature(); - - if (extender != nullptr) { - QString sePluginPath = extender->PluginPath(); - if (dir.exists(sePluginPath)) { - m_CachedContent.push_back(CONTENT_SKSEFILES); - QDir sePluginDir(absolutePath() + "/" + sePluginPath); - if (sePluginDir.entryList(QStringList() << "*.dll").size() > 0) { - m_CachedContent.push_back(CONTENT_SKSE); + ScriptExtender* extender = m_GamePlugin->feature(); + if (extender != nullptr) { + auto e = tree->findDirectory(extender->PluginPath()); + if (e) { + contents.push_back(CONTENT_SKSEFILES); + for (auto f : *e) { + if (e->suffix().compare("dll") == 0) { + contents.push_back(CONTENT_SKSE); + break; } } } - if (dir.exists("textures") || dir.exists("icons") || dir.exists("bookart")) - m_CachedContent.push_back(CONTENT_TEXTURE); - if (dir.exists("meshes")) - m_CachedContent.push_back(CONTENT_MESH); - if (dir.exists("interface") || dir.exists("menus")) - m_CachedContent.push_back(CONTENT_INTERFACE); - if (dir.exists("music") || dir.exists("sound")) - m_CachedContent.push_back(CONTENT_SOUND); - if (dir.exists("scripts")) - m_CachedContent.push_back(CONTENT_SCRIPT); - if (dir.exists("SkyProc Patchers")) - m_CachedContent.push_back(CONTENT_SKYPROC); - if (dir.exists("MCM")) - m_CachedContent.push_back(CONTENT_MCM); - - m_LastContentCheck = QTime::currentTime(); - } - - return m_CachedContent; + } + + return contents; } -- cgit v1.3.1 From a62bf7aa1289b21e0e9df75c860b2fd97fb915e4 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 15:21:08 +0200 Subject: Fix typo in getContents(). --- src/modinforegular.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 3c1d49ea..87f6ce77 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -699,7 +699,7 @@ std::vector ModInfoRegular::getContents() const if (e) { contents.push_back(CONTENT_SKSEFILES); for (auto f : *e) { - if (e->suffix().compare("dll") == 0) { + if (f->suffix().compare("dll") == 0) { contents.push_back(CONTENT_SKSE); break; } -- cgit v1.3.1 From a67a99acb7394861e253c28336eba28e7b68b77c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 15:35:09 +0200 Subject: Force lower case comparison for extensions in getContents(). --- src/modinforegular.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 87f6ce77..85659bd2 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -660,7 +660,7 @@ std::vector ModInfoRegular::getContents() const for (auto e : *tree) { if (e->isFile()) { - auto suffix = e->suffix(); + auto suffix = e->suffix().toLower(); if (suffix == "esp" || suffix == "esm" || suffix == "esl") { contents.push_back(CONTENT_PLUGIN); } -- cgit v1.3.1 From 4d8b5aaae8adc08f5392bc631e7f88c501dea386 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 15:35:35 +0200 Subject: Remove old comment. --- src/modinforegular.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 85659bd2..87483a64 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -667,7 +667,6 @@ std::vector ModInfoRegular::getContents() const else if (suffix == "bsa" || suffix == "ba2") { contents.push_back(CONTENT_BSA); } - //use >1 for ini files since there is meta.ini in all mods already. else if (suffix == "ini" && e->compare("meta.ini") != 0) { contents.push_back(CONTENT_INI); } -- cgit v1.3.1 From 238e233c18d22d01e966efaa86975f5f37bb7fa2 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 23:33:21 +0200 Subject: Use memoization for file tree, contents and validity of ModInfo. --- src/modinforegular.cpp | 3 +-- src/modinforegular.h | 4 ++-- src/modinfowithconflictinfo.cpp | 25 ++++++++++++++++--------- src/modinfowithconflictinfo.h | 31 ++++++++++++++++++++++++------- 4 files changed, 43 insertions(+), 20 deletions(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 87483a64..d8e42383 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -653,7 +653,7 @@ std::vector ModInfoRegular::getFlags() const } -std::vector ModInfoRegular::getContents() const +std::vector ModInfoRegular::doGetContents() const { auto tree = contentFileTree(); std::vector contents; @@ -707,7 +707,6 @@ std::vector ModInfoRegular::getContents() const } return contents; - } diff --git a/src/modinforegular.h b/src/modinforegular.h index 08546c69..e63e7570 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -289,8 +289,6 @@ public: */ virtual std::vector getFlags() const override; - virtual std::vector getContents() const override; - /** * @return an indicator if and how this mod should be highlighted by the UI */ @@ -418,6 +416,8 @@ private slots: protected: + virtual std::vector doGetContents() const override; + ModInfoRegular(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &path, MOShared::DirectoryEntry **directoryStructure); private: diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index d2202c3d..d2a0ca51 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -14,7 +14,9 @@ namespace fs = std::filesystem; ModInfoWithConflictInfo::ModInfoWithConflictInfo( PluginContainer *pluginContainer, const MOBase::IPluginGame* gamePlugin, DirectoryEntry **directoryStructure) - : ModInfo(pluginContainer), m_GamePlugin(gamePlugin), m_DirectoryStructure(directoryStructure), m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {} + : ModInfo(pluginContainer), m_GamePlugin(gamePlugin), + m_FileTree(&ModInfoWithConflictInfo::updateFileTree), m_Valid(&ModInfoWithConflictInfo::doTestValid), m_Contents(&ModInfoWithConflictInfo::doGetContents), + m_DirectoryStructure(directoryStructure), m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {} void ModInfoWithConflictInfo::clearCaches() { @@ -297,16 +299,17 @@ bool ModInfoWithConflictInfo::hasHiddenFiles() const } void ModInfoWithConflictInfo::diskContentModified() { - std::unique_lock lock(m_Mutex); - m_FileTree = nullptr; + m_FileTree.invalidate(); + m_Valid.invalidate(); + m_Contents.invalidate(); +} + +std::shared_ptr ModInfoWithConflictInfo::updateFileTree() const { + return QDirFileTree::makeTree(absolutePath()); } std::shared_ptr ModInfoWithConflictInfo::contentFileTree() const { - std::unique_lock lock(m_Mutex); - if (!m_FileTree) { - m_FileTree = QDirFileTree::makeTree(absolutePath()); - } - return m_FileTree; + return m_FileTree.value(this); } void ModInfoWithConflictInfo::prefetch() { @@ -326,5 +329,9 @@ bool ModInfoWithConflictInfo::doTestValid() const { } bool ModInfoWithConflictInfo::isValid() const { - return doTestValid(); + return m_Valid.value(this); +} + +std::vector ModInfoWithConflictInfo::getContents() const { + return m_Contents.value(this); } diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 68675397..3adbb998 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -3,6 +3,7 @@ #include +#include "thread_utils.h" #include "modinfo.h" #include @@ -20,6 +21,11 @@ public: **/ virtual bool isValid() const override; + /** + * @return a list of content types contained in a mod + */ + virtual std::vector getContents() const override; + /** * @brief clear all caches held for this mod */ @@ -49,12 +55,19 @@ public slots: protected: /** - * @brief check if the content of this mod is valid. + * @brief Check if the content of this mod is valid. * - * @return true if the content is valid, false otherwize. + * @return true if the content is valid, false otherwise. **/ virtual bool doTestValid() const; + /** + * @brief Compute the contents for this mod. + * + * @return the contents for this mod. + **/ + virtual std::vector doGetContents() const { return {}; } + /** * @brief Retrieve a file tree corresponding to the underlying disk content * of this mod. @@ -122,12 +135,16 @@ protected: private: - // Mutex: - mutable std::mutex m_Mutex; + /** + * @return a file tree for this mod. + */ + std::shared_ptr updateFileTree() const; - // File tree representing the content of the disk. A null pointer indicates - // that the content needs to be loaded from the disk: - mutable std::shared_ptr m_FileTree = nullptr; + MOShared::MemoizedLocked< + std::shared_ptr, + decltype(&ModInfoWithConflictInfo::updateFileTree)> m_FileTree; + MOShared::MemoizedLocked m_Valid; + MOShared::MemoizedLocked, decltype(&ModInfoWithConflictInfo::doGetContents)> m_Contents; MOShared::DirectoryEntry **m_DirectoryStructure; -- cgit v1.3.1 From c5bbf7360c4fc60e691f5e42606e4510172698f2 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 25 May 2020 17:58:58 +0200 Subject: Fix suffix comparison for SKSE DLLs. --- src/modinforegular.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index d8e42383..8d5d702d 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -698,7 +698,7 @@ std::vector ModInfoRegular::doGetContents() const if (e) { contents.push_back(CONTENT_SKSEFILES); for (auto f : *e) { - if (f->suffix().compare("dll") == 0) { + if (f->suffix().compare("dll", FileNameComparator::CaseSensitivity) == 0) { contents.push_back(CONTENT_SKSE); break; } -- cgit v1.3.1 From 9212a7d2e9611994dfc5fa2066b8ecbe68b198a8 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 25 May 2020 18:27:49 +0200 Subject: Use hasSuffix() where needed. --- src/modinforegular.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modinforegular.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 8d5d702d..a1f1a04d 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -698,7 +698,7 @@ std::vector ModInfoRegular::doGetContents() const if (e) { contents.push_back(CONTENT_SKSEFILES); for (auto f : *e) { - if (f->suffix().compare("dll", FileNameComparator::CaseSensitivity) == 0) { + if (f->hasSuffix("dll")) { contents.push_back(CONTENT_SKSE); break; } -- cgit v1.3.1