
- Minor refactoring - Fixed an NRE from cancelling file writes - Added more information to IO warnings - Updated the help menu - Added a custom program icon created by [Mattahan](https://www.mattahan.com)
362 lines
No EOL
19 KiB
C#
362 lines
No EOL
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using CreamInstaller.Components;
|
|
using CreamInstaller.Forms;
|
|
using CreamInstaller.Utility;
|
|
using static CreamInstaller.Resources.Resources;
|
|
|
|
namespace CreamInstaller.Resources;
|
|
|
|
internal static class Koaloader
|
|
{
|
|
internal static readonly List<(string unlocker, string dll)> AutoLoadDLLs = new()
|
|
{
|
|
("Koaloader", "Unlocker.dll"), ("Koaloader", "Unlocker32.dll"), ("Koaloader", "Unlocker64.dll"), ("Lyptus", "Lyptus.dll"),
|
|
("Lyptus", "Lyptus32.dll"), ("Lyptus", "Lyptus64.dll"), ("SmokeAPI", "SmokeAPI.dll"), ("SmokeAPI", "SmokeAPI32.dll"),
|
|
("SmokeAPI", "SmokeAPI64.dll"), ("ScreamAPI", "ScreamAPI.dll"), ("ScreamAPI", "ScreamAPI32.dll"), ("ScreamAPI", "ScreamAPI64.dll"),
|
|
("Uplay R1 Unlocker", "UplayR1Unlocker.dll"), ("Uplay R1 Unlocker", "UplayR1Unlocker32.dll"), ("Uplay R1 Unlocker", "UplayR1Unlocker64.dll"),
|
|
("Uplay R2 Unlocker", "UplayR2Unlocker.dll"), ("Uplay R2 Unlocker", "UplayR2Unlocker32.dll"), ("Uplay R2 Unlocker", "UplayR2Unlocker64.dll")
|
|
};
|
|
|
|
internal static IEnumerable<string> GetKoaloaderProxies(this string directory)
|
|
=> from resource in EmbeddedResources
|
|
select resource[(resource.IndexOf('.') + 1)..]
|
|
into resource
|
|
select resource[(resource.IndexOf('.') + 1)..]
|
|
into resource
|
|
select directory + @"\" + resource;
|
|
|
|
internal static void GetKoaloaderComponents(this string directory, out string old_config, out string config)
|
|
{
|
|
old_config = directory + @"\Koaloader.json";
|
|
config = directory + @"\Koaloader.config.json";
|
|
}
|
|
|
|
private static void WriteProxy(this string path, string proxyName, BinaryType binaryType)
|
|
{
|
|
foreach (string resourceIdentifier in EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)))
|
|
{
|
|
resourceIdentifier.GetProxyInfoFromIdentifier(out string _proxyName, out BinaryType _binaryType);
|
|
if (_proxyName != proxyName || _binaryType != binaryType)
|
|
continue;
|
|
resourceIdentifier.WriteManifestResource(path);
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal static void GetProxyInfoFromIdentifier(this string resourceIdentifier, out string proxyName, out BinaryType binaryType)
|
|
{
|
|
string baseIdentifier = resourceIdentifier[(resourceIdentifier.IndexOf('.') + 1)..];
|
|
baseIdentifier = baseIdentifier[..baseIdentifier.IndexOf('.')];
|
|
proxyName = baseIdentifier[..baseIdentifier.LastIndexOf('_')];
|
|
string bitness = baseIdentifier[(baseIdentifier.LastIndexOf('_') + 1)..];
|
|
binaryType = bitness switch { "32" => BinaryType.BIT32, "64" => BinaryType.BIT64, _ => BinaryType.Unknown };
|
|
}
|
|
|
|
private static void CheckConfig(string directory, InstallForm installForm = null)
|
|
{
|
|
directory.GetKoaloaderComponents(out string old_config, out string config);
|
|
if (old_config.FileExists())
|
|
{
|
|
if (!config.FileExists())
|
|
{
|
|
old_config.MoveFile(config!);
|
|
installForm?.UpdateUser($"Converted old configuration: {Path.GetFileName(old_config)} -> {Path.GetFileName(config)}", LogTextBox.Action, false);
|
|
}
|
|
else
|
|
{
|
|
old_config.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted old configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
|
|
}
|
|
}
|
|
SortedList<string, string> targets = new(PlatformIdComparer.String);
|
|
SortedList<string, string> modules = new(PlatformIdComparer.String);
|
|
if (targets.Count > 0 || modules.Count > 0)
|
|
{
|
|
/*if (installForm is not null)
|
|
installForm.UpdateUser("Generating Koaloader configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
|
|
config.CreateFile(true, installForm)?.Close();
|
|
StreamWriter writer = new(config, true, Encoding.UTF8);
|
|
WriteConfig(writer, targets, modules, installForm);
|
|
writer.Flush();
|
|
writer.Close();
|
|
}
|
|
else if (config.FileExists())
|
|
{
|
|
config.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
|
}
|
|
}
|
|
|
|
private static void WriteConfig(TextWriter writer, SortedList<string, string> targets, SortedList<string, string> modules, InstallForm installForm = null)
|
|
{
|
|
writer.WriteLine("{");
|
|
writer.WriteLine(" \"logging\": false,");
|
|
writer.WriteLine(" \"enabled\": true,");
|
|
writer.WriteLine(" \"auto_load\": " + (modules.Count > 0 ? "false" : "true") + ",");
|
|
if (targets.Count > 0)
|
|
{
|
|
writer.WriteLine(" \"targets\": [");
|
|
KeyValuePair<string, string> lastTarget = targets.Last();
|
|
foreach (KeyValuePair<string, string> pair in targets)
|
|
{
|
|
string path = pair.Value;
|
|
writer.WriteLine($" \"{path}\"{(pair.Equals(lastTarget) ? "" : ",")}");
|
|
installForm?.UpdateUser($"Added target to Koaloader.json with path {path}", LogTextBox.Action, false);
|
|
}
|
|
writer.WriteLine(" ]");
|
|
}
|
|
else
|
|
writer.WriteLine(" \"targets\": []");
|
|
if (modules.Count > 0)
|
|
{
|
|
writer.WriteLine(" \"modules\": [");
|
|
KeyValuePair<string, string> lastModule = modules.Last();
|
|
foreach (KeyValuePair<string, string> pair in modules)
|
|
{
|
|
string path = pair.Value;
|
|
writer.WriteLine(" {");
|
|
writer.WriteLine(" \"path\": \"" + path + "\",");
|
|
writer.WriteLine(" \"required\": true");
|
|
writer.WriteLine(" }" + (pair.Equals(lastModule) ? "" : ","));
|
|
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, false);
|
|
}
|
|
writer.WriteLine(" ]");
|
|
}
|
|
else
|
|
writer.WriteLine(" \"modules\": []");
|
|
writer.WriteLine("}");
|
|
}
|
|
|
|
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null, bool deleteConfig = true)
|
|
=> await Task.Run(async () =>
|
|
{
|
|
directory.GetKoaloaderComponents(out string old_config, out string config);
|
|
foreach (string proxyPath in directory.GetKoaloaderProxies().Where(proxyPath
|
|
=> proxyPath.FileExists() && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
|
|
{
|
|
proxyPath.DeleteFile(true);
|
|
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(proxyPath)}", LogTextBox.Action, false);
|
|
}
|
|
foreach ((string unlocker, string path) in AutoLoadDLLs.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
|
.Where(pair => pair.path.FileExists() && pair.path.IsResourceFile()))
|
|
{
|
|
path.DeleteFile(true);
|
|
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
|
}
|
|
if (deleteConfig && old_config.FileExists())
|
|
{
|
|
old_config.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
|
|
}
|
|
if (deleteConfig && config.FileExists())
|
|
{
|
|
config.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
|
}
|
|
await SmokeAPI.Uninstall(directory, installForm, deleteConfig);
|
|
await ScreamAPI.Uninstall(directory, installForm, deleteConfig);
|
|
await UplayR1.Uninstall(directory, installForm, deleteConfig);
|
|
await UplayR2.Uninstall(directory, installForm, deleteConfig);
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
await Uninstall(rootDirectory, null, installForm, deleteConfig);
|
|
});
|
|
|
|
internal static async Task Install(string directory, BinaryType binaryType, Selection selection, string rootDirectory = null,
|
|
InstallForm installForm = null, bool generateConfig = true)
|
|
=> await Task.Run(() =>
|
|
{
|
|
string proxy = selection.KoaloaderProxy ?? Selection.DefaultKoaloaderProxy;
|
|
string path = directory + @"\" + proxy + ".dll";
|
|
foreach (string _path in directory.GetKoaloaderProxies().Where(p => p != path && p.FileExists() && p.IsResourceFile(ResourceIdentifier.Koaloader)))
|
|
{
|
|
_path.DeleteFile(true);
|
|
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", LogTextBox.Action, false);
|
|
}
|
|
if (path.FileExists() && !path.IsResourceFile(ResourceIdentifier.Koaloader))
|
|
throw new CustomMessageException("A non-Koaloader DLL named " + proxy + ".dll already exists in this directory!");
|
|
path.WriteProxy(proxy, binaryType);
|
|
installForm?.UpdateUser($"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}", LogTextBox.Action,
|
|
false);
|
|
bool bit32 = false, bit64 = false;
|
|
foreach (string executable in directory.EnumerateDirectory("*.exe"))
|
|
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
|
|
{
|
|
switch (binaryType)
|
|
{
|
|
case BinaryType.BIT32:
|
|
bit32 = true;
|
|
break;
|
|
case BinaryType.BIT64:
|
|
bit64 = true;
|
|
break;
|
|
}
|
|
if (bit32 && bit64)
|
|
break;
|
|
}
|
|
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
|
{
|
|
if (bit32)
|
|
{
|
|
path = directory + @"\SmokeAPI32.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
|
}
|
|
path = rootDirectory + @"\SmokeAPI32.dll";
|
|
}
|
|
"SmokeAPI.steam_api.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
if (bit64)
|
|
{
|
|
path = directory + @"\SmokeAPI64.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
|
}
|
|
path = rootDirectory + @"\SmokeAPI64.dll";
|
|
}
|
|
"SmokeAPI.steam_api64.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
SmokeAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
|
}
|
|
switch (selection.Platform)
|
|
{
|
|
case Platform.Epic or Platform.Paradox:
|
|
{
|
|
if (bit32)
|
|
{
|
|
path = directory + @"\ScreamAPI32.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
|
}
|
|
path = rootDirectory + @"\ScreamAPI32.dll";
|
|
}
|
|
"ScreamAPI.EOSSDK-Win32-Shipping.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
if (bit64)
|
|
{
|
|
path = directory + @"\ScreamAPI64.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
|
}
|
|
path = rootDirectory + @"\ScreamAPI64.dll";
|
|
}
|
|
"ScreamAPI.EOSSDK-Win64-Shipping.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
ScreamAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
|
break;
|
|
}
|
|
case Platform.Ubisoft:
|
|
{
|
|
if (bit32)
|
|
{
|
|
path = directory + @"\UplayR1Unlocker32.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
|
|
false);
|
|
}
|
|
path = rootDirectory + @"\UplayR1Unlocker32.dll";
|
|
}
|
|
"UplayR1.uplay_r1_loader.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
if (bit64)
|
|
{
|
|
path = directory + @"\UplayR1Unlocker64.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
|
|
false);
|
|
}
|
|
path = rootDirectory + @"\UplayR1Unlocker64.dll";
|
|
}
|
|
"UplayR1.uplay_r1_loader64.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
UplayR1.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
|
if (bit32)
|
|
{
|
|
path = directory + @"\UplayR2Unlocker32.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
|
|
false);
|
|
}
|
|
path = rootDirectory + @"\UplayR2Unlocker32.dll";
|
|
}
|
|
"UplayR2.upc_r2_loader.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
if (bit64)
|
|
{
|
|
path = directory + @"\UplayR2Unlocker64.dll";
|
|
if (rootDirectory is not null && directory != rootDirectory)
|
|
{
|
|
if (path.FileExists())
|
|
{
|
|
path.DeleteFile();
|
|
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
|
|
false);
|
|
}
|
|
path = rootDirectory + @"\UplayR2Unlocker64.dll";
|
|
}
|
|
"UplayR2.upc_r2_loader64.dll".WriteManifestResource(path);
|
|
installForm?.UpdateUser(
|
|
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
|
LogTextBox.Action, false);
|
|
}
|
|
UplayR2.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
|
break;
|
|
}
|
|
}
|
|
if (generateConfig)
|
|
CheckConfig(directory, installForm);
|
|
});
|
|
} |