From 95e5816e6cd453fd815cae7f18ca7a47c7ca8a20 Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 17:47:34 -0500 Subject: [PATCH 1/7] Fixed thread gridlock that casued mesh patching to get suck occasionally Fixed PBR JSON delete: true not working Fixed uncaught exception if mod folder does not exist in MO2 Fixed dyncubemap blocklist not showing up on start in the GUI if advanced options is enabled Fixed uncaught exception when a NIF has non-ASCII chars as a texture slot --- CHANGELOG.md | 8 +++ CMakeLists.txt | 4 +- ParallaxGen/src/GUI/LauncherWindow.cpp | 3 +- ParallaxGen/src/main.cpp | 3 +- ParallaxGenLib/include/ParallaxGenTask.hpp | 10 ++-- ParallaxGenLib/src/ModManagerDirectory.cpp | 11 ++-- ParallaxGenLib/src/ParallaxGen.cpp | 51 +++++++++++-------- ParallaxGenLib/src/ParallaxGenDirectory.cpp | 51 ++++++++++--------- ParallaxGenLib/src/ParallaxGenTask.cpp | 16 +++--- .../src/patchers/PatcherTruePBR.cpp | 25 ++++++--- 10 files changed, 112 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f83559b..ce87cb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.7.3] - UNRELEASED + +- Fixed thread gridlock that casued mesh patching to get suck occasionally +- Fixed PBR JSON delete: true not working +- Fixed uncaught exception if mod folder does not exist in MO2 +- Fixed dyncubemap blocklist not showing up on start in the GUI if advanced options is enabled +- Fixed uncaught exception when a NIF has non-ASCII chars as a texture slot + ## [0.7.2] - 2024-12-07 - Added mesh allowlist diff --git a/CMakeLists.txt b/CMakeLists.txt index d3a21cd..a4de6bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,12 +22,12 @@ add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) set(PROJECT_NAME "ParallaxGen") # Initialize Project -set(PARALLAXGEN_VERSION 0.7.2) +set(PARALLAXGEN_VERSION 0.7.3) project(${PROJECT_NAME} VERSION ${PARALLAXGEN_VERSION}) add_compile_definitions(PARALLAXGEN_VERSION="${PARALLAXGEN_VERSION}") # Set test version (set this to 0 for prod releases) -add_compile_definitions(PARALLAXGEN_TEST_VERSION=0) +add_compile_definitions(PARALLAXGEN_TEST_VERSION=1) # Setup Folders set(EXTRN_BUILD_DIR ${CMAKE_BINARY_DIR}/external/blds) diff --git a/ParallaxGen/src/GUI/LauncherWindow.cpp b/ParallaxGen/src/GUI/LauncherWindow.cpp index 4b7cbc2..e7ea0fa 100644 --- a/ParallaxGen/src/GUI/LauncherWindow.cpp +++ b/ParallaxGen/src/GUI/LauncherWindow.cpp @@ -509,7 +509,6 @@ void LauncherWindow::loadConfig() { // Advanced AdvancedOptionsCheckbox->SetValue(InitParams.Advanced); - updateAdvanced(); // Processing ProcessingPluginPatchingCheckbox->SetValue(InitParams.Processing.PluginPatching); @@ -571,6 +570,8 @@ void LauncherWindow::loadConfig() { TextureRulesVanillaBSAList->InsertItem(TextureRulesVanillaBSAList->GetItemCount(), VanillaBSA); } TextureRulesVanillaBSAList->InsertItem(TextureRulesVanillaBSAList->GetItemCount(), ""); // Add empty line + + updateAdvanced(); } // Component event handlers diff --git a/ParallaxGen/src/main.cpp b/ParallaxGen/src/main.cpp index 1a42755..4dcab6f 100644 --- a/ParallaxGen/src/main.cpp +++ b/ParallaxGen/src/main.cpp @@ -444,8 +444,9 @@ auto main(int ArgC, char **ArgV) -> int { initLogger(LogPath, Args); // Main Runner (Catches all exceptions) + mainRunner(Args, ExePath); try { - mainRunner(Args, ExePath); + //mainRunner(Args, ExePath); } catch (const exception &E) { auto Trace = boost::stacktrace::stacktrace(); spdlog::critical("An unhandled exception occurred (Please provide this entire message " diff --git a/ParallaxGenLib/include/ParallaxGenTask.hpp b/ParallaxGenLib/include/ParallaxGenTask.hpp index 759562d..5d6d466 100644 --- a/ParallaxGenLib/include/ParallaxGenTask.hpp +++ b/ParallaxGenLib/include/ParallaxGenTask.hpp @@ -28,12 +28,14 @@ class ParallaxGenTask { ParallaxGenTask(std::string TaskName, const size_t &TotalJobs, const int &ProgressPrintModulo = 1); void completeJob(const PGResult &Result); - void initJobStatus(); - void printJobStatus(bool Force = false); - void printJobSummary(); - [[nodiscard]] auto getCompletedJobs() -> size_t; [[nodiscard]] auto isCompleted() -> bool; static void updatePGResult(PGResult &Result, const PGResult &CurrentResult, const PGResult &Threshold = PGResult::FAILURE); + +private: + void initJobStatus(); + void printJobStatus(bool Force = false); + void printJobSummary(); + [[nodiscard]] auto getCompletedJobs() -> size_t; }; diff --git a/ParallaxGenLib/src/ModManagerDirectory.cpp b/ParallaxGenLib/src/ModManagerDirectory.cpp index 2ec1d85..b41343e 100644 --- a/ParallaxGenLib/src/ModManagerDirectory.cpp +++ b/ParallaxGenLib/src/ModManagerDirectory.cpp @@ -157,6 +157,12 @@ void ModManagerDirectory::populateModFileMapMO2(const filesystem::path &Instance Mod.erase(0, 1); // remove + const auto CurModDir = ModDir / Mod; + // Check if mod folder exists + if (!filesystem::exists(CurModDir)) { + spdlog::warn(L"Mod directory from modlist.txt does not exist: {}", CurModDir.wstring()); + continue; + } + // check if mod dir is output dir if (filesystem::equivalent(CurModDir, OutputDir)) { spdlog::critical(L"If outputting to MO2 you must disable the mod {} first to prevent issues with MO2 VFS", Mod); @@ -166,11 +172,6 @@ void ModManagerDirectory::populateModFileMapMO2(const filesystem::path &Instance AllMods.insert(Mod); InferredOrder.insert(InferredOrder.begin(), Mod); - if (!filesystem::exists(CurModDir)) { - spdlog::warn(L"Mod directory from modlist.txt does not exist: {}", CurModDir.wstring()); - continue; - } - try { for (const auto &File : filesystem::recursive_directory_iterator(CurModDir, filesystem::directory_options::skip_permission_denied)) { diff --git a/ParallaxGenLib/src/ParallaxGen.cpp b/ParallaxGenLib/src/ParallaxGen.cpp index 866a8b7..356f837 100644 --- a/ParallaxGenLib/src/ParallaxGen.cpp +++ b/ParallaxGenLib/src/ParallaxGen.cpp @@ -69,19 +69,17 @@ void ParallaxGen::patchMeshes(const PatcherUtil::PatcherSet &Patchers, const uno boost::asio::thread_pool MeshPatchPool(NumThreads); - bool KillThreads = false; - mutex KillThreadsMutex; + atomic KillThreads = false; for (const auto &Mesh : Meshes) { boost::asio::post(MeshPatchPool, [this, &TaskTracker, &DiffJSON, &Mesh, &PatchPlugin, &Patchers, &ModPriority, - &KillThreads, &KillThreadsMutex] { + &KillThreads] { ParallaxGenTask::PGResult Result = ParallaxGenTask::PGResult::SUCCESS; try { Result = processNIF(Patchers, ModPriority, Mesh, &DiffJSON, PatchPlugin); } catch (const exception &E) { - lock_guard Lock(KillThreadsMutex); spdlog::error(L"Exception in thread patching NIF {}: {}", Mesh.wstring(), ASCIItoUTF16(E.what())); - KillThreads = true; + KillThreads.store(true, std::memory_order_release); Result = ParallaxGenTask::PGResult::FAILURE; } @@ -90,10 +88,12 @@ void ParallaxGen::patchMeshes(const PatcherUtil::PatcherSet &Patchers, const uno } while (!TaskTracker.isCompleted()) { - if (KillThreads) { + if (KillThreads.load(std::memory_order_acquire)) { MeshPatchPool.stop(); throw runtime_error("Exception in thread patching NIF"); } + + this_thread::sleep_for(std::chrono::milliseconds(10)); } // verify that all threads complete (should be redundant) @@ -138,21 +138,19 @@ auto ParallaxGen::findModConflicts(const PatcherUtil::PatcherSet &Patchers, cons const size_t NumThreads = boost::thread::hardware_concurrency(); #endif - bool KillThreads = false; - mutex KillThreadsMutex; + atomic KillThreads = false; boost::asio::thread_pool MeshPatchPool(NumThreads); for (const auto &Mesh : Meshes) { boost::asio::post(MeshPatchPool, [this, &TaskTracker, &Mesh, &PatchPlugin, &ConflictMods, &ConflictModsMutex, - &Patchers, &KillThreads, &KillThreadsMutex] { + &Patchers, &KillThreads] { ParallaxGenTask::PGResult Result = ParallaxGenTask::PGResult::SUCCESS; try { Result = processNIF(Patchers, nullptr, Mesh, nullptr, PatchPlugin, true, &ConflictMods, &ConflictModsMutex); } catch (const exception &E) { - lock_guard Lock(KillThreadsMutex); spdlog::error(L"Exception in thread finding mod conflicts {}: {}", Mesh.wstring(), ASCIItoUTF16(E.what())); - KillThreads = true; + KillThreads.store(true, std::memory_order_release); Result = ParallaxGenTask::PGResult::FAILURE; } @@ -161,10 +159,12 @@ auto ParallaxGen::findModConflicts(const PatcherUtil::PatcherSet &Patchers, cons } while (!TaskTracker.isCompleted()) { - if (KillThreads) { + if (KillThreads.load(std::memory_order_acquire)) { MeshPatchPool.stop(); throw runtime_error("Exception in thread finding mod conflicts"); } + + this_thread::sleep_for(std::chrono::milliseconds(10)); } // verify that all threads complete (should be redundant) @@ -303,6 +303,17 @@ auto ParallaxGen::processNIF( bool OneShapeSuccess = false; vector> ShapeTracker; for (NiShape *NIFShape : NIF.GetShapes()) { + // Check for any non-ascii chars + for (uint32_t Slot = 0; Slot < NUM_TEXTURE_SLOTS; Slot++) { + string Texture; + NIF.GetTextureSlot(NIFShape, Texture, Slot); + + if (!ContainsOnlyAscii(Texture)) { + spdlog::error(L"NIF {} has texture slot(s) with invalid non-ASCII chars (skipping)", NIFFile.wstring()); + return ParallaxGenTask::PGResult::FAILURE; + } + } + // get shape name and blockid const auto ShapeBlockID = NIF.GetBlockID(NIFShape); const auto ShapeName = ASCIItoUTF16(NIFShape->name.get()); @@ -320,16 +331,14 @@ auto ParallaxGen::processNIF( ConflictModsMutex), ParallaxGenTask::PGResult::SUCCESS_WITH_WARNINGS); + NIFModified |= ShapeModified; + // Update NIFModified if shape was modified - if (ShapeModified && ShaderApplied != NIFUtil::ShapeShader::NONE) { - NIFModified = true; - - if (PatchPlugin) { - // Process plugin - array NewSlots; - ParallaxGenPlugin::processShape(ShaderApplied, NIFFile.wstring(), ShapeName, OldShapeIndex, PatcherObjects, - ModPriority, NewSlots); - } + if (ShaderApplied != NIFUtil::ShapeShader::NONE && PatchPlugin) { + // Process plugin + array NewSlots; + ParallaxGenPlugin::processShape(ShaderApplied, NIFFile.wstring(), ShapeName, OldShapeIndex, PatcherObjects, + ModPriority, NewSlots); } if (Result == ParallaxGenTask::PGResult::SUCCESS) { diff --git a/ParallaxGenLib/src/ParallaxGenDirectory.cpp b/ParallaxGenLib/src/ParallaxGenDirectory.cpp index 0676986..9cfbe20 100644 --- a/ParallaxGenLib/src/ParallaxGenDirectory.cpp +++ b/ParallaxGenLib/src/ParallaxGenDirectory.cpp @@ -96,8 +96,7 @@ auto ParallaxGenDirectory::mapFiles(const vector &NIFBlocklist, const v const size_t NumThreads = boost::thread::hardware_concurrency(); #endif - bool KillThreads = false; - mutex KillThreadsMutex; + atomic KillThreads = false; boost::asio::thread_pool MapTextureFromMeshPool(NumThreads); @@ -125,36 +124,31 @@ auto ParallaxGenDirectory::mapFiles(const vector &NIFBlocklist, const v } if (Multithreading) { - boost::asio::post( - MapTextureFromMeshPool, [this, &TaskTracker, &Mesh, &CacheNIFs, &KillThreads, &KillThreadsMutex] { - ParallaxGenTask::PGResult Result = ParallaxGenTask::PGResult::SUCCESS; - try { - Result = mapTexturesFromNIF(Mesh, CacheNIFs); - } catch (const exception &E) { - lock_guard Lock(KillThreadsMutex); - spdlog::error(L"Exception in thread loading NIF \"{}\": {}", Mesh.wstring(), ASCIItoUTF16(E.what())); - KillThreads = true; - Result = ParallaxGenTask::PGResult::FAILURE; - } - - TaskTracker.completeJob(Result); - }); + boost::asio::post(MapTextureFromMeshPool, [this, &TaskTracker, &Mesh, &CacheNIFs, &KillThreads] { + ParallaxGenTask::PGResult Result = ParallaxGenTask::PGResult::SUCCESS; + try { + Result = mapTexturesFromNIF(Mesh, CacheNIFs); + } catch (const exception &E) { + spdlog::error(L"Exception in thread loading NIF \"{}\": {}", Mesh.wstring(), ASCIItoUTF16(E.what())); + KillThreads.store(true, std::memory_order_release); + Result = ParallaxGenTask::PGResult::FAILURE; + } + + TaskTracker.completeJob(Result); + }); } else { - try { - TaskTracker.completeJob(mapTexturesFromNIF(Mesh, CacheNIFs)); - } catch (const exception &E) { - spdlog::error(L"Exception loading NIF \"{}\": {}", Mesh.wstring(), ASCIItoUTF16(E.what())); - TaskTracker.completeJob(ParallaxGenTask::PGResult::FAILURE); - } + TaskTracker.completeJob(mapTexturesFromNIF(Mesh, CacheNIFs)); } } if (Multithreading) { while (!TaskTracker.isCompleted()) { - if (KillThreads) { + if (KillThreads.load(std::memory_order_acquire)) { MapTextureFromMeshPool.stop(); throw runtime_error("Exception in thread mapping textures from NIFs"); } + + this_thread::sleep_for(std::chrono::milliseconds(10)); } // Wait for all threads to complete @@ -233,6 +227,11 @@ auto ParallaxGenDirectory::checkGlobMatchInVector(const wstring &Check, const ve auto ParallaxGenDirectory::mapTexturesFromNIF(const filesystem::path &NIFPath, const bool &CacheNIFs) -> ParallaxGenTask::PGResult { + if (boost::icontains(NIFPath.wstring(), "opheliamarryringsmall")) { + // Skip LOD meshes + spdlog::trace("DEBUG"); + } + auto Result = ParallaxGenTask::PGResult::SUCCESS; // Load NIF @@ -281,6 +280,12 @@ auto ParallaxGenDirectory::mapTexturesFromNIF(const filesystem::path &NIFPath, for (uint32_t Slot = 0; Slot < NUM_TEXTURE_SLOTS; Slot++) { string Texture; NIF.GetTextureSlot(Shape, Texture, Slot); + + if (!ContainsOnlyAscii(Texture)) { + spdlog::error(L"NIF {} has texture slot(s) with invalid non-ASCII chars (skipping)", NIFPath.wstring()); + return ParallaxGenTask::PGResult::FAILURE; + } + if (Texture.empty()) { // No texture in this slot continue; diff --git a/ParallaxGenLib/src/ParallaxGenTask.cpp b/ParallaxGenLib/src/ParallaxGenTask.cpp index 086f34b..f88c7b7 100644 --- a/ParallaxGenLib/src/ParallaxGenTask.cpp +++ b/ParallaxGenLib/src/ParallaxGenTask.cpp @@ -13,11 +13,6 @@ void ParallaxGenTask::completeJob(const PGResult &Result) { // Use lock_guard to make this method thread-safe const lock_guard Lock(NumJobsCompletedMutex); - // Check if NumJobsCompleted has Result for key - if (NumJobsCompleted.find(Result) == NumJobsCompleted.end()) { - NumJobsCompleted[Result] = 0; - } - NumJobsCompleted[Result]++; printJobStatus(); } @@ -25,6 +20,11 @@ void ParallaxGenTask::completeJob(const PGResult &Result) { void ParallaxGenTask::initJobStatus() { LastPerc = 0; + // Initialize all known PGResult values + NumJobsCompleted[PGResult::FAILURE] = 0; + NumJobsCompleted[PGResult::SUCCESS] = 0; + NumJobsCompleted[PGResult::SUCCESS_WITH_WARNINGS] = 0; + spdlog::info("{} Starting...", TaskName); } @@ -48,8 +48,10 @@ void ParallaxGenTask::printJobSummary() { // Print each job status Result string OutputLog = TaskName + " Summary: "; for (const auto &Pair : NumJobsCompleted) { - const string StateStr = PGResultStr[Pair.first]; - OutputLog += "[ " + StateStr + " : " + to_string(Pair.second) + " ] "; + if (Pair.second > 0) { + const string StateStr = PGResultStr[Pair.first]; + OutputLog += "[ " + StateStr + " : " + to_string(Pair.second) + " ] "; + } } OutputLog += "See log to see error messages, if any."; spdlog::info(OutputLog); diff --git a/ParallaxGenLib/src/patchers/PatcherTruePBR.cpp b/ParallaxGenLib/src/patchers/PatcherTruePBR.cpp index aff3789..8166acc 100644 --- a/ParallaxGenLib/src/patchers/PatcherTruePBR.cpp +++ b/ParallaxGenLib/src/patchers/PatcherTruePBR.cpp @@ -209,14 +209,27 @@ auto PatcherTruePBR::shouldApply(const std::array(JSONData); + // loop through json data + bool DeleteShape = false; + for (const auto &[Sequence, Data] : JSONData) { + if (get<0>(Data).contains("delete") && get<0>(Data)["delete"].get()) { + Logger::trace(L"PBR JSON Match: Result marked for deletion, skipping slot checks"); + DeleteShape = true; + break; + } + } + // check paths bool Valid = true; - const auto NewSlots = applyPatchSlots(OldSlots, Match); - for (size_t I = 0; I < NUM_TEXTURE_SLOTS; I++) { - if (!NewSlots[I].empty() && !getPGD()->isFile(NewSlots[I])) { - // Slot does not exist - Logger::trace(L"PBR JSON Match: Result texture slot {} does not exist", NewSlots[I]); - Valid = false; + + if (!DeleteShape) { + const auto NewSlots = applyPatchSlots(OldSlots, Match); + for (size_t I = 0; I < NUM_TEXTURE_SLOTS; I++) { + if (!NewSlots[I].empty() && !getPGD()->isFile(NewSlots[I])) { + // Slot does not exist + Logger::trace(L"PBR JSON Match: Result texture slot {} does not exist", NewSlots[I]); + Valid = false; + } } } From 2f08f44919427e6ebd8b84759f8bbe29d009f434 Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 17:52:11 -0500 Subject: [PATCH 2/7] fixed leftover debug stuff --- ParallaxGen/src/main.cpp | 3 +-- ParallaxGenLib/src/ParallaxGenDirectory.cpp | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/ParallaxGen/src/main.cpp b/ParallaxGen/src/main.cpp index 4dcab6f..1a42755 100644 --- a/ParallaxGen/src/main.cpp +++ b/ParallaxGen/src/main.cpp @@ -444,9 +444,8 @@ auto main(int ArgC, char **ArgV) -> int { initLogger(LogPath, Args); // Main Runner (Catches all exceptions) - mainRunner(Args, ExePath); try { - //mainRunner(Args, ExePath); + mainRunner(Args, ExePath); } catch (const exception &E) { auto Trace = boost::stacktrace::stacktrace(); spdlog::critical("An unhandled exception occurred (Please provide this entire message " diff --git a/ParallaxGenLib/src/ParallaxGenDirectory.cpp b/ParallaxGenLib/src/ParallaxGenDirectory.cpp index 9cfbe20..1aa6b68 100644 --- a/ParallaxGenLib/src/ParallaxGenDirectory.cpp +++ b/ParallaxGenLib/src/ParallaxGenDirectory.cpp @@ -227,11 +227,6 @@ auto ParallaxGenDirectory::checkGlobMatchInVector(const wstring &Check, const ve auto ParallaxGenDirectory::mapTexturesFromNIF(const filesystem::path &NIFPath, const bool &CacheNIFs) -> ParallaxGenTask::PGResult { - if (boost::icontains(NIFPath.wstring(), "opheliamarryringsmall")) { - // Skip LOD meshes - spdlog::trace("DEBUG"); - } - auto Result = ParallaxGenTask::PGResult::SUCCESS; // Load NIF From cce84c4a045f75921f92ec064298901ba4cd51ad Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 21:15:42 -0500 Subject: [PATCH 3/7] fixed dyncubemapblocklist GUI behavior --- CHANGELOG.md | 1 + ParallaxGen/src/GUI/LauncherWindow.cpp | 2 +- ParallaxGen/src/ParallaxGenConfig.cpp | 16 +++++++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce87cb7..5f9d3db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Fixed thread gridlock that casued mesh patching to get suck occasionally - Fixed PBR JSON delete: true not working - Fixed uncaught exception if mod folder does not exist in MO2 +- Fixed dyncubemap blocklist not saving/loading correctly in the GUI - Fixed dyncubemap blocklist not showing up on start in the GUI if advanced options is enabled - Fixed uncaught exception when a NIF has non-ASCII chars as a texture slot diff --git a/ParallaxGen/src/GUI/LauncherWindow.cpp b/ParallaxGen/src/GUI/LauncherWindow.cpp index e7ea0fa..72c0cc0 100644 --- a/ParallaxGen/src/GUI/LauncherWindow.cpp +++ b/ParallaxGen/src/GUI/LauncherWindow.cpp @@ -209,7 +209,7 @@ LauncherWindow::LauncherWindow(ParallaxGenConfig &PGC) ShaderPatcherComplexMaterialDynCubemapBlocklist->SetColumnWidth( 0, ShaderPatcherComplexMaterialDynCubemapBlocklist->GetClientSize().GetWidth() - ScrollbarWidth); ShaderPatcherComplexMaterialDynCubemapBlocklist->Bind( - wxEVT_LIST_ITEM_ACTIVATED, &LauncherWindow::onShaderPatcherComplexMaterialDynCubemapBlocklistChange, this); + wxEVT_LIST_END_LABEL_EDIT, &LauncherWindow::onShaderPatcherComplexMaterialDynCubemapBlocklistChange, this); ShaderPatcherComplexMaterialDynCubemapBlocklist->Bind(wxEVT_LIST_ITEM_ACTIVATED, &LauncherWindow::onListItemActivated, this); ShaderPatcherComplexMaterialOptionsSizer->Add(ShaderPatcherComplexMaterialDynCubemapBlocklist, 0, wxEXPAND | wxALL, diff --git a/ParallaxGen/src/ParallaxGenConfig.cpp b/ParallaxGen/src/ParallaxGenConfig.cpp index c309e28..2a5ddaa 100644 --- a/ParallaxGen/src/ParallaxGenConfig.cpp +++ b/ParallaxGen/src/ParallaxGenConfig.cpp @@ -68,9 +68,8 @@ auto ParallaxGenConfig::getDefaultParams() -> PGParams { OutParams.Output.Dir = ExePath / "ParallaxGen_Output"; // Mesh Rules - static const vector DefaultMeshBlocklist = {L"*\\cameras\\*", L"*\\dyndolod\\*", L"*\\lod\\*", - L"*\\magic\\*", L"*\\markers\\*", L"*\\mps\\*", - L"*\\sky\\*"}; + static const vector DefaultMeshBlocklist = { + L"*\\cameras\\*", L"*\\dyndolod\\*", L"*\\lod\\*", L"*\\magic\\*", L"*\\markers\\*", L"*\\mps\\*", L"*\\sky\\*"}; OutParams.MeshRules.BlockList = DefaultMeshBlocklist; // Texture Rules @@ -230,6 +229,12 @@ auto ParallaxGenConfig::addConfigJSON(const nlohmann::json &J) -> void { if (ParamJ.contains("shaderpatcher") && ParamJ["shaderpatcher"].contains("complexmaterial")) { ParamJ["shaderpatcher"]["complexmaterial"].get_to(Params.ShaderPatcher.ComplexMaterial); } + if (ParamJ.contains("shaderpatcher") && ParamJ["shaderpatcher"].contains("complexmaterialdyncubemapblocklist")) { + for (const auto &Item : ParamJ["shaderpatcher"]["complexmaterialdyncubemapblocklist"]) { + Params.ShaderPatcher.ShaderPatcherComplexMaterial.ListsDyncubemapBlocklist.push_back( + UTF8toUTF16(Item.get())); + } + } if (ParamJ.contains("shaderpatcher") && ParamJ["shaderpatcher"].contains("truepbr")) { ParamJ["shaderpatcher"]["truepbr"].get_to(Params.ShaderPatcher.TruePBR); } @@ -384,8 +389,7 @@ auto ParallaxGenConfig::validateParams(const PGParams &Params, vector &E } // Check if the MO2 profile exists - const auto Profiles = - ModManagerDirectory::getMO2ProfilesFromInstanceDir(Params.ModManager.MO2InstanceDir); + const auto Profiles = ModManagerDirectory::getMO2ProfilesFromInstanceDir(Params.ModManager.MO2InstanceDir); if (find(Profiles.begin(), Profiles.end(), Params.ModManager.MO2Profile) == Profiles.end()) { Errors.emplace_back("MO2 Profile does not exist"); } @@ -513,6 +517,8 @@ void ParallaxGenConfig::saveUserConfig() { // "shaderpatcher" J["params"]["shaderpatcher"]["parallax"] = Params.ShaderPatcher.Parallax; J["params"]["shaderpatcher"]["complexmaterial"] = Params.ShaderPatcher.ComplexMaterial; + J["params"]["shaderpatcher"]["complexmaterialdyncubemapblocklist"] = + utf16VectorToUTF8(Params.ShaderPatcher.ShaderPatcherComplexMaterial.ListsDyncubemapBlocklist); J["params"]["shaderpatcher"]["truepbr"] = Params.ShaderPatcher.TruePBR; // "shadertransforms" From ad21342d023c34709f1db7f7d9339589c13c5330 Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 21:16:05 -0500 Subject: [PATCH 4/7] fixed PGWarnings not being thread-safe --- ParallaxGenLib/src/ParallaxGenWarnings.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ParallaxGenLib/src/ParallaxGenWarnings.cpp b/ParallaxGenLib/src/ParallaxGenWarnings.cpp index f21b7d7..72801e2 100644 --- a/ParallaxGenLib/src/ParallaxGenWarnings.cpp +++ b/ParallaxGenLib/src/ParallaxGenWarnings.cpp @@ -1,5 +1,6 @@ #include "ParallaxGenWarnings.hpp" +#include #include using namespace std; @@ -46,8 +47,15 @@ void ParallaxGenWarnings::mismatchWarn(const wstring &MatchedPath, const wstring return; } - MismatchWarnDebugTracker[MatchedPathMod].insert(std::make_pair(MatchedPath,BaseTex)); - MismatchWarnTracker[MatchedPathMod].insert(BaseTexMod); + { + const lock_guard Lock(MismatchWarnDebugTrackerMutex); + MismatchWarnDebugTracker[MatchedPathMod].insert(std::make_pair(MatchedPath,BaseTex)); + } + + { + const lock_guard Lock2(MismatchWarnTrackerMutex); + MismatchWarnTracker[MatchedPathMod].insert(BaseTexMod); + } } void ParallaxGenWarnings::printWarnings() { @@ -132,9 +140,4 @@ void ParallaxGenWarnings::meshWarn(const wstring &MatchedPath, const wstring &NI // add to tracker if not MeshWarnTracker.insert(Key); } - - // log warning - //spdlog::warn( - // L"[Potential Mesh Mismatch] Mod \"{}\" assets were used on meshes from mod \"{}\". Please verify that this is intended.", - // MatchedPathMod, NIFPathMod); } From f67056acc5a5c7aeeffe49a930fba9304cb6e134 Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 21:17:05 -0500 Subject: [PATCH 5/7] bump test version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4de6bf..70891b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ project(${PROJECT_NAME} VERSION ${PARALLAXGEN_VERSION}) add_compile_definitions(PARALLAXGEN_VERSION="${PARALLAXGEN_VERSION}") # Set test version (set this to 0 for prod releases) -add_compile_definitions(PARALLAXGEN_TEST_VERSION=1) +add_compile_definitions(PARALLAXGEN_TEST_VERSION=2) # Setup Folders set(EXTRN_BUILD_DIR ${CMAKE_BINARY_DIR}/external/blds) From cc2d0f3e534e0f984a5b3ee81ca2b7967edc86bf Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Sun, 8 Dec 2024 21:32:54 -0500 Subject: [PATCH 6/7] added warning for SoS --- CHANGELOG.md | 1 + ParallaxGen/src/main.cpp | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9d3db..91b62f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [0.7.3] - UNRELEASED +- Added a warning for simplicity of snow users if PBR or CM is enabled (SoS is incompatible with these shaders) - Fixed thread gridlock that casued mesh patching to get suck occasionally - Fixed PBR JSON delete: true not working - Fixed uncaught exception if mod folder does not exist in MO2 diff --git a/ParallaxGen/src/main.cpp b/ParallaxGen/src/main.cpp index 1a42755..861eb38 100644 --- a/ParallaxGen/src/main.cpp +++ b/ParallaxGen/src/main.cpp @@ -75,8 +75,7 @@ auto getGameTypeMapStr() -> string { return GameTypeStr; } -auto deployAssets(const filesystem::path &OutputDir, - const filesystem::path &ExePath) -> void { +auto deployAssets(const filesystem::path &OutputDir, const filesystem::path &ExePath) -> void { // Install default cubemap file if needed static const filesystem::path DynCubeMapPath = "textures/cubemaps/dynamic1pxcubemap_black.dds"; @@ -200,6 +199,20 @@ void mainRunner(ParallaxGenCLIArgs &Args, const filesystem::path &ExePath) { exit(1); } + // Check if dyndolod.esp exists + const auto ActivePlugins = BG.getActivePlugins(false, true); + if (find(ActivePlugins.begin(), ActivePlugins.end(), L"dyndolod.esp") != ActivePlugins.end()) { + spdlog::critical("DynDoLOD and TexGen outputs must be disabled prior to running ParallaxGen. It is recommended to " + "generate LODs after running ParallaxGen with the ParallaxGen output enabled."); + exit(1); + } + + if (find(ActivePlugins.begin(), ActivePlugins.end(), L"simplicity of snow.esp") != ActivePlugins.end() && + (Params.ShaderPatcher.TruePBR || Params.ShaderPatcher.ComplexMaterial)) { + spdlog::warn("You have Simplicity of Snow installed. SoS is incompatible with complex material and PBR. Use a " + "single-pass snow mod such as Better Dynamic Snow v3 instead."); + } + // Init PGP library if (Params.Processing.PluginPatching) { spdlog::info("Initializing plugin patcher"); @@ -229,14 +242,6 @@ void mainRunner(ParallaxGenCLIArgs &Args, const filesystem::path &ExePath) { exit(1); } - // Check if dyndolod.esp exists - const auto ActivePlugins = BG.getActivePlugins(false, true); - if (find(ActivePlugins.begin(), ActivePlugins.end(), L"dyndolod.esp") != ActivePlugins.end()) { - spdlog::critical("DynDoLOD and TexGen outputs must be disabled prior to running ParallaxGen. It is recommended to " - "generate LODs after running ParallaxGen with the ParallaxGen output enabled."); - exit(1); - } - // Init file map PGD.populateFileMap(Params.Processing.BSA); From 97cd00891b689e4ce2ca4e190f0dbf7047d691b1 Mon Sep 17 00:00:00 2001 From: Hakan Saplakoglu Date: Mon, 9 Dec 2024 12:19:18 -0500 Subject: [PATCH 7/7] 0.7.3 release --- CHANGELOG.md | 2 +- CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91b62f8..373f3e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [0.7.3] - UNRELEASED +## [0.7.3] - 2024-12-09 - Added a warning for simplicity of snow users if PBR or CM is enabled (SoS is incompatible with these shaders) - Fixed thread gridlock that casued mesh patching to get suck occasionally diff --git a/CMakeLists.txt b/CMakeLists.txt index 70891b5..378c5e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ project(${PROJECT_NAME} VERSION ${PARALLAXGEN_VERSION}) add_compile_definitions(PARALLAXGEN_VERSION="${PARALLAXGEN_VERSION}") # Set test version (set this to 0 for prod releases) -add_compile_definitions(PARALLAXGEN_TEST_VERSION=2) +add_compile_definitions(PARALLAXGEN_TEST_VERSION=0) # Setup Folders set(EXTRN_BUILD_DIR ${CMAKE_BINARY_DIR}/external/blds)