From 2406a5048cc290968eae97c690a91b249d1e9607 Mon Sep 17 00:00:00 2001 From: pointfeev Date: Fri, 26 Aug 2022 17:40:51 -0400 Subject: [PATCH] v4.0.2.0 - Koaloader installations are now automatically uninstalled from the incorrect directories - Koaloader executable directories are now found more broadly, with common incorrect paths being omitted (ones that contain setups, redistributables or crash reporters) - Fixed Paradox Launcher Repair reinstalling in proxy mode if a config file was found --- CreamInstaller/CreamInstaller.csproj | 2 +- CreamInstaller/Epic/EpicLibrary.cs | 3 ++ CreamInstaller/Forms/InstallForm.cs | 38 +++++++++++++++---- CreamInstaller/Forms/SelectForm.cs | 29 ++------------ CreamInstaller/Paradox/ParadoxLauncher.cs | 8 +++- CreamInstaller/Properties/launchSettings.json | 2 +- CreamInstaller/Resources/Resources.cs | 32 ++++++++++++---- CreamInstaller/Steam/SteamLibrary.cs | 3 ++ CreamInstaller/Ubisoft/UbisoftLibrary.cs | 3 ++ 9 files changed, 76 insertions(+), 44 deletions(-) diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index cc79ce6..17a5239 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -5,7 +5,7 @@ True Resources\ini.ico true - 4.0.1.0 + 4.0.2.0 Resources\ini.ico LICENSE 2021, pointfeev (https://github.com/pointfeev) diff --git a/CreamInstaller/Epic/EpicLibrary.cs b/CreamInstaller/Epic/EpicLibrary.cs index 32393a2..1415c0b 100644 --- a/CreamInstaller/Epic/EpicLibrary.cs +++ b/CreamInstaller/Epic/EpicLibrary.cs @@ -27,6 +27,9 @@ internal static class EpicLibrary } } + internal static async Task> GetExecutableDirectories(string gameDirectory) => + await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); + internal static async Task> GetGames() => await Task.Run(() => { List games = new(); diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index b9ce438..b5355b5 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; @@ -63,6 +64,21 @@ internal partial class InstallForm : CustomForm UpdateUser($"Repairing Paradox Launcher . . . ", InstallationLog.Operation); _ = await Repair(this, selection); } + IEnumerable invalidDirectories = (await selection.RootDirectory.GetExecutables()).Where(d => !selection.ExecutableDirectories.Contains(d)); + if (!selection.ExecutableDirectories.Contains(selection.RootDirectory)) invalidDirectories = invalidDirectories.Append(selection.RootDirectory); + invalidDirectories = invalidDirectories.Distinct(); + foreach (string directory in invalidDirectories) + { + directory.GetKoaloaderComponents(out List proxies, out string config); + if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(Resources.Resources.ResourceIdentifier.Koaloader)) + || Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll)) + || File.Exists(config)) + { + UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in incorrect directory \"{directory}\" . . . ", InstallationLog.Operation); + await Koaloader.Uninstall(directory, this); + } + Thread.Sleep(0); + } if (Uninstalling || !selection.Koaloader) { foreach (string directory in selection.ExecutableDirectories) @@ -81,12 +97,14 @@ internal partial class InstallForm : CustomForm int count = selection.DllDirectories.Count, cur = 0; foreach (string directory in selection.DllDirectories) { - if (selection.Platform is Platform.Steam || selection.SelectedDlc.Any(d => d.Value.type is DlcType.Steam or DlcType.SteamHidden) - || selection.Platform is Platform.Paradox || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.Steam or DlcType.SteamHidden))) + if (selection.Platform is Platform.Steam or Platform.Paradox + && (selection.SelectedDlc.Any(d => d.Value.type is DlcType.Steam or DlcType.SteamHidden) + || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.Steam or DlcType.SteamHidden)))) { directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string cache); if (!uninstallProxy && (File.Exists(api32) || File.Exists(api64)) - || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache))) + || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) + || !selection.Koaloader && (File.Exists(config) || File.Exists(cache)))) { UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); @@ -96,12 +114,14 @@ internal partial class InstallForm : CustomForm await SmokeAPI.Install(directory, selection, this); } } - if (selection.Platform is Platform.Epic || selection.SelectedDlc.Any(d => d.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement) - || selection.Platform is Platform.Paradox || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement))) + if (selection.Platform is Platform.Epic or Platform.Paradox + && (selection.SelectedDlc.Any(d => d.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement) + || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement)))) { directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config); if (!uninstallProxy && (File.Exists(api32) || File.Exists(api64)) - || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config))) + || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) + || !selection.Koaloader && File.Exists(config))) { UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); @@ -115,7 +135,8 @@ internal partial class InstallForm : CustomForm { directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config); if (!uninstallProxy && (File.Exists(api32) || File.Exists(api64)) - || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config))) + || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) + || !selection.Koaloader && File.Exists(config))) { UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); @@ -126,7 +147,8 @@ internal partial class InstallForm : CustomForm } directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config); if (!uninstallProxy && (File.Exists(old_api32) || File.Exists(old_api64) || File.Exists(api32) || File.Exists(api64)) - || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config))) + || uninstallProxy && (File.Exists(api32_o) || File.Exists(api64_o) + || !selection.Koaloader && File.Exists(config))) { UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index 50e6282..e88cc5d 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -123,9 +123,7 @@ internal partial class SelectForm : CustomForm selection.Id = "PL"; selection.Name = "Paradox Launcher"; selection.RootDirectory = ParadoxLauncher.InstallPath; - selection.ExecutableDirectories = (await selection.RootDirectory - .GetExecutables(d => !Path.GetFileName(d).Contains("bootstrapper"))) - .Select(e => e = Path.GetDirectoryName(e)).Distinct().ToList(); + selection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory); selection.DllDirectories = dllDirectories; selection.Platform = Platform.Paradox; @@ -240,16 +238,7 @@ internal partial class SelectForm : CustomForm selection.Id = appId; selection.Name = appData?.name ?? name; selection.RootDirectory = gameDirectory; - selection.ExecutableDirectories = new(); - VToken launch = appInfo?.Value?.GetChild("config")?.GetChild("launch"); - if (launch is not null) - foreach (VToken token in launch.Children()) - if (token?.GetChild("executable")?.ToString() is string executable - && (selection.RootDirectory + @"\" + Path.GetDirectoryName(executable)).BeautifyPath() is string path - && !selection.ExecutableDirectories.Contains(path)) - selection.ExecutableDirectories.Add(path); - if (!selection.ExecutableDirectories.Any()) - selection.ExecutableDirectories.Add(selection.RootDirectory); + selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory); selection.DllDirectories = dllDirectories; selection.Platform = Platform.Steam; selection.ProductUrl = "https://store.steampowered.com/app/" + appId; @@ -348,11 +337,7 @@ internal partial class SelectForm : CustomForm selection.Id = @namespace; selection.Name = name; selection.RootDirectory = directory; - selection.ExecutableDirectories = new(); - if (manifest.LaunchExecutable is string executable && (selection.RootDirectory + @"\" + Path.GetDirectoryName(executable)).BeautifyPath() is string path) - selection.ExecutableDirectories.Add(path); - else - selection.ExecutableDirectories.Add(selection.RootDirectory); + selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory); selection.DllDirectories = dllDirectories; selection.Platform = Platform.Epic; foreach (KeyValuePair pair in entitlements.Where(p => p.Value.name == selection.Name)) @@ -437,13 +422,7 @@ internal partial class SelectForm : CustomForm selection.Id = gameId; selection.Name = name; selection.RootDirectory = gameDirectory; - // need a solid method for obtaining ubisoft game executables (below is likely temporary) - selection.ExecutableDirectories = (await selection.RootDirectory - .GetExecutables(d => - { - string subPath = d[selection.RootDirectory.Length..].ToUpperInvariant(); - return !subPath.Contains("SETUP") && !subPath.Contains("REDIST"); - })).Select(e => e = Path.GetDirectoryName(e)).Distinct().ToList(); + selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory); selection.DllDirectories = dllDirectories; selection.Platform = Platform.Ubisoft; selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com"); diff --git a/CreamInstaller/Paradox/ParadoxLauncher.cs b/CreamInstaller/Paradox/ParadoxLauncher.cs index 8bb6797..a2f64a6 100644 --- a/CreamInstaller/Paradox/ParadoxLauncher.cs +++ b/CreamInstaller/Paradox/ParadoxLauncher.cs @@ -3,6 +3,7 @@ using CreamInstaller.Utility; using Microsoft.Win32; +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; @@ -26,6 +27,9 @@ internal static class ParadoxLauncher } } + internal static async Task> GetExecutableDirectories(string gameDirectory) => + await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: d => !Path.GetFileName(d).Contains("bootstrapper"))); + private static void PopulateDlc(ProgramSelection paradoxLauncher = null) { paradoxLauncher ??= ProgramSelection.FromPlatformId(Platform.Paradox, "PL"); @@ -126,7 +130,7 @@ internal static class ParadoxLauncher installForm.UpdateUser("Corrected Steamworks: " + api64, InstallationLog.Action); neededRepair = true; } - if (smokeConfig) + if (!selection.Koaloader && smokeConfig) await SmokeAPI.Install(directory, selection, generateConfig: false); directory.GetScreamApiComponents(out api32, out _, out api64, out _, out _); @@ -144,7 +148,7 @@ internal static class ParadoxLauncher installForm.UpdateUser("Corrected Epic Online Services: " + api64, InstallationLog.Action); neededRepair = true; } - if (screamConfig) + if (!selection.Koaloader && screamConfig) await ScreamAPI.Install(directory, selection, generateConfig: false); } if (neededRepair) diff --git a/CreamInstaller/Properties/launchSettings.json b/CreamInstaller/Properties/launchSettings.json index 18d0154..ecbd0d2 100644 --- a/CreamInstaller/Properties/launchSettings.json +++ b/CreamInstaller/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CreamInstaller": { "commandName": "Project", - "hotReloadEnabled": true, + "hotReloadEnabled": false, "nativeDebugging": false } } diff --git a/CreamInstaller/Resources/Resources.cs b/CreamInstaller/Resources/Resources.cs index c030019..2ea11ab 100644 --- a/CreamInstaller/Resources/Resources.cs +++ b/CreamInstaller/Resources/Resources.cs @@ -1,9 +1,12 @@ -using System; +using CreamInstaller.Utility; + +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Security.Cryptography; +using System.Threading; using System.Threading.Tasks; namespace CreamInstaller.Resources; @@ -56,20 +59,32 @@ internal static class Resources return false; } - internal static async Task> GetExecutables(this string rootDirectory, Func validFunc = null) => await Task.Run(async () => + internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path) + { + string subPath = path[rootDirectory.Length..].ToUpperInvariant().BeautifyPath(); + return subPath.Contains("SETUP") || subPath.Contains("REDIST") + || subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT")); + } + + internal static async Task> GetExecutables(this string rootDirectory, string subDirectory = null, bool filterCommon = false, Func validFunc = null) => await Task.Run(async () => { List executables = new(); - if (Program.Canceled || !Directory.Exists(rootDirectory)) return null; - foreach (string path in Directory.GetFiles(rootDirectory, "*.exe")) - if (validFunc is null || validFunc(path)) + if (Program.Canceled || !Directory.Exists(subDirectory ?? rootDirectory)) return null; + Thread.Sleep(0); + foreach (string path in Directory.GetFiles(subDirectory ?? rootDirectory, "*.exe")) + { + Thread.Sleep(0); + if ((!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) && (validFunc is null || validFunc(path))) executables.Add(path); - string[] directories = Directory.GetDirectories(rootDirectory); + } + string[] directories = Directory.GetDirectories(subDirectory ?? rootDirectory); foreach (string directory in directories) { if (Program.Canceled) return null; + Thread.Sleep(0); try { - List moreExecutables = await directory.GetExecutables(validFunc); + List moreExecutables = await rootDirectory.GetExecutables(directory, filterCommon, validFunc); if (moreExecutables is not null) executables.AddRange(moreExecutables); } @@ -78,6 +93,9 @@ internal static class Resources return !executables.Any() ? null : executables; }); + internal static async Task> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false, Func validFunc = null) => await Task.Run(async () => + (await rootDirectory.GetExecutables(filterCommon: filterCommon, validFunc: validFunc) ?? await rootDirectory.GetExecutables()).Select(e => e = Path.GetDirectoryName(e)).Distinct().ToList()); + internal static void GetCreamApiComponents( this string directory, out string api32, out string api32_o, diff --git a/CreamInstaller/Steam/SteamLibrary.cs b/CreamInstaller/Steam/SteamLibrary.cs index f635459..8bedd00 100644 --- a/CreamInstaller/Steam/SteamLibrary.cs +++ b/CreamInstaller/Steam/SteamLibrary.cs @@ -26,6 +26,9 @@ internal static class SteamLibrary } } + internal static async Task> GetExecutableDirectories(string gameDirectory) => + await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); + internal static async Task> GetGames() => await Task.Run(async () => { List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new(); diff --git a/CreamInstaller/Ubisoft/UbisoftLibrary.cs b/CreamInstaller/Ubisoft/UbisoftLibrary.cs index a07142c..9173a94 100644 --- a/CreamInstaller/Ubisoft/UbisoftLibrary.cs +++ b/CreamInstaller/Ubisoft/UbisoftLibrary.cs @@ -23,6 +23,9 @@ internal static class UbisoftLibrary } } + internal static async Task> GetExecutableDirectories(string gameDirectory) => + await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); + internal static async Task> GetGames() => await Task.Run(() => { List<(string gameId, string name, string gameDirectory)> games = new();