diff --git a/CreamInstaller/Components/ContextMenuItem.cs b/CreamInstaller/Components/ContextMenuItem.cs
index 5eddf62..9149300 100644
--- a/CreamInstaller/Components/ContextMenuItem.cs
+++ b/CreamInstaller/Components/ContextMenuItem.cs
@@ -53,6 +53,9 @@ internal class ContextMenuItem : ToolStripMenuItem
case "Epic Games":
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("epicgames.com"));
break;
+ case "Ubisoft Store":
+ image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("store.ubi.com"));
+ break;
default:
return;
}
diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj
index 28fbde1..fc61998 100644
--- a/CreamInstaller/CreamInstaller.csproj
+++ b/CreamInstaller/CreamInstaller.csproj
@@ -5,7 +5,7 @@
True
Resources\ini.ico
true
- 3.5.4.2
+ 3.6.0.0
Resources\ini.ico
LICENSE
2021, pointfeev (https://github.com/pointfeev)
@@ -15,7 +15,7 @@
git
CreamInstaller
CreamInstaller
- SmokeAPI/ScreamAPI Installer & Configuration Generator
+ Automatic DLC Unlocker Installer & Configuration Generator
pointfeev
pointfeev.creaminstaller
CreamInstaller.Program
diff --git a/CreamInstaller/Epic/EpicLibrary.cs b/CreamInstaller/Epic/EpicLibrary.cs
index ac0660b..f038e68 100644
--- a/CreamInstaller/Epic/EpicLibrary.cs
+++ b/CreamInstaller/Epic/EpicLibrary.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
-using System.Threading;
using System.Threading.Tasks;
namespace CreamInstaller.Epic;
@@ -36,7 +35,6 @@ internal static class EpicLibrary
foreach (string file in files)
{
if (Program.Canceled) return games;
- Thread.Sleep(0);
string json = File.ReadAllText(file);
try
{
@@ -64,7 +62,6 @@ internal static class EpicLibrary
foreach (string _directory in directories)
{
if (Program.Canceled) return null;
- Thread.Sleep(0);
try
{
List moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs
index 331b944..51e2d97 100644
--- a/CreamInstaller/Forms/InstallForm.cs
+++ b/CreamInstaller/Forms/InstallForm.cs
@@ -7,8 +7,6 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -54,311 +52,9 @@ internal partial class InstallForm : CustomForm
logTextBox.AppendText(text, color);
logTextBox.Refresh();
});
- Thread.Sleep(0);
}
}
- internal static void WriteSmokeConfiguration(StreamWriter writer, SortedList overrideDlc, SortedList injectDlc, InstallForm installForm = null)
- {
- Thread.Sleep(0);
- writer.WriteLine("{");
- writer.WriteLine(" \"$version\": 1,");
- writer.WriteLine(" \"logging\": false,");
- writer.WriteLine(" \"hook_steamclient\": true,");
- writer.WriteLine(" \"unlock_all\": true,");
- if (overrideDlc.Count > 0)
- {
- writer.WriteLine(" \"override\": [");
- KeyValuePair lastOverrideDlc = overrideDlc.Last();
- foreach (KeyValuePair pair in overrideDlc)
- {
- Thread.Sleep(0);
- string dlcId = pair.Key;
- (_, string dlcName, _) = pair.Value;
- writer.WriteLine($" {dlcId}{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
- if (installForm is not null)
- installForm.UpdateUser($"Added override DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
- }
- writer.WriteLine(" ],");
- }
- else
- writer.WriteLine(" \"override\": [],");
- if (injectDlc.Count > 0)
- {
- writer.WriteLine(" \"dlc_ids\": [");
- KeyValuePair lastInjectDlc = injectDlc.Last();
- foreach (KeyValuePair pair in injectDlc)
- {
- Thread.Sleep(0);
- string dlcId = pair.Key;
- (_, string dlcName, _) = pair.Value;
- writer.WriteLine($" {dlcId}{(pair.Equals(lastInjectDlc) ? "" : ",")}");
- if (installForm is not null)
- installForm.UpdateUser($"Added inject DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
- }
- writer.WriteLine(" ],");
- }
- else
- writer.WriteLine(" \"dlc_ids\": [],");
- writer.WriteLine(" \"auto_inject_inventory\": true,");
- writer.WriteLine(" \"inventory_items\": []");
- writer.WriteLine("}");
- }
-
- internal static async Task UninstallSmokeAPI(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
- {
- directory.GetSmokeApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config, out string cache);
- if (File.Exists(sdk32_o))
- {
- if (File.Exists(sdk32))
- {
- File.Delete(sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- File.Move(sdk32_o, sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Restored Steamworks: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64_o))
- {
- if (File.Exists(sdk64))
- {
- File.Delete(sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- File.Move(sdk64_o, sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Restored Steamworks: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- if (deleteConfig && File.Exists(config))
- {
- File.Delete(config);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
- }
- if (deleteConfig && File.Exists(cache))
- {
- File.Delete(cache);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", InstallationLog.Action, info: false);
- }
- });
-
- internal static async Task InstallSmokeAPI(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
- {
- directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
- if (File.Exists(oldConfig))
- {
- File.Delete(oldConfig);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}", InstallationLog.Action, info: false);
- }
- directory.GetSmokeApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config, out _);
- if (File.Exists(sdk32) && !File.Exists(sdk32_o))
- {
- File.Move(sdk32, sdk32_o);
- if (installForm is not null)
- installForm.UpdateUser($"Renamed Steamworks: {Path.GetFileName(sdk32)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk32_o))
- {
- Properties.Resources.Steamworks32.Write(sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64) && !File.Exists(sdk64_o))
- {
- File.Move(sdk64, sdk64_o);
- if (installForm is not null)
- installForm.UpdateUser($"Renamed Steamworks: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64_o))
- {
- Properties.Resources.Steamworks64.Write(sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- if (generateConfig)
- {
- IEnumerable> overrideDlc = selection.AllDlc.Except(selection.SelectedDlc);
- foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
- overrideDlc = overrideDlc.Except(extraDlc);
- IEnumerable> injectDlc = new List>();
- if (selection.AllDlc.Count > 64 || selection.ExtraDlc.Any(e => e.dlc.Count > 64))
- {
- injectDlc = injectDlc.Concat(selection.SelectedDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
- foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
- if (selection.ExtraDlc.Where(e => e.id == id).Single().dlc.Count > 64)
- injectDlc = injectDlc.Concat(extraDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
- }
- if (overrideDlc.Any() || injectDlc.Any())
- {
- if (installForm is not null)
- installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
- File.Create(config).Close();
- StreamWriter writer = new(config, true, Encoding.UTF8);
- WriteSmokeConfiguration(writer,
- new(overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
- new(injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
- installForm);
- writer.Flush();
- writer.Close();
- }
- else if (File.Exists(config))
- {
- File.Delete(config);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
- }
- }
- });
-
- internal static void WriteScreamConfiguration(StreamWriter writer, SortedList overrideCatalogItems, SortedList entitlements, InstallForm installForm = null)
- {
- Thread.Sleep(0);
- writer.WriteLine("{");
- writer.WriteLine(" \"version\": 2,");
- writer.WriteLine(" \"logging\": false,");
- writer.WriteLine(" \"eos_logging\": false,");
- writer.WriteLine(" \"block_metrics\": false,");
- writer.WriteLine(" \"catalog_items\": {");
- writer.WriteLine(" \"unlock_all\": true,");
- if (overrideCatalogItems.Any())
- {
- writer.WriteLine(" \"override\": [");
- KeyValuePair lastOverrideCatalogItem = overrideCatalogItems.Last();
- foreach (KeyValuePair pair in overrideCatalogItems)
- {
- Thread.Sleep(0);
- string id = pair.Key;
- (_, string name, _) = pair.Value;
- writer.WriteLine($" \"{id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
- if (installForm is not null)
- installForm.UpdateUser($"Added override catalog item to ScreamAPI.json with id {id} ({name})", InstallationLog.Action, info: false);
- }
- writer.WriteLine(" ]");
- }
- else
- writer.WriteLine(" \"override\": []");
- writer.WriteLine(" },");
- writer.WriteLine(" \"entitlements\": {");
- writer.WriteLine(" \"unlock_all\": true,");
- writer.WriteLine(" \"auto_inject\": true,");
- if (entitlements.Any())
- {
- writer.WriteLine(" \"inject\": [");
- KeyValuePair lastEntitlement = entitlements.Last();
- foreach (KeyValuePair pair in entitlements)
- {
- Thread.Sleep(0);
- string id = pair.Key;
- (_, string name, _) = pair.Value;
- writer.WriteLine($" \"{id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
- if (installForm is not null)
- installForm.UpdateUser($"Added entitlement to ScreamAPI.json with id {id} ({name})", InstallationLog.Action, info: false);
- }
- writer.WriteLine(" ]");
- }
- else
- writer.WriteLine(" \"inject\": []");
- writer.WriteLine(" }");
- writer.WriteLine("}");
- }
-
- internal static async Task UninstallScreamAPI(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
- {
- directory.GetScreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
- if (File.Exists(sdk32_o))
- {
- if (File.Exists(sdk32))
- {
- File.Delete(sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- File.Move(sdk32_o, sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Restored Epic Online Services: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64_o))
- {
- if (File.Exists(sdk64))
- {
- File.Delete(sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- File.Move(sdk64_o, sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Restored Epic Online Services: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- if (deleteConfig && File.Exists(config))
- {
- File.Delete(config);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
- }
- });
-
- internal static async Task InstallScreamAPI(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
- {
- directory.GetScreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
- if (File.Exists(sdk32) && !File.Exists(sdk32_o))
- {
- File.Move(sdk32, sdk32_o);
- if (installForm is not null)
- installForm.UpdateUser($"Renamed Epic Online Services: {Path.GetFileName(sdk32)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk32_o))
- {
- Properties.Resources.EpicOnlineServices32.Write(sdk32);
- if (installForm is not null)
- installForm.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64) && !File.Exists(sdk64_o))
- {
- File.Move(sdk64, sdk64_o);
- if (installForm is not null)
- installForm.UpdateUser($"Renamed Epic Online Services: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
- }
- if (File.Exists(sdk64_o))
- {
- Properties.Resources.EpicOnlineServices64.Write(sdk64);
- if (installForm is not null)
- installForm.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
- }
- if (generateConfig)
- {
- IEnumerable> overrideCatalogItems = selection.AllDlc.Where(pair => pair.Value.type is DlcType.EpicCatalogItem).Except(selection.SelectedDlc);
- foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
- overrideCatalogItems = overrideCatalogItems.Except(extraDlc);
- IEnumerable> entitlements = selection.SelectedDlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement);
- foreach ((string id, string name, SortedList _dlc) in selection.ExtraSelectedDlc)
- entitlements = entitlements.Concat(_dlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement));
- if (overrideCatalogItems.Any() || entitlements.Any())
- {
- if (installForm is not null)
- installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
- File.Create(config).Close();
- StreamWriter writer = new(config, true, Encoding.UTF8);
- WriteScreamConfiguration(writer,
- new(overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
- new(entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
- installForm);
- writer.Flush();
- writer.Close();
- }
- else if (File.Exists(config))
- {
- File.Delete(config);
- if (installForm is not null)
- installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
- }
- }
- });
-
private async Task OperateFor(ProgramSelection selection)
{
UpdateProgress(0);
@@ -371,7 +67,6 @@ internal partial class InstallForm : CustomForm
}
foreach (string directory in selection.DllDirectories)
{
- Thread.Sleep(0);
if (selection.IsSteam && 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)))
{
@@ -381,9 +76,9 @@ internal partial class InstallForm : CustomForm
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} SmokeAPI" +
$" {(Uninstalling ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
if (Uninstalling)
- await UninstallSmokeAPI(directory, this);
+ await SmokeAPI.Uninstall(directory, this);
else
- await InstallSmokeAPI(directory, selection, this);
+ await SmokeAPI.Install(directory, selection, this);
}
}
if (selection.IsEpic && selection.SelectedDlc.Any(d => d.Value.type is DlcType.EpicCatalogItem or DlcType.EpicEntitlement)
@@ -395,9 +90,32 @@ internal partial class InstallForm : CustomForm
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} ScreamAPI" +
$" {(Uninstalling ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
if (Uninstalling)
- await UninstallScreamAPI(directory, this);
+ await ScreamAPI.Uninstall(directory, this);
else
- await InstallScreamAPI(directory, selection, this);
+ await ScreamAPI.Install(directory, selection, this);
+ }
+ }
+ if (selection.IsUbisoft)
+ {
+ directory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32) || File.Exists(sdk32_o) || File.Exists(sdk64) || File.Exists(sdk64_o) || File.Exists(config))
+ {
+ UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" +
+ $" {(Uninstalling ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ if (Uninstalling)
+ await UplayR1.Uninstall(directory, this);
+ else
+ await UplayR1.Install(directory, selection, this);
+ }
+ directory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config);
+ if (File.Exists(old_sdk32) || File.Exists(old_sdk64) || File.Exists(sdk32) || File.Exists(sdk32_o) || File.Exists(sdk64) || File.Exists(sdk64_o) || File.Exists(config))
+ {
+ UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" +
+ $" {(Uninstalling ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ if (Uninstalling)
+ await UplayR2.Uninstall(directory, this);
+ else
+ await UplayR2.Install(directory, selection, this);
}
}
UpdateProgress(++cur / count * 100);
@@ -414,7 +132,6 @@ internal partial class InstallForm : CustomForm
foreach (ProgramSelection selection in programSelections)
{
if (Program.Canceled || !Program.IsProgramRunningDialog(this, selection)) throw new CustomMessageException("The operation was canceled.");
- Thread.Sleep(0);
try
{
await OperateFor(selection);
diff --git a/CreamInstaller/Forms/SelectForm.Designer.cs b/CreamInstaller/Forms/SelectForm.Designer.cs
index afc5f63..4920dec 100644
--- a/CreamInstaller/Forms/SelectForm.Designer.cs
+++ b/CreamInstaller/Forms/SelectForm.Designer.cs
@@ -109,8 +109,7 @@ namespace CreamInstaller
this.noneFoundLabel.Name = "noneFoundLabel";
this.noneFoundLabel.Size = new System.Drawing.Size(554, 218);
this.noneFoundLabel.TabIndex = 1002;
- this.noneFoundLabel.Text = "No SmokeAPI-applicable or ScreamAPI-applicable programs were found on your comput" +
- "er!";
+ this.noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.noneFoundLabel.Visible = false;
//
diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs
index a0d856e..2b2b9b2 100644
--- a/CreamInstaller/Forms/SelectForm.cs
+++ b/CreamInstaller/Forms/SelectForm.cs
@@ -5,6 +5,7 @@ using CreamInstaller.Epic;
using CreamInstaller.Paradox;
using CreamInstaller.Resources;
using CreamInstaller.Steam;
+using CreamInstaller.Ubisoft;
using CreamInstaller.Utility;
using Gameloop.Vdf.Linq;
@@ -104,7 +105,7 @@ internal partial class SelectForm : CustomForm
RemainingGames.Clear(); // for display purposes only, otherwise ignorable
RemainingDLCs.Clear(); // for display purposes only, otherwise ignorable
List appTasks = new();
- if (Directory.Exists(ParadoxLauncher.InstallPath) && ProgramsToScan.Any(c => c.platform == "Paradox" && c.id == "ParadoxLauncher"))
+ if (ProgramsToScan.Any(c => c.platform == "Paradox"))
{
List steamDllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(ParadoxLauncher.InstallPath);
List epicDllDirectories = await EpicLibrary.GetDllDirectoriesFromGameDirectory(ParadoxLauncher.InstallPath);
@@ -128,7 +129,7 @@ internal partial class SelectForm : CustomForm
_ = selectionTreeView.Nodes.Add(programNode);
}
}
- if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan.Any(c => c.platform == "Steam"))
+ if (ProgramsToScan.Any(c => c.platform == "Steam"))
{
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames = await SteamLibrary.GetGames();
int totalGames = steamGames.Count;
@@ -136,7 +137,6 @@ internal partial class SelectForm : CustomForm
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
{
if (Program.Canceled) return;
- Thread.Sleep(0);
if (Program.IsGameBlocked(name, gameDirectory) || !ProgramsToScan.Any(c => c.id == appId))
{
gamesChecked++;
@@ -146,7 +146,6 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
- Thread.Sleep(0);
List dllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(gameDirectory);
if (dllDirectories is null)
{
@@ -173,12 +172,13 @@ internal partial class SelectForm : CustomForm
foreach (string dlcAppId in dlcIds)
{
if (Program.Canceled) return;
- Thread.Sleep(0);
AddToRemainingDLCs(dlcAppId);
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
- do Thread.Sleep(10); while (!Program.Canceled && gamesChecked < totalGames); // give games steam store api limit priority
+ do // give games steam store api limit priority
+ Thread.Sleep(100);
+ while (!Program.Canceled && gamesChecked < totalGames);
if (Program.Canceled) return;
string dlcName = null;
string dlcIcon = null;
@@ -209,7 +209,6 @@ internal partial class SelectForm : CustomForm
RemoveFromRemainingDLCs(dlcAppId);
});
dlcTasks.Add(task);
- Thread.Sleep(10); // to reduce control & window freezing
}
}
else
@@ -241,7 +240,6 @@ internal partial class SelectForm : CustomForm
Program.Invoke(selectionTreeView, delegate
{
if (Program.Canceled) return;
- Thread.Sleep(0);
TreeNode programNode = treeNodes.Find(s => s.Name == appId) ?? new();
programNode.Name = appId;
programNode.Text = appData?.name ?? name;
@@ -251,7 +249,6 @@ internal partial class SelectForm : CustomForm
foreach (KeyValuePair pair in dlc)
{
if (Program.Canceled || programNode is null) return;
- Thread.Sleep(0);
string appId = pair.Key;
(DlcType type, string name, string icon) dlcApp = pair.Value;
selection.AllDlc[appId] = dlcApp;
@@ -270,7 +267,7 @@ internal partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
- if (Directory.Exists(EpicLibrary.EpicManifestsPath) && ProgramsToScan.Any(c => c.platform == "Epic"))
+ if (ProgramsToScan.Any(c => c.platform == "Epic"))
{
List epicGames = await EpicLibrary.GetGames();
foreach (Manifest manifest in epicGames)
@@ -279,13 +276,11 @@ internal partial class SelectForm : CustomForm
string name = manifest.DisplayName;
string directory = manifest.InstallLocation;
if (Program.Canceled) return;
- Thread.Sleep(0);
if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.id == @namespace)) continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
- Thread.Sleep(0);
List dllDirectories = await EpicLibrary.GetDllDirectoriesFromGameDirectory(directory);
if (dllDirectories is null)
{
@@ -301,17 +296,14 @@ internal partial class SelectForm : CustomForm
foreach ((string id, string name, string product, string icon, string developer) in entitlementIds)
{
if (Program.Canceled) return;
- Thread.Sleep(0);
AddToRemainingDLCs(id);
Task task = Task.Run(() =>
{
if (Program.Canceled) return;
- Thread.Sleep(0);
entitlements[id] = (name, product, icon, developer);
RemoveFromRemainingDLCs(id);
});
dlcTasks.Add(task);
- Thread.Sleep(10); // to reduce control & window freezing
}
}
if (/*!catalogItems.Any() && */!entitlements.Any())
@@ -335,7 +327,6 @@ internal partial class SelectForm : CustomForm
selection.IsEpic = true;
foreach (KeyValuePair pair in entitlements)
{
- Thread.Sleep(0);
if (pair.Value.name == selection.Name)
{
selection.ProductUrl = "https://www.epicgames.com/store/product/" + pair.Value.product;
@@ -348,7 +339,6 @@ internal partial class SelectForm : CustomForm
Program.Invoke(selectionTreeView, delegate
{
if (Program.Canceled) return;
- Thread.Sleep(0);
TreeNode programNode = treeNodes.Find(s => s.Name == @namespace) ?? new();
programNode.Name = @namespace;
programNode.Text = name;
@@ -372,7 +362,6 @@ internal partial class SelectForm : CustomForm
foreach (KeyValuePair pair in entitlements)
{
if (programNode is null/* || entitlementsNode is null*/) return;
- Thread.Sleep(0);
string dlcId = pair.Key;
(DlcType type, string name, string icon) dlcApp = (DlcType.EpicEntitlement, pair.Value.name, pair.Value.icon);
selection.AllDlc[dlcId] = dlcApp;
@@ -392,6 +381,50 @@ internal partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
+ if (ProgramsToScan.Any(c => c.platform == "Ubisoft"))
+ {
+ List<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
+ foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
+ {
+ if (Program.Canceled) return;
+ if (Program.IsGameBlocked(name, gameDirectory) || !ProgramsToScan.Any(c => c.id == gameId)) continue;
+ AddToRemainingGames(name);
+ Task task = Task.Run(async () =>
+ {
+ if (Program.Canceled) return;
+ List dllDirectories = await UbisoftLibrary.GetDllDirectoriesFromGameDirectory(gameDirectory);
+ if (dllDirectories is null)
+ {
+ RemoveFromRemainingGames(name);
+ return;
+ }
+ if (Program.Canceled) return;
+
+ ProgramSelection selection = ProgramSelection.FromId(gameId) ?? new();
+ selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
+ selection.Id = gameId;
+ selection.Name = name;
+ selection.RootDirectory = gameDirectory;
+ selection.DllDirectories = dllDirectories;
+ selection.IsUbisoft = true;
+ selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
+
+ Program.Invoke(selectionTreeView, delegate
+ {
+ if (Program.Canceled) return;
+ TreeNode programNode = treeNodes.Find(s => s.Name == gameId) ?? new();
+ programNode.Name = gameId;
+ programNode.Text = name;
+ programNode.Checked = selection.Enabled;
+ programNode.Remove();
+ _ = selectionTreeView.Nodes.Add(programNode);
+ });
+ if (Program.Canceled) return;
+ RemoveFromRemainingGames(name);
+ });
+ appTasks.Add(task);
+ }
+ }
foreach (Task task in appTasks)
{
if (Program.Canceled) return;
@@ -430,22 +463,24 @@ internal partial class SelectForm : CustomForm
if (Directory.Exists(EpicLibrary.EpicManifestsPath))
foreach (Manifest manifest in (await EpicLibrary.GetGames()).Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)))
gameChoices.Add(("Epic", manifest.CatalogNamespace, manifest.DisplayName, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == manifest.CatalogNamespace)));
+ foreach ((string gameId, string name, string gameDirectory) in await UbisoftLibrary.GetGames())
+ gameChoices.Add(("Ubisoft", gameId, name, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == gameId)));
if (gameChoices.Any())
{
using SelectDialogForm form = new(this);
- List<(string platform, string id, string name)> choices = form.QueryUser("Choose which programs/games to scan for DLC:", gameChoices);
+ List<(string platform, string id, string name)> choices = form.QueryUser("Choose which programs and/or games to scan for DLC:", gameChoices);
scan = choices is not null && choices.Any();
string retry = "\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
if (scan)
{
ProgramsToScan = choices;
- noneFoundLabel.Text = "None of the chosen programs/games were SmokeAPI-applicable or ScreamAPI-applicable!" + retry;
+ noneFoundLabel.Text = "None of the chosen programs nor games were applicable!" + retry;
}
else
- noneFoundLabel.Text = "You didn't choose any programs/games!" + retry;
+ noneFoundLabel.Text = "You didn't choose any programs nor games!" + retry;
}
else
- noneFoundLabel.Text = "No SmokeAPI-applicable or ScreamAPI-applicable programs/games were found on your computer!";
+ noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
}
if (scan)
@@ -458,7 +493,6 @@ internal partial class SelectForm : CustomForm
progress.ProgressChanged += (sender, _progress) =>
{
if (Program.Canceled) return;
- Thread.Sleep(0);
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
else curProgress = _progress;
int p = Math.Max(Math.Min((int)((float)curProgress / maxProgress * 100), 100), 0);
@@ -475,7 +509,6 @@ internal partial class SelectForm : CustomForm
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
ProgramSelection.ValidateAll(ProgramsToScan);
TreeNodes.ForEach(node => node.Remove());
- Thread.Sleep(0);
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
}
@@ -692,6 +725,23 @@ internal partial class SelectForm : CustomForm
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
}
}
+ if (selection.IsUbisoft)
+ for (int i = 0, r1 = 0, r2 = 0; i < directories.Count; i++)
+ {
+ string directory = directories[i];
+ directory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32) || File.Exists(sdk32_o) || File.Exists(sdk64) || File.Exists(sdk64_o) || File.Exists(config))
+ {
+ contextMenuStrip.Items.Add(new ContextMenuItem($"Open Uplay R1 SDK Directory #{++r1}", "File Explorer",
+ new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
+ }
+ directory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config);
+ if (File.Exists(old_sdk32) || File.Exists(old_sdk64) || File.Exists(sdk32) || File.Exists(sdk32_o) || File.Exists(sdk64) || File.Exists(sdk64_o) || File.Exists(config))
+ {
+ contextMenuStrip.Items.Add(new ContextMenuItem($"Open Uplay R2 SDK Directory #{++r2}", "File Explorer",
+ new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
+ }
+ }
}
if (id != "ParadoxLauncher")
{
@@ -718,6 +768,15 @@ internal partial class SelectForm : CustomForm
contextMenuStrip.Items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl))));
}
+ else if (selection.IsUbisoft)
+ {
+ contextMenuStrip.Items.Add(new ToolStripSeparator());
+#pragma warning disable CA1308 // Normalize strings to uppercase
+ contextMenuStrip.Items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
+ new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://store.ubi.com/us/" + selection.Name.Replace(" ", "-").ToLowerInvariant()))));
+#pragma warning restore CA1308 // Normalize strings to uppercase
+
+ }
}
}
if (selection is not null && selection.WebsiteUrl is not null)
diff --git a/CreamInstaller/Paradox/ParadoxLauncher.cs b/CreamInstaller/Paradox/ParadoxLauncher.cs
index 09943d2..518b7e1 100644
--- a/CreamInstaller/Paradox/ParadoxLauncher.cs
+++ b/CreamInstaller/Paradox/ParadoxLauncher.cs
@@ -91,7 +91,7 @@ internal static class ParadoxLauncher
{
directory.GetSmokeApiComponents(out string sdk32, out _, out string sdk64, out _, out string config, out _);
smokeConfig = smokeConfig || File.Exists(config);
- await InstallForm.UninstallSmokeAPI(directory, deleteConfig: false);
+ await SmokeAPI.Uninstall(directory, deleteConfig: false);
if (steamOriginalSdk32 is null && File.Exists(sdk32) && !sdk32.IsResourceFile(ResourceIdentifier.Steamworks32))
steamOriginalSdk32 = File.ReadAllBytes(sdk32);
if (steamOriginalSdk64 is null && File.Exists(sdk64) && !sdk64.IsResourceFile(ResourceIdentifier.Steamworks64))
@@ -99,7 +99,7 @@ internal static class ParadoxLauncher
directory.GetScreamApiComponents(out sdk32, out _, out sdk64, out _, out config);
screamConfig = screamConfig || File.Exists(config);
- await InstallForm.UninstallScreamAPI(directory, deleteConfig: false);
+ await ScreamAPI.Uninstall(directory, deleteConfig: false);
if (epicOriginalSdk32 is null && File.Exists(sdk32) && !sdk32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
epicOriginalSdk32 = File.ReadAllBytes(sdk32);
if (epicOriginalSdk64 is null && File.Exists(sdk64) && !sdk64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
@@ -127,7 +127,7 @@ internal static class ParadoxLauncher
neededRepair = true;
}
if (smokeConfig)
- await InstallForm.InstallSmokeAPI(directory, selection, generateConfig: false);
+ await SmokeAPI.Install(directory, selection, generateConfig: false);
directory.GetScreamApiComponents(out sdk32, out _, out sdk64, out _, out _);
if (epicOriginalSdk32 is not null && sdk32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
@@ -145,7 +145,7 @@ internal static class ParadoxLauncher
neededRepair = true;
}
if (screamConfig)
- await InstallForm.InstallScreamAPI(directory, selection, generateConfig: false);
+ await ScreamAPI.Install(directory, selection, generateConfig: false);
}
if (neededRepair)
{
diff --git a/CreamInstaller/ProgramSelection.cs b/CreamInstaller/ProgramSelection.cs
index bdc14b3..d0c8eca 100644
--- a/CreamInstaller/ProgramSelection.cs
+++ b/CreamInstaller/ProgramSelection.cs
@@ -35,6 +35,7 @@ internal class ProgramSelection
internal bool IsSteam;
internal bool IsEpic;
+ internal bool IsUbisoft;
internal readonly SortedList AllDlc = new(AppIdComparer.Comparer);
internal readonly SortedList SelectedDlc = new(AppIdComparer.Comparer);
@@ -48,21 +49,53 @@ internal class ProgramSelection
{
foreach (string directory in DllDirectories)
{
- directory.GetSmokeApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config, out string cache);
- if (sdk32.IsFilePathLocked()
- || sdk32_o.IsFilePathLocked()
- || sdk64.IsFilePathLocked()
- || sdk64_o.IsFilePathLocked()
- || config.IsFilePathLocked()
- || cache.IsFilePathLocked())
- return true;
- directory.GetScreamApiComponents(out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config);
- if (sdk32.IsFilePathLocked()
- || sdk32_o.IsFilePathLocked()
- || sdk64.IsFilePathLocked()
- || sdk64_o.IsFilePathLocked()
- || config.IsFilePathLocked())
- return true;
+ if (IsSteam)
+ {
+ directory.GetCreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (sdk32.IsFilePathLocked()
+ || sdk32_o.IsFilePathLocked()
+ || sdk64.IsFilePathLocked()
+ || sdk64_o.IsFilePathLocked()
+ || config.IsFilePathLocked())
+ return true;
+ directory.GetSmokeApiComponents(out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config, out string cache);
+ if (sdk32.IsFilePathLocked()
+ || sdk32_o.IsFilePathLocked()
+ || sdk64.IsFilePathLocked()
+ || sdk64_o.IsFilePathLocked()
+ || config.IsFilePathLocked()
+ || cache.IsFilePathLocked())
+ return true;
+ }
+ else if (IsEpic)
+ {
+ directory.GetScreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (sdk32.IsFilePathLocked()
+ || sdk32_o.IsFilePathLocked()
+ || sdk64.IsFilePathLocked()
+ || sdk64_o.IsFilePathLocked()
+ || config.IsFilePathLocked())
+ return true;
+ }
+ else if (IsUbisoft)
+ {
+ directory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (sdk32.IsFilePathLocked()
+ || sdk32_o.IsFilePathLocked()
+ || sdk64.IsFilePathLocked()
+ || sdk64_o.IsFilePathLocked()
+ || config.IsFilePathLocked())
+ return true;
+ directory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config);
+ if (old_sdk32.IsFilePathLocked()
+ || old_sdk64.IsFilePathLocked()
+ || sdk32.IsFilePathLocked()
+ || sdk32_o.IsFilePathLocked()
+ || sdk64.IsFilePathLocked()
+ || sdk64_o.IsFilePathLocked()
+ || config.IsFilePathLocked())
+ return true;
+ }
}
return false;
}
diff --git a/CreamInstaller/Properties/Resources.Designer.cs b/CreamInstaller/Properties/Resources.Designer.cs
index 4689a77..c546ee0 100644
--- a/CreamInstaller/Properties/Resources.Designer.cs
+++ b/CreamInstaller/Properties/Resources.Designer.cs
@@ -109,5 +109,45 @@ namespace CreamInstaller.Properties {
return ((byte[])(obj));
}
}
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Upc32 {
+ get {
+ object obj = ResourceManager.GetObject("Upc32", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Upc64 {
+ get {
+ object obj = ResourceManager.GetObject("Upc64", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Uplay32 {
+ get {
+ object obj = ResourceManager.GetObject("Uplay32", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] Uplay64 {
+ get {
+ object obj = ResourceManager.GetObject("Uplay64", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/CreamInstaller/Properties/Resources.resx b/CreamInstaller/Properties/Resources.resx
index 56a3421..ab7460f 100644
--- a/CreamInstaller/Properties/Resources.resx
+++ b/CreamInstaller/Properties/Resources.resx
@@ -133,4 +133,16 @@
..\resources\smokeapi\steam_api64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\resources\uplayr2\upc_r2_loader.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\uplayr2\upc_r2_loader64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\uplayr1\uplay_r1_loader.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\resources\uplayr1\uplay_r1_loader64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
\ No newline at end of file
diff --git a/CreamInstaller/Resources/Resources.cs b/CreamInstaller/Resources/Resources.cs
index 5f1592b..1c6f44e 100644
--- a/CreamInstaller/Resources/Resources.cs
+++ b/CreamInstaller/Resources/Resources.cs
@@ -8,29 +8,6 @@ namespace CreamInstaller.Resources;
internal static class Resources
{
- internal static void Write(this byte[] resource, string filePath)
- {
- using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
- file.Write(resource);
- }
-
- internal static bool IsFilePathLocked(this string filePath)
- {
- try
- {
- File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None).Close();
- }
- catch (FileNotFoundException)
- {
- return false;
- }
- catch (IOException)
- {
- return true;
- }
- return false;
- }
-
internal static void GetCreamApiComponents(
this string directory,
out string sdk32, out string sdk32_o,
@@ -44,71 +21,16 @@ internal static class Resources
config = directory + @"\cream_api.ini";
}
- internal static void GetSmokeApiComponents(
- this string directory,
- out string sdk32, out string sdk32_o,
- out string sdk64, out string sdk64_o,
- out string config,
- out string cache)
- {
- sdk32 = directory + @"\steam_api.dll";
- sdk32_o = directory + @"\steam_api_o.dll";
- sdk64 = directory + @"\steam_api64.dll";
- sdk64_o = directory + @"\steam_api64_o.dll";
- config = directory + @"\SmokeAPI.json";
- cache = directory + @"\SmokeAPI.cache.json";
- }
-
- internal static void GetScreamApiComponents(
- this string directory,
- out string sdk32, out string sdk32_o,
- out string sdk64, out string sdk64_o,
- out string config
- )
- {
- sdk32 = directory + @"\EOSSDK-Win32-Shipping.dll";
- sdk32_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
- sdk64 = directory + @"\EOSSDK-Win64-Shipping.dll";
- sdk64_o = directory + @"\EOSSDK-Win64-Shipping_o.dll";
- config = directory + @"\ScreamAPI.json";
- }
-
- internal static void GetUplayR1Components(
- this string directory,
- out string sdk32, out string sdk32_o,
- out string sdk64, out string sdk64_o,
- out string config
- )
- {
- sdk32 = directory + @"\uplay_r1_loader.dll";
- sdk32_o = directory + @"\uplay_r1_loader_o.dll";
- sdk64 = directory + @"\uplay_r1_loader64.dll";
- sdk64_o = directory + @"\uplay_r1_loader64_o.dll";
- config = directory + @"\UplayR1Unlocker.jsonc";
- }
-
- internal static void GetUplayR2Components(
- this string directory,
- out string old_sdk32, out string old_sdk64,
- out string sdk32, out string sdk32_o,
- out string sdk64, out string sdk64_o,
- out string config)
- {
- old_sdk32 = directory + @"\uplay_r2_loader.dll";
- old_sdk64 = directory + @"\uplay_r2_loader64.dll";
- sdk32 = directory + @"\upc_r2_loader.dll";
- sdk32_o = directory + @"\upc_r2_loader_o.dll";
- sdk64 = directory + @"\upc_r2_loader64.dll";
- sdk64_o = directory + @"\upc_r2_loader64_o.dll";
- config = directory + @"\UplayR2Unlocker.jsonc";
- }
-
public enum ResourceIdentifier
{
Steamworks32 = 0,
Steamworks64 = 1,
EpicOnlineServices32 = 2,
- EpicOnlineServices64 = 3
+ EpicOnlineServices64 = 3,
+ Uplay32 = 4,
+ Uplay64 = 5,
+ Upc32 = 6,
+ Upc64 = 7,
}
internal static readonly Dictionary> ResourceMD5s = new()
@@ -150,6 +72,36 @@ internal static class Resources
"49122A2E2E51CBB0AE5E1D59B280E4CD", // SmokeAPI v1.0.2
"13F3E9476116F7670E21365A400357AC" // SmokeAPI v1.0.3
}
+ },
+ {
+ ResourceIdentifier.Uplay32,
+ new List()
+ {
+ "1977967B2549A38EC2DB39D4C8ED499B" // Uplay R1 Unlocker v2.0.0
+ }
+ },
+ {
+ ResourceIdentifier.Uplay64,
+ new List()
+ {
+ "333FEDD9DC2B299419B37ED1624FF8DB" // Uplay R1 Unlocker v2.0.0
+ }
+ },
+ {
+ ResourceIdentifier.Upc32,
+ new List()
+ {
+ "C14368BC4EE19FDE8DBAC07E31C67AE4", // Uplay R2 Unlocker v3.0.0
+ "DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
+ }
+ },
+ {
+ ResourceIdentifier.Upc64,
+ new List()
+ {
+ "7D9A4C12972BAABCB6C181920CC0F19B", // Uplay R2 Unlocker v3.0.0
+ "D7FDBFE0FC8D7600FEB8EC0A97713184" // Uplay R2 Unlocker v3.0.1
+ }
}
};
@@ -167,4 +119,27 @@ internal static class Resources
internal static bool IsResourceFile(this string filePath, ResourceIdentifier identifier) => filePath.ComputeMD5() is string hash && ResourceMD5s[identifier].Contains(hash);
internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is string hash && ResourceMD5s.Values.Any(hashes => hashes.Contains(hash));
+
+ internal static bool IsFilePathLocked(this string filePath)
+ {
+ try
+ {
+ File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None).Close();
+ }
+ catch (FileNotFoundException)
+ {
+ return false;
+ }
+ catch (IOException)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ internal static void Write(this byte[] resource, string filePath)
+ {
+ using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
+ file.Write(resource);
+ }
}
diff --git a/CreamInstaller/Resources/ScreamAPI.cs b/CreamInstaller/Resources/ScreamAPI.cs
new file mode 100644
index 0000000..c5c3798
--- /dev/null
+++ b/CreamInstaller/Resources/ScreamAPI.cs
@@ -0,0 +1,168 @@
+using CreamInstaller.Components;
+using CreamInstaller.Utility;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CreamInstaller.Resources;
+
+internal static class ScreamAPI
+{
+ internal static void GetScreamApiComponents(
+ this string directory,
+ out string sdk32, out string sdk32_o,
+ out string sdk64, out string sdk64_o,
+ out string config
+ )
+ {
+ sdk32 = directory + @"\EOSSDK-Win32-Shipping.dll";
+ sdk32_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
+ sdk64 = directory + @"\EOSSDK-Win64-Shipping.dll";
+ sdk64_o = directory + @"\EOSSDK-Win64-Shipping_o.dll";
+ config = directory + @"\ScreamAPI.json";
+ }
+
+ internal static void WriteConfig(StreamWriter writer, SortedList overrideCatalogItems, SortedList entitlements, InstallForm installForm = null)
+ {
+ writer.WriteLine("{");
+ writer.WriteLine(" \"version\": 2,");
+ writer.WriteLine(" \"logging\": false,");
+ writer.WriteLine(" \"eos_logging\": false,");
+ writer.WriteLine(" \"block_metrics\": false,");
+ writer.WriteLine(" \"catalog_items\": {");
+ writer.WriteLine(" \"unlock_all\": true,");
+ if (overrideCatalogItems.Any())
+ {
+ writer.WriteLine(" \"override\": [");
+ KeyValuePair lastOverrideCatalogItem = overrideCatalogItems.Last();
+ foreach (KeyValuePair pair in overrideCatalogItems)
+ {
+ string id = pair.Key;
+ (_, string name, _) = pair.Value;
+ writer.WriteLine($" \"{id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added override catalog item to ScreamAPI.json with id {id} ({name})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ]");
+ }
+ else
+ writer.WriteLine(" \"override\": []");
+ writer.WriteLine(" },");
+ writer.WriteLine(" \"entitlements\": {");
+ writer.WriteLine(" \"unlock_all\": true,");
+ writer.WriteLine(" \"auto_inject\": true,");
+ if (entitlements.Any())
+ {
+ writer.WriteLine(" \"inject\": [");
+ KeyValuePair lastEntitlement = entitlements.Last();
+ foreach (KeyValuePair pair in entitlements)
+ {
+ string id = pair.Key;
+ (_, string name, _) = pair.Value;
+ writer.WriteLine($" \"{id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added entitlement to ScreamAPI.json with id {id} ({name})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ]");
+ }
+ else
+ writer.WriteLine(" \"inject\": []");
+ writer.WriteLine(" }");
+ writer.WriteLine("}");
+ }
+
+ internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
+ {
+ directory.GetScreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32_o))
+ {
+ if (File.Exists(sdk32))
+ {
+ File.Delete(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk32_o, sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Epic Online Services: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ if (File.Exists(sdk64))
+ {
+ File.Delete(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk64_o, sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Epic Online Services: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (deleteConfig && File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ });
+
+ internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
+ {
+ directory.GetScreamApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32) && !File.Exists(sdk32_o))
+ {
+ File.Move(sdk32, sdk32_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Epic Online Services: {Path.GetFileName(sdk32)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk32_o))
+ {
+ Properties.Resources.EpicOnlineServices32.Write(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64) && !File.Exists(sdk64_o))
+ {
+ File.Move(sdk64, sdk64_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Epic Online Services: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ Properties.Resources.EpicOnlineServices64.Write(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (generateConfig)
+ {
+ IEnumerable> overrideCatalogItems = selection.AllDlc.Where(pair => pair.Value.type is DlcType.EpicCatalogItem).Except(selection.SelectedDlc);
+ foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
+ overrideCatalogItems = overrideCatalogItems.Except(extraDlc);
+ IEnumerable> entitlements = selection.SelectedDlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement);
+ foreach ((string id, string name, SortedList _dlc) in selection.ExtraSelectedDlc)
+ entitlements = entitlements.Concat(_dlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement));
+ if (overrideCatalogItems.Any() || entitlements.Any())
+ {
+ if (installForm is not null)
+ installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ File.Create(config).Close();
+ StreamWriter writer = new(config, true, Encoding.UTF8);
+ WriteConfig(writer,
+ new(overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
+ new(entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
+ installForm);
+ writer.Flush();
+ writer.Close();
+ }
+ else if (File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ }
+ });
+}
diff --git a/CreamInstaller/Resources/SmokeAPI.cs b/CreamInstaller/Resources/SmokeAPI.cs
new file mode 100644
index 0000000..ac60eb8
--- /dev/null
+++ b/CreamInstaller/Resources/SmokeAPI.cs
@@ -0,0 +1,182 @@
+using CreamInstaller.Components;
+using CreamInstaller.Utility;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CreamInstaller.Resources;
+
+internal static class SmokeAPI
+{
+ internal static void GetSmokeApiComponents(
+ this string directory,
+ out string sdk32, out string sdk32_o,
+ out string sdk64, out string sdk64_o,
+ out string config,
+ out string cache)
+ {
+ sdk32 = directory + @"\steam_api.dll";
+ sdk32_o = directory + @"\steam_api_o.dll";
+ sdk64 = directory + @"\steam_api64.dll";
+ sdk64_o = directory + @"\steam_api64_o.dll";
+ config = directory + @"\SmokeAPI.json";
+ cache = directory + @"\SmokeAPI.cache.json";
+ }
+
+ internal static void WriteConfig(StreamWriter writer, SortedList overrideDlc, SortedList injectDlc, InstallForm installForm = null)
+ {
+ writer.WriteLine("{");
+ writer.WriteLine(" \"$version\": 1,");
+ writer.WriteLine(" \"logging\": false,");
+ writer.WriteLine(" \"hook_steamclient\": true,");
+ writer.WriteLine(" \"unlock_all\": true,");
+ if (overrideDlc.Count > 0)
+ {
+ writer.WriteLine(" \"override\": [");
+ KeyValuePair lastOverrideDlc = overrideDlc.Last();
+ foreach (KeyValuePair pair in overrideDlc)
+ {
+ string dlcId = pair.Key;
+ (_, string dlcName, _) = pair.Value;
+ writer.WriteLine($" {dlcId}{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added override DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ],");
+ }
+ else
+ writer.WriteLine(" \"override\": [],");
+ if (injectDlc.Count > 0)
+ {
+ writer.WriteLine(" \"dlc_ids\": [");
+ KeyValuePair lastInjectDlc = injectDlc.Last();
+ foreach (KeyValuePair pair in injectDlc)
+ {
+ string dlcId = pair.Key;
+ (_, string dlcName, _) = pair.Value;
+ writer.WriteLine($" {dlcId}{(pair.Equals(lastInjectDlc) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added inject DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ],");
+ }
+ else
+ writer.WriteLine(" \"dlc_ids\": [],");
+ writer.WriteLine(" \"auto_inject_inventory\": true,");
+ writer.WriteLine(" \"inventory_items\": []");
+ writer.WriteLine("}");
+ }
+
+ internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
+ {
+ directory.GetSmokeApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config, out string cache);
+ if (File.Exists(sdk32_o))
+ {
+ if (File.Exists(sdk32))
+ {
+ File.Delete(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk32_o, sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Steamworks: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ if (File.Exists(sdk64))
+ {
+ File.Delete(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk64_o, sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Steamworks: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (deleteConfig && File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ if (deleteConfig && File.Exists(cache))
+ {
+ File.Delete(cache);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", InstallationLog.Action, info: false);
+ }
+ });
+
+ internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
+ {
+ directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
+ if (File.Exists(oldConfig))
+ {
+ File.Delete(oldConfig);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}", InstallationLog.Action, info: false);
+ }
+ directory.GetSmokeApiComponents(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config, out _);
+ if (File.Exists(sdk32) && !File.Exists(sdk32_o))
+ {
+ File.Move(sdk32, sdk32_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Steamworks: {Path.GetFileName(sdk32)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk32_o))
+ {
+ Properties.Resources.Steamworks32.Write(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64) && !File.Exists(sdk64_o))
+ {
+ File.Move(sdk64, sdk64_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Steamworks: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ Properties.Resources.Steamworks64.Write(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (generateConfig)
+ {
+ IEnumerable> overrideDlc = selection.AllDlc.Except(selection.SelectedDlc);
+ foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
+ overrideDlc = overrideDlc.Except(extraDlc);
+ IEnumerable> injectDlc = new List>();
+ if (selection.AllDlc.Count > 64 || selection.ExtraDlc.Any(e => e.dlc.Count > 64))
+ {
+ injectDlc = injectDlc.Concat(selection.SelectedDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
+ foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
+ if (selection.ExtraDlc.Where(e => e.id == id).Single().dlc.Count > 64)
+ injectDlc = injectDlc.Concat(extraDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
+ }
+ if (overrideDlc.Any() || injectDlc.Any())
+ {
+ if (installForm is not null)
+ installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ File.Create(config).Close();
+ StreamWriter writer = new(config, true, Encoding.UTF8);
+ WriteConfig(writer,
+ new(overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
+ new(injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer),
+ installForm);
+ writer.Flush();
+ writer.Close();
+ }
+ else if (File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ }
+ });
+}
diff --git a/CreamInstaller/Resources/UplayR1.cs b/CreamInstaller/Resources/UplayR1.cs
new file mode 100644
index 0000000..b90e87f
--- /dev/null
+++ b/CreamInstaller/Resources/UplayR1.cs
@@ -0,0 +1,138 @@
+using CreamInstaller.Components;
+using CreamInstaller.Utility;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CreamInstaller.Resources;
+
+internal static class UplayR1
+{
+ internal static void GetUplayR1Components(
+ this string directory,
+ out string sdk32, out string sdk32_o,
+ out string sdk64, out string sdk64_o,
+ out string config
+ )
+ {
+ sdk32 = directory + @"\uplay_r1_loader.dll";
+ sdk32_o = directory + @"\uplay_r1_loader_o.dll";
+ sdk64 = directory + @"\uplay_r1_loader64.dll";
+ sdk64_o = directory + @"\uplay_r1_loader64_o.dll";
+ config = directory + @"\UplayR1Unlocker.jsonc";
+ }
+
+ internal static void WriteConfig(StreamWriter writer, SortedList blacklistDlc, InstallForm installForm = null)
+ {
+ writer.WriteLine("{");
+ writer.WriteLine(" \"logging\": false,");
+ writer.WriteLine(" \"lang\": \"default\",");
+ writer.WriteLine(" \"hook_loader\": false,");
+ if (blacklistDlc.Count > 0)
+ {
+ writer.WriteLine(" \"blacklist\": [");
+ KeyValuePair lastBlacklistDlc = blacklistDlc.Last();
+ foreach (KeyValuePair pair in blacklistDlc)
+ {
+ string dlcId = pair.Key;
+ (_, string dlcName, _) = pair.Value;
+ writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ],");
+ }
+ else
+ writer.WriteLine(" \"blacklist\": [],");
+ writer.WriteLine("}");
+ }
+
+ internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
+ {
+ directory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32_o))
+ {
+ if (File.Exists(sdk32))
+ {
+ File.Delete(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk32_o, sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Uplay R1: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ if (File.Exists(sdk64))
+ {
+ File.Delete(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk64_o, sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Uplay R1: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (deleteConfig && File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ });
+
+ internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
+ {
+ directory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32) && !File.Exists(sdk32_o))
+ {
+ File.Move(sdk32, sdk32_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(sdk32)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk32_o))
+ {
+ Properties.Resources.Uplay32.Write(sdk32);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(sdk32)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64) && !File.Exists(sdk64_o))
+ {
+ File.Move(sdk64, sdk64_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(sdk64)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ Properties.Resources.Uplay64.Write(sdk64);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(sdk64)}", InstallationLog.Action, info: false);
+ }
+ if (generateConfig)
+ {
+ IEnumerable> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
+ foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
+ blacklistDlc = blacklistDlc.Except(extraDlc);
+ if (blacklistDlc.Any())
+ {
+ if (installForm is not null)
+ installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ File.Create(config).Close();
+ StreamWriter writer = new(config, true, Encoding.UTF8);
+ WriteConfig(writer, new(blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer), installForm);
+ writer.Flush();
+ writer.Close();
+ }
+ else if (File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ }
+ });
+}
diff --git a/CreamInstaller/Resources/UplayR1/uplay_r1_loader.dll b/CreamInstaller/Resources/UplayR1/uplay_r1_loader.dll
new file mode 100644
index 0000000..b045448
Binary files /dev/null and b/CreamInstaller/Resources/UplayR1/uplay_r1_loader.dll differ
diff --git a/CreamInstaller/Resources/UplayR1/uplay_r1_loader64.dll b/CreamInstaller/Resources/UplayR1/uplay_r1_loader64.dll
new file mode 100644
index 0000000..c2850d4
Binary files /dev/null and b/CreamInstaller/Resources/UplayR1/uplay_r1_loader64.dll differ
diff --git a/CreamInstaller/Resources/UplayR2.cs b/CreamInstaller/Resources/UplayR2.cs
new file mode 100644
index 0000000..8408a74
--- /dev/null
+++ b/CreamInstaller/Resources/UplayR2.cs
@@ -0,0 +1,146 @@
+using CreamInstaller.Components;
+using CreamInstaller.Utility;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CreamInstaller.Resources;
+
+internal static class UplayR2
+{
+ internal static void GetUplayR2Components(
+ this string directory,
+ out string old_sdk32, out string old_sdk64,
+ out string sdk32, out string sdk32_o,
+ out string sdk64, out string sdk64_o,
+ out string config)
+ {
+ old_sdk32 = directory + @"\uplay_r2_loader.dll";
+ old_sdk64 = directory + @"\uplay_r2_loader64.dll";
+ sdk32 = directory + @"\upc_r2_loader.dll";
+ sdk32_o = directory + @"\upc_r2_loader_o.dll";
+ sdk64 = directory + @"\upc_r2_loader64.dll";
+ sdk64_o = directory + @"\upc_r2_loader64_o.dll";
+ config = directory + @"\UplayR2Unlocker.jsonc";
+ }
+
+ internal static void WriteConfig(StreamWriter writer, SortedList blacklistDlc, InstallForm installForm = null)
+ {
+ writer.WriteLine("{");
+ writer.WriteLine(" \"logging\": false,");
+ writer.WriteLine(" \"lang\": \"default\",");
+ writer.WriteLine(" \"auto_fetch\": true,");
+ writer.WriteLine(" \"dlcs\": [],");
+ writer.WriteLine(" \"items\": [],");
+ if (blacklistDlc.Count > 0)
+ {
+ writer.WriteLine(" \"blacklist\": [");
+ KeyValuePair lastBlacklistDlc = blacklistDlc.Last();
+ foreach (KeyValuePair pair in blacklistDlc)
+ {
+ string dlcId = pair.Key;
+ (_, string dlcName, _) = pair.Value;
+ writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
+ if (installForm is not null)
+ installForm.UpdateUser($"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {dlcId} ({dlcName})", InstallationLog.Action, info: false);
+ }
+ writer.WriteLine(" ],");
+ }
+ else
+ writer.WriteLine(" \"blacklist\": [],");
+ writer.WriteLine("}");
+ }
+
+ internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
+ {
+ directory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32_o))
+ {
+ string sdk = File.Exists(old_sdk32) ? old_sdk32 : sdk32;
+ if (File.Exists(sdk))
+ {
+ File.Delete(sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk32_o, sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Uplay R2: {Path.GetFileName(sdk32_o)} -> {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ string sdk = File.Exists(old_sdk64) ? old_sdk64 : sdk64;
+ if (File.Exists(sdk))
+ {
+ File.Delete(sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ File.Move(sdk64_o, sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Restored Uplay R2: {Path.GetFileName(sdk64_o)} -> {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ if (deleteConfig && File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ });
+
+ internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
+ {
+ directory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ string sdk = File.Exists(old_sdk32) ? old_sdk32 : sdk32;
+ if (File.Exists(sdk) && !File.Exists(sdk32_o))
+ {
+ File.Move(sdk, sdk32_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(sdk)} -> {Path.GetFileName(sdk32_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk32_o))
+ {
+ Properties.Resources.Upc32.Write(sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ sdk = File.Exists(old_sdk64) ? old_sdk64 : sdk64;
+ if (File.Exists(sdk) && !File.Exists(sdk64_o))
+ {
+ File.Move(sdk, sdk64_o);
+ if (installForm is not null)
+ installForm.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(sdk)} -> {Path.GetFileName(sdk64_o)}", InstallationLog.Action, info: false);
+ }
+ if (File.Exists(sdk64_o))
+ {
+ Properties.Resources.Upc64.Write(sdk);
+ if (installForm is not null)
+ installForm.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(sdk)}", InstallationLog.Action, info: false);
+ }
+ if (generateConfig)
+ {
+ IEnumerable> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
+ foreach ((string id, string name, SortedList extraDlc) in selection.ExtraSelectedDlc)
+ blacklistDlc = blacklistDlc.Except(extraDlc);
+ if (blacklistDlc.Any())
+ {
+ if (installForm is not null)
+ installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
+ File.Create(config).Close();
+ StreamWriter writer = new(config, true, Encoding.UTF8);
+ WriteConfig(writer, new(blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), AppIdComparer.Comparer), installForm);
+ writer.Flush();
+ writer.Close();
+ }
+ else if (File.Exists(config))
+ {
+ File.Delete(config);
+ if (installForm is not null)
+ installForm.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", InstallationLog.Action, info: false);
+ }
+ }
+ });
+}
diff --git a/CreamInstaller/Resources/UplayR2/upc_r2_loader.dll b/CreamInstaller/Resources/UplayR2/upc_r2_loader.dll
new file mode 100644
index 0000000..5c6d001
Binary files /dev/null and b/CreamInstaller/Resources/UplayR2/upc_r2_loader.dll differ
diff --git a/CreamInstaller/Resources/UplayR2/upc_r2_loader64.dll b/CreamInstaller/Resources/UplayR2/upc_r2_loader64.dll
new file mode 100644
index 0000000..e7d0222
Binary files /dev/null and b/CreamInstaller/Resources/UplayR2/upc_r2_loader64.dll differ
diff --git a/CreamInstaller/Steam/SteamCMD.cs b/CreamInstaller/Steam/SteamCMD.cs
index 9daafe7..0bd46af 100644
--- a/CreamInstaller/Steam/SteamCMD.cs
+++ b/CreamInstaller/Steam/SteamCMD.cs
@@ -36,11 +36,9 @@ internal static class SteamCMD
{
wait_for_lock:
if (Program.Canceled) return "";
- Thread.Sleep(0);
for (int i = 0; i < locks.Length; i++)
{
if (Program.Canceled) return "";
- Thread.Sleep(0);
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
{
if (appId is not null)
@@ -77,7 +75,6 @@ internal static class SteamCMD
process.Close();
break;
}
- Thread.Sleep(0);
int c = process.StandardOutput.Read();
if (c != -1)
{
diff --git a/CreamInstaller/Steam/SteamLibrary.cs b/CreamInstaller/Steam/SteamLibrary.cs
index 402c9cc..77dc24d 100644
--- a/CreamInstaller/Steam/SteamLibrary.cs
+++ b/CreamInstaller/Steam/SteamLibrary.cs
@@ -8,7 +8,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
namespace CreamInstaller.Steam;
@@ -33,7 +32,6 @@ internal static class SteamLibrary
foreach (string libraryDirectory in gameLibraryDirectories)
{
if (Program.Canceled) return games;
- Thread.Sleep(0);
List<(string appId, string name, string branch, int buildId, string gameDirectory)> directoryGames = await GetGamesFromLibraryDirectory(libraryDirectory);
if (directoryGames is not null)
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in directoryGames
@@ -59,7 +57,6 @@ internal static class SteamLibrary
foreach (string _directory in directories)
{
if (Program.Canceled) return null;
- Thread.Sleep(0);
try
{
List moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
@@ -78,7 +75,6 @@ internal static class SteamLibrary
foreach (string file in files)
{
if (Program.Canceled) return null;
- Thread.Sleep(0);
if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
{
string appId = result.Value.GetChild("appid")?.ToString();
diff --git a/CreamInstaller/Ubisoft/UbisoftLibrary.cs b/CreamInstaller/Ubisoft/UbisoftLibrary.cs
new file mode 100644
index 0000000..6a50058
--- /dev/null
+++ b/CreamInstaller/Ubisoft/UbisoftLibrary.cs
@@ -0,0 +1,76 @@
+using CreamInstaller.Resources;
+
+using Microsoft.Win32;
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace CreamInstaller.Ubisoft;
+
+internal static class UbisoftLibrary
+{
+ private static RegistryKey installsKey;
+ internal static RegistryKey InstallsKey
+ {
+ get
+ {
+ installsKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Ubisoft\Launcher\Installs");
+ installsKey ??= Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs");
+ return installsKey;
+ }
+ }
+
+ internal static async Task> GetGames() => await Task.Run(() =>
+ {
+ List<(string gameId, string name, string gameDirectory)> games = new();
+ RegistryKey installsKey = InstallsKey;
+ if (installsKey is null) return games;
+ foreach (string gameId in installsKey.GetSubKeyNames())
+ {
+ RegistryKey installKey = installsKey.OpenSubKey(gameId);
+ string installDir = installKey?.GetValue("InstallDir")?.ToString();
+ if (installDir is not null)
+ games.Add((gameId, new DirectoryInfo(installDir).Name, Path.GetFullPath(installDir)));
+ }
+ return games;
+ });
+
+ internal static async Task> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
+ {
+ List dllDirectories = new();
+ if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
+ gameDirectory.GetUplayR1Components(out string sdk32, out string sdk32_o, out string sdk64, out string sdk64_o, out string config);
+ if (File.Exists(sdk32)
+ || File.Exists(sdk32_o)
+ || File.Exists(sdk64)
+ || File.Exists(sdk64_o)
+ || File.Exists(config))
+ dllDirectories.Add(gameDirectory);
+ else
+ {
+ gameDirectory.GetUplayR2Components(out string old_sdk32, out string old_sdk64, out sdk32, out sdk32_o, out sdk64, out sdk64_o, out config);
+ if (File.Exists(old_sdk32)
+ || File.Exists(old_sdk64)
+ || File.Exists(sdk32)
+ || File.Exists(sdk32_o)
+ || File.Exists(sdk64)
+ || File.Exists(sdk64_o)
+ || File.Exists(config))
+ dllDirectories.Add(gameDirectory);
+ }
+ string[] directories = Directory.GetDirectories(gameDirectory);
+ foreach (string _directory in directories)
+ {
+ if (Program.Canceled) return null;
+ try
+ {
+ List moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
+ if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
+ }
+ catch { }
+ }
+ return !dllDirectories.Any() ? null : dllDirectories;
+ });
+}
diff --git a/README.md b/README.md
index 2cedcc0..931eb27 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,27 @@
-### CreamInstaller: SmokeAPI/ScreamAPI Installer & Configuration Generator
+### CreamInstaller: Automatic DLC Unlocker Installer & Configuration Generator
-![Program Preview Image](https://i.imgur.com/c8bAUwL.png)
+![Program Preview Image](https://i.imgur.com/4mqizfE.png)
-###### Refer to [this post](https://cs.rin.ru/forum/viewtopic.php?f=29&t=122487) and/or [this repository](https://github.com/acidicoala/SmokeAPI) if you don't know what SmokeAPI is! ;;)
-###### Refer to [this post](https://cs.rin.ru/forum/viewtopic.php?f=29&t=106474) and/or [this repository](https://github.com/acidicoala/ScreamAPI) if you don't know what ScreamAPI is! ;)
-
-###### The program utilizes SmokeAPI v1.0.3 and ScreamAPI v3.0.1 downloaded from those posts and embedded into the program itself; no download necessary on your part!
+###### The program utilizes the latest versions of [SmokeAPI](https://github.com/acidicoala/SmokeAPI), [ScreamAPI](https://github.com/acidicoala/ScreamAPI), [Uplay R1 Unlocker](https://github.com/acidicoala/UplayR1Unlocker), and [Uplay R2 Unlocker](https://github.com/acidicoala/UplayR2Unlocker), all by the wonderful [acidicoala](https://github.com/acidicoala), and all downloaded from the posts above and embedded into the program itself; no further downloads necessary on your part!
---
#### Description:
-Automatically finds all installed Steam and Epic games with their respective Steamworks and Epic Online Services DLL locations on the user's computer,
-parses SteamCMD, Steam Store, and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface utilizing the gathered information.
+Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,
+parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface utilizing the gathered information.
-The primary function of the program is to **automatically generate and install SmokeAPI and/or ScreamAPI** for whichever
+The primary function of the program is to **automatically generate and install DLC unlockers** for whichever
games and DLCs the user selects; however, through the use of **right-click context menus** the user can also:
* automatically repair the Paradox Launcher
* open parsed Steam and/or Epic Games appinfo in Notepad(++)
* refresh parsed Steam and/or Epic Games appinfo
-* open root game directories and Steamworks/Epic Online Services DLL directories in Explorer
-* open SteamDB, ScreamDB, Steam Store, Epic Games Store, Steam Community, and official game website links in the default browser
+* open root game directories and important DLL directories in Explorer
+* open SteamDB, ScreamDB, Steam Store, Epic Games Store, Steam Community, Ubisoft Store, and official game website links (where applicable) in the default browser
---
#### Features:
* Automatic download and installation of SteamCMD as necessary whenever a Steam game is chosen. *for gathering appinfo such as name, buildid, listofdlc, depots*
* Automatic gathering and caching of appinfo for all selected Steam and Epic games and **ALL** of their DLCs.
-* Automatic generation of SmokeAPI.json and/or ScreamAPI.json configuration and installation of SmokeAPI and/or ScreamAPI DLLs.
-* Automatic uninstallation of CreamAPI, SmokeAPI, and/or ScreamAPI DLLs and cream_api.ini, SmokeAPI.json, and/or ScreamAPI.json configuration.
+* Automatic generation of SmokeAPI.json, ScreamAPI.json, UplayR1Unlocker.jsonc and/or UplayR2Unlocker.jsonc configuration and installation of DLC unlocker DLLs.
+* Automatic uninstallation of DLC unlocker DLLs and SmokeAPI.json, ScreamAPI.json, UplayR1Unlocker.jsonc and/or UplayR2Unlocker.jsonc configurations.
* Automatic reparation of the Paradox Launcher via the right-click context menu "Repair" option. *for when the launcher updates whilst you have CreamAPI, SmokeAPI or ScreamAPI installed to it*
---
@@ -33,18 +30,18 @@ games and DLCs the user selects; however, through the use of **right-click conte
2. Extract the executable to anywhere on your computer you want. *it's completely self-contained*
---
-#### **NOTE:** This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's only a SmokeAPI/ScreamAPI installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for the game(s) you're tinkering with; you'll usually find any answer to your problems there.
+#### **NOTE:** This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for the game(s) you're tinkering with; you'll usually find any answer to your problems there.
---
#### Usage:
1. Start the program executable.
-2. Choose which programs/games the program should scan for DLC. *the program automatically gathers all installed games from Steam and Epic directories*
+2. Choose which programs/games the program should scan for DLC. *the program automatically gathers all installed games from Steam, Epic and Ubisoft directories*
3. Wait for the program to download and install SteamCMD (if you chose a Steam game). *very fast, depends on internet speed*
-4. Wait for the program to gather and cache the chosen Steam/Epic games' appinfo & DLCs. *may take a good amount of time on the first run, depends on how many games you chose and how many DLCs they have*
-5. **CAREFULLY** select which games' DLCs you wish to unlock. *SmokeAPI and ScreamAPI are not tested for every game!*
+4. Wait for the program to gather and cache the chosen Steam and/or Epic games' appinfo & DLCs. *may take a good amount of time on the first run, depends on how many games you chose and how many DLCs they have*
+5. **CAREFULLY** select which games' DLCs you wish to unlock. *Obviously none of the DLC unlockers are tested for every single game!*
6. Click the **Generate and Install** button.
7. Click the **OK** button to close the program.
-8. If SmokeAPI or ScreamAPI cause problems with any of the games you installed them on, simply go back to step 5 and select what games you wish you **revert** changes to, and instead click the **Uninstall** button this time.
+8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back to step 5 and select what games you wish you **revert** changes to, and instead click the **Uninstall** button this time.
---
##### Bugs/Crashes/Issues:
@@ -54,4 +51,4 @@ For reliable and quick assistance, all bugs, crashes and other issues should be
##### More Information:
* SteamCMD installation and appinfo cache can be found at **C:\ProgramData\CreamInstaller**.
* The program automatically and very quickly updates from [GitHub](https://github.com/pointfeev/CreamInstaller) using [Onova](https://github.com/Tyrrrz/Onova). *updates can be ignored*
-* The program source and other information can be found on [GitHub](https://github.com/pointfeev/CreamInstaller).
+* The program source and other information can be found on [GitHub](https://github.com/pointfeev/CreamInstaller).
\ No newline at end of file