From a6ed117088a3962e61660124dc96582d4970e686 Mon Sep 17 00:00:00 2001 From: GoaLitiuM Date: Wed, 26 May 2021 19:56:39 +0300 Subject: [PATCH] Add support for Rider 2021, use latest detected version of Rider Handles additional registry location where installation paths are stored for Rider 2021. The detected installations are now sorted by version, so the latest detected version is always used when opening the scripts project. --- .../Scripting/CodeEditors/RiderCodeEditor.cpp | 97 +++++++++++++++---- 1 file changed, 77 insertions(+), 20 deletions(-) diff --git a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp index 4299b8865..2c5265a06 100644 --- a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp +++ b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp @@ -10,12 +10,24 @@ #if PLATFORM_WINDOWS +#include "Engine/Core/Collections/Sorting.h" #include "Engine/Platform/File.h" #include "Engine/Platform/Win32/IncludeWindowsHeaders.h" #include "Engine/Serialization/Json.h" namespace { + struct RiderInstallation + { + String path; + String version; + + RiderInstallation(const String& path_, const String& version_) + : path(path_), version(version_) + { + } + }; + bool FindRegistryKeyItems(HKEY hKey, Array& results) { Char nameBuffer[256]; @@ -31,7 +43,7 @@ namespace return true; } - void SearchDirectory(Array* output, const String& directory) + void SearchDirectory(Array* installations, const String& directory) { if (!FileSystem::DirectoryExists(directory)) return; @@ -46,24 +58,29 @@ namespace if (document.HasParseError()) return; + // Find version + auto versionMember = document.FindMember("version"); + if (versionMember == document.MemberEnd()) + return; + // Find executable file path auto launchMember = document.FindMember("launch"); - if (launchMember != document.MemberEnd() && launchMember->value.IsArray() && launchMember->value.Size() > 0) - { - auto launcherPathMember = launchMember->value[0].FindMember("launcherPath"); - if (launcherPathMember != launchMember->value[0].MemberEnd()) - { - auto launcherPath = launcherPathMember->value.GetText(); - auto exePath = directory / launcherPath; - if (launcherPath.HasChars() && FileSystem::FileExists(exePath)) - { - output->Add(New(exePath)); - } - } - } + if (launchMember == document.MemberEnd() || !launchMember->value.IsArray() || launchMember->value.Size() == 0) + return; + + auto launcherPathMember = launchMember->value[0].FindMember("launcherPath"); + if (launcherPathMember == launchMember->value[0].MemberEnd()) + return; + + auto launcherPath = launcherPathMember->value.GetText(); + auto exePath = directory / launcherPath; + if (!launcherPath.HasChars() || !FileSystem::FileExists(exePath)) + return; + + installations->Add(New(exePath, versionMember->value.GetText())); } - void SearchRegistry(Array* output, HKEY root, const Char* key) + void SearchRegistry(Array* installations, HKEY root, const Char* key, const Char* valueName = TEXT("")) { // Open key HKEY keyH; @@ -83,14 +100,14 @@ namespace // Read subkey value DWORD type; DWORD cbData; - if (RegQueryValueExW(subKeyH, TEXT(""), nullptr, &type, nullptr, &cbData) != ERROR_SUCCESS || type != REG_SZ) + if (RegQueryValueExW(subKeyH, valueName, nullptr, &type, nullptr, &cbData) != ERROR_SUCCESS || type != REG_SZ) { RegCloseKey(subKeyH); continue; } Array data; data.Resize((int32)cbData / sizeof(Char)); - if (RegQueryValueExW(subKeyH, TEXT(""), nullptr, nullptr, reinterpret_cast(data.Get()), &cbData) != ERROR_SUCCESS) + if (RegQueryValueExW(subKeyH, valueName, nullptr, nullptr, reinterpret_cast(data.Get()), &cbData) != ERROR_SUCCESS) { RegCloseKey(subKeyH); continue; @@ -98,7 +115,7 @@ namespace // Check if it's a valid installation path String path(data.Get(), data.Count() - 1); - SearchDirectory(output, path); + SearchDirectory(installations, path); RegCloseKey(subKeyH); } @@ -108,6 +125,31 @@ namespace } } +bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i2) +{ + Array values1, values2; + i1->version.Split('.', values1); + i2->version.Split('.', values2); + + int32 version1[3] = { 0 }; + int32 version2[3] = { 0 }; + StringUtils::Parse(values1[0].Get(), &version1[0]); + StringUtils::Parse(values1[1].Get(), &version1[1]); + StringUtils::Parse(values1[2].Get(), &version1[2]); + StringUtils::Parse(values2[0].Get(), &version2[0]); + StringUtils::Parse(values2[1].Get(), &version2[1]); + StringUtils::Parse(values2[2].Get(), &version2[2]); + + // Compare by MAJOR.MINOR.BUILD + if (version1[0] == version2[0]) + { + if (version1[1] == version2[1]) + return version1[2] > version2[2]; + return version1[1] > version2[1]; + } + return version1[0] > version2[0]; +} + #endif RiderCodeEditor::RiderCodeEditor(const String& execPath) @@ -119,8 +161,23 @@ RiderCodeEditor::RiderCodeEditor(const String& execPath) void RiderCodeEditor::FindEditors(Array* output) { #if PLATFORM_WINDOWS - SearchRegistry(output, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider")); - SearchRegistry(output, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider")); + Array installations; + + // For versions 2021 or later + SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\JetBrains\\Rider"), TEXT("InstallDir")); + + // For versions 2020 or earlier + SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider")); + SearchRegistry(&installations, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider")); + + // Sort found installations by version number + Sorting::QuickSort(installations.Get(), installations.Count(), &sortInstallations); + + for (RiderInstallation* installation : installations) + { + output->Add(New(installation->path)); + Delete(installation); + } #endif }