diff --git a/src/Feature.cpp b/src/Feature.cpp index 42ff7df094..5f9b5dc8e2 100644 --- a/src/Feature.cpp +++ b/src/Feature.cpp @@ -128,7 +128,12 @@ void Feature::Load(json& o_json) auto iter = FeatureVersions::FEATURE_MINIMAL_VERSIONS.find(shortName); if (iter != FeatureVersions::FEATURE_MINIMAL_VERSIONS.end()) { std::string minimalVersionString = iter->second.string(); - minimumVersion = minimalVersionString.substr(0, minimalVersionString.size() - 2); + // Only remove trailing ".0" if it exists, don't truncate non-zero patch versions + if (minimalVersionString.ends_with(".0")) { + minimumVersion = minimalVersionString.substr(0, minimalVersionString.size() - 2); + } else { + minimumVersion = minimalVersionString; + } } } @@ -210,14 +215,34 @@ const std::vector& Feature::GetFeatureList() globals::features::ibl }; - static std::vector featuresVR = [] { - auto v = features; - v.push_back(globals::features::vr); - std::erase_if(v, [](Feature* a) { return !a->SupportsVR(); }); - return v; - }(); + if (REL::Module::IsVR()) { + // Helper function to build VR feature list + static auto BuildVRList = []() -> std::vector { + auto v = features; + v.push_back(globals::features::vr); + + // In developer mode, keep all features for testing + // In production mode, filter to VR-compatible only + if (!globals::state->IsDeveloperMode()) { + std::erase_if(v, [](Feature* a) { return !a->SupportsVR(); }); + } + return v; + }; + + // Cache the VR feature list but invalidate when developer mode changes + static std::vector featuresVR; + static bool cachedDevMode = false; - return (REL::Module::IsVR() && !globals::state->IsDeveloperMode()) ? featuresVR : features; + bool currentDevMode = globals::state->IsDeveloperMode(); + if (featuresVR.empty() || currentDevMode != cachedDevMode) { + featuresVR = BuildVRList(); + cachedDevMode = currentDevMode; + } + + return featuresVR; + } else { + return features; + } } bool Feature::ToggleAtBootSetting() diff --git a/src/FeatureIssues.cpp b/src/FeatureIssues.cpp index f3d17f978a..efd8fd0893 100644 --- a/src/FeatureIssues.cpp +++ b/src/FeatureIssues.cpp @@ -816,8 +816,7 @@ namespace FeatureIssues bool TestIniInfo::wasManuallyDeleted() const { - // If marker exists but test INI doesn't, it was manually deleted - return std::filesystem::exists(testMarkerPath) && !std::filesystem::exists(testIniPath); + return !std::filesystem::exists(testIniPath); } bool LoadPersistentTestState() @@ -841,7 +840,6 @@ namespace FeatureIssues for (const auto& testData : stateData["testInis"]) { TestIniInfo testInfo; testInfo.testIniPath = testData["testIniPath"].get(); - testInfo.testMarkerPath = testData["testMarkerPath"].get(); testInfo.isNewFile = testData["isNewFile"].get(); testInfo.testType = testData["testType"].get(); testInfo.featureName = testData["featureName"].get(); @@ -869,7 +867,6 @@ namespace FeatureIssues for (const auto& testInfo : s_activeTestInis) { nlohmann::json testData; testData["testIniPath"] = testInfo.testIniPath; - testData["testMarkerPath"] = testInfo.testMarkerPath; testData["isNewFile"] = testInfo.isNewFile; testData["testType"] = testInfo.testType; testData["featureName"] = testInfo.featureName; @@ -1085,16 +1082,8 @@ namespace FeatureIssues if (outFile.fail()) { throw std::runtime_error("Failed to write file contents"); } - - // Create marker file to track this test INI - const std::filesystem::path testMarkerPath = featuresPath / (testCase.selectedFeature + ".test"); - std::ofstream markerFile(testMarkerPath); - markerFile << "# Test marker created by CS Developer Mode\n"; - markerFile.close(); - TestIniInfo testInfo; testInfo.testIniPath = iniPath.string(); - testInfo.testMarkerPath = testMarkerPath.string(); testInfo.isNewFile = true; testInfo.testType = "obsolete"; testInfo.featureName = testCase.selectedFeature; @@ -1131,16 +1120,8 @@ namespace FeatureIssues if (outFile.fail()) { throw std::runtime_error("Failed to write file contents"); } - - // Create marker file - const std::filesystem::path testMarkerPath = featuresPath / (unknownFeature + ".test"); - std::ofstream markerFile(testMarkerPath); - markerFile << "# Test marker created by CS Developer Mode\n"; - markerFile.close(); - TestIniInfo testInfo; testInfo.testIniPath = unknownIniPath.string(); - testInfo.testMarkerPath = testMarkerPath.string(); testInfo.isNewFile = true; testInfo.testType = "unknown"; testInfo.featureName = unknownFeature; @@ -1168,12 +1149,6 @@ namespace FeatureIssues // Analyze ALL features (loaded and unloaded) to find safe version mismatch candidates for (const auto& [featureName, feature] : loadedFeatureMap) { const std::filesystem::path iniPath = featuresPath / (featureName + ".ini"); - const std::filesystem::path testStatePath = featuresPath / (featureName + ".test"); - - // Skip if we already have a test state for this feature - if (std::filesystem::exists(testStatePath)) { - continue; - } std::string modLink = GetFeatureModLink(featureName); bool hasModLink = !modLink.empty(); @@ -1290,7 +1265,6 @@ namespace FeatureIssues TestIniInfo testInfo; testInfo.testIniPath = iniPath.string(); - testInfo.testMarkerPath = ""; // No marker needed for modified files testInfo.isNewFile = false; testInfo.testType = "version mismatch"; testInfo.featureName = testFeatureName; @@ -1320,16 +1294,8 @@ namespace FeatureIssues if (outFile.fail()) { throw std::runtime_error("Failed to write file contents"); } - - // Create marker file to track this test INI - const std::filesystem::path testMarkerPath = featuresPath / (testFeatureName + ".test"); - std::ofstream markerFile(testMarkerPath); - markerFile << "# Test marker created by CS Developer Mode\n"; - markerFile.close(); - TestIniInfo testInfo; testInfo.testIniPath = iniPath.string(); - testInfo.testMarkerPath = testMarkerPath.string(); testInfo.isNewFile = true; testInfo.testType = "version mismatch"; testInfo.featureName = testFeatureName; @@ -1397,11 +1363,6 @@ namespace FeatureIssues std::filesystem::remove(testInfo.testIniPath); logger::debug("Removed test INI: {}", testInfo.testIniPath); } - // Remove marker file - if (std::filesystem::exists(testInfo.testMarkerPath)) { - std::filesystem::remove(testInfo.testMarkerPath); - logger::debug("Removed test marker: {}", testInfo.testMarkerPath); - } } else { // Restore original version using INI functions CSimpleIniA ini; diff --git a/src/FeatureIssues.h b/src/FeatureIssues.h index 81d91649c1..d34ca735b4 100644 --- a/src/FeatureIssues.h +++ b/src/FeatureIssues.h @@ -187,7 +187,6 @@ namespace FeatureIssues struct TestIniInfo { std::string testIniPath; // Path to the test INI file created - std::string testMarkerPath; // Path to .test marker file for tracking (new files only) bool isNewFile{ true }; // Whether this is a completely new file or modified existing std::string testType; // Description of test type (obsolete, unknown, version mismatch) std::string featureName; // Name of the feature being tested