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();