- 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
This commit is contained in:
pointfeev 2022-08-26 17:40:51 -04:00
parent ad88fd8b49
commit 2406a5048c
9 changed files with 76 additions and 44 deletions

View file

@ -5,7 +5,7 @@
<UseWindowsForms>True</UseWindowsForms> <UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon> <ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract> <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>4.0.1.0</Version> <Version>4.0.2.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon> <PackageIcon>Resources\ini.ico</PackageIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile> <PackageLicenseFile>LICENSE</PackageLicenseFile>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright> <Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>

View file

@ -27,6 +27,9 @@ internal static class EpicLibrary
} }
} }
internal static async Task<List<string>> GetExecutableDirectories(string gameDirectory) =>
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
internal static async Task<List<Manifest>> GetGames() => await Task.Run(() => internal static async Task<List<Manifest>> GetGames() => await Task.Run(() =>
{ {
List<Manifest> games = new(); List<Manifest> games = new();

View file

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -63,6 +64,21 @@ internal partial class InstallForm : CustomForm
UpdateUser($"Repairing Paradox Launcher . . . ", InstallationLog.Operation); UpdateUser($"Repairing Paradox Launcher . . . ", InstallationLog.Operation);
_ = await Repair(this, selection); _ = await Repair(this, selection);
} }
IEnumerable<string> 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<string> 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) if (Uninstalling || !selection.Koaloader)
{ {
foreach (string directory in selection.ExecutableDirectories) foreach (string directory in selection.ExecutableDirectories)
@ -81,12 +97,14 @@ internal partial class InstallForm : CustomForm
int count = selection.DllDirectories.Count, cur = 0; int count = selection.DllDirectories.Count, cur = 0;
foreach (string directory in selection.DllDirectories) 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) if (selection.Platform is Platform.Steam or Platform.Paradox
|| selection.Platform is Platform.Paradox || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.Steam or DlcType.SteamHidden))) && (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); 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)) 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" + UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); $" {(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); 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) if (selection.Platform is Platform.Epic or Platform.Paradox
|| selection.Platform is Platform.Paradox || selection.ExtraSelectedDlc.Any(item => item.dlc.Any(dlc => dlc.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement))) && (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); 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)) 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" + UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); $" {(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); 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)) 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" + UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); $" {(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); 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)) 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" + UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); $" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);

View file

@ -123,9 +123,7 @@ internal partial class SelectForm : CustomForm
selection.Id = "PL"; selection.Id = "PL";
selection.Name = "Paradox Launcher"; selection.Name = "Paradox Launcher";
selection.RootDirectory = ParadoxLauncher.InstallPath; selection.RootDirectory = ParadoxLauncher.InstallPath;
selection.ExecutableDirectories = (await selection.RootDirectory selection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
.GetExecutables(d => !Path.GetFileName(d).Contains("bootstrapper")))
.Select(e => e = Path.GetDirectoryName(e)).Distinct().ToList();
selection.DllDirectories = dllDirectories; selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Paradox; selection.Platform = Platform.Paradox;
@ -240,16 +238,7 @@ internal partial class SelectForm : CustomForm
selection.Id = appId; selection.Id = appId;
selection.Name = appData?.name ?? name; selection.Name = appData?.name ?? name;
selection.RootDirectory = gameDirectory; selection.RootDirectory = gameDirectory;
selection.ExecutableDirectories = new(); selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
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.DllDirectories = dllDirectories; selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Steam; selection.Platform = Platform.Steam;
selection.ProductUrl = "https://store.steampowered.com/app/" + appId; selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
@ -348,11 +337,7 @@ internal partial class SelectForm : CustomForm
selection.Id = @namespace; selection.Id = @namespace;
selection.Name = name; selection.Name = name;
selection.RootDirectory = directory; selection.RootDirectory = directory;
selection.ExecutableDirectories = new(); selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
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.DllDirectories = dllDirectories; selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Epic; selection.Platform = Platform.Epic;
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements.Where(p => p.Value.name == selection.Name)) foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements.Where(p => p.Value.name == selection.Name))
@ -437,13 +422,7 @@ internal partial class SelectForm : CustomForm
selection.Id = gameId; selection.Id = gameId;
selection.Name = name; selection.Name = name;
selection.RootDirectory = gameDirectory; selection.RootDirectory = gameDirectory;
// need a solid method for obtaining ubisoft game executables (below is likely temporary) selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
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.DllDirectories = dllDirectories; selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Ubisoft; selection.Platform = Platform.Ubisoft;
selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com"); selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");

View file

@ -3,6 +3,7 @@ using CreamInstaller.Utility;
using Microsoft.Win32; using Microsoft.Win32;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -26,6 +27,9 @@ internal static class ParadoxLauncher
} }
} }
internal static async Task<List<string>> GetExecutableDirectories(string gameDirectory) =>
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: d => !Path.GetFileName(d).Contains("bootstrapper")));
private static void PopulateDlc(ProgramSelection paradoxLauncher = null) private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
{ {
paradoxLauncher ??= ProgramSelection.FromPlatformId(Platform.Paradox, "PL"); paradoxLauncher ??= ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
@ -126,7 +130,7 @@ internal static class ParadoxLauncher
installForm.UpdateUser("Corrected Steamworks: " + api64, InstallationLog.Action); installForm.UpdateUser("Corrected Steamworks: " + api64, InstallationLog.Action);
neededRepair = true; neededRepair = true;
} }
if (smokeConfig) if (!selection.Koaloader && smokeConfig)
await SmokeAPI.Install(directory, selection, generateConfig: false); await SmokeAPI.Install(directory, selection, generateConfig: false);
directory.GetScreamApiComponents(out api32, out _, out api64, out _, out _); 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); installForm.UpdateUser("Corrected Epic Online Services: " + api64, InstallationLog.Action);
neededRepair = true; neededRepair = true;
} }
if (screamConfig) if (!selection.Koaloader && screamConfig)
await ScreamAPI.Install(directory, selection, generateConfig: false); await ScreamAPI.Install(directory, selection, generateConfig: false);
} }
if (neededRepair) if (neededRepair)

View file

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"CreamInstaller": { "CreamInstaller": {
"commandName": "Project", "commandName": "Project",
"hotReloadEnabled": true, "hotReloadEnabled": false,
"nativeDebugging": false "nativeDebugging": false
} }
} }

View file

@ -1,9 +1,12 @@
using System; using CreamInstaller.Utility;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace CreamInstaller.Resources; namespace CreamInstaller.Resources;
@ -56,20 +59,32 @@ internal static class Resources
return false; return false;
} }
internal static async Task<List<string>> GetExecutables(this string rootDirectory, Func<string, bool> 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<List<string>> GetExecutables(this string rootDirectory, string subDirectory = null, bool filterCommon = false, Func<string, bool> validFunc = null) => await Task.Run(async () =>
{ {
List<string> executables = new(); List<string> executables = new();
if (Program.Canceled || !Directory.Exists(rootDirectory)) return null; if (Program.Canceled || !Directory.Exists(subDirectory ?? rootDirectory)) return null;
foreach (string path in Directory.GetFiles(rootDirectory, "*.exe")) Thread.Sleep(0);
if (validFunc is null || validFunc(path)) 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); executables.Add(path);
string[] directories = Directory.GetDirectories(rootDirectory); }
string[] directories = Directory.GetDirectories(subDirectory ?? rootDirectory);
foreach (string directory in directories) foreach (string directory in directories)
{ {
if (Program.Canceled) return null; if (Program.Canceled) return null;
Thread.Sleep(0);
try try
{ {
List<string> moreExecutables = await directory.GetExecutables(validFunc); List<string> moreExecutables = await rootDirectory.GetExecutables(directory, filterCommon, validFunc);
if (moreExecutables is not null) if (moreExecutables is not null)
executables.AddRange(moreExecutables); executables.AddRange(moreExecutables);
} }
@ -78,6 +93,9 @@ internal static class Resources
return !executables.Any() ? null : executables; return !executables.Any() ? null : executables;
}); });
internal static async Task<List<string>> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false, Func<string, bool> 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( internal static void GetCreamApiComponents(
this string directory, this string directory,
out string api32, out string api32_o, out string api32, out string api32_o,

View file

@ -26,6 +26,9 @@ internal static class SteamLibrary
} }
} }
internal static async Task<List<string>> GetExecutableDirectories(string gameDirectory) =>
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames() => await Task.Run(async () => internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames() => await Task.Run(async () =>
{ {
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new(); List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();

View file

@ -23,6 +23,9 @@ internal static class UbisoftLibrary
} }
} }
internal static async Task<List<string>> GetExecutableDirectories(string gameDirectory) =>
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames() => await Task.Run(() => internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames() => await Task.Run(() =>
{ {
List<(string gameId, string name, string gameDirectory)> games = new(); List<(string gameId, string name, string gameDirectory)> games = new();