- 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>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>4.0.1.0</Version>
<Version>4.0.2.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<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(() =>
{
List<Manifest> games = new();

View file

@ -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<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)
{
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);

View file

@ -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<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.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");

View file

@ -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<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)
{
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)

View file

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

View file

@ -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<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();
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<string> moreExecutables = await directory.GetExecutables(validFunc);
List<string> 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<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(
this string directory,
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 () =>
{
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(() =>
{
List<(string gameId, string name, string gameDirectory)> games = new();