v4.3.0.0
- Upgraded to .NET 7 - String culture fixes - Rare SteamCMD exception fix - Fixed Steam store scanning getting stuck on certain games - Code cleanup
This commit is contained in:
parent
195287601e
commit
9736e6dc1d
41 changed files with 1758 additions and 1359 deletions
|
@ -1,12 +1,11 @@
|
||||||
using CreamInstaller.Platforms.Paradox;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Platforms.Paradox;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Components;
|
namespace CreamInstaller.Components;
|
||||||
|
|
||||||
|
@ -14,64 +13,79 @@ internal class ContextMenuItem : ToolStripMenuItem
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, Image> images = new();
|
private static readonly ConcurrentDictionary<string, Image> images = new();
|
||||||
|
|
||||||
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run(async () =>
|
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run(
|
||||||
{
|
async () =>
|
||||||
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null) item.Image = image;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
switch (imageIdentifier)
|
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null)
|
||||||
{
|
{
|
||||||
case "Paradox Launcher":
|
|
||||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
|
||||||
foreach (string file in Directory.EnumerateFiles(ParadoxLauncher.InstallPath, "*.exe"))
|
|
||||||
{
|
|
||||||
image = IconGrabber.GetFileIconImage(file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Notepad":
|
|
||||||
image = IconGrabber.GetNotepadImage();
|
|
||||||
break;
|
|
||||||
case "Command Prompt":
|
|
||||||
image = IconGrabber.GetCommandPromptImage();
|
|
||||||
break;
|
|
||||||
case "File Explorer":
|
|
||||||
image = IconGrabber.GetFileExplorerImage();
|
|
||||||
break;
|
|
||||||
case "SteamDB":
|
|
||||||
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("steamdb.info"));
|
|
||||||
break;
|
|
||||||
case "Steam Store":
|
|
||||||
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("store.steampowered.com"));
|
|
||||||
break;
|
|
||||||
case "Steam Community":
|
|
||||||
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("steamcommunity.com"));
|
|
||||||
break;
|
|
||||||
case "ScreamDB":
|
|
||||||
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("scream-db.web.app"));
|
|
||||||
break;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (image is not null)
|
|
||||||
{
|
|
||||||
images[imageIdentifier] = image;
|
|
||||||
item.Image = image;
|
item.Image = image;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
});
|
{
|
||||||
|
switch (imageIdentifier)
|
||||||
|
{
|
||||||
|
case "Paradox Launcher":
|
||||||
|
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||||
|
foreach (string file in Directory.EnumerateFiles(ParadoxLauncher.InstallPath, "*.exe"))
|
||||||
|
{
|
||||||
|
image = file.GetFileIconImage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Notepad":
|
||||||
|
image = IconGrabber.GetNotepadImage();
|
||||||
|
break;
|
||||||
|
case "Command Prompt":
|
||||||
|
image = IconGrabber.GetCommandPromptImage();
|
||||||
|
break;
|
||||||
|
case "File Explorer":
|
||||||
|
image = IconGrabber.GetFileExplorerImage();
|
||||||
|
break;
|
||||||
|
case "SteamDB":
|
||||||
|
image = await HttpClientManager.GetImageFromUrl(
|
||||||
|
IconGrabber.GetDomainFaviconUrl("steamdb.info"));
|
||||||
|
break;
|
||||||
|
case "Steam Store":
|
||||||
|
image = await HttpClientManager.GetImageFromUrl(
|
||||||
|
IconGrabber.GetDomainFaviconUrl("store.steampowered.com"));
|
||||||
|
break;
|
||||||
|
case "Steam Community":
|
||||||
|
image = await HttpClientManager.GetImageFromUrl(
|
||||||
|
IconGrabber.GetDomainFaviconUrl("steamcommunity.com"));
|
||||||
|
break;
|
||||||
|
case "ScreamDB":
|
||||||
|
image = await HttpClientManager.GetImageFromUrl(
|
||||||
|
IconGrabber.GetDomainFaviconUrl("scream-db.web.app"));
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (image is not null)
|
||||||
|
{
|
||||||
|
images[imageIdentifier] = image;
|
||||||
|
item.Image = image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private static async Task TryImageIdentifierInfo(ContextMenuItem item, (string id, string iconUrl) imageIdentifierInfo, Action onFail = null) => await Task.Run(async () =>
|
private static async Task TryImageIdentifierInfo(ContextMenuItem item,
|
||||||
|
(string id, string iconUrl) imageIdentifierInfo,
|
||||||
|
Action onFail = null) => await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
(string id, string iconUrl) = imageIdentifierInfo;
|
(string id, string iconUrl) = imageIdentifierInfo;
|
||||||
string imageIdentifier = "Icon_" + id;
|
string imageIdentifier = "Icon_" + id;
|
||||||
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null) item.Image = image;
|
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null)
|
||||||
|
{
|
||||||
|
item.Image = image;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
image = await HttpClientManager.GetImageFromUrl(iconUrl);
|
image = await HttpClientManager.GetImageFromUrl(iconUrl);
|
||||||
|
@ -81,11 +95,14 @@ internal class ContextMenuItem : ToolStripMenuItem
|
||||||
item.Image = image;
|
item.Image = image;
|
||||||
}
|
}
|
||||||
else if (onFail is not null)
|
else if (onFail is not null)
|
||||||
|
{
|
||||||
onFail();
|
onFail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
private readonly EventHandler OnClickEvent;
|
private readonly EventHandler OnClickEvent;
|
||||||
|
|
||||||
protected override void OnClick(EventArgs e)
|
protected override void OnClick(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnClick(e);
|
base.OnClick(e);
|
||||||
|
@ -105,9 +122,15 @@ internal class ContextMenuItem : ToolStripMenuItem
|
||||||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, EventHandler onClick = null)
|
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, EventHandler onClick = null)
|
||||||
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo);
|
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo);
|
||||||
|
|
||||||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, string imageIdentifierFallback, EventHandler onClick = null)
|
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo,
|
||||||
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, async () => await TryImageIdentifier(this, imageIdentifierFallback));
|
string imageIdentifierFallback, EventHandler onClick = null)
|
||||||
|
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo,
|
||||||
|
async () => await TryImageIdentifier(
|
||||||
|
this, imageIdentifierFallback));
|
||||||
|
|
||||||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, (string id, string iconUrl) imageIdentifierInfoFallback, EventHandler onClick = null)
|
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo,
|
||||||
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, async () => await TryImageIdentifierInfo(this, imageIdentifierInfoFallback));
|
(string id, string iconUrl) imageIdentifierInfoFallback, EventHandler onClick = null)
|
||||||
|
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo,
|
||||||
|
async () => await TryImageIdentifierInfo(
|
||||||
|
this, imageIdentifierInfoFallback));
|
||||||
}
|
}
|
|
@ -4,12 +4,21 @@ using System.Drawing.Drawing2D;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller.Components;
|
namespace CreamInstaller.Components;
|
||||||
|
|
||||||
internal class CustomForm : Form
|
internal class CustomForm : Form
|
||||||
{
|
{
|
||||||
internal CustomForm() : base()
|
internal const short SWP_NOACTIVATE = 0x0010;
|
||||||
|
internal const short SWP_SHOWWINDOW = 0x0040;
|
||||||
|
internal const short SWP_NOMOVE = 0x0002;
|
||||||
|
internal const short SWP_NOSIZE = 0x0001;
|
||||||
|
|
||||||
|
internal static readonly IntPtr HWND_NOTOPMOST = new(-2);
|
||||||
|
internal static readonly IntPtr HWND_TOPMOST = new(-1);
|
||||||
|
|
||||||
|
internal CustomForm()
|
||||||
{
|
{
|
||||||
Icon = Properties.Resources.Icon;
|
Icon = Properties.Resources.Icon;
|
||||||
KeyPreview = true;
|
KeyPreview = true;
|
||||||
|
@ -19,47 +28,6 @@ internal class CustomForm : Form
|
||||||
HelpButtonClicked += OnHelpButtonClicked;
|
HelpButtonClicked += OnHelpButtonClicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnHelpButtonClicked(object sender, EventArgs args)
|
|
||||||
{
|
|
||||||
using DialogForm helpDialog = new(this);
|
|
||||||
helpDialog.HelpButton = false;
|
|
||||||
string acidicoala = "https://github.com/acidicoala";
|
|
||||||
string repository = $"https://github.com/{Program.RepositoryOwner}/{Program.RepositoryName}";
|
|
||||||
_ = helpDialog.Show(SystemIcons.Information,
|
|
||||||
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
|
|
||||||
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
|
|
||||||
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ $"The program utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [SmokeAPI]({acidicoala}/SmokeAPI), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1 Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by\n"
|
|
||||||
+ $"the wonderful [acidicoala]({acidicoala}), and all downloaded and embedded into the program itself; no further downloads necessary on your part!\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "NOTE: This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's\n"
|
|
||||||
+ "only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many\n"
|
|
||||||
+ "do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for\n"
|
|
||||||
+ "the game(s) you're tinkering with; you'll usually find any answer to your problems there.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "USAGE:\n"
|
|
||||||
+ " 1. Choose which programs and/or games the program should scan for DLC.\n"
|
|
||||||
+ " The program automatically gathers all installed games from Steam, Epic and Ubisoft directories.\n"
|
|
||||||
+ " 2. Wait for the program to download and install SteamCMD (if you chose a Steam game).\n"
|
|
||||||
+ " 3. Wait for the program to gather and cache the chosen games' information && DLCs.\n"
|
|
||||||
+ " May take some time on the first run; depends on how many DLCs the games you chose have.\n"
|
|
||||||
+ " 4. CAREFULLY select which games' DLCs you wish to unlock.\n"
|
|
||||||
+ " Obviously none of the DLC unlockers are tested for every single game!\n"
|
|
||||||
+ " 5. Choose whether or not to install with Koaloader, and if so then also pick the proxy DLL to use.\n"
|
|
||||||
+ " If the default \'version.dll\' doesn't work, then see [here](https://cs.rin.ru/forum/viewtopic.php?p=2552172#p2552172) to find one that does.\n"
|
|
||||||
+ " 6. Click the \"Generate and Install\" button.\n"
|
|
||||||
+ " 7. Click the \"OK\" button to close the program.\n"
|
|
||||||
+ " 8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back\n"
|
|
||||||
+ " to step 5 and select what games you wish you revert changes to, and instead click the \"Uninstall\" button this time.\n"
|
|
||||||
+ "\n"
|
|
||||||
+ $"For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues]({repository}/issues) page!\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "SteamCMD installation and appinfo cache can be found at [C:\\ProgramData\\CreamInstaller]().\n"
|
|
||||||
+ $"The program automatically and very quickly updates from [GitHub]({repository}) using [Onova](https://github.com/Tyrrrz/Onova). (updates can be ignored)\n"
|
|
||||||
+ $"The program source and other information can be found on [GitHub]({repository}).");
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CustomForm(IWin32Window owner) : this()
|
internal CustomForm(IWin32Window owner) : this()
|
||||||
{
|
{
|
||||||
if (owner is Form form)
|
if (owner is Form form)
|
||||||
|
@ -73,27 +41,6 @@ internal class CustomForm : Form
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnActivation(object sender, EventArgs args) => Activate();
|
|
||||||
|
|
||||||
internal static readonly IntPtr HWND_NOTOPMOST = new(-2);
|
|
||||||
internal static readonly IntPtr HWND_TOPMOST = new(-1);
|
|
||||||
internal const short SWP_NOACTIVATE = 0x0010;
|
|
||||||
internal const short SWP_SHOWWINDOW = 0x0040;
|
|
||||||
internal const short SWP_NOMOVE = 0x0002;
|
|
||||||
internal const short SWP_NOSIZE = 0x0001;
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
||||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
|
||||||
internal static extern void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
|
|
||||||
|
|
||||||
internal void BringToFrontWithoutActivation()
|
|
||||||
{
|
|
||||||
bool topMost = TopMost;
|
|
||||||
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
||||||
if (!topMost)
|
|
||||||
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CreateParams CreateParams // Double buffering for all controls
|
protected override CreateParams CreateParams // Double buffering for all controls
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -104,13 +51,69 @@ internal class CustomForm : Form
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void OnHelpButtonClicked(object sender, EventArgs args)
|
||||||
|
{
|
||||||
|
using DialogForm helpDialog = new(this);
|
||||||
|
helpDialog.HelpButton = false;
|
||||||
|
string acidicoala = "https://github.com/acidicoala";
|
||||||
|
string repository = $"https://github.com/{Program.RepositoryOwner}/{Program.RepositoryName}";
|
||||||
|
_ = helpDialog.Show(SystemIcons.Information,
|
||||||
|
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
|
||||||
|
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
|
||||||
|
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ $"The program utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [SmokeAPI]({acidicoala}/SmokeAPI), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1 Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by\n"
|
||||||
|
+ $"the wonderful [acidicoala]({acidicoala}), and all downloaded and embedded into the program itself; no further downloads necessary on your part!\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "NOTE: This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's\n"
|
||||||
|
+ "only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many\n"
|
||||||
|
+ "do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for\n"
|
||||||
|
+ "the game(s) you're tinkering with; you'll usually find any answer to your problems there.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "USAGE:\n"
|
||||||
|
+ " 1. Choose which programs and/or games the program should scan for DLC.\n"
|
||||||
|
+ " The program automatically gathers all installed games from Steam, Epic and Ubisoft directories.\n"
|
||||||
|
+ " 2. Wait for the program to download and install SteamCMD (if you chose a Steam game).\n"
|
||||||
|
+ " 3. Wait for the program to gather and cache the chosen games' information && DLCs.\n"
|
||||||
|
+ " May take some time on the first run; depends on how many DLCs the games you chose have.\n"
|
||||||
|
+ " 4. CAREFULLY select which games' DLCs you wish to unlock.\n"
|
||||||
|
+ " Obviously none of the DLC unlockers are tested for every single game!\n"
|
||||||
|
+ " 5. Choose whether or not to install with Koaloader, and if so then also pick the proxy DLL to use.\n"
|
||||||
|
+ " If the default \'version.dll\' doesn't work, then see [here](https://cs.rin.ru/forum/viewtopic.php?p=2552172#p2552172) to find one that does.\n"
|
||||||
|
+ " 6. Click the \"Generate and Install\" button.\n"
|
||||||
|
+ " 7. Click the \"OK\" button to close the program.\n"
|
||||||
|
+ " 8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back\n"
|
||||||
|
+ " to step 5 and select what games you wish you revert changes to, and instead click the \"Uninstall\" button this time.\n"
|
||||||
|
+ "\n"
|
||||||
|
+ $"For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues]({repository}/issues) page!\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "SteamCMD installation and appinfo cache can be found at [C:\\ProgramData\\CreamInstaller]().\n"
|
||||||
|
+ $"The program automatically and very quickly updates from [GitHub]({repository}) using [Onova](https://github.com/Tyrrrz/Onova). (updates can be ignored)\n"
|
||||||
|
+ $"The program source and other information can be found on [GitHub]({repository}).");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void OnActivation(object sender, EventArgs args) => Activate();
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||||
|
internal static extern void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy,
|
||||||
|
uint uFlags);
|
||||||
|
|
||||||
|
internal void BringToFrontWithoutActivation()
|
||||||
|
{
|
||||||
|
bool topMost = TopMost;
|
||||||
|
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
||||||
|
if (!topMost)
|
||||||
|
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
internal void InheritLocation(Form fromForm)
|
internal void InheritLocation(Form fromForm)
|
||||||
{
|
{
|
||||||
if (fromForm is null)
|
if (fromForm is null)
|
||||||
return;
|
return;
|
||||||
int X = fromForm.Location.X + fromForm.Size.Width / 2 - Size.Width / 2;
|
int X = fromForm.Location.X + fromForm.Size.Width / 2 - Size.Width / 2;
|
||||||
int Y = fromForm.Location.Y + fromForm.Size.Height / 2 - Size.Height / 2;
|
int Y = fromForm.Location.Y + fromForm.Size.Height / 2 - Size.Height / 2;
|
||||||
Location = new(X, Y);
|
Location = new Point(X, Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeyPress(object s, KeyPressEventArgs e)
|
private void OnKeyPress(object s, KeyPressEventArgs e)
|
||||||
|
@ -124,7 +127,8 @@ internal class CustomForm : Form
|
||||||
using EncoderParameters encoding = new(1);
|
using EncoderParameters encoding = new(1);
|
||||||
using EncoderParameter encoderParam = new(Encoder.Quality, 100L);
|
using EncoderParameter encoderParam = new(Encoder.Quality, 100L);
|
||||||
encoding.Param[0] = encoderParam;
|
encoding.Param[0] = encoderParam;
|
||||||
graphics.CopyFromScreen(new(bounds.Left + 7, bounds.Top), Point.Empty, new(Size.Width - 14, Size.Height - 7));
|
graphics.CopyFromScreen(new Point(bounds.Left + 7, bounds.Top), Point.Empty,
|
||||||
|
new Size(Size.Width - 14, Size.Height - 7));
|
||||||
Clipboard.SetImage(bitmap);
|
Clipboard.SetImage(bitmap);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
using CreamInstaller.Resources;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Forms.VisualStyles;
|
using System.Windows.Forms.VisualStyles;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
using TreeView = System.Windows.Forms.TreeView;
|
|
||||||
|
|
||||||
namespace CreamInstaller.Components;
|
namespace CreamInstaller.Components;
|
||||||
|
|
||||||
internal class CustomTreeView : TreeView
|
internal class CustomTreeView : TreeView
|
||||||
{
|
{
|
||||||
private Form form;
|
private const string koaloaderToggleString = "Koaloader";
|
||||||
|
private readonly Dictionary<ProgramSelection, Rectangle> checkBoxBounds = new();
|
||||||
|
private readonly Dictionary<ProgramSelection, Rectangle> comboBoxBounds = new();
|
||||||
|
|
||||||
|
private readonly Dictionary<TreeNode, Rectangle> selectionBounds = new();
|
||||||
private SolidBrush backBrush;
|
private SolidBrush backBrush;
|
||||||
private Font comboBoxFont;
|
|
||||||
private ToolStripDropDown comboBoxDropDown;
|
private ToolStripDropDown comboBoxDropDown;
|
||||||
|
private Font comboBoxFont;
|
||||||
|
private Form form;
|
||||||
|
|
||||||
|
internal CustomTreeView()
|
||||||
|
{
|
||||||
|
DrawMode = TreeViewDrawMode.OwnerDrawText;
|
||||||
|
DrawNode += DrawTreeNode;
|
||||||
|
TreeViewNodeSorter = PlatformIdComparer.NodeName;
|
||||||
|
Disposed += OnDisposed;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void WndProc(ref Message m)
|
protected override void WndProc(ref Message m)
|
||||||
{
|
{
|
||||||
|
@ -30,14 +40,6 @@ internal class CustomTreeView : TreeView
|
||||||
form = FindForm();
|
form = FindForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CustomTreeView() : base()
|
|
||||||
{
|
|
||||||
DrawMode = TreeViewDrawMode.OwnerDrawText;
|
|
||||||
DrawNode += new DrawTreeNodeEventHandler(DrawTreeNode);
|
|
||||||
TreeViewNodeSorter = PlatformIdComparer.NodeName;
|
|
||||||
Disposed += OnDisposed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisposed(object sender, EventArgs e)
|
private void OnDisposed(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
backBrush?.Dispose();
|
backBrush?.Dispose();
|
||||||
|
@ -48,72 +50,68 @@ internal class CustomTreeView : TreeView
|
||||||
comboBoxDropDown = null;
|
comboBoxDropDown = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<TreeNode, Rectangle> selectionBounds = new();
|
|
||||||
private readonly Dictionary<ProgramSelection, Rectangle> checkBoxBounds = new();
|
|
||||||
private readonly Dictionary<ProgramSelection, Rectangle> comboBoxBounds = new();
|
|
||||||
private const string koaloaderToggleString = "Koaloader";
|
|
||||||
|
|
||||||
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
|
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
|
||||||
{
|
{
|
||||||
e.DrawDefault = true;
|
e.DrawDefault = true;
|
||||||
TreeNode node = e.Node;
|
TreeNode node = e.Node;
|
||||||
if (!node.IsVisible)
|
if (!node.IsVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool highlighted = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected && Focused;
|
bool highlighted = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected && Focused;
|
||||||
|
|
||||||
Graphics graphics = e.Graphics;
|
Graphics graphics = e.Graphics;
|
||||||
backBrush ??= new(BackColor);
|
backBrush ??= new SolidBrush(BackColor);
|
||||||
Font font = node.NodeFont ?? Font;
|
Font font = node.NodeFont ?? Font;
|
||||||
|
|
||||||
Brush brush = highlighted ? SystemBrushes.Highlight : backBrush;
|
Brush brush = highlighted ? SystemBrushes.Highlight : backBrush;
|
||||||
string text;// = e.Node.Text;
|
string text; // = e.Node.Text;
|
||||||
Size size;
|
Size size;
|
||||||
Rectangle bounds = node.Bounds;
|
Rectangle bounds = node.Bounds;
|
||||||
Rectangle selectionBounds = bounds;
|
Rectangle selectionBounds = bounds;
|
||||||
Color color;// = highlighted ? SystemColors.HighlightText : (node.ForeColor != Color.Empty) ? node.ForeColor : node.TreeView.ForeColor;
|
Color
|
||||||
|
color; // = highlighted ? SystemColors.HighlightText : (node.ForeColor != Color.Empty) ? node.ForeColor : node.TreeView.ForeColor;
|
||||||
Point point;
|
Point point;
|
||||||
|
|
||||||
/*Size textSize = TextRenderer.MeasureText(text, font);
|
/*Size textSize = TextRenderer.MeasureText(text, font);
|
||||||
Point textLoc = new(bounds.X - 1, bounds.Y);
|
Point textLoc = new(bounds.X - 1, bounds.Y);
|
||||||
bounds = new Rectangle(textLoc, new Size(textSize.Width, bounds.Height));
|
bounds = new Rectangle(textLoc, new Size(textSize.Width, bounds.Height));
|
||||||
graphics.FillRectangle(brush, bounds);
|
graphics.FillRectangle(brush, bounds);
|
||||||
TextRenderer.DrawText(graphics, text, font, bounds, color, TextFormatFlags.Default);*/
|
TextRenderer.DrawText(graphics, text, font, bounds, color, TextFormatFlags.Default);*/
|
||||||
|
|
||||||
Form form = FindForm();
|
Form form = FindForm();
|
||||||
if (form is not SelectForm and not SelectDialogForm)
|
if (form is not SelectForm and not SelectDialogForm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string platformId = node.Name;
|
string platformId = node.Name;
|
||||||
Platform platform = (node.Tag as Platform?).GetValueOrDefault(Platform.None);
|
Platform platform = (node.Tag as Platform?).GetValueOrDefault(Platform.None);
|
||||||
if (string.IsNullOrWhiteSpace(platformId) || platform is Platform.None)
|
if (string.IsNullOrWhiteSpace(platformId) || platform is Platform.None)
|
||||||
return;
|
return;
|
||||||
|
color = highlighted
|
||||||
color = highlighted ? ColorTranslator.FromHtml("#FFFF99") : Enabled ? ColorTranslator.FromHtml("#696900") : ColorTranslator.FromHtml("#AAAA69");
|
? ColorTranslator.FromHtml("#FFFF99")
|
||||||
|
: Enabled
|
||||||
|
? ColorTranslator.FromHtml("#696900")
|
||||||
|
: ColorTranslator.FromHtml("#AAAA69");
|
||||||
text = platform.ToString();
|
text = platform.ToString();
|
||||||
size = TextRenderer.MeasureText(graphics, text, font);
|
size = TextRenderer.MeasureText(graphics, text, font);
|
||||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
selectionBounds
|
||||||
|
= new Rectangle(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||||
graphics.FillRectangle(brush, bounds);
|
graphics.FillRectangle(brush, bounds);
|
||||||
point = new(bounds.Location.X - 1, bounds.Location.Y + 1);
|
point = new Point(bounds.Location.X - 1, bounds.Location.Y + 1);
|
||||||
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
|
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
|
||||||
|
|
||||||
if (platform is not Platform.Paradox)
|
if (platform is not Platform.Paradox)
|
||||||
{
|
{
|
||||||
color = highlighted ? ColorTranslator.FromHtml("#99FFFF") : Enabled ? ColorTranslator.FromHtml("#006969") : ColorTranslator.FromHtml("#69AAAA");
|
color = highlighted
|
||||||
text = platformId.ToString();
|
? ColorTranslator.FromHtml("#99FFFF")
|
||||||
|
: Enabled
|
||||||
|
? ColorTranslator.FromHtml("#006969")
|
||||||
|
: ColorTranslator.FromHtml("#69AAAA");
|
||||||
|
text = platformId;
|
||||||
size = TextRenderer.MeasureText(graphics, text, font);
|
size = TextRenderer.MeasureText(graphics, text, font);
|
||||||
int left = -4;
|
int left = -4;
|
||||||
bounds = new(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||||
|
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||||
graphics.FillRectangle(brush, bounds);
|
graphics.FillRectangle(brush, bounds);
|
||||||
point = new(bounds.Location.X - 1, bounds.Location.Y + 1);
|
point = new Point(bounds.Location.X - 1, bounds.Location.Y + 1);
|
||||||
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
|
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (highlighted)
|
/*if (highlighted)
|
||||||
ControlPaint.DrawFocusRectangle(graphics, selectionBounds, color, SystemColors.Highlight);*/
|
ControlPaint.DrawFocusRectangle(graphics, selectionBounds, color, SystemColors.Highlight);*/
|
||||||
|
|
||||||
if (form is SelectForm)
|
if (form is SelectForm)
|
||||||
{
|
{
|
||||||
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, platformId);
|
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, platformId);
|
||||||
|
@ -121,64 +119,71 @@ internal class CustomTreeView : TreeView
|
||||||
{
|
{
|
||||||
if (bounds == node.Bounds)
|
if (bounds == node.Bounds)
|
||||||
{
|
{
|
||||||
size = new(4, 0);
|
size = new Size(4, 0);
|
||||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||||
graphics.FillRectangle(brush, bounds);
|
graphics.FillRectangle(brush, bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBoxState checkBoxState = selection.Koaloader
|
CheckBoxState checkBoxState = selection.Koaloader
|
||||||
? Enabled ? CheckBoxState.CheckedPressed : CheckBoxState.CheckedDisabled
|
? Enabled ? CheckBoxState.CheckedPressed : CheckBoxState.CheckedDisabled
|
||||||
: Enabled ? CheckBoxState.UncheckedPressed : CheckBoxState.UncheckedDisabled;
|
: Enabled
|
||||||
|
? CheckBoxState.UncheckedPressed
|
||||||
|
: CheckBoxState.UncheckedDisabled;
|
||||||
size = CheckBoxRenderer.GetGlyphSize(graphics, checkBoxState);
|
size = CheckBoxRenderer.GetGlyphSize(graphics, checkBoxState);
|
||||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||||
|
selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||||
Rectangle checkBoxBounds = bounds;
|
Rectangle checkBoxBounds = bounds;
|
||||||
graphics.FillRectangle(backBrush, bounds);
|
graphics.FillRectangle(backBrush, bounds);
|
||||||
point = new(bounds.Left, bounds.Top + bounds.Height / 2 - size.Height / 2 - 1);
|
point = new Point(bounds.Left, bounds.Top + bounds.Height / 2 - size.Height / 2 - 1);
|
||||||
CheckBoxRenderer.DrawCheckBox(graphics, point, checkBoxState);
|
CheckBoxRenderer.DrawCheckBox(graphics, point, checkBoxState);
|
||||||
|
|
||||||
text = koaloaderToggleString;
|
text = koaloaderToggleString;
|
||||||
size = TextRenderer.MeasureText(graphics, text, font);
|
size = TextRenderer.MeasureText(graphics, text, font);
|
||||||
int left = 1;
|
int left = 1;
|
||||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width + left, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width + left, bounds.Height);
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||||
checkBoxBounds = new(checkBoxBounds.Location, checkBoxBounds.Size + new Size(bounds.Size.Width, 0));
|
selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||||
|
checkBoxBounds = new Rectangle(checkBoxBounds.Location,
|
||||||
|
checkBoxBounds.Size + new Size(bounds.Size.Width, 0));
|
||||||
graphics.FillRectangle(backBrush, bounds);
|
graphics.FillRectangle(backBrush, bounds);
|
||||||
point = new(bounds.Location.X - 1 + left, bounds.Location.Y + 1);
|
point = new Point(bounds.Location.X - 1 + left, bounds.Location.Y + 1);
|
||||||
TextRenderer.DrawText(graphics, text, font, point,
|
TextRenderer.DrawText(graphics, text, font, point,
|
||||||
Enabled ? ColorTranslator.FromHtml("#006900") : ColorTranslator.FromHtml("#69AA69"),
|
Enabled
|
||||||
TextFormatFlags.Default);
|
? ColorTranslator.FromHtml("#006900")
|
||||||
|
: ColorTranslator.FromHtml("#69AA69"),
|
||||||
|
TextFormatFlags.Default);
|
||||||
this.checkBoxBounds[selection] = RectangleToClient(checkBoxBounds);
|
this.checkBoxBounds[selection] = RectangleToClient(checkBoxBounds);
|
||||||
|
|
||||||
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
||||||
if (selection.Koaloader && proxy is not null)
|
if (selection.Koaloader && proxy is not null)
|
||||||
{
|
{
|
||||||
comboBoxFont ??= new(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet, font.GdiVerticalFont);
|
comboBoxFont ??= new Font(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet,
|
||||||
|
font.GdiVerticalFont);
|
||||||
ComboBoxState comboBoxState = Enabled ? ComboBoxState.Normal : ComboBoxState.Disabled;
|
ComboBoxState comboBoxState = Enabled ? ComboBoxState.Normal : ComboBoxState.Disabled;
|
||||||
|
|
||||||
text = proxy + ".dll";
|
text = proxy + ".dll";
|
||||||
size = TextRenderer.MeasureText(graphics, text, comboBoxFont) + new Size(6, 0);
|
size = TextRenderer.MeasureText(graphics, text, comboBoxFont) + new Size(6, 0);
|
||||||
int padding = 2;
|
int padding = 2;
|
||||||
bounds = new(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width, bounds.Height - padding);
|
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width,
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
bounds.Height - padding);
|
||||||
|
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||||
|
selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||||
Rectangle comboBoxBounds = bounds;
|
Rectangle comboBoxBounds = bounds;
|
||||||
graphics.FillRectangle(backBrush, bounds);
|
graphics.FillRectangle(backBrush, bounds);
|
||||||
ComboBoxRenderer.DrawTextBox(graphics, bounds, text, comboBoxFont, comboBoxState);
|
ComboBoxRenderer.DrawTextBox(graphics, bounds, text, comboBoxFont, comboBoxState);
|
||||||
|
size = new Size(14, 0);
|
||||||
size = new(14, 0);
|
|
||||||
left = -1;
|
left = -1;
|
||||||
bounds = new(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
bounds = new Rectangle(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||||
comboBoxBounds = new(comboBoxBounds.Location, comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
|
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||||
|
comboBoxBounds = new Rectangle(comboBoxBounds.Location,
|
||||||
|
comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||||
ComboBoxRenderer.DrawDropDownButton(graphics, bounds, comboBoxState);
|
ComboBoxRenderer.DrawDropDownButton(graphics, bounds, comboBoxState);
|
||||||
|
|
||||||
this.comboBoxBounds[selection] = RectangleToClient(comboBoxBounds);
|
this.comboBoxBounds[selection] = RectangleToClient(comboBoxBounds);
|
||||||
}
|
}
|
||||||
else _ = comboBoxBounds.Remove(selection);
|
else
|
||||||
|
{
|
||||||
|
_ = comboBoxBounds.Remove(selection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectionBounds[node] = RectangleToClient(selectionBounds);
|
this.selectionBounds[node] = RectangleToClient(selectionBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,9 +194,10 @@ internal class CustomTreeView : TreeView
|
||||||
Point clickPoint = PointToClient(e.Location);
|
Point clickPoint = PointToClient(e.Location);
|
||||||
SelectForm selectForm = (form ??= FindForm()) as SelectForm;
|
SelectForm selectForm = (form ??= FindForm()) as SelectForm;
|
||||||
foreach (KeyValuePair<TreeNode, Rectangle> pair in selectionBounds.ToList())
|
foreach (KeyValuePair<TreeNode, Rectangle> pair in selectionBounds.ToList())
|
||||||
{
|
|
||||||
if (pair.Key.TreeView is null)
|
if (pair.Key.TreeView is null)
|
||||||
|
{
|
||||||
_ = selectionBounds.Remove(pair.Key);
|
_ = selectionBounds.Remove(pair.Key);
|
||||||
|
}
|
||||||
else if (pair.Key.IsVisible && pair.Value.Contains(clickPoint))
|
else if (pair.Key.IsVisible && pair.Value.Contains(clickPoint))
|
||||||
{
|
{
|
||||||
SelectedNode = pair.Key;
|
SelectedNode = pair.Key;
|
||||||
|
@ -199,23 +205,24 @@ internal class CustomTreeView : TreeView
|
||||||
selectForm.OnNodeRightClick(pair.Key, e.Location);
|
selectForm.OnNodeRightClick(pair.Key, e.Location);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (e.Button is MouseButtons.Left)
|
if (e.Button is MouseButtons.Left)
|
||||||
{
|
{
|
||||||
if (comboBoxBounds.Any() && selectForm is not null)
|
if (comboBoxBounds.Any() && selectForm is not null)
|
||||||
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in comboBoxBounds.ToList())
|
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in comboBoxBounds.ToList())
|
||||||
{
|
|
||||||
if (!ProgramSelection.All.Contains(pair.Key))
|
if (!ProgramSelection.All.Contains(pair.Key))
|
||||||
|
{
|
||||||
_ = comboBoxBounds.Remove(pair.Key);
|
_ = comboBoxBounds.Remove(pair.Key);
|
||||||
|
}
|
||||||
else if (pair.Value.Contains(clickPoint))
|
else if (pair.Value.Contains(clickPoint))
|
||||||
{
|
{
|
||||||
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))
|
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))
|
||||||
.Select(p =>
|
.Select(p =>
|
||||||
{
|
{
|
||||||
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
|
p.GetProxyInfoFromIdentifier(
|
||||||
return proxyName;
|
out string proxyName, out _);
|
||||||
}).Distinct().ToList();
|
return proxyName;
|
||||||
comboBoxDropDown ??= new();
|
}).Distinct().ToList();
|
||||||
|
comboBoxDropDown ??= new ToolStripDropDown();
|
||||||
comboBoxDropDown.ShowItemToolTips = false;
|
comboBoxDropDown.ShowItemToolTips = false;
|
||||||
comboBoxDropDown.Items.Clear();
|
comboBoxDropDown.Items.Clear();
|
||||||
foreach (string proxy in proxies)
|
foreach (string proxy in proxies)
|
||||||
|
@ -233,26 +240,25 @@ internal class CustomTreeView : TreeView
|
||||||
if (canUse)
|
if (canUse)
|
||||||
_ = comboBoxDropDown.Items.Add(new ToolStripButton(proxy + ".dll", null, (s, e) =>
|
_ = comboBoxDropDown.Items.Add(new ToolStripButton(proxy + ".dll", null, (s, e) =>
|
||||||
{
|
{
|
||||||
pair.Key.KoaloaderProxy = proxy == ProgramSelection.DefaultKoaloaderProxy ? null : proxy;
|
pair.Key.KoaloaderProxy
|
||||||
|
= proxy == ProgramSelection.DefaultKoaloaderProxy ? null : proxy;
|
||||||
selectForm.OnKoaloaderChanged();
|
selectForm.OnKoaloaderChanged();
|
||||||
})
|
}) { Font = comboBoxFont });
|
||||||
{ Font = comboBoxFont });
|
|
||||||
}
|
}
|
||||||
comboBoxDropDown.Show(this, PointToScreen(new(pair.Value.Left, pair.Value.Bottom - 1)));
|
comboBoxDropDown.Show(this, PointToScreen(new Point(pair.Value.Left, pair.Value.Bottom - 1)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in checkBoxBounds.ToList())
|
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in checkBoxBounds.ToList())
|
||||||
{
|
|
||||||
if (!ProgramSelection.All.Contains(pair.Key))
|
if (!ProgramSelection.All.Contains(pair.Key))
|
||||||
|
{
|
||||||
_ = checkBoxBounds.Remove(pair.Key);
|
_ = checkBoxBounds.Remove(pair.Key);
|
||||||
|
}
|
||||||
else if (pair.Value.Contains(clickPoint))
|
else if (pair.Value.Contains(clickPoint))
|
||||||
{
|
{
|
||||||
pair.Key.Koaloader = !pair.Key.Koaloader;
|
pair.Key.Koaloader = !pair.Key.Koaloader;
|
||||||
selectForm.OnKoaloaderChanged();
|
selectForm.OnKoaloaderChanged();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,45 +8,68 @@ namespace CreamInstaller.Components;
|
||||||
internal static class PlatformIdComparer
|
internal static class PlatformIdComparer
|
||||||
{
|
{
|
||||||
private static StringComparer stringComparer;
|
private static StringComparer stringComparer;
|
||||||
internal static StringComparer String => stringComparer ??= new();
|
internal static StringComparer String => stringComparer ??= new StringComparer();
|
||||||
|
|
||||||
private static NodeComparer nodeComparer;
|
private static NodeComparer nodeComparer;
|
||||||
internal static NodeComparer Node => nodeComparer ??= new();
|
internal static NodeComparer Node => nodeComparer ??= new NodeComparer();
|
||||||
|
|
||||||
private static NodeNameComparer nodeNameComparer;
|
private static NodeNameComparer nodeNameComparer;
|
||||||
internal static NodeNameComparer NodeName => nodeNameComparer ??= new();
|
internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer();
|
||||||
|
|
||||||
private static NodeTextComparer nodeTextComparer;
|
private static NodeTextComparer nodeTextComparer;
|
||||||
internal static NodeTextComparer NodeText => nodeTextComparer ??= new();
|
internal static NodeTextComparer NodeText => nodeTextComparer ??= new NodeTextComparer();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class StringComparer : IComparer<string>
|
internal class StringComparer : IComparer<string>
|
||||||
{
|
{
|
||||||
public int Compare(string a, string b) =>
|
public int Compare(string a, string b) =>
|
||||||
!int.TryParse(a, out _) && !int.TryParse(b, out _) ? string.Compare(a, b, StringComparison.Ordinal)
|
!int.TryParse(a, out _) && !int.TryParse(b, out _)
|
||||||
: !int.TryParse(a, out int A) ? 1 : !int.TryParse(b, out int B) ? -1
|
? string.Compare(a, b, StringComparison.Ordinal)
|
||||||
: A > B ? 1 : A < B ? -1 : 0;
|
: !int.TryParse(a, out int A)
|
||||||
|
? 1
|
||||||
|
: !int.TryParse(b, out int B)
|
||||||
|
? -1
|
||||||
|
: A > B
|
||||||
|
? 1
|
||||||
|
: A < B
|
||||||
|
? -1
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NodeComparer : IComparer<TreeNode>
|
internal class NodeComparer : IComparer<TreeNode>
|
||||||
{
|
{
|
||||||
public int Compare(TreeNode a, TreeNode b) =>
|
public int Compare(TreeNode a, TreeNode b) =>
|
||||||
a.Tag is not Platform A ? 1 : b.Tag is not Platform B ? -1
|
a.Tag is not Platform A
|
||||||
: A > B ? 1 : A < B ? -1 : 0;
|
? 1
|
||||||
|
: b.Tag is not Platform B
|
||||||
|
? -1
|
||||||
|
: A > B
|
||||||
|
? 1
|
||||||
|
: A < B
|
||||||
|
? -1
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NodeNameComparer : IComparer
|
internal class NodeNameComparer : IComparer
|
||||||
{
|
{
|
||||||
public int Compare(object a, object b) =>
|
public int Compare(object a, object b) =>
|
||||||
a is not TreeNode A ? 1 : b is not TreeNode B ? -1
|
a is not TreeNode A
|
||||||
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0 ? c
|
? 1
|
||||||
: PlatformIdComparer.String.Compare(A.Name, B.Name);
|
: b is not TreeNode B
|
||||||
|
? -1
|
||||||
|
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0
|
||||||
|
? c
|
||||||
|
: PlatformIdComparer.String.Compare(A.Name, B.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NodeTextComparer : IComparer
|
internal class NodeTextComparer : IComparer
|
||||||
{
|
{
|
||||||
public int Compare(object a, object b) =>
|
public int Compare(object a, object b) =>
|
||||||
a is not TreeNode A ? 1 : b is not TreeNode B ? -1
|
a is not TreeNode A
|
||||||
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0 ? c
|
? 1
|
||||||
: PlatformIdComparer.String.Compare(A.Text, B.Text);
|
: b is not TreeNode B
|
||||||
|
? -1
|
||||||
|
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0
|
||||||
|
? c
|
||||||
|
: PlatformIdComparer.String.Compare(A.Text, B.Text);
|
||||||
}
|
}
|
|
@ -1,17 +1,16 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net6.0-windows10.0.22621.0</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||||
<Version>4.2.3.1</Version>
|
<Version>4.3.0.0</Version>
|
||||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||||
<Company>CreamInstaller</Company>
|
<Company>CreamInstaller</Company>
|
||||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||||
<StartupObject>CreamInstaller.Program</StartupObject>
|
<StartupObject>CreamInstaller.Program</StartupObject>
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
<AnalysisLevel>latest-all</AnalysisLevel>
|
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||||
|
@ -27,6 +26,12 @@
|
||||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
<AssemblyName>$(Company)-debug</AssemblyName>
|
<AssemblyName>$(Company)-debug</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Resources\Koaloader\audioses-32\audioses.dll" />
|
<None Remove="Resources\Koaloader\audioses-32\audioses.dll" />
|
||||||
<None Remove="Resources\Koaloader\audioses-64\audioses.dll" />
|
<None Remove="Resources\Koaloader\audioses-64\audioses.dll" />
|
||||||
|
@ -137,10 +142,10 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.45" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||||
<PackageReference Include="Onova" Version="2.6.2" />
|
<PackageReference Include="Onova" Version="2.6.3" />
|
||||||
<PackageReference Include="System.Reflection.Metadata" Version="6.0.1" />
|
<PackageReference Include="System.Reflection.Metadata" Version="7.0.0" />
|
||||||
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.0" />
|
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
9
CreamInstaller/Forms/DebugForm.Designer.cs
generated
9
CreamInstaller/Forms/DebugForm.Designer.cs
generated
|
@ -1,11 +1,14 @@
|
||||||
namespace CreamInstaller;
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
partial class DebugForm
|
partial class DebugForm
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private System.ComponentModel.IContainer components = null;
|
private IContainer components = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clean up any resources being used.
|
/// Clean up any resources being used.
|
||||||
|
@ -65,5 +68,5 @@ partial class DebugForm
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private System.Windows.Forms.RichTextBox debugTextBox;
|
private RichTextBox debugTextBox;
|
||||||
}
|
}
|
|
@ -1,32 +1,34 @@
|
||||||
using CreamInstaller.Components;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class DebugForm : CustomForm
|
internal partial class DebugForm : CustomForm
|
||||||
{
|
{
|
||||||
internal static DebugForm current;
|
internal static DebugForm current;
|
||||||
|
|
||||||
|
private Form attachedForm;
|
||||||
|
|
||||||
|
internal DebugForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
debugTextBox.BackColor = LogTextBox.Background;
|
||||||
|
}
|
||||||
|
|
||||||
internal static DebugForm Current
|
internal static DebugForm Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (current is not null && (current.Disposing || current.IsDisposed))
|
if (current is not null && (current.Disposing || current.IsDisposed))
|
||||||
current = null;
|
current = null;
|
||||||
return current ??= new();
|
return current ??= new DebugForm();
|
||||||
}
|
}
|
||||||
set => current = value;
|
set => current = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DebugForm() : base()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
debugTextBox.BackColor = LogTextBox.Background;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message message) // make form immovable by user
|
protected override void WndProc(ref Message message) // make form immovable by user
|
||||||
{
|
{
|
||||||
if (message.Msg == 0x0112) // WM_SYSCOMMAND
|
if (message.Msg == 0x0112) // WM_SYSCOMMAND
|
||||||
|
@ -38,8 +40,6 @@ internal partial class DebugForm : CustomForm
|
||||||
base.WndProc(ref message);
|
base.WndProc(ref message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Form attachedForm;
|
|
||||||
|
|
||||||
internal void Attach(Form form)
|
internal void Attach(Form form)
|
||||||
{
|
{
|
||||||
if (attachedForm is not null)
|
if (attachedForm is not null)
|
||||||
|
@ -64,7 +64,7 @@ internal partial class DebugForm : CustomForm
|
||||||
if (attachedForm is not null && attachedForm.Visible)
|
if (attachedForm is not null && attachedForm.Visible)
|
||||||
{
|
{
|
||||||
//Size = new(Size.Width, attachedForm.Size.Height);
|
//Size = new(Size.Width, attachedForm.Size.Height);
|
||||||
Location = new(attachedForm.Right, attachedForm.Top);
|
Location = new Point(attachedForm.Right, attachedForm.Top);
|
||||||
BringToFrontWithoutActivation();
|
BringToFrontWithoutActivation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,13 +74,11 @@ internal partial class DebugForm : CustomForm
|
||||||
internal void Log(string text, Color color)
|
internal void Log(string text, Color color)
|
||||||
{
|
{
|
||||||
if (!debugTextBox.Disposing && !debugTextBox.IsDisposed)
|
if (!debugTextBox.Disposing && !debugTextBox.IsDisposed)
|
||||||
{
|
|
||||||
debugTextBox.Invoke(() =>
|
debugTextBox.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (debugTextBox.Text.Length > 0)
|
if (debugTextBox.Text.Length > 0)
|
||||||
debugTextBox.AppendText(Environment.NewLine, color, scroll: true);
|
debugTextBox.AppendText(Environment.NewLine, color, true);
|
||||||
debugTextBox.AppendText(text, color, scroll: true);
|
debugTextBox.AppendText(text, color, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
CreamInstaller/Forms/DialogForm.Designer.cs
generated
5
CreamInstaller/Forms/DialogForm.Designer.cs
generated
|
@ -1,8 +1,7 @@
|
||||||
|
using System.ComponentModel;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller
|
namespace CreamInstaller.Forms
|
||||||
{
|
{
|
||||||
partial class DialogForm
|
partial class DialogForm
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,31 +1,30 @@
|
||||||
using CreamInstaller.Components;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class DialogForm : CustomForm
|
internal partial class DialogForm : CustomForm
|
||||||
{
|
{
|
||||||
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
||||||
|
|
||||||
internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText = "OK", string cancelButtonText = null, string customFormText = null, Icon customFormIcon = null)
|
internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText = "OK",
|
||||||
|
string cancelButtonText = null, string customFormText = null, Icon customFormIcon = null)
|
||||||
{
|
{
|
||||||
descriptionIcon ??= Icon;
|
descriptionIcon ??= Icon;
|
||||||
icon.Image = descriptionIcon.ToBitmap();
|
icon.Image = descriptionIcon.ToBitmap();
|
||||||
List<LinkLabel.Link> links = new();
|
List<LinkLabel.Link> links = new();
|
||||||
for (int i = 0; i < descriptionText.Length; i++)
|
for (int i = 0; i < descriptionText.Length; i++)
|
||||||
{
|
|
||||||
if (descriptionText[i] == '[')
|
if (descriptionText[i] == '[')
|
||||||
{
|
{
|
||||||
int textLeft = descriptionText.IndexOf("[", i);
|
int textLeft = descriptionText.IndexOf("[", i, StringComparison.Ordinal);
|
||||||
int textRight = descriptionText.IndexOf("]", textLeft == -1 ? i : textLeft);
|
int textRight = descriptionText.IndexOf("]", textLeft == -1 ? i : textLeft, StringComparison.Ordinal);
|
||||||
int linkLeft = descriptionText.IndexOf("(", textRight == -1 ? i : textRight);
|
int linkLeft = descriptionText.IndexOf("(", textRight == -1 ? i : textRight, StringComparison.Ordinal);
|
||||||
int linkRight = descriptionText.IndexOf(")", linkLeft == -1 ? i : linkLeft);
|
int linkRight = descriptionText.IndexOf(")", linkLeft == -1 ? i : linkLeft, StringComparison.Ordinal);
|
||||||
if (textLeft != -1 && textRight == linkLeft - 1 && linkRight != -1)
|
if (textLeft != -1 && textRight == linkLeft - 1 && linkRight != -1)
|
||||||
{
|
{
|
||||||
string text = descriptionText[(textLeft + 1)..textRight];
|
string text = descriptionText[(textLeft + 1)..textRight];
|
||||||
|
@ -36,7 +35,6 @@ internal partial class DialogForm : CustomForm
|
||||||
links.Add(new LinkLabel.Link(i, text.Length, link));
|
links.Add(new LinkLabel.Link(i, text.Length, link));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
descriptionLabel.Text = descriptionText;
|
descriptionLabel.Text = descriptionText;
|
||||||
acceptButton.Text = acceptButtonText;
|
acceptButton.Text = acceptButtonText;
|
||||||
if (cancelButtonText is null)
|
if (cancelButtonText is null)
|
||||||
|
@ -44,9 +42,14 @@ internal partial class DialogForm : CustomForm
|
||||||
cancelButton.Enabled = false;
|
cancelButton.Enabled = false;
|
||||||
cancelButton.Visible = false;
|
cancelButton.Visible = false;
|
||||||
}
|
}
|
||||||
else cancelButton.Text = cancelButtonText;
|
else
|
||||||
|
{
|
||||||
|
cancelButton.Text = cancelButtonText;
|
||||||
|
}
|
||||||
if (customFormText is not null)
|
if (customFormText is not null)
|
||||||
|
{
|
||||||
Text = customFormText;
|
Text = customFormText;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnResize(null, null);
|
OnResize(null, null);
|
||||||
|
@ -58,7 +61,8 @@ internal partial class DialogForm : CustomForm
|
||||||
{
|
{
|
||||||
foreach (LinkLabel.Link link in links)
|
foreach (LinkLabel.Link link in links)
|
||||||
_ = descriptionLabel.Links.Add(link);
|
_ = descriptionLabel.Links.Add(link);
|
||||||
descriptionLabel.LinkClicked += (s, e) => Process.Start(new ProcessStartInfo((string)e.Link.LinkData) { UseShellExecute = true });
|
descriptionLabel.LinkClicked += (s, e)
|
||||||
|
=> Process.Start(new ProcessStartInfo((string)e.Link.LinkData) { UseShellExecute = true });
|
||||||
}
|
}
|
||||||
return ShowDialog();
|
return ShowDialog();
|
||||||
}
|
}
|
||||||
|
@ -66,7 +70,7 @@ internal partial class DialogForm : CustomForm
|
||||||
private void OnResize(object s, EventArgs e) =>
|
private void OnResize(object s, EventArgs e) =>
|
||||||
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
||||||
? TextRenderer.MeasureText(Program.ApplicationNameShort, Font).Width > Size.Width - 100
|
? TextRenderer.MeasureText(Program.ApplicationNameShort, Font).Width > Size.Width - 100
|
||||||
? Program.Name
|
? Program.Name
|
||||||
: Program.ApplicationNameShort
|
: Program.ApplicationNameShort
|
||||||
: Program.ApplicationName;
|
: Program.ApplicationName;
|
||||||
}
|
}
|
||||||
|
|
5
CreamInstaller/Forms/InstallForm.Designer.cs
generated
5
CreamInstaller/Forms/InstallForm.Designer.cs
generated
|
@ -1,8 +1,7 @@
|
||||||
|
using System.ComponentModel;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller
|
namespace CreamInstaller.Forms
|
||||||
{
|
{
|
||||||
partial class InstallForm
|
partial class InstallForm
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
using CreamInstaller.Components;
|
using System;
|
||||||
using CreamInstaller.Resources;
|
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
using static CreamInstaller.Platforms.Paradox.ParadoxLauncher;
|
using static CreamInstaller.Platforms.Paradox.ParadoxLauncher;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class InstallForm : CustomForm
|
internal partial class InstallForm : CustomForm
|
||||||
{
|
{
|
||||||
internal bool Reselecting;
|
private readonly List<ProgramSelection> DisabledSelections = new();
|
||||||
internal readonly bool Uninstalling;
|
|
||||||
|
|
||||||
internal InstallForm(bool uninstall = false) : base()
|
private readonly int ProgramCount = ProgramSelection.AllEnabled.Count;
|
||||||
|
internal readonly bool Uninstalling;
|
||||||
|
private int CompleteOperationsCount;
|
||||||
|
|
||||||
|
private int OperationsCount;
|
||||||
|
internal bool Reselecting;
|
||||||
|
|
||||||
|
internal InstallForm(bool uninstall = false)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Text = Program.ApplicationName;
|
Text = Program.ApplicationName;
|
||||||
|
@ -28,9 +32,6 @@ internal partial class InstallForm : CustomForm
|
||||||
Uninstalling = uninstall;
|
Uninstalling = uninstall;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int OperationsCount;
|
|
||||||
private int CompleteOperationsCount;
|
|
||||||
|
|
||||||
internal void UpdateProgress(int progress)
|
internal void UpdateProgress(int progress)
|
||||||
{
|
{
|
||||||
if (!userProgressBar.Disposing && !userProgressBar.IsDisposed)
|
if (!userProgressBar.Disposing && !userProgressBar.IsDisposed)
|
||||||
|
@ -46,14 +47,12 @@ internal partial class InstallForm : CustomForm
|
||||||
{
|
{
|
||||||
if (info) _ = userInfoLabel.Invoke(() => userInfoLabel.Text = text);
|
if (info) _ = userInfoLabel.Invoke(() => userInfoLabel.Text = text);
|
||||||
if (log && !logTextBox.Disposing && !logTextBox.IsDisposed)
|
if (log && !logTextBox.Disposing && !logTextBox.IsDisposed)
|
||||||
{
|
|
||||||
logTextBox.Invoke(() =>
|
logTextBox.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (logTextBox.Text.Length > 0) logTextBox.AppendText(Environment.NewLine, color);
|
if (logTextBox.Text.Length > 0) logTextBox.AppendText(Environment.NewLine, color);
|
||||||
logTextBox.AppendText(text, color);
|
logTextBox.AppendText(text, color);
|
||||||
logTextBox.Invalidate();
|
logTextBox.Invalidate();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OperateFor(ProgramSelection selection)
|
private async Task OperateFor(ProgramSelection selection)
|
||||||
|
@ -61,14 +60,16 @@ internal partial class InstallForm : CustomForm
|
||||||
UpdateProgress(0);
|
UpdateProgress(0);
|
||||||
if (selection.Id == "PL")
|
if (selection.Id == "PL")
|
||||||
{
|
{
|
||||||
UpdateUser($"Repairing Paradox Launcher . . . ", LogTextBox.Operation);
|
UpdateUser("Repairing Paradox Launcher . . . ", LogTextBox.Operation);
|
||||||
_ = await Repair(this, selection);
|
_ = await Repair(this, selection);
|
||||||
}
|
}
|
||||||
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")}" +
|
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")}" +
|
||||||
$" {(Uninstalling ? "from" : "for")} " + selection.Name + $" with root directory \"{selection.RootDirectory}\" . . . ", LogTextBox.Operation);
|
$" {(Uninstalling ? "from" : "for")} " + selection.Name
|
||||||
|
+ $" with root directory \"{selection.RootDirectory}\" . . . ", LogTextBox.Operation);
|
||||||
IEnumerable<string> invalidDirectories = (await selection.RootDirectory.GetExecutables())
|
IEnumerable<string> invalidDirectories = (await selection.RootDirectory.GetExecutables())
|
||||||
?.Where(d => !selection.ExecutableDirectories.Any(s => s.directory == Path.GetDirectoryName(d.path)))
|
?.Where(d => !selection.ExecutableDirectories.Any(
|
||||||
?.Select(d => Path.GetDirectoryName(d.path));
|
s => s.directory == Path.GetDirectoryName(d.path)))
|
||||||
|
?.Select(d => Path.GetDirectoryName(d.path));
|
||||||
if (!selection.ExecutableDirectories.Any(s => s.directory == selection.RootDirectory))
|
if (!selection.ExecutableDirectories.Any(s => s.directory == selection.RootDirectory))
|
||||||
invalidDirectories = invalidDirectories?.Append(selection.RootDirectory);
|
invalidDirectories = invalidDirectories?.Append(selection.RootDirectory);
|
||||||
invalidDirectories = invalidDirectories?.Distinct();
|
invalidDirectories = invalidDirectories?.Distinct();
|
||||||
|
@ -78,30 +79,33 @@ internal partial class InstallForm : CustomForm
|
||||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||||
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
||||||
|| directory != selection.RootDirectory && Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
|| (directory != selection.RootDirectory
|
||||||
|| File.Exists(config))
|
&& Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll)))
|
||||||
|
|| File.Exists(config))
|
||||||
{
|
{
|
||||||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
|
UpdateUser("Uninstalling Koaloader from " + selection.Name
|
||||||
await Koaloader.Uninstall(directory, rootDirectory: selection.RootDirectory, this);
|
+ $" in incorrect directory \"{directory}\" . . . ",
|
||||||
|
LogTextBox.Operation);
|
||||||
|
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||||
}
|
}
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
if (Uninstalling || !selection.Koaloader)
|
if (Uninstalling || !selection.Koaloader)
|
||||||
{
|
|
||||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||||
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
||||||
|| Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
|| Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
||||||
|| File.Exists(config))
|
|| File.Exists(config))
|
||||||
{
|
{
|
||||||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
UpdateUser(
|
||||||
await Koaloader.Uninstall(directory, rootDirectory: selection.RootDirectory, this);
|
"Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ",
|
||||||
|
LogTextBox.Operation);
|
||||||
|
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||||
}
|
}
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
bool uninstallProxy = Uninstalling || selection.Koaloader;
|
bool uninstallProxy = Uninstalling || selection.Koaloader;
|
||||||
int count = selection.DllDirectories.Count, cur = 0;
|
int count = selection.DllDirectories.Count, cur = 0;
|
||||||
foreach (string directory in selection.DllDirectories)
|
foreach (string directory in selection.DllDirectories)
|
||||||
|
@ -109,11 +113,15 @@ internal partial class InstallForm : CustomForm
|
||||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||||
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
||||||
{
|
{
|
||||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string cache);
|
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache) : File.Exists(api32) || File.Exists(api64))
|
out string api64_o, out string config, out string cache);
|
||||||
|
if (uninstallProxy
|
||||||
|
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache)
|
||||||
|
: File.Exists(api32) || File.Exists(api64))
|
||||||
{
|
{
|
||||||
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" +
|
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" +
|
||||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||||
|
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||||
if (uninstallProxy)
|
if (uninstallProxy)
|
||||||
await SmokeAPI.Uninstall(directory, this);
|
await SmokeAPI.Uninstall(directory, this);
|
||||||
else
|
else
|
||||||
|
@ -122,11 +130,15 @@ internal partial class InstallForm : CustomForm
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Epic or Platform.Paradox)
|
if (selection.Platform is Platform.Epic or Platform.Paradox)
|
||||||
{
|
{
|
||||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
|
out string api64_o, out string config);
|
||||||
|
if (uninstallProxy
|
||||||
|
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config)
|
||||||
|
: File.Exists(api32) || File.Exists(api64))
|
||||||
{
|
{
|
||||||
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" +
|
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" +
|
||||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||||
|
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||||
if (uninstallProxy)
|
if (uninstallProxy)
|
||||||
await ScreamAPI.Uninstall(directory, this);
|
await ScreamAPI.Uninstall(directory, this);
|
||||||
else
|
else
|
||||||
|
@ -135,21 +147,29 @@ internal partial class InstallForm : CustomForm
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Ubisoft)
|
if (selection.Platform is Platform.Ubisoft)
|
||||||
{
|
{
|
||||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
|
||||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
|
out string api64_o, out string config);
|
||||||
|
if (uninstallProxy
|
||||||
|
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config)
|
||||||
|
: File.Exists(api32) || File.Exists(api64))
|
||||||
{
|
{
|
||||||
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" +
|
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" +
|
||||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||||
|
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||||
if (uninstallProxy)
|
if (uninstallProxy)
|
||||||
await UplayR1.Uninstall(directory, this);
|
await UplayR1.Uninstall(directory, this);
|
||||||
else
|
else
|
||||||
await UplayR1.Install(directory, selection, this);
|
await UplayR1.Install(directory, selection, this);
|
||||||
}
|
}
|
||||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config);
|
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o,
|
||||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(old_api32) || File.Exists(old_api64) || File.Exists(api32) || File.Exists(api64))
|
out api64, out api64_o, out config);
|
||||||
|
if (uninstallProxy
|
||||||
|
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config)
|
||||||
|
: File.Exists(old_api32) || File.Exists(old_api64) || File.Exists(api32) || File.Exists(api64))
|
||||||
{
|
{
|
||||||
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" +
|
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" +
|
||||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||||
|
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||||
if (uninstallProxy)
|
if (uninstallProxy)
|
||||||
await UplayR2.Uninstall(directory, this);
|
await UplayR2.Uninstall(directory, this);
|
||||||
else
|
else
|
||||||
|
@ -160,20 +180,17 @@ internal partial class InstallForm : CustomForm
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
if (selection.Koaloader && !Uninstalling)
|
if (selection.Koaloader && !Uninstalling)
|
||||||
{
|
|
||||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||||
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ",
|
||||||
await Koaloader.Install(directory, binaryType, selection, rootDirectory: selection.RootDirectory, this);
|
LogTextBox.Operation);
|
||||||
|
await Koaloader.Install(directory, binaryType, selection, selection.RootDirectory, this);
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
UpdateProgress(100);
|
UpdateProgress(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<ProgramSelection> DisabledSelections = new();
|
|
||||||
|
|
||||||
private async Task Operate()
|
private async Task Operate()
|
||||||
{
|
{
|
||||||
List<ProgramSelection> programSelections = ProgramSelection.AllEnabled;
|
List<ProgramSelection> programSelections = ProgramSelection.AllEnabled;
|
||||||
|
@ -181,7 +198,8 @@ internal partial class InstallForm : CustomForm
|
||||||
CompleteOperationsCount = 0;
|
CompleteOperationsCount = 0;
|
||||||
foreach (ProgramSelection selection in programSelections)
|
foreach (ProgramSelection selection in programSelections)
|
||||||
{
|
{
|
||||||
if (Program.Canceled || !Program.IsProgramRunningDialog(this, selection)) throw new CustomMessageException("The operation was canceled.");
|
if (Program.Canceled || !Program.IsProgramRunningDialog(this, selection))
|
||||||
|
throw new CustomMessageException("The operation was canceled.");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await OperateFor(selection);
|
await OperateFor(selection);
|
||||||
|
@ -207,8 +225,6 @@ internal partial class InstallForm : CustomForm
|
||||||
DisabledSelections.Clear();
|
DisabledSelections.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly int ProgramCount = ProgramSelection.AllEnabled.Count;
|
|
||||||
|
|
||||||
private async void Start()
|
private async void Start()
|
||||||
{
|
{
|
||||||
Program.Canceled = false;
|
Program.Canceled = false;
|
||||||
|
@ -220,11 +236,13 @@ internal partial class InstallForm : CustomForm
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Operate();
|
await Operate();
|
||||||
UpdateUser($"DLC unlocker(s) successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for " + ProgramCount + " program(s).", LogTextBox.Success);
|
UpdateUser($"DLC unlocker(s) successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for "
|
||||||
|
+ ProgramCount + " program(s).", LogTextBox.Success);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
UpdateUser($"DLC unlocker {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: " + exception, LogTextBox.Error);
|
UpdateUser($"DLC unlocker {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: "
|
||||||
|
+ exception, LogTextBox.Error);
|
||||||
retryButton.Enabled = true;
|
retryButton.Enabled = true;
|
||||||
}
|
}
|
||||||
userProgressBar.Value = userProgressBar.Maximum;
|
userProgressBar.Value = userProgressBar.Maximum;
|
||||||
|
@ -235,7 +253,7 @@ internal partial class InstallForm : CustomForm
|
||||||
|
|
||||||
private void OnLoad(object sender, EventArgs _)
|
private void OnLoad(object sender, EventArgs _)
|
||||||
{
|
{
|
||||||
retry:
|
retry:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
userInfoLabel.Text = "Loading . . . ";
|
userInfoLabel.Text = "Loading . . . ";
|
||||||
|
@ -244,7 +262,7 @@ internal partial class InstallForm : CustomForm
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (e.HandleException(form: this)) goto retry;
|
if (e.HandleException(this)) goto retry;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
CreamInstaller/Forms/MainForm.Designer.cs
generated
7
CreamInstaller/Forms/MainForm.Designer.cs
generated
|
@ -1,11 +1,8 @@
|
||||||
|
using System.ComponentModel;
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
using CreamInstaller.Components;
|
using CreamInstaller.Components;
|
||||||
|
|
||||||
namespace CreamInstaller
|
namespace CreamInstaller.Forms
|
||||||
{
|
{
|
||||||
partial class MainForm
|
partial class MainForm
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
using CreamInstaller.Components;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using HtmlAgilityPack;
|
|
||||||
|
|
||||||
using Onova;
|
|
||||||
using Onova.Models;
|
|
||||||
using Onova.Services;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -16,19 +7,29 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using HtmlAgilityPack;
|
||||||
|
using Onova;
|
||||||
|
using Onova.Models;
|
||||||
|
using Onova.Services;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class MainForm : CustomForm
|
internal partial class MainForm : CustomForm
|
||||||
{
|
{
|
||||||
internal MainForm() : base()
|
private CancellationTokenSource cancellationTokenSource;
|
||||||
|
private Version latestVersion;
|
||||||
|
|
||||||
|
private UpdateManager updateManager;
|
||||||
|
private IReadOnlyList<Version> versions;
|
||||||
|
|
||||||
|
internal MainForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Text = Program.ApplicationNameShort;
|
Text = Program.ApplicationNameShort;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource cancellationTokenSource;
|
|
||||||
|
|
||||||
private void StartProgram()
|
private void StartProgram()
|
||||||
{
|
{
|
||||||
if (cancellationTokenSource is not null)
|
if (cancellationTokenSource is not null)
|
||||||
|
@ -49,10 +50,6 @@ internal partial class MainForm : CustomForm
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpdateManager updateManager;
|
|
||||||
private Version latestVersion;
|
|
||||||
private IReadOnlyList<Version> versions;
|
|
||||||
|
|
||||||
private async void OnLoad()
|
private async void OnLoad()
|
||||||
{
|
{
|
||||||
progressBar.Visible = false;
|
progressBar.Visible = false;
|
||||||
|
@ -61,18 +58,22 @@ internal partial class MainForm : CustomForm
|
||||||
updateButton.Click -= OnUpdateCancel;
|
updateButton.Click -= OnUpdateCancel;
|
||||||
progressLabel.Text = "Checking for updates . . .";
|
progressLabel.Text = "Checking for updates . . .";
|
||||||
changelogTreeView.Visible = false;
|
changelogTreeView.Visible = false;
|
||||||
changelogTreeView.Location = new(progressLabel.Location.X, progressLabel.Location.Y + progressLabel.Size.Height + 13);
|
changelogTreeView.Location = new Point(progressLabel.Location.X,
|
||||||
|
progressLabel.Location.Y + progressLabel.Size.Height + 13);
|
||||||
Refresh();
|
Refresh();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugForm.Current.Attach(this);
|
DebugForm.Current.Attach(this);
|
||||||
#endif
|
#endif
|
||||||
GithubPackageResolver resolver = new(Program.RepositoryOwner, Program.RepositoryName, Program.RepositoryPackage);
|
GithubPackageResolver resolver = new(Program.RepositoryOwner, Program.RepositoryName,
|
||||||
|
Program.RepositoryPackage);
|
||||||
ZipPackageExtractor extractor = new();
|
ZipPackageExtractor extractor = new();
|
||||||
updateManager = new(AssemblyMetadata.FromAssembly(Program.EntryAssembly, Program.CurrentProcessFilePath), resolver, extractor);
|
updateManager
|
||||||
|
= new UpdateManager(AssemblyMetadata.FromAssembly(Program.EntryAssembly, Program.CurrentProcessFilePath),
|
||||||
|
resolver, extractor);
|
||||||
if (latestVersion is null)
|
if (latestVersion is null)
|
||||||
{
|
{
|
||||||
CheckForUpdatesResult checkForUpdatesResult = null;
|
CheckForUpdatesResult checkForUpdatesResult = null;
|
||||||
cancellationTokenSource = new();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
checkForUpdatesResult = await updateManager.CheckForUpdatesAsync(cancellationTokenSource.Token);
|
checkForUpdatesResult = await updateManager.CheckForUpdatesAsync(cancellationTokenSource.Token);
|
||||||
|
@ -80,8 +81,8 @@ internal partial class MainForm : CustomForm
|
||||||
if (checkForUpdatesResult.CanUpdate)
|
if (checkForUpdatesResult.CanUpdate)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
latestVersion = checkForUpdatesResult.LastVersion;
|
latestVersion = checkForUpdatesResult.LastVersion;
|
||||||
versions = checkForUpdatesResult.Versions;
|
versions = checkForUpdatesResult.Versions;
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -90,7 +91,8 @@ internal partial class MainForm : CustomForm
|
||||||
catch (TaskCanceledException) { }
|
catch (TaskCanceledException) { }
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
DebugForm.Current.Log($"Exception while checking for updates: {e.GetType()} ({e.Message})", LogTextBox.Warning);
|
DebugForm.Current.Log($"Exception while checking for updates: {e.GetType()} ({e.Message})",
|
||||||
|
LogTextBox.Warning);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
catch { }
|
catch { }
|
||||||
|
@ -112,19 +114,17 @@ internal partial class MainForm : CustomForm
|
||||||
progressLabel.Text = $"An update is available: v{latestVersion}";
|
progressLabel.Text = $"An update is available: v{latestVersion}";
|
||||||
ignoreButton.Enabled = true;
|
ignoreButton.Enabled = true;
|
||||||
updateButton.Enabled = true;
|
updateButton.Enabled = true;
|
||||||
updateButton.Click += new(OnUpdate);
|
updateButton.Click += OnUpdate;
|
||||||
changelogTreeView.Visible = true;
|
changelogTreeView.Visible = true;
|
||||||
Version currentVersion = new(Program.Version);
|
Version currentVersion = new(Program.Version);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
foreach (Version version in versions.Where(v => (v > currentVersion || v == latestVersion) && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
foreach (Version version in versions.Where(v => (v > currentVersion || v == latestVersion)
|
||||||
|
&& !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
||||||
#else
|
#else
|
||||||
foreach (Version version in versions.Where(v => v > currentVersion && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
foreach (Version version in versions.Where(v => v > currentVersion && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
TreeNode root = new($"v{version}")
|
TreeNode root = new($"v{version}") { Name = version.ToString() };
|
||||||
{
|
|
||||||
Name = version.ToString()
|
|
||||||
};
|
|
||||||
changelogTreeView.Nodes.Add(root);
|
changelogTreeView.Nodes.Add(root);
|
||||||
if (changelogTreeView.Nodes.Count > 0)
|
if (changelogTreeView.Nodes.Count > 0)
|
||||||
changelogTreeView.Nodes[0].EnsureVisible();
|
changelogTreeView.Nodes[0].EnsureVisible();
|
||||||
|
@ -137,19 +137,14 @@ internal partial class MainForm : CustomForm
|
||||||
changelogTreeView.Nodes.Remove(root);
|
changelogTreeView.Nodes.Remove(root);
|
||||||
else
|
else
|
||||||
foreach (HtmlNode node in nodes)
|
foreach (HtmlNode node in nodes)
|
||||||
{
|
|
||||||
changelogTreeView.Invoke(delegate
|
changelogTreeView.Invoke(delegate
|
||||||
{
|
{
|
||||||
TreeNode change = new()
|
TreeNode change = new() { Text = HttpUtility.HtmlDecode(node.InnerText) };
|
||||||
{
|
|
||||||
Text = HttpUtility.HtmlDecode(node.InnerText)
|
|
||||||
};
|
|
||||||
root.Nodes.Add(change);
|
root.Nodes.Add(change);
|
||||||
root.Expand();
|
root.Expand();
|
||||||
if (changelogTreeView.Nodes.Count > 0)
|
if (changelogTreeView.Nodes.Count > 0)
|
||||||
changelogTreeView.Nodes[0].EnsureVisible();
|
changelogTreeView.Nodes[0].EnsureVisible();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +152,7 @@ internal partial class MainForm : CustomForm
|
||||||
|
|
||||||
private void OnLoad(object sender, EventArgs _)
|
private void OnLoad(object sender, EventArgs _)
|
||||||
{
|
{
|
||||||
retry:
|
retry:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string FileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
string FileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
||||||
|
@ -165,9 +160,9 @@ internal partial class MainForm : CustomForm
|
||||||
{
|
{
|
||||||
using DialogForm form = new(this);
|
using DialogForm form = new(this);
|
||||||
if (form.Show(SystemIcons.Warning,
|
if (form.Show(SystemIcons.Warning,
|
||||||
"WARNING: " + Program.ApplicationExecutable + " was renamed!" +
|
"WARNING: " + Program.ApplicationExecutable + " was renamed!" +
|
||||||
"\n\nThis will cause undesirable behavior when updating the program!",
|
"\n\nThis will cause undesirable behavior when updating the program!",
|
||||||
"Ignore", "Abort") == DialogResult.Cancel)
|
"Ignore", "Abort") == DialogResult.Cancel)
|
||||||
{
|
{
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
return;
|
return;
|
||||||
|
@ -177,7 +172,7 @@ internal partial class MainForm : CustomForm
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (e.HandleException(form: this)) goto retry;
|
if (e.HandleException(this)) goto retry;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,19 +185,18 @@ internal partial class MainForm : CustomForm
|
||||||
ignoreButton.Visible = false;
|
ignoreButton.Visible = false;
|
||||||
updateButton.Text = "Cancel";
|
updateButton.Text = "Cancel";
|
||||||
updateButton.Click -= OnUpdate;
|
updateButton.Click -= OnUpdate;
|
||||||
updateButton.Click += new(OnUpdateCancel);
|
updateButton.Click += OnUpdateCancel;
|
||||||
changelogTreeView.Location = new(progressBar.Location.X, progressBar.Location.Y + progressBar.Size.Height + 6);
|
changelogTreeView.Location
|
||||||
|
= new Point(progressBar.Location.X, progressBar.Location.Y + progressBar.Size.Height + 6);
|
||||||
Refresh();
|
Refresh();
|
||||||
|
|
||||||
Progress<double> progress = new();
|
Progress<double> progress = new();
|
||||||
progress.ProgressChanged += new(delegate (object sender, double _progress)
|
progress.ProgressChanged += delegate(object sender, double _progress)
|
||||||
{
|
{
|
||||||
progressLabel.Text = $"Updating . . . {(int)_progress}%";
|
progressLabel.Text = $"Updating . . . {(int)_progress}%";
|
||||||
progressBar.Value = (int)_progress;
|
progressBar.Value = (int)_progress;
|
||||||
});
|
};
|
||||||
|
|
||||||
progressLabel.Text = "Updating . . . ";
|
progressLabel.Text = "Updating . . . ";
|
||||||
cancellationTokenSource = new();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await updateManager.PrepareUpdateAsync(latestVersion, progress, cancellationTokenSource.Token);
|
await updateManager.PrepareUpdateAsync(latestVersion, progress, cancellationTokenSource.Token);
|
||||||
|
@ -211,7 +205,8 @@ internal partial class MainForm : CustomForm
|
||||||
catch (TaskCanceledException) { }
|
catch (TaskCanceledException) { }
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
DebugForm.Current.Log($"Exception while preparing update: {ex.GetType()} ({ex.Message})", LogTextBox.Warning);
|
DebugForm.Current.Log($"Exception while preparing update: {ex.GetType()} ({ex.Message})",
|
||||||
|
LogTextBox.Warning);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
catch { }
|
catch { }
|
||||||
|
@ -221,14 +216,13 @@ internal partial class MainForm : CustomForm
|
||||||
cancellationTokenSource.Dispose();
|
cancellationTokenSource.Dispose();
|
||||||
cancellationTokenSource = null;
|
cancellationTokenSource = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateManager is not null && updateManager.IsUpdatePrepared(latestVersion))
|
if (updateManager is not null && updateManager.IsUpdatePrepared(latestVersion))
|
||||||
{
|
{
|
||||||
updateManager.LaunchUpdater(latestVersion);
|
updateManager.LaunchUpdater(latestVersion);
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else OnLoad();
|
OnLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdateCancel(object sender, EventArgs e)
|
private void OnUpdateCancel(object sender, EventArgs e)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows.Forms;
|
||||||
using CreamInstaller.Components;
|
using CreamInstaller.Components;
|
||||||
|
|
||||||
using System.ComponentModel;
|
namespace CreamInstaller.Forms
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace CreamInstaller
|
|
||||||
{
|
{
|
||||||
partial class SelectDialogForm
|
partial class SelectDialogForm
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
using CreamInstaller.Components;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class SelectDialogForm : CustomForm
|
internal partial class SelectDialogForm : CustomForm
|
||||||
{
|
{
|
||||||
|
private readonly List<(Platform platform, string id, string name)> selected = new();
|
||||||
internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
||||||
|
|
||||||
private readonly List<(Platform platform, string id, string name)> selected = new();
|
internal List<(Platform platform, string id, string name)> QueryUser(
|
||||||
internal List<(Platform platform, string id, string name)> QueryUser(string groupBoxText, List<(Platform platform, string id, string name, bool alreadySelected)> choices)
|
string groupBoxText, List<(Platform platform, string id, string name, bool alreadySelected)> choices)
|
||||||
{
|
{
|
||||||
if (!choices.Any()) return null;
|
if (!choices.Any()) return null;
|
||||||
groupBox.Text = groupBoxText;
|
groupBox.Text = groupBoxText;
|
||||||
|
@ -23,13 +22,7 @@ internal partial class SelectDialogForm : CustomForm
|
||||||
selectionTreeView.AfterCheck += OnTreeNodeChecked;
|
selectionTreeView.AfterCheck += OnTreeNodeChecked;
|
||||||
foreach ((Platform platform, string id, string name, bool alreadySelected) in choices)
|
foreach ((Platform platform, string id, string name, bool alreadySelected) in choices)
|
||||||
{
|
{
|
||||||
TreeNode node = new()
|
TreeNode node = new() { Tag = platform, Name = id, Text = name, Checked = alreadySelected };
|
||||||
{
|
|
||||||
Tag = platform,
|
|
||||||
Name = id,
|
|
||||||
Text = name,
|
|
||||||
Checked = alreadySelected
|
|
||||||
};
|
|
||||||
OnTreeNodeChecked(node);
|
OnTreeNodeChecked(node);
|
||||||
_ = selectionTreeView.Nodes.Add(node);
|
_ = selectionTreeView.Nodes.Add(node);
|
||||||
}
|
}
|
||||||
|
|
6
CreamInstaller/Forms/SelectForm.Designer.cs
generated
6
CreamInstaller/Forms/SelectForm.Designer.cs
generated
|
@ -1,10 +1,8 @@
|
||||||
using System;
|
using System.ComponentModel;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Drawing;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using CreamInstaller.Components;
|
using CreamInstaller.Components;
|
||||||
|
|
||||||
namespace CreamInstaller
|
namespace CreamInstaller.Forms
|
||||||
{
|
{
|
||||||
partial class SelectForm
|
partial class SelectForm
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,5 @@
|
||||||
#pragma warning disable IDE0058
|
#pragma warning disable IDE0058
|
||||||
|
|
||||||
using CreamInstaller.Components;
|
|
||||||
using CreamInstaller.Platforms.Epic;
|
|
||||||
using CreamInstaller.Platforms.Paradox;
|
|
||||||
using CreamInstaller.Platforms.Steam;
|
|
||||||
using CreamInstaller.Platforms.Ubisoft;
|
|
||||||
using CreamInstaller.Resources;
|
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Gameloop.Vdf.Linq;
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -20,26 +10,45 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Platforms.Epic;
|
||||||
|
using CreamInstaller.Platforms.Paradox;
|
||||||
|
using CreamInstaller.Platforms.Steam;
|
||||||
|
using CreamInstaller.Platforms.Ubisoft;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Gameloop.Vdf.Linq;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
internal partial class SelectForm : CustomForm
|
internal partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
internal SelectForm() : base()
|
private readonly string helpButtonListPrefix = "\n • ";
|
||||||
|
|
||||||
|
private readonly SynchronizedCollection<string> RemainingDLCs = new();
|
||||||
|
|
||||||
|
private readonly SynchronizedCollection<string> RemainingGames = new();
|
||||||
|
|
||||||
|
private List<(Platform platform, string id, string name)> ProgramsToScan;
|
||||||
|
|
||||||
|
internal SelectForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Text = Program.ApplicationName;
|
Text = Program.ApplicationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new();
|
public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new ContextMenuStrip();
|
||||||
|
|
||||||
|
internal List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
|
||||||
|
|
||||||
private static void UpdateRemaining(Label label, SynchronizedCollection<string> list, string descriptor) =>
|
private static void UpdateRemaining(Label label, SynchronizedCollection<string> list, string descriptor) =>
|
||||||
label.Text = list.Any() ? $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list).Replace("&", "&&") : "";
|
label.Text = list.Any()
|
||||||
|
? $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list).Replace("&", "&&")
|
||||||
|
: "";
|
||||||
|
|
||||||
private readonly SynchronizedCollection<string> RemainingGames = new();
|
|
||||||
private void UpdateRemainingGames() => UpdateRemaining(progressLabelGames, RemainingGames, "games");
|
private void UpdateRemainingGames() => UpdateRemaining(progressLabelGames, RemainingGames, "games");
|
||||||
|
|
||||||
private void AddToRemainingGames(string gameName)
|
private void AddToRemainingGames(string gameName)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
@ -51,6 +60,7 @@ internal partial class SelectForm : CustomForm
|
||||||
UpdateRemainingGames();
|
UpdateRemainingGames();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveFromRemainingGames(string gameName)
|
private void RemoveFromRemainingGames(string gameName)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
@ -62,8 +72,8 @@ internal partial class SelectForm : CustomForm
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly SynchronizedCollection<string> RemainingDLCs = new();
|
|
||||||
private void UpdateRemainingDLCs() => UpdateRemaining(progressLabelDLCs, RemainingDLCs, "DLCs");
|
private void UpdateRemainingDLCs() => UpdateRemaining(progressLabelDLCs, RemainingDLCs, "DLCs");
|
||||||
|
|
||||||
private void AddToRemainingDLCs(string dlcId)
|
private void AddToRemainingDLCs(string dlcId)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
@ -75,6 +85,7 @@ internal partial class SelectForm : CustomForm
|
||||||
UpdateRemainingDLCs();
|
UpdateRemainingDLCs();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveFromRemainingDLCs(string dlcId)
|
private void RemoveFromRemainingDLCs(string dlcId)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
@ -109,21 +120,23 @@ internal partial class SelectForm : CustomForm
|
||||||
List<Task> appTasks = new();
|
List<Task> appTasks = new();
|
||||||
if (ProgramsToScan.Any(c => c.platform is Platform.Paradox))
|
if (ProgramsToScan.Any(c => c.platform is Platform.Paradox))
|
||||||
{
|
{
|
||||||
List<string> dllDirectories = await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
|
List<string> dllDirectories
|
||||||
|
= await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
|
||||||
if (dllDirectories is not null)
|
if (dllDirectories is not null)
|
||||||
{
|
{
|
||||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
|
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
|
||||||
selection ??= new();
|
selection ??= new ProgramSelection();
|
||||||
if (allCheckBox.Checked) selection.Enabled = true;
|
if (allCheckBox.Checked) selection.Enabled = true;
|
||||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||||
selection.Id = "PL";
|
selection.Id = "PL";
|
||||||
selection.Name = "Paradox Launcher";
|
selection.Name = "Paradox Launcher";
|
||||||
selection.RootDirectory = ParadoxLauncher.InstallPath;
|
selection.RootDirectory = ParadoxLauncher.InstallPath;
|
||||||
selection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
|
selection.ExecutableDirectories
|
||||||
|
= await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
|
||||||
selection.DllDirectories = dllDirectories;
|
selection.DllDirectories = dllDirectories;
|
||||||
selection.Platform = Platform.Paradox;
|
selection.Platform = Platform.Paradox;
|
||||||
|
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id)
|
||||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id) ?? new();
|
?? new TreeNode();
|
||||||
programNode.Tag = selection.Platform;
|
programNode.Tag = selection.Platform;
|
||||||
programNode.Name = selection.Id;
|
programNode.Name = selection.Id;
|
||||||
programNode.Text = selection.Name;
|
programNode.Text = selection.Name;
|
||||||
|
@ -135,12 +148,14 @@ internal partial class SelectForm : CustomForm
|
||||||
int steamGamesToCheck;
|
int steamGamesToCheck;
|
||||||
if (ProgramsToScan.Any(c => c.platform is Platform.Steam))
|
if (ProgramsToScan.Any(c => c.platform is Platform.Steam))
|
||||||
{
|
{
|
||||||
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames = await SteamLibrary.GetGames();
|
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames
|
||||||
|
= await SteamLibrary.GetGames();
|
||||||
steamGamesToCheck = steamGames.Count;
|
steamGamesToCheck = steamGames.Count;
|
||||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
|
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
if (Program.IsGameBlocked(name, gameDirectory) || !ProgramsToScan.Any(c => c.platform is Platform.Steam && c.id == appId))
|
if (Program.IsGameBlocked(name, gameDirectory)
|
||||||
|
|| !ProgramsToScan.Any(c => c.platform is Platform.Steam && c.id == appId))
|
||||||
{
|
{
|
||||||
Interlocked.Decrement(ref steamGamesToCheck);
|
Interlocked.Decrement(ref steamGamesToCheck);
|
||||||
continue;
|
continue;
|
||||||
|
@ -149,7 +164,8 @@ internal partial class SelectForm : CustomForm
|
||||||
Task task = Task.Run(async () =>
|
Task task = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
|
List<string> dllDirectories
|
||||||
|
= await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
|
||||||
if (dllDirectories is null)
|
if (dllDirectories is null)
|
||||||
{
|
{
|
||||||
Interlocked.Decrement(ref steamGamesToCheck);
|
Interlocked.Decrement(ref steamGamesToCheck);
|
||||||
|
@ -199,11 +215,15 @@ internal partial class SelectForm : CustomForm
|
||||||
if (dlcAppInfo is not null)
|
if (dlcAppInfo is not null)
|
||||||
{
|
{
|
||||||
dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
|
dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
|
||||||
string dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
string dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")
|
||||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")?.ToString();
|
?.ToString();
|
||||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")?.ToString();
|
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")
|
||||||
|
?.ToString();
|
||||||
|
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")
|
||||||
|
?.ToString();
|
||||||
if (dlcIconStaticId is not null)
|
if (dlcIconStaticId is not null)
|
||||||
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
dlcIcon = IconGrabber.SteamAppImagesPath
|
||||||
|
+ @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
@ -227,27 +247,32 @@ internal partial class SelectForm : CustomForm
|
||||||
await task;
|
await task;
|
||||||
}
|
}
|
||||||
steamGamesToCheck = 0;
|
steamGamesToCheck = 0;
|
||||||
|
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Steam, appId)
|
||||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Steam, appId) ?? new();
|
?? new ProgramSelection();
|
||||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||||
|
|| selection.ExtraSelectedDlc.Any();
|
||||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||||
selection.Id = appId;
|
selection.Id = appId;
|
||||||
selection.Name = appData?.name ?? name;
|
selection.Name = appData?.name ?? name;
|
||||||
selection.RootDirectory = gameDirectory;
|
selection.RootDirectory = gameDirectory;
|
||||||
selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
|
selection.ExecutableDirectories
|
||||||
|
= await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||||
selection.DllDirectories = dllDirectories;
|
selection.DllDirectories = dllDirectories;
|
||||||
selection.Platform = Platform.Steam;
|
selection.Platform = Platform.Steam;
|
||||||
selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
|
selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
|
||||||
selection.IconUrl = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("icon")}.jpg";
|
selection.IconUrl = IconGrabber.SteamAppImagesPath
|
||||||
selection.SubIconUrl = appData?.header_image ?? IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("clienticon")}.ico";
|
+ @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("icon")}.jpg";
|
||||||
selection.Publisher = appData?.publishers[0] ?? appInfo?.Value?.GetChild("extended")?.GetChild("publisher")?.ToString();
|
selection.SubIconUrl = appData?.header_image ?? IconGrabber.SteamAppImagesPath
|
||||||
|
+ @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("clienticon")}.ico";
|
||||||
|
selection.Publisher = appData?.publishers[0]
|
||||||
|
?? appInfo?.Value?.GetChild("extended")?.GetChild("publisher")?.ToString();
|
||||||
selection.WebsiteUrl = appData?.website;
|
selection.WebsiteUrl = appData?.website;
|
||||||
|
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
selectionTreeView.Invoke(delegate
|
selectionTreeView.Invoke(delegate
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new();
|
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId)
|
||||||
|
?? new TreeNode();
|
||||||
programNode.Tag = selection.Platform;
|
programNode.Tag = selection.Platform;
|
||||||
programNode.Name = appId;
|
programNode.Name = appId;
|
||||||
programNode.Text = appData?.name ?? name;
|
programNode.Text = appData?.name ?? name;
|
||||||
|
@ -261,7 +286,8 @@ internal partial class SelectForm : CustomForm
|
||||||
(DlcType type, string name, string icon) dlcApp = pair.Value;
|
(DlcType type, string name, string icon) dlcApp = pair.Value;
|
||||||
selection.AllDlc[appId] = dlcApp;
|
selection.AllDlc[appId] = dlcApp;
|
||||||
if (allCheckBox.Checked && dlcApp.name != "Unknown") selection.SelectedDlc[appId] = dlcApp;
|
if (allCheckBox.Checked && dlcApp.name != "Unknown") selection.SelectedDlc[appId] = dlcApp;
|
||||||
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new();
|
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId)
|
||||||
|
?? new TreeNode();
|
||||||
dlcNode.Tag = selection.Platform;
|
dlcNode.Tag = selection.Platform;
|
||||||
dlcNode.Name = appId;
|
dlcNode.Name = appId;
|
||||||
dlcNode.Text = dlcApp.name;
|
dlcNode.Text = dlcApp.name;
|
||||||
|
@ -285,7 +311,8 @@ internal partial class SelectForm : CustomForm
|
||||||
string name = manifest.DisplayName;
|
string name = manifest.DisplayName;
|
||||||
string directory = manifest.InstallLocation;
|
string directory = manifest.InstallLocation;
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.platform is Platform.Epic && c.id == @namespace)) continue;
|
if (Program.IsGameBlocked(name, directory)
|
||||||
|
|| !ProgramsToScan.Any(c => c.platform is Platform.Epic && c.id == @namespace)) continue;
|
||||||
AddToRemainingGames(name);
|
AddToRemainingGames(name);
|
||||||
Task task = Task.Run(async () =>
|
Task task = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
@ -297,12 +324,14 @@ internal partial class SelectForm : CustomForm
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
ConcurrentDictionary<string, (string name, string product, string icon, string developer)> entitlements = new();
|
ConcurrentDictionary<string, (string name, string product, string icon, string developer)>
|
||||||
|
entitlements = new();
|
||||||
List<Task> dlcTasks = new();
|
List<Task> dlcTasks = new();
|
||||||
List<(string id, string name, string product, string icon, string developer)> entitlementIds = await EpicStore.QueryEntitlements(@namespace);
|
List<(string id, string name, string product, string icon, string developer)> entitlementIds
|
||||||
|
= await EpicStore.QueryEntitlements(@namespace);
|
||||||
if (entitlementIds.Any())
|
if (entitlementIds.Any())
|
||||||
{
|
foreach ((string id, string name, string product, string icon, string developer) in
|
||||||
foreach ((string id, string name, string product, string icon, string developer) in entitlementIds)
|
entitlementIds)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
AddToRemainingDLCs(id);
|
AddToRemainingDLCs(id);
|
||||||
|
@ -314,8 +343,7 @@ internal partial class SelectForm : CustomForm
|
||||||
});
|
});
|
||||||
dlcTasks.Add(task);
|
dlcTasks.Add(task);
|
||||||
}
|
}
|
||||||
}
|
if ( /*!catalogItems.Any() && */!entitlements.Any())
|
||||||
if (/*!catalogItems.Any() && */!entitlements.Any())
|
|
||||||
{
|
{
|
||||||
RemoveFromRemainingGames(name);
|
RemoveFromRemainingGames(name);
|
||||||
return;
|
return;
|
||||||
|
@ -326,28 +354,31 @@ internal partial class SelectForm : CustomForm
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
await task;
|
await task;
|
||||||
}
|
}
|
||||||
|
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace)
|
||||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace) ?? new();
|
?? new ProgramSelection();
|
||||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||||
|
|| selection.ExtraSelectedDlc.Any();
|
||||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||||
selection.Id = @namespace;
|
selection.Id = @namespace;
|
||||||
selection.Name = name;
|
selection.Name = name;
|
||||||
selection.RootDirectory = directory;
|
selection.RootDirectory = directory;
|
||||||
selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
|
selection.ExecutableDirectories
|
||||||
|
= await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||||
selection.DllDirectories = dllDirectories;
|
selection.DllDirectories = dllDirectories;
|
||||||
selection.Platform = Platform.Epic;
|
selection.Platform = Platform.Epic;
|
||||||
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements.Where(p => p.Value.name == selection.Name))
|
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in
|
||||||
|
entitlements.Where(p => p.Value.name == selection.Name))
|
||||||
{
|
{
|
||||||
selection.ProductUrl = "https://www.epicgames.com/store/product/" + pair.Value.product;
|
selection.ProductUrl = "https://www.epicgames.com/store/product/" + pair.Value.product;
|
||||||
selection.IconUrl = pair.Value.icon;
|
selection.IconUrl = pair.Value.icon;
|
||||||
selection.Publisher = pair.Value.developer;
|
selection.Publisher = pair.Value.developer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
selectionTreeView.Invoke(delegate
|
selectionTreeView.Invoke(delegate
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace) ?? new();
|
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace)
|
||||||
|
?? new TreeNode();
|
||||||
programNode.Tag = selection.Platform;
|
programNode.Tag = selection.Platform;
|
||||||
programNode.Name = @namespace;
|
programNode.Name = @namespace;
|
||||||
programNode.Text = name;
|
programNode.Text = name;
|
||||||
|
@ -362,7 +393,6 @@ internal partial class SelectForm : CustomForm
|
||||||
if (catalogItemsNode.Parent is null)
|
if (catalogItemsNode.Parent is null)
|
||||||
programNode.Nodes.Add(catalogItemsNode);*/
|
programNode.Nodes.Add(catalogItemsNode);*/
|
||||||
if (entitlements.Any())
|
if (entitlements.Any())
|
||||||
{
|
|
||||||
/*TreeNode entitlementsNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace + "_entitlements") ?? new();
|
/*TreeNode entitlementsNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace + "_entitlements") ?? new();
|
||||||
entitlementsNode.Tag = selection.Platform;
|
entitlementsNode.Tag = selection.Platform;
|
||||||
entitlementsNode.Name = @namespace + "_entitlements";
|
entitlementsNode.Name = @namespace + "_entitlements";
|
||||||
|
@ -370,14 +400,17 @@ internal partial class SelectForm : CustomForm
|
||||||
entitlementsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.Entitlement);
|
entitlementsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.Entitlement);
|
||||||
if (entitlementsNode.Parent is null)
|
if (entitlementsNode.Parent is null)
|
||||||
programNode.Nodes.Add(entitlementsNode);*/
|
programNode.Nodes.Add(entitlementsNode);*/
|
||||||
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements)
|
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)>
|
||||||
|
pair in entitlements)
|
||||||
{
|
{
|
||||||
if (programNode is null/* || entitlementsNode is null*/) return;
|
if (programNode is null /* || entitlementsNode is null*/) return;
|
||||||
string dlcId = pair.Key;
|
string dlcId = pair.Key;
|
||||||
(DlcType type, string name, string icon) dlcApp = (DlcType.EpicEntitlement, pair.Value.name, pair.Value.icon);
|
(DlcType type, string name, string icon) dlcApp = (
|
||||||
|
DlcType.EpicEntitlement, pair.Value.name, pair.Value.icon);
|
||||||
selection.AllDlc[dlcId] = dlcApp;
|
selection.AllDlc[dlcId] = dlcApp;
|
||||||
if (allCheckBox.Checked) selection.SelectedDlc[dlcId] = dlcApp;
|
if (allCheckBox.Checked) selection.SelectedDlc[dlcId] = dlcApp;
|
||||||
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == dlcId) ?? new();
|
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == dlcId)
|
||||||
|
?? new TreeNode();
|
||||||
dlcNode.Tag = selection.Platform;
|
dlcNode.Tag = selection.Platform;
|
||||||
dlcNode.Name = dlcId;
|
dlcNode.Name = dlcId;
|
||||||
dlcNode.Text = dlcApp.name;
|
dlcNode.Text = dlcApp.name;
|
||||||
|
@ -385,7 +418,6 @@ internal partial class SelectForm : CustomForm
|
||||||
if (dlcNode.Parent is null)
|
if (dlcNode.Parent is null)
|
||||||
_ = programNode.Nodes.Add(dlcNode); //entitlementsNode.Nodes.Add(dlcNode);
|
_ = programNode.Nodes.Add(dlcNode); //entitlementsNode.Nodes.Add(dlcNode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
RemoveFromRemainingGames(name);
|
RemoveFromRemainingGames(name);
|
||||||
|
@ -399,34 +431,38 @@ internal partial class SelectForm : CustomForm
|
||||||
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
|
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
if (Program.IsGameBlocked(name, gameDirectory) || !ProgramsToScan.Any(c => c.platform is Platform.Ubisoft && c.id == gameId)) continue;
|
if (Program.IsGameBlocked(name, gameDirectory)
|
||||||
|
|| !ProgramsToScan.Any(c => c.platform is Platform.Ubisoft && c.id == gameId)) continue;
|
||||||
AddToRemainingGames(name);
|
AddToRemainingGames(name);
|
||||||
Task task = Task.Run(async () =>
|
Task task = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
|
List<string> dllDirectories
|
||||||
|
= await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
|
||||||
if (dllDirectories is null)
|
if (dllDirectories is null)
|
||||||
{
|
{
|
||||||
RemoveFromRemainingGames(name);
|
RemoveFromRemainingGames(name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
|
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId)
|
||||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId) ?? new();
|
?? new ProgramSelection();
|
||||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||||
|
|| selection.ExtraSelectedDlc.Any();
|
||||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||||
selection.Id = gameId;
|
selection.Id = gameId;
|
||||||
selection.Name = name;
|
selection.Name = name;
|
||||||
selection.RootDirectory = gameDirectory;
|
selection.RootDirectory = gameDirectory;
|
||||||
selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
|
selection.ExecutableDirectories
|
||||||
|
= await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||||
selection.DllDirectories = dllDirectories;
|
selection.DllDirectories = dllDirectories;
|
||||||
selection.Platform = Platform.Ubisoft;
|
selection.Platform = Platform.Ubisoft;
|
||||||
selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
||||||
|
|
||||||
selectionTreeView.Invoke(delegate
|
selectionTreeView.Invoke(delegate
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return;
|
if (Program.Canceled) return;
|
||||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Ubisoft && s.Name == gameId) ?? new();
|
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Ubisoft && s.Name == gameId)
|
||||||
|
?? new TreeNode();
|
||||||
programNode.Tag = selection.Platform;
|
programNode.Tag = selection.Platform;
|
||||||
programNode.Name = gameId;
|
programNode.Name = gameId;
|
||||||
programNode.Text = name;
|
programNode.Text = name;
|
||||||
|
@ -448,7 +484,6 @@ internal partial class SelectForm : CustomForm
|
||||||
steamGamesToCheck = 0;
|
steamGamesToCheck = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<(Platform platform, string id, string name)> ProgramsToScan;
|
|
||||||
private async void OnLoad(bool forceScan = false, bool forceProvideChoices = false)
|
private async void OnLoad(bool forceScan = false, bool forceProvideChoices = false)
|
||||||
{
|
{
|
||||||
Program.Canceled = false;
|
Program.Canceled = false;
|
||||||
|
@ -470,27 +505,37 @@ internal partial class SelectForm : CustomForm
|
||||||
resetKoaloaderButton.Enabled = false;
|
resetKoaloaderButton.Enabled = false;
|
||||||
progressLabel.Text = "Waiting for user to select which programs/games to scan . . .";
|
progressLabel.Text = "Waiting for user to select which programs/games to scan . . .";
|
||||||
ShowProgressBar();
|
ShowProgressBar();
|
||||||
|
|
||||||
await ProgramData.Setup();
|
await ProgramData.Setup();
|
||||||
|
|
||||||
bool scan = forceScan;
|
bool scan = forceScan;
|
||||||
if (!scan && (ProgramsToScan is null || !ProgramsToScan.Any() || forceProvideChoices))
|
if (!scan && (ProgramsToScan is null || !ProgramsToScan.Any() || forceProvideChoices))
|
||||||
{
|
{
|
||||||
List<(Platform platform, string id, string name, bool alreadySelected)> gameChoices = new();
|
List<(Platform platform, string id, string name, bool alreadySelected)> gameChoices = new();
|
||||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||||
gameChoices.Add((Platform.Paradox, "PL", "Paradox Launcher", ProgramsToScan is not null && ProgramsToScan.Any(p => p.platform is Platform.Paradox && p.id == "PL")));
|
gameChoices.Add((Platform.Paradox, "PL", "Paradox Launcher",
|
||||||
|
ProgramsToScan is not null
|
||||||
|
&& ProgramsToScan.Any(p => p.platform is Platform.Paradox && p.id == "PL")));
|
||||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in (await SteamLibrary.GetGames()).Where(g => !Program.IsGameBlocked(g.name, g.gameDirectory)))
|
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in
|
||||||
gameChoices.Add((Platform.Steam, appId, name, ProgramsToScan is not null && ProgramsToScan.Any(p => p.platform is Platform.Steam && p.id == appId)));
|
(await SteamLibrary.GetGames()).Where(g => !Program.IsGameBlocked(g.name, g.gameDirectory)))
|
||||||
|
gameChoices.Add((Platform.Steam, appId, name,
|
||||||
|
ProgramsToScan is not null
|
||||||
|
&& ProgramsToScan.Any(p => p.platform is Platform.Steam && p.id == appId)));
|
||||||
if (Directory.Exists(EpicLibrary.EpicManifestsPath))
|
if (Directory.Exists(EpicLibrary.EpicManifestsPath))
|
||||||
foreach (Manifest manifest in (await EpicLibrary.GetGames()).Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)))
|
foreach (Manifest manifest in (await EpicLibrary.GetGames()).Where(
|
||||||
gameChoices.Add((Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName, ProgramsToScan is not null && ProgramsToScan.Any(p => p.platform is Platform.Epic && p.id == manifest.CatalogNamespace)));
|
m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)))
|
||||||
foreach ((string gameId, string name, string gameDirectory) in (await UbisoftLibrary.GetGames()).Where(g => !Program.IsGameBlocked(g.name, g.gameDirectory)))
|
gameChoices.Add((Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName,
|
||||||
gameChoices.Add((Platform.Ubisoft, gameId, name, ProgramsToScan is not null && ProgramsToScan.Any(p => p.platform is Platform.Ubisoft && p.id == gameId)));
|
ProgramsToScan is not null && ProgramsToScan.Any(
|
||||||
|
p => p.platform is Platform.Epic && p.id == manifest.CatalogNamespace)));
|
||||||
|
foreach ((string gameId, string name, string gameDirectory) in (await UbisoftLibrary.GetGames()).Where(
|
||||||
|
g => !Program.IsGameBlocked(g.name, g.gameDirectory)))
|
||||||
|
gameChoices.Add((Platform.Ubisoft, gameId, name,
|
||||||
|
ProgramsToScan is not null
|
||||||
|
&& ProgramsToScan.Any(p => p.platform is Platform.Ubisoft && p.id == gameId)));
|
||||||
if (gameChoices.Any())
|
if (gameChoices.Any())
|
||||||
{
|
{
|
||||||
using SelectDialogForm form = new(this);
|
using SelectDialogForm form = new(this);
|
||||||
List<(Platform platform, string id, string name)> choices = form.QueryUser("Choose which programs and/or games to scan for DLC:", gameChoices);
|
List<(Platform 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();
|
scan = choices is not null && choices.Any();
|
||||||
string retry = "\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
|
string retry = "\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
|
||||||
if (scan)
|
if (scan)
|
||||||
|
@ -499,12 +544,15 @@ internal partial class SelectForm : CustomForm
|
||||||
noneFoundLabel.Text = "None of the chosen programs nor games were applicable!" + retry;
|
noneFoundLabel.Text = "None of the chosen programs nor games were applicable!" + retry;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
noneFoundLabel.Text = "You didn't choose any programs nor games!" + retry;
|
noneFoundLabel.Text = "You didn't choose any programs nor games!" + retry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
|
noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scan)
|
if (scan)
|
||||||
{
|
{
|
||||||
bool setup = true;
|
bool setup = true;
|
||||||
|
@ -518,13 +566,15 @@ internal partial class SelectForm : CustomForm
|
||||||
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
|
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
|
||||||
else curProgress = _progress;
|
else curProgress = _progress;
|
||||||
int p = Math.Max(Math.Min((int)((float)curProgress / maxProgress * 100), 100), 0);
|
int p = Math.Max(Math.Min((int)((float)curProgress / maxProgress * 100), 100), 0);
|
||||||
progressLabel.Text = setup ? $"Setting up SteamCMD . . . {p}%"
|
progressLabel.Text = setup
|
||||||
|
? $"Setting up SteamCMD . . . {p}%"
|
||||||
: $"Gathering and caching your applicable games and their DLCs . . . {p}%";
|
: $"Gathering and caching your applicable games and their DLCs . . . {p}%";
|
||||||
progressBar.Value = p;
|
progressBar.Value = p;
|
||||||
};
|
};
|
||||||
if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan is not null && ProgramsToScan.Any(c => c.platform is Platform.Steam))
|
if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan is not null
|
||||||
|
&& ProgramsToScan.Any(c => c.platform is Platform.Steam))
|
||||||
{
|
{
|
||||||
progressLabel.Text = $"Setting up SteamCMD . . . ";
|
progressLabel.Text = "Setting up SteamCMD . . . ";
|
||||||
await SteamCMD.Setup(iProgress);
|
await SteamCMD.Setup(iProgress);
|
||||||
}
|
}
|
||||||
setup = false;
|
setup = false;
|
||||||
|
@ -542,10 +592,8 @@ internal partial class SelectForm : CustomForm
|
||||||
await GetApplicablePrograms(iProgress);
|
await GetApplicablePrograms(iProgress);
|
||||||
await SteamCMD.Cleanup();
|
await SteamCMD.Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
OnLoadDlc(null, null);
|
OnLoadDlc(null, null);
|
||||||
OnLoadKoaloader(null, null);
|
OnLoadKoaloader(null, null);
|
||||||
|
|
||||||
HideProgressBar();
|
HideProgressBar();
|
||||||
selectionTreeView.Enabled = ProgramSelection.All.Any();
|
selectionTreeView.Enabled = ProgramSelection.All.Any();
|
||||||
allCheckBox.Enabled = selectionTreeView.Enabled;
|
allCheckBox.Enabled = selectionTreeView.Enabled;
|
||||||
|
@ -605,7 +653,8 @@ internal partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
string id = node.Name;
|
string id = node.Name;
|
||||||
Platform platform = (Platform)node.Tag;
|
Platform platform = (Platform)node.Tag;
|
||||||
(string gameId, (DlcType type, string name, string icon) app)? dlc = ProgramSelection.GetDlcFromPlatformId(platform, id);
|
(string gameId, (DlcType type, string name, string icon) app)? dlc
|
||||||
|
= ProgramSelection.GetDlcFromPlatformId(platform, id);
|
||||||
if (dlc.HasValue)
|
if (dlc.HasValue)
|
||||||
{
|
{
|
||||||
(string gameId, _) = dlc.Value;
|
(string gameId, _) = dlc.Value;
|
||||||
|
@ -620,7 +669,6 @@ internal partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
|
|
||||||
private List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
|
private List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
|
||||||
{
|
{
|
||||||
List<TreeNode> treeNodes = new();
|
List<TreeNode> treeNodes = new();
|
||||||
|
@ -642,12 +690,13 @@ internal partial class SelectForm : CustomForm
|
||||||
progressLabelDLCs.Text = "";
|
progressLabelDLCs.Text = "";
|
||||||
progressLabelDLCs.Visible = true;
|
progressLabelDLCs.Visible = true;
|
||||||
progressBar.Visible = true;
|
progressBar.Visible = true;
|
||||||
programsGroupBox.Size = new(programsGroupBox.Size.Width, programsGroupBox.Size.Height - 3
|
programsGroupBox.Size = new Size(programsGroupBox.Size.Width, programsGroupBox.Size.Height - 3
|
||||||
- progressLabel.Size.Height
|
- progressLabel.Size.Height
|
||||||
- progressLabelGames.Size.Height
|
- progressLabelGames.Size.Height
|
||||||
- progressLabelDLCs.Size.Height
|
- progressLabelDLCs.Size.Height
|
||||||
- progressBar.Size.Height);
|
- progressBar.Size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideProgressBar()
|
private void HideProgressBar()
|
||||||
{
|
{
|
||||||
progressBar.Value = 100;
|
progressBar.Value = 100;
|
||||||
|
@ -655,11 +704,11 @@ internal partial class SelectForm : CustomForm
|
||||||
progressLabelGames.Visible = false;
|
progressLabelGames.Visible = false;
|
||||||
progressLabelDLCs.Visible = false;
|
progressLabelDLCs.Visible = false;
|
||||||
progressBar.Visible = false;
|
progressBar.Visible = false;
|
||||||
programsGroupBox.Size = new(programsGroupBox.Size.Width, programsGroupBox.Size.Height + 3
|
programsGroupBox.Size = new Size(programsGroupBox.Size.Width, programsGroupBox.Size.Height + 3
|
||||||
+ progressLabel.Size.Height
|
+ progressLabel.Size.Height
|
||||||
+ progressLabelGames.Size.Height
|
+ progressLabelGames.Size.Height
|
||||||
+ progressLabelDLCs.Size.Height
|
+ progressLabelDLCs.Size.Height
|
||||||
+ progressBar.Size.Height);
|
+ progressBar.Size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnNodeRightClick(TreeNode node, Point location) => Invoke(() =>
|
internal void OnNodeRightClick(TreeNode node, Point location) => Invoke(() =>
|
||||||
|
@ -683,11 +732,11 @@ internal partial class SelectForm : CustomForm
|
||||||
return;
|
return;
|
||||||
ContextMenuItem header = null;
|
ContextMenuItem header = null;
|
||||||
if (id == "PL")
|
if (id == "PL")
|
||||||
header = new(node.Text, "Paradox Launcher");
|
header = new ContextMenuItem(node.Text, "Paradox Launcher");
|
||||||
else if (selection is not null)
|
else if (selection is not null)
|
||||||
header = new(node.Text, (id, selection.IconUrl));
|
header = new ContextMenuItem(node.Text, (id, selection.IconUrl));
|
||||||
else if (dlc is not null && dlcParentSelection is not null)
|
else if (dlc is not null && dlcParentSelection is not null)
|
||||||
header = new(node.Text, (id, dlc.Value.app.icon), (id, dlcParentSelection.IconUrl));
|
header = new ContextMenuItem(node.Text, (id, dlc.Value.app.icon), (id, dlcParentSelection.IconUrl));
|
||||||
items.Add(header ?? new ContextMenuItem(node.Text));
|
items.Add(header ?? new ContextMenuItem(node.Text));
|
||||||
string appInfoVDF = $@"{SteamCMD.AppInfoPath}\{id}.vdf";
|
string appInfoVDF = $@"{SteamCMD.AppInfoPath}\{id}.vdf";
|
||||||
string appInfoJSON = $@"{SteamCMD.AppInfoPath}\{id}.json";
|
string appInfoJSON = $@"{SteamCMD.AppInfoPath}\{id}.json";
|
||||||
|
@ -697,39 +746,42 @@ internal partial class SelectForm : CustomForm
|
||||||
List<ContextMenuItem> queries = new();
|
List<ContextMenuItem> queries = new();
|
||||||
if (File.Exists(appInfoJSON))
|
if (File.Exists(appInfoJSON))
|
||||||
{
|
{
|
||||||
string platformString = (selection is null || selection.Platform is Platform.Steam) ? "Steam Store "
|
string platformString = selection is null || selection.Platform is Platform.Steam
|
||||||
: selection.Platform is Platform.Epic ? "Epic GraphQL " : "";
|
? "Steam Store "
|
||||||
|
: selection.Platform is Platform.Epic
|
||||||
|
? "Epic GraphQL "
|
||||||
|
: "";
|
||||||
queries.Add(new ContextMenuItem($"Open {platformString}Query", "Notepad",
|
queries.Add(new ContextMenuItem($"Open {platformString}Query", "Notepad",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON))));
|
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
|
||||||
}
|
}
|
||||||
if (File.Exists(appInfoVDF))
|
if (File.Exists(appInfoVDF))
|
||||||
queries.Add(new ContextMenuItem("Open SteamCMD Query", "Notepad",
|
queries.Add(new ContextMenuItem("Open SteamCMD Query", "Notepad",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenFileInNotepad(appInfoVDF))));
|
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
|
||||||
if (queries.Any())
|
if (queries.Any())
|
||||||
{
|
{
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
foreach (ContextMenuItem query in queries)
|
foreach (ContextMenuItem query in queries)
|
||||||
items.Add(query);
|
items.Add(query);
|
||||||
items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt",
|
items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt",
|
||||||
new EventHandler((sender, e) =>
|
(sender, e) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(appInfoVDF);
|
File.Delete(appInfoVDF);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(appInfoJSON);
|
File.Delete(appInfoJSON);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.Delete(cooldown);
|
File.Delete(cooldown);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
OnLoad(forceScan: true);
|
OnLoad(true);
|
||||||
})));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selection is not null)
|
if (selection is not null)
|
||||||
|
@ -738,89 +790,109 @@ internal partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
items.Add(new ContextMenuItem("Repair", "Command Prompt",
|
items.Add(new ContextMenuItem("Repair", "Command Prompt",
|
||||||
new EventHandler(async (sender, e) => await ParadoxLauncher.Repair(this, selection))));
|
async (sender, e) => await ParadoxLauncher.Repair(this, selection)));
|
||||||
}
|
}
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
items.Add(new ContextMenuItem("Open Root Directory", "File Explorer",
|
items.Add(new ContextMenuItem("Open Root Directory", "File Explorer",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(selection.RootDirectory))));
|
(sender, e) => Diagnostics.OpenDirectoryInFileExplorer(
|
||||||
|
selection.RootDirectory)));
|
||||||
int executables = 0;
|
int executables = 0;
|
||||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories.ToList())
|
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories.ToList())
|
||||||
{
|
items.Add(new ContextMenuItem(
|
||||||
items.Add(new ContextMenuItem($"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)", "File Explorer",
|
$"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
"File Explorer",
|
||||||
}
|
(sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
|
||||||
List<string> directories = selection.DllDirectories.ToList();
|
List<string> directories = selection.DllDirectories.ToList();
|
||||||
int steam = 0, epic = 0, r1 = 0, r2 = 0;
|
int steam = 0, epic = 0, r1 = 0, r2 = 0;
|
||||||
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string cache);
|
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache))
|
out string api64_o, out string config, out string cache);
|
||||||
|
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o)
|
||||||
|
|| File.Exists(config) || File.Exists(cache))
|
||||||
items.Add(new ContextMenuItem($"Open Steamworks Directory #{++steam}", "File Explorer",
|
items.Add(new ContextMenuItem($"Open Steamworks Directory #{++steam}", "File Explorer",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
(sender, e) => Diagnostics
|
||||||
|
.OpenDirectoryInFileExplorer(directory)));
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Epic or Platform.Paradox)
|
if (selection.Platform is Platform.Epic or Platform.Paradox)
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(config))
|
out string api64_o, out string config);
|
||||||
|
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o)
|
||||||
|
|| File.Exists(config))
|
||||||
items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
|
items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
(sender, e) => Diagnostics
|
||||||
|
.OpenDirectoryInFileExplorer(directory)));
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Ubisoft)
|
if (selection.Platform is Platform.Ubisoft)
|
||||||
foreach (string directory in directories)
|
foreach (string directory in directories)
|
||||||
{
|
{
|
||||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
|
||||||
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(config))
|
out string api64_o, out string config);
|
||||||
|
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o)
|
||||||
|
|| File.Exists(config))
|
||||||
items.Add(new ContextMenuItem($"Open Uplay R1 Directory #{++r1}", "File Explorer",
|
items.Add(new ContextMenuItem($"Open Uplay R1 Directory #{++r1}", "File Explorer",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
(sender, e) => Diagnostics
|
||||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config);
|
.OpenDirectoryInFileExplorer(directory)));
|
||||||
if (File.Exists(old_api32) || File.Exists(old_api64) || File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(config))
|
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o,
|
||||||
|
out api64, out api64_o, out config);
|
||||||
|
if (File.Exists(old_api32) || File.Exists(old_api64) || File.Exists(api32) || File.Exists(api32_o)
|
||||||
|
|| File.Exists(api64) || File.Exists(api64_o) || File.Exists(config))
|
||||||
items.Add(new ContextMenuItem($"Open Uplay R2 Directory #{++r2}", "File Explorer",
|
items.Add(new ContextMenuItem($"Open Uplay R2 Directory #{++r2}", "File Explorer",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
(sender, e) => Diagnostics
|
||||||
|
.OpenDirectoryInFileExplorer(directory)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (id != "PL")
|
if (id != "PL")
|
||||||
{
|
{
|
||||||
if (selection is not null && selection.Platform is Platform.Steam
|
if ((selection is not null && selection.Platform is Platform.Steam)
|
||||||
|| dlcParentSelection is not null && dlcParentSelection.Platform is Platform.Steam)
|
|| (dlcParentSelection is not null && dlcParentSelection.Platform is Platform.Steam))
|
||||||
{
|
{
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
items.Add(new ContextMenuItem("Open SteamDB", "SteamDB",
|
items.Add(new ContextMenuItem("Open SteamDB", "SteamDB",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamdb.info/app/" + id))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
|
"https://steamdb.info/app/" + id)));
|
||||||
}
|
}
|
||||||
if (selection is not null)
|
if (selection is not null)
|
||||||
{
|
{
|
||||||
if (selection.Platform is Platform.Steam)
|
if (selection.Platform is Platform.Steam)
|
||||||
{
|
{
|
||||||
items.Add(new ContextMenuItem("Open Steam Store", "Steam Store",
|
items.Add(new ContextMenuItem("Open Steam Store", "Steam Store",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIconUrl), "Steam Community",
|
selection.ProductUrl)));
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + id))));
|
items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIconUrl),
|
||||||
|
"Steam Community",
|
||||||
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
|
"https://steamcommunity.com/app/" + id)));
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Epic)
|
if (selection.Platform is Platform.Epic)
|
||||||
{
|
{
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
items.Add(new ContextMenuItem("Open ScreamDB", "ScreamDB",
|
items.Add(new ContextMenuItem("Open ScreamDB", "ScreamDB",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://scream-db.web.app/offers/" + id))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
|
"https://scream-db.web.app/offers/" + id)));
|
||||||
items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
|
items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
|
selection.ProductUrl)));
|
||||||
}
|
}
|
||||||
if (selection.Platform is Platform.Ubisoft)
|
if (selection.Platform is Platform.Ubisoft)
|
||||||
{
|
{
|
||||||
items.Add(new ToolStripSeparator());
|
items.Add(new ToolStripSeparator());
|
||||||
#pragma warning disable CA1308 // Normalize strings to uppercase
|
#pragma warning disable CA1308 // Normalize strings to uppercase
|
||||||
items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
|
items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://store.ubi.com/us/" + selection.Name.Replace(" ", "-").ToLowerInvariant()))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||||
|
"https://store.ubi.com/us/" + selection.Name.Replace(" ", "-")
|
||||||
|
.ToLowerInvariant())));
|
||||||
#pragma warning restore CA1308 // Normalize strings to uppercase
|
#pragma warning restore CA1308 // Normalize strings to uppercase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selection is not null && selection.WebsiteUrl is not null)
|
if (selection is not null && selection.WebsiteUrl is not null)
|
||||||
{
|
items.Add(new ContextMenuItem("Open Official Website",
|
||||||
items.Add(new ContextMenuItem("Open Official Website", ("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.WebsiteUrl)),
|
("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.WebsiteUrl)),
|
||||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.WebsiteUrl))));
|
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.WebsiteUrl)));
|
||||||
}
|
|
||||||
contextMenuStrip.Show(selectionTreeView, location);
|
contextMenuStrip.Show(selectionTreeView, location);
|
||||||
contextMenuStrip.Refresh();
|
contextMenuStrip.Refresh();
|
||||||
ContextMenuStrip.Tag = null;
|
ContextMenuStrip.Tag = null;
|
||||||
|
@ -828,7 +900,7 @@ internal partial class SelectForm : CustomForm
|
||||||
|
|
||||||
private void OnLoad(object sender, EventArgs _)
|
private void OnLoad(object sender, EventArgs _)
|
||||||
{
|
{
|
||||||
retry:
|
retry:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HideProgressBar();
|
HideProgressBar();
|
||||||
|
@ -837,7 +909,7 @@ internal partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (e.HandleException(form: this)) goto retry;
|
if (e.HandleException(this)) goto retry;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -847,7 +919,8 @@ internal partial class SelectForm : CustomForm
|
||||||
if (ProgramSelection.All.Any())
|
if (ProgramSelection.All.Any())
|
||||||
{
|
{
|
||||||
foreach (ProgramSelection selection in ProgramSelection.AllEnabled)
|
foreach (ProgramSelection selection in ProgramSelection.AllEnabled)
|
||||||
if (!Program.IsProgramRunningDialog(this, selection)) return;
|
if (!Program.IsProgramRunningDialog(this, selection))
|
||||||
|
return;
|
||||||
if (!uninstall && ParadoxLauncher.DlcDialog(this)) return;
|
if (!uninstall && ParadoxLauncher.DlcDialog(this)) return;
|
||||||
Hide();
|
Hide();
|
||||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||||
|
@ -865,7 +938,10 @@ internal partial class SelectForm : CustomForm
|
||||||
#endif
|
#endif
|
||||||
OnLoad();
|
OnLoad();
|
||||||
}
|
}
|
||||||
else Close();
|
else
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
form.Show();
|
form.Show();
|
||||||
Hide();
|
Hide();
|
||||||
|
@ -875,7 +951,7 @@ internal partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInstall(object sender, EventArgs e) => OnAccept(false);
|
private void OnInstall(object sender, EventArgs e) => OnAccept();
|
||||||
|
|
||||||
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
|
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
|
||||||
|
|
||||||
|
@ -900,7 +976,7 @@ internal partial class SelectForm : CustomForm
|
||||||
if (node.Parent is null && node.Checked != shouldCheck)
|
if (node.Parent is null && node.Checked != shouldCheck)
|
||||||
{
|
{
|
||||||
node.Checked = shouldCheck;
|
node.Checked = shouldCheck;
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
|
||||||
}
|
}
|
||||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||||
allCheckBox.Checked = shouldCheck;
|
allCheckBox.Checked = shouldCheck;
|
||||||
|
@ -927,16 +1003,20 @@ internal partial class SelectForm : CustomForm
|
||||||
private bool AreSelectionsDefault()
|
private bool AreSelectionsDefault()
|
||||||
{
|
{
|
||||||
foreach (TreeNode node in TreeNodes)
|
foreach (TreeNode node in TreeNodes)
|
||||||
if (node.Parent is not null && node.Tag is Platform && (node.Text == "Unknown" ? node.Checked : !node.Checked))
|
if (node.Parent is not null && node.Tag is Platform
|
||||||
|
&& (node.Text == "Unknown" ? node.Checked : !node.Checked))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanSaveDlc() => installButton.Enabled && (ProgramData.ReadDlcChoices() is not null || !AreSelectionsDefault());
|
private bool CanSaveDlc()
|
||||||
|
=> installButton.Enabled && (ProgramData.ReadDlcChoices() is not null || !AreSelectionsDefault());
|
||||||
|
|
||||||
private void OnSaveDlc(object sender, EventArgs e)
|
private void OnSaveDlc(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices() ?? new();
|
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices()
|
||||||
|
?? new List<(Platform platform, string gameId,
|
||||||
|
string dlcId)>();
|
||||||
foreach (TreeNode node in TreeNodes)
|
foreach (TreeNode node in TreeNodes)
|
||||||
if (node.Parent is TreeNode parent && node.Tag is Platform platform)
|
if (node.Parent is TreeNode parent && node.Tag is Platform platform)
|
||||||
{
|
{
|
||||||
|
@ -960,10 +1040,11 @@ internal partial class SelectForm : CustomForm
|
||||||
foreach (TreeNode node in TreeNodes)
|
foreach (TreeNode node in TreeNodes)
|
||||||
if (node.Parent is TreeNode parent && node.Tag is Platform platform)
|
if (node.Parent is TreeNode parent && node.Tag is Platform platform)
|
||||||
{
|
{
|
||||||
node.Checked = choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name)
|
node.Checked
|
||||||
? node.Text == "Unknown"
|
= choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name)
|
||||||
: node.Text != "Unknown";
|
? node.Text == "Unknown"
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
: node.Text != "Unknown";
|
||||||
|
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -975,7 +1056,7 @@ internal partial class SelectForm : CustomForm
|
||||||
if (node.Parent is not null && node.Tag is Platform)
|
if (node.Parent is not null && node.Tag is Platform)
|
||||||
{
|
{
|
||||||
node.Checked = node.Text != "Unknown";
|
node.Checked = node.Text != "Unknown";
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
|
||||||
}
|
}
|
||||||
resetButton.Enabled = CanResetDlc();
|
resetButton.Enabled = CanResetDlc();
|
||||||
}
|
}
|
||||||
|
@ -988,16 +1069,22 @@ internal partial class SelectForm : CustomForm
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanSaveKoaloader() => ProgramData.ReadKoaloaderChoices() is not null || !AreKoaloaderSelectionsDefault();
|
private static bool CanSaveKoaloader()
|
||||||
|
=> ProgramData.ReadKoaloaderChoices() is not null || !AreKoaloaderSelectionsDefault();
|
||||||
|
|
||||||
private void OnSaveKoaloader(object sender, EventArgs e)
|
private void OnSaveKoaloader(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices() ?? new();
|
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices()
|
||||||
|
?? new List<(Platform platform, string id, string proxy, bool enabled)>();
|
||||||
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
|
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
|
||||||
{
|
{
|
||||||
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
|
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
|
||||||
if (selection.KoaloaderProxy is not null and not ProgramSelection.DefaultKoaloaderProxy || !selection.Koaloader)
|
if (selection.KoaloaderProxy is not null and not ProgramSelection.DefaultKoaloaderProxy
|
||||||
choices.Add((selection.Platform, selection.Id, selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy, selection.Koaloader));
|
|| !selection.Koaloader)
|
||||||
|
choices.Add((selection.Platform, selection.Id,
|
||||||
|
selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy
|
||||||
|
? null
|
||||||
|
: selection.KoaloaderProxy, selection.Koaloader));
|
||||||
}
|
}
|
||||||
ProgramData.WriteKoaloaderProxyChoices(choices);
|
ProgramData.WriteKoaloaderProxyChoices(choices);
|
||||||
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
||||||
|
@ -1011,7 +1098,6 @@ internal partial class SelectForm : CustomForm
|
||||||
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices();
|
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices();
|
||||||
if (choices is null) return;
|
if (choices is null) return;
|
||||||
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
|
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
|
||||||
{
|
|
||||||
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
|
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
|
||||||
{
|
{
|
||||||
(Platform platform, string id, string proxy, bool enabled) choice =
|
(Platform platform, string id, string proxy, bool enabled) choice =
|
||||||
|
@ -1023,11 +1109,14 @@ internal partial class SelectForm : CustomForm
|
||||||
if (proxy != currentProxy && choices.Remove(choice)) // convert pre-v4.1.0.0 choices
|
if (proxy != currentProxy && choices.Remove(choice)) // convert pre-v4.1.0.0 choices
|
||||||
choices.Add((platform, id, currentProxy, enabled));
|
choices.Add((platform, id, currentProxy, enabled));
|
||||||
if (currentProxy is null or ProgramSelection.DefaultKoaloaderProxy && enabled)
|
if (currentProxy is null or ProgramSelection.DefaultKoaloaderProxy && enabled)
|
||||||
|
{
|
||||||
_ = choices.RemoveAll(c => c.platform == platform && c.id == id);
|
_ = choices.RemoveAll(c => c.platform == platform && c.id == id);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selection.Koaloader = enabled;
|
selection.Koaloader = enabled;
|
||||||
selection.KoaloaderProxy = currentProxy == ProgramSelection.DefaultKoaloaderProxy ? currentProxy : proxy;
|
selection.KoaloaderProxy
|
||||||
|
= currentProxy == ProgramSelection.DefaultKoaloaderProxy ? currentProxy : proxy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1035,7 +1124,6 @@ internal partial class SelectForm : CustomForm
|
||||||
selection.Koaloader = true;
|
selection.Koaloader = true;
|
||||||
selection.KoaloaderProxy = null;
|
selection.KoaloaderProxy = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ProgramData.WriteKoaloaderProxyChoices(choices);
|
ProgramData.WriteKoaloaderProxyChoices(choices);
|
||||||
loadKoaloaderButton.Enabled = CanLoadKoaloader();
|
loadKoaloaderButton.Enabled = CanLoadKoaloader();
|
||||||
OnKoaloaderChanged();
|
OnKoaloaderChanged();
|
||||||
|
@ -1069,7 +1157,6 @@ internal partial class SelectForm : CustomForm
|
||||||
OnLoad(forceProvideChoices: true);
|
OnLoad(forceProvideChoices: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly string helpButtonListPrefix = "\n • ";
|
|
||||||
private void OnBlockProtectedGamesHelpButtonClicked(object sender, EventArgs e)
|
private void OnBlockProtectedGamesHelpButtonClicked(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
StringBuilder blockedGames = new();
|
StringBuilder blockedGames = new();
|
||||||
|
@ -1083,12 +1170,18 @@ internal partial class SelectForm : CustomForm
|
||||||
_ = blockedDirectoryExceptions.Append(helpButtonListPrefix + name);
|
_ = blockedDirectoryExceptions.Append(helpButtonListPrefix + name);
|
||||||
using DialogForm form = new(this);
|
using DialogForm form = new(this);
|
||||||
_ = form.Show(SystemIcons.Information,
|
_ = form.Show(SystemIcons.Information,
|
||||||
"Blocks the program from caching and displaying games protected by anti-cheats." +
|
"Blocks the program from caching and displaying games protected by anti-cheats." +
|
||||||
"\nYou disable this option and install DLC unlockers to protected games at your own risk!" +
|
"\nYou disable this option and install DLC unlockers to protected games at your own risk!" +
|
||||||
"\n\nBlocked games: " + (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) +
|
"\n\nBlocked games: "
|
||||||
"\n\nBlocked game sub-directories: " + (string.IsNullOrWhiteSpace(blockedDirectories.ToString()) ? "(none)" : blockedDirectories) +
|
+ (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) +
|
||||||
"\n\nBlocked game sub-directory exceptions: " + (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString()) ? "(none)" : blockedDirectoryExceptions),
|
"\n\nBlocked game sub-directories: " + (string.IsNullOrWhiteSpace(blockedDirectories.ToString())
|
||||||
"OK", customFormText: "Block Protected Games");
|
? "(none)"
|
||||||
|
: blockedDirectories) +
|
||||||
|
"\n\nBlocked game sub-directory exceptions: "
|
||||||
|
+ (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString())
|
||||||
|
? "(none)"
|
||||||
|
: blockedDirectoryExceptions),
|
||||||
|
"OK", customFormText: "Block Protected Games");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSortCheckBoxChanged(object sender, EventArgs e) => selectionTreeView.TreeViewNodeSorter
|
private void OnSortCheckBoxChanged(object sender, EventArgs e) => selectionTreeView.TreeViewNodeSorter
|
||||||
|
|
|
@ -10,4 +10,4 @@
|
||||||
|
|
||||||
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types")]
|
||||||
|
|
||||||
[assembly: SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task")]
|
[assembly: SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task")]
|
|
@ -1,14 +1,10 @@
|
||||||
using CreamInstaller.Resources;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Microsoft.Win32;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Epic;
|
namespace CreamInstaller.Platforms.Epic;
|
||||||
|
@ -16,21 +12,32 @@ namespace CreamInstaller.Platforms.Epic;
|
||||||
internal static class EpicLibrary
|
internal static class EpicLibrary
|
||||||
{
|
{
|
||||||
private static string epicManifestsPath;
|
private static string epicManifestsPath;
|
||||||
|
|
||||||
internal static string EpicManifestsPath
|
internal static string EpicManifestsPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
epicManifestsPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir", null) as string;
|
epicManifestsPath
|
||||||
epicManifestsPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Wow6432Node\Epic Games\EOS", "ModSdkMetadataDir", null) as string;
|
??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir",
|
||||||
epicManifestsPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Epic Games\EpicGamesLauncher", "AppDataPath", null) as string;
|
null) as string;
|
||||||
epicManifestsPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Epic Games\EpicGamesLauncher", "AppDataPath", null) as string;
|
epicManifestsPath
|
||||||
if (epicManifestsPath is not null && epicManifestsPath.EndsWith(@"\Data")) epicManifestsPath += @"\Manifests";
|
??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Wow6432Node\Epic Games\EOS", "ModSdkMetadataDir",
|
||||||
|
null) as string;
|
||||||
|
epicManifestsPath
|
||||||
|
??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Epic Games\EpicGamesLauncher", "AppDataPath",
|
||||||
|
null) as string;
|
||||||
|
epicManifestsPath
|
||||||
|
??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Epic Games\EpicGamesLauncher",
|
||||||
|
"AppDataPath", null) as string;
|
||||||
|
if (epicManifestsPath is not null && epicManifestsPath.EndsWith(@"\Data"))
|
||||||
|
epicManifestsPath += @"\Manifests";
|
||||||
return epicManifestsPath.BeautifyPath();
|
return epicManifestsPath.BeautifyPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
string gameDirectory) =>
|
||||||
|
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||||
|
|
||||||
internal static async Task<List<Manifest>> GetGames() => await Task.Run(() =>
|
internal static async Task<List<Manifest>> GetGames() => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
@ -45,10 +52,12 @@ internal static class EpicLibrary
|
||||||
{
|
{
|
||||||
Manifest manifest = JsonSerializer.Deserialize<Manifest>(json);
|
Manifest manifest = JsonSerializer.Deserialize<Manifest>(json);
|
||||||
if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId
|
if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId
|
||||||
&& !games.Any(g => g.CatalogItemId == manifest.CatalogItemId && g.InstallLocation == manifest.InstallLocation))
|
&& !games.Any(g => g.CatalogItemId == manifest.CatalogItemId
|
||||||
|
&& g.InstallLocation == manifest.InstallLocation))
|
||||||
games.Add(manifest);
|
games.Add(manifest);
|
||||||
}
|
}
|
||||||
catch { };
|
catch { }
|
||||||
|
;
|
||||||
}
|
}
|
||||||
return games;
|
return games;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
using CreamInstaller.Platforms.Epic.GraphQL;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -11,6 +6,9 @@ using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using CreamInstaller.Platforms.Epic.GraphQL;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Epic;
|
namespace CreamInstaller.Platforms.Epic;
|
||||||
|
|
||||||
|
@ -24,7 +22,9 @@ internal static class EpicStore
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
private const int COOLDOWN_ENTITLEMENT = 600;
|
private const int COOLDOWN_ENTITLEMENT = 600;
|
||||||
internal static async Task<List<(string id, string name, string product, string icon, string developer)>> QueryEntitlements(string categoryNamespace)
|
|
||||||
|
internal static async Task<List<(string id, string name, string product, string icon, string developer)>>
|
||||||
|
QueryEntitlements(string categoryNamespace)
|
||||||
{
|
{
|
||||||
List<(string id, string name, string product, string icon, string developer)> dlcIds = new();
|
List<(string id, string name, string product, string icon, string developer)> dlcIds = new();
|
||||||
string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json";
|
string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json";
|
||||||
|
@ -35,19 +35,21 @@ internal static class EpicStore
|
||||||
response = await QueryGraphQL(categoryNamespace);
|
response = await QueryGraphQL(categoryNamespace);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented));
|
await File.WriteAllTextAsync(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
else if (cachedExists)
|
else if (cachedExists)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
response = JsonConvert.DeserializeObject<Response>(File.ReadAllText(cacheFile));
|
response = JsonConvert.DeserializeObject<Response>(await File.ReadAllTextAsync(cacheFile));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
File.Delete(cacheFile);
|
File.Delete(cacheFile);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (response is null)
|
if (response is null)
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
List<Element> searchStore = new(response.Data.Catalog.SearchStore.Elements);
|
List<Element> searchStore = new(response.Data.Catalog.SearchStore.Elements);
|
||||||
|
@ -55,7 +57,8 @@ internal static class EpicStore
|
||||||
{
|
{
|
||||||
string title = element.Title;
|
string title = element.Title;
|
||||||
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any()
|
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any()
|
||||||
? element.CatalogNs.Mappings.First().PageSlug : null;
|
? element.CatalogNs.Mappings.First().PageSlug
|
||||||
|
: null;
|
||||||
string icon = null;
|
string icon = null;
|
||||||
for (int i = 0; i < element.KeyImages?.Length; i++)
|
for (int i = 0; i < element.KeyImages?.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -67,14 +70,15 @@ internal static class EpicStore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (Item item in element.Items)
|
foreach (Item item in element.Items)
|
||||||
dlcIds.Populate(item.Id, title, product, icon, null, canOverwrite: element.Items.Length == 1);
|
dlcIds.Populate(item.Id, title, product, icon, null, element.Items.Length == 1);
|
||||||
}
|
}
|
||||||
List<Element> catalogOffers = new(response.Data.Catalog.CatalogOffers.Elements);
|
List<Element> catalogOffers = new(response.Data.Catalog.CatalogOffers.Elements);
|
||||||
foreach (Element element in catalogOffers)
|
foreach (Element element in catalogOffers)
|
||||||
{
|
{
|
||||||
string title = element.Title;
|
string title = element.Title;
|
||||||
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any()
|
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any()
|
||||||
? element.CatalogNs.Mappings.First().PageSlug : null;
|
? element.CatalogNs.Mappings.First().PageSlug
|
||||||
|
: null;
|
||||||
string icon = null;
|
string icon = null;
|
||||||
for (int i = 0; i < element.KeyImages?.Length; i++)
|
for (int i = 0; i < element.KeyImages?.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -86,12 +90,14 @@ internal static class EpicStore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (Item item in element.Items)
|
foreach (Item item in element.Items)
|
||||||
dlcIds.Populate(item.Id, title, product, icon, item.Developer, canOverwrite: element.Items.Length == 1);
|
dlcIds.Populate(item.Id, title, product, icon, item.Developer, element.Items.Length == 1);
|
||||||
}
|
}
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Populate(this List<(string id, string name, string product, string icon, string developer)> dlcIds, string id, string title, string product, string icon, string developer, bool canOverwrite = false)
|
private static void Populate(
|
||||||
|
this List<(string id, string name, string product, string icon, string developer)> dlcIds, string id,
|
||||||
|
string title, string product, string icon, string developer, bool canOverwrite = false)
|
||||||
{
|
{
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -121,7 +127,8 @@ internal static class EpicStore
|
||||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
HttpClient client = HttpClientManager.HttpClient;
|
HttpClient client = HttpClientManager.HttpClient;
|
||||||
if (client is null) return null;
|
if (client is null) return null;
|
||||||
HttpResponseMessage httpResponse = await client.PostAsync(new Uri("https://graphql.epicgames.com/graphql"), content);
|
HttpResponseMessage httpResponse
|
||||||
|
= await client.PostAsync(new Uri("https://graphql.epicgames.com/graphql"), content);
|
||||||
_ = httpResponse.EnsureSuccessStatusCode();
|
_ = httpResponse.EnsureSuccessStatusCode();
|
||||||
string response = await httpResponse.Content.ReadAsStringAsync();
|
string response = await httpResponse.Content.ReadAsStringAsync();
|
||||||
return JsonConvert.DeserializeObject<Response>(response);
|
return JsonConvert.DeserializeObject<Response>(response);
|
||||||
|
|
|
@ -64,7 +64,6 @@ internal class Request
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "Content-Type")]
|
[JsonProperty(PropertyName = "Content-Type")]
|
||||||
private string ContentType => "application/graphql";
|
private string ContentType => "application/graphql";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Variables
|
private class Variables
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#pragma warning disable CA1819 // Properties should not return arrays
|
#pragma warning disable CA1819 // Properties should not return arrays
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Epic.GraphQL;
|
namespace CreamInstaller.Platforms.Epic.GraphQL;
|
||||||
|
|
||||||
public class Response
|
public class Response
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "data")]
|
[JsonProperty(PropertyName = "data")] public ResponseData Data { get; protected set; }
|
||||||
public ResponseData Data { get; protected set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ResponseData
|
public class ResponseData
|
||||||
|
@ -35,17 +33,14 @@ public class ElementContainer
|
||||||
|
|
||||||
public class Element
|
public class Element
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "id")]
|
[JsonProperty(PropertyName = "id")] public string Id { get; protected set; }
|
||||||
public string Id { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "title")]
|
[JsonProperty(PropertyName = "title")] public string Title { get; protected set; }
|
||||||
public string Title { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "keyImages")]
|
[JsonProperty(PropertyName = "keyImages")]
|
||||||
public KeyImage[] KeyImages { get; protected set; }
|
public KeyImage[] KeyImages { get; protected set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "items")]
|
[JsonProperty(PropertyName = "items")] public Item[] Items { get; protected set; }
|
||||||
public Item[] Items { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "catalogNs")]
|
[JsonProperty(PropertyName = "catalogNs")]
|
||||||
public CatalogNs CatalogNs { get; protected set; }
|
public CatalogNs CatalogNs { get; protected set; }
|
||||||
|
@ -53,11 +48,9 @@ public class Element
|
||||||
|
|
||||||
public class Item
|
public class Item
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "id")]
|
[JsonProperty(PropertyName = "id")] public string Id { get; protected set; }
|
||||||
public string Id { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "title")]
|
[JsonProperty(PropertyName = "title")] public string Title { get; protected set; }
|
||||||
public string Title { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "developer")]
|
[JsonProperty(PropertyName = "developer")]
|
||||||
public string Developer { get; protected set; }
|
public string Developer { get; protected set; }
|
||||||
|
@ -65,11 +58,9 @@ public class Item
|
||||||
|
|
||||||
public class KeyImage
|
public class KeyImage
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "type")]
|
[JsonProperty(PropertyName = "type")] public string Type { get; protected set; }
|
||||||
public string Type { get; protected set; }
|
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "url")]
|
[JsonProperty(PropertyName = "url")] public Uri Url { get; protected set; }
|
||||||
public Uri Url { get; protected set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CatalogNs
|
public class CatalogNs
|
||||||
|
|
|
@ -1,34 +1,46 @@
|
||||||
using CreamInstaller.Resources;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Microsoft.Win32;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Paradox;
|
namespace CreamInstaller.Platforms.Paradox;
|
||||||
|
|
||||||
internal static class ParadoxLauncher
|
internal static class ParadoxLauncher
|
||||||
{
|
{
|
||||||
|
public enum RepairResult
|
||||||
|
{
|
||||||
|
ProgramRunning = -2, Failure, Unnecessary = 0,
|
||||||
|
Success
|
||||||
|
}
|
||||||
|
|
||||||
private static string installPath;
|
private static string installPath;
|
||||||
|
|
||||||
internal static string InstallPath
|
internal static string InstallPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2",
|
||||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Wow6432Node\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
"LauncherInstallation", null) as string;
|
||||||
|
installPath ??= Registry.GetValue(
|
||||||
|
@"HKEY_CURRENT_USER\Software\Wow6432Node\Paradox Interactive\Paradox Launcher v2",
|
||||||
|
"LauncherInstallation", null) as string;
|
||||||
return installPath.BeautifyPath();
|
return installPath.BeautifyPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
|
string gameDirectory) =>
|
||||||
|
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path
|
||||||
|
=> !Path.GetFileName(path)
|
||||||
|
.Contains("bootstrapper")));
|
||||||
|
|
||||||
private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
|
private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
|
||||||
{
|
{
|
||||||
|
@ -37,16 +49,26 @@ internal static class ParadoxLauncher
|
||||||
{
|
{
|
||||||
paradoxLauncher.ExtraDlc.Clear();
|
paradoxLauncher.ExtraDlc.Clear();
|
||||||
paradoxLauncher.ExtraSelectedDlc.Clear();
|
paradoxLauncher.ExtraSelectedDlc.Clear();
|
||||||
foreach (ProgramSelection selection in ProgramSelection.AllEnabled.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
foreach (ProgramSelection selection in ProgramSelection.AllEnabled.Where(
|
||||||
|
s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
||||||
{
|
{
|
||||||
paradoxLauncher.ExtraDlc.Add(new(selection.Id, selection.Name, selection.AllDlc));
|
paradoxLauncher.ExtraDlc.Add(
|
||||||
paradoxLauncher.ExtraSelectedDlc.Add(new(selection.Id, selection.Name, selection.SelectedDlc));
|
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
|
||||||
|
selection.Id, selection.Name, selection.AllDlc));
|
||||||
|
paradoxLauncher.ExtraSelectedDlc.Add(
|
||||||
|
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
|
||||||
|
selection.Id, selection.Name, selection.SelectedDlc));
|
||||||
}
|
}
|
||||||
if (!paradoxLauncher.ExtraDlc.Any())
|
if (!paradoxLauncher.ExtraDlc.Any())
|
||||||
foreach (ProgramSelection selection in ProgramSelection.AllSafe.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
foreach (ProgramSelection selection in ProgramSelection.AllSafe.Where(
|
||||||
|
s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
||||||
{
|
{
|
||||||
paradoxLauncher.ExtraDlc.Add(new(selection.Id, selection.Name, selection.AllDlc));
|
paradoxLauncher.ExtraDlc.Add(
|
||||||
paradoxLauncher.ExtraSelectedDlc.Add(new(selection.Id, selection.Name, selection.AllDlc));
|
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
|
||||||
|
selection.Id, selection.Name, selection.AllDlc));
|
||||||
|
paradoxLauncher.ExtraSelectedDlc.Add(
|
||||||
|
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
|
||||||
|
selection.Id, selection.Name, selection.AllDlc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,27 +83,21 @@ internal static class ParadoxLauncher
|
||||||
{
|
{
|
||||||
using DialogForm dialogForm = new(form);
|
using DialogForm dialogForm = new(form);
|
||||||
return dialogForm.Show(SystemIcons.Warning,
|
return dialogForm.Show(SystemIcons.Warning,
|
||||||
$"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!" +
|
"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!"
|
||||||
"\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!",
|
+
|
||||||
"Ignore", "Cancel", customFormText: "Paradox Launcher") != DialogResult.OK;
|
"\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!",
|
||||||
|
"Ignore", "Cancel", "Paradox Launcher") != DialogResult.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RepairResult
|
|
||||||
{
|
|
||||||
ProgramRunning = -2,
|
|
||||||
Failure,
|
|
||||||
Unnecessary = 0,
|
|
||||||
Success
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static async Task<RepairResult> Repair(Form form, ProgramSelection selection)
|
internal static async Task<RepairResult> Repair(Form form, ProgramSelection selection)
|
||||||
{
|
{
|
||||||
InstallForm installForm = form as InstallForm;
|
InstallForm installForm = form as InstallForm;
|
||||||
if (!Program.IsProgramRunningDialog(form, selection))
|
if (!Program.IsProgramRunningDialog(form, selection))
|
||||||
return form is InstallForm ? throw new CustomMessageException("Repair failed! The launcher is currently running!")
|
return form is InstallForm
|
||||||
|
? throw new CustomMessageException("Repair failed! The launcher is currently running!")
|
||||||
: RepairResult.ProgramRunning;
|
: RepairResult.ProgramRunning;
|
||||||
bool smokeInstalled = false;
|
bool smokeInstalled = false;
|
||||||
byte[] steamOriginalSdk32 = null;
|
byte[] steamOriginalSdk32 = null;
|
||||||
|
@ -92,33 +108,39 @@ internal static class ParadoxLauncher
|
||||||
foreach (string directory in selection.DllDirectories)
|
foreach (string directory in selection.DllDirectories)
|
||||||
{
|
{
|
||||||
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
||||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||||
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
||||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out _);
|
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config, out _);
|
||||||
smokeInstalled = smokeInstalled
|
smokeInstalled = smokeInstalled
|
||||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled
|
|| (File.Exists(config) && !koaloaderInstalled)
|
||||||
|| File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.Steamworks32)
|
|| (File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
||||||
|| File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.Steamworks64);
|
|| (File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.Steamworks64));
|
||||||
await SmokeAPI.Uninstall(directory, deleteConfig: false);
|
await SmokeAPI.Uninstall(directory, deleteConfig: false);
|
||||||
if (steamOriginalSdk32 is null && File.Exists(api32) && !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
if (steamOriginalSdk32 is null && File.Exists(api32)
|
||||||
steamOriginalSdk32 = File.ReadAllBytes(api32);
|
&& !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
||||||
if (steamOriginalSdk64 is null && File.Exists(api64) && !api64.IsResourceFile(ResourceIdentifier.Steamworks64))
|
steamOriginalSdk32 = await File.ReadAllBytesAsync(api32);
|
||||||
steamOriginalSdk64 = File.ReadAllBytes(api64);
|
if (steamOriginalSdk64 is null && File.Exists(api64)
|
||||||
|
&& !api64.IsResourceFile(ResourceIdentifier.Steamworks64))
|
||||||
|
steamOriginalSdk64 = await File.ReadAllBytesAsync(api64);
|
||||||
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out config);
|
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out config);
|
||||||
screamInstalled = screamInstalled
|
screamInstalled = screamInstalled
|
||||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled
|
|| (File.Exists(config) && !koaloaderInstalled)
|
||||||
|| File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32)
|
|| (File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
||||||
|| File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64);
|
|| (File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64));
|
||||||
await ScreamAPI.Uninstall(directory, deleteConfig: false);
|
await ScreamAPI.Uninstall(directory, deleteConfig: false);
|
||||||
if (epicOriginalSdk32 is null && File.Exists(api32) && !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
if (epicOriginalSdk32 is null && File.Exists(api32)
|
||||||
epicOriginalSdk32 = File.ReadAllBytes(api32);
|
&& !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
||||||
if (epicOriginalSdk64 is null && File.Exists(api64) && !api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
|
epicOriginalSdk32 = await File.ReadAllBytesAsync(api32);
|
||||||
epicOriginalSdk64 = File.ReadAllBytes(api64);
|
if (epicOriginalSdk64 is null && File.Exists(api64)
|
||||||
|
&& !api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
|
||||||
|
epicOriginalSdk64 = await File.ReadAllBytesAsync(api64);
|
||||||
}
|
}
|
||||||
using DialogForm dialogForm = new(form);
|
using DialogForm dialogForm = new(form);
|
||||||
if (steamOriginalSdk32 is not null || steamOriginalSdk64 is not null || epicOriginalSdk32 is not null || epicOriginalSdk64 is not null)
|
if (steamOriginalSdk32 is not null || steamOriginalSdk64 is not null || epicOriginalSdk32 is not null
|
||||||
|
|| epicOriginalSdk64 is not null)
|
||||||
{
|
{
|
||||||
bool neededRepair = false;
|
bool neededRepair = false;
|
||||||
foreach (string directory in selection.DllDirectories)
|
foreach (string directory in selection.DllDirectories)
|
||||||
|
@ -159,28 +181,26 @@ internal static class ParadoxLauncher
|
||||||
if (installForm is not null)
|
if (installForm is not null)
|
||||||
installForm.UpdateUser("Paradox Launcher successfully repaired!", LogTextBox.Success);
|
installForm.UpdateUser("Paradox Launcher successfully repaired!", LogTextBox.Success);
|
||||||
else
|
else
|
||||||
_ = dialogForm.Show(form.Icon, "Paradox Launcher successfully repaired!", "OK", customFormText: "Paradox Launcher");
|
_ = dialogForm.Show(form.Icon, "Paradox Launcher successfully repaired!", "OK",
|
||||||
|
customFormText: "Paradox Launcher");
|
||||||
return RepairResult.Success;
|
return RepairResult.Success;
|
||||||
}
|
}
|
||||||
|
if (installForm is not null)
|
||||||
|
installForm.UpdateUser("Paradox Launcher did not need to be repaired.", LogTextBox.Success);
|
||||||
else
|
else
|
||||||
{
|
_ = dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK",
|
||||||
if (installForm is not null)
|
customFormText: "Paradox Launcher");
|
||||||
installForm.UpdateUser("Paradox Launcher did not need to be repaired.", LogTextBox.Success);
|
return RepairResult.Unnecessary;
|
||||||
else
|
|
||||||
_ = dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK", customFormText: "Paradox Launcher");
|
|
||||||
return RepairResult.Unnecessary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ = form is InstallForm
|
|
||||||
? throw new CustomMessageException("Repair failed! " +
|
|
||||||
"An original Steamworks and/or Epic Online Services file could not be found. " +
|
|
||||||
"You will likely have to reinstall Paradox Launcher to fix this issue.")
|
|
||||||
: dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed!"
|
|
||||||
+ "\n\nAn original Steamworks and/or Epic Online Services file could not be found."
|
|
||||||
+ "\nYou will likely have to reinstall Paradox Launcher to fix this issue.", "OK", customFormText: "Paradox Launcher");
|
|
||||||
return RepairResult.Failure;
|
|
||||||
}
|
}
|
||||||
|
_ = form is InstallForm
|
||||||
|
? throw new CustomMessageException("Repair failed! " +
|
||||||
|
"An original Steamworks and/or Epic Online Services file could not be found. "
|
||||||
|
+
|
||||||
|
"You will likely have to reinstall Paradox Launcher to fix this issue.")
|
||||||
|
: dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed!"
|
||||||
|
+ "\n\nAn original Steamworks and/or Epic Online Services file could not be found."
|
||||||
|
+ "\nYou will likely have to reinstall Paradox Launcher to fix this issue.",
|
||||||
|
"OK", customFormText: "Paradox Launcher");
|
||||||
|
return RepairResult.Failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
using CreamInstaller.Resources;
|
using System;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Gameloop.Vdf.Linq;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -14,6 +9,9 @@ using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Gameloop.Vdf.Linq;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Steam;
|
namespace CreamInstaller.Platforms.Steam;
|
||||||
|
|
||||||
|
@ -21,20 +19,33 @@ internal static class SteamCMD
|
||||||
{
|
{
|
||||||
internal const int ProcessLimit = 20;
|
internal const int ProcessLimit = 20;
|
||||||
|
|
||||||
|
internal static readonly string FilePath = DirectoryPath + @"\steamcmd.exe";
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<string, int>
|
||||||
|
AttemptCount = new(); // the more app_updates, the longer SteamCMD should wait for app_info_print
|
||||||
|
|
||||||
|
private static readonly int[] locks = new int[ProcessLimit];
|
||||||
|
|
||||||
|
internal static readonly string ArchivePath = DirectoryPath + @"\steamcmd.zip";
|
||||||
|
internal static readonly string DllPath = DirectoryPath + @"\steamclient.dll";
|
||||||
|
|
||||||
|
internal static readonly string AppCachePath = DirectoryPath + @"\appcache";
|
||||||
|
internal static readonly string ConfigPath = DirectoryPath + @"\config";
|
||||||
|
internal static readonly string DumpsPath = DirectoryPath + @"\dumps";
|
||||||
|
internal static readonly string LogsPath = DirectoryPath + @"\logs";
|
||||||
|
internal static readonly string SteamAppsPath = DirectoryPath + @"\steamapps";
|
||||||
|
|
||||||
internal static string DirectoryPath => ProgramData.DirectoryPath;
|
internal static string DirectoryPath => ProgramData.DirectoryPath;
|
||||||
internal static string AppInfoPath => ProgramData.AppInfoPath;
|
internal static string AppInfoPath => ProgramData.AppInfoPath;
|
||||||
|
|
||||||
internal static readonly string FilePath = DirectoryPath + @"\steamcmd.exe";
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, int> AttemptCount = new(); // the more app_updates, the longer SteamCMD should wait for app_info_print
|
|
||||||
private static string GetArguments(string appId) => AttemptCount.TryGetValue(appId, out int attempts)
|
private static string GetArguments(string appId) => AttemptCount.TryGetValue(appId, out int attempts)
|
||||||
? $@"@ShutdownOnFailedCommand 0 +force_install_dir {DirectoryPath} +login anonymous +app_info_print {appId} " + string.Concat(Enumerable.Repeat("+app_update 4 ", attempts)) + "+quit"
|
? $@"@ShutdownOnFailedCommand 0 +force_install_dir {DirectoryPath} +login anonymous +app_info_print {appId} "
|
||||||
|
+ string.Concat(Enumerable.Repeat("+app_update 4 ", attempts)) + "+quit"
|
||||||
: $"+login anonymous +app_info_print {appId} +quit";
|
: $"+login anonymous +app_info_print {appId} +quit";
|
||||||
|
|
||||||
private static readonly int[] locks = new int[ProcessLimit];
|
|
||||||
internal static async Task<string> Run(string appId) => await Task.Run(() =>
|
internal static async Task<string> Run(string appId) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
wait_for_lock:
|
wait_for_lock:
|
||||||
if (Program.Canceled) return "";
|
if (Program.Canceled) return "";
|
||||||
for (int i = 0; i < locks.Length; i++)
|
for (int i = 0; i < locks.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -42,22 +53,17 @@ internal static class SteamCMD
|
||||||
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
|
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
|
||||||
{
|
{
|
||||||
if (appId is not null)
|
if (appId is not null)
|
||||||
if (AttemptCount.ContainsKey(appId))
|
{
|
||||||
AttemptCount[appId]++;
|
AttemptCount.TryGetValue(appId, out int count);
|
||||||
else
|
AttemptCount[appId] = ++count;
|
||||||
AttemptCount[appId] = 0;
|
}
|
||||||
if (Program.Canceled) return "";
|
if (Program.Canceled) return "";
|
||||||
ProcessStartInfo processStartInfo = new()
|
ProcessStartInfo processStartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = FilePath,
|
FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true,
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardError = true, UseShellExecute = false,
|
||||||
RedirectStandardInput = true,
|
Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
|
||||||
RedirectStandardError = true,
|
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8,
|
||||||
UseShellExecute = false,
|
|
||||||
Arguments = appId is null ? "+quit" : GetArguments(appId),
|
|
||||||
CreateNoWindow = true,
|
|
||||||
StandardInputEncoding = Encoding.UTF8,
|
|
||||||
StandardOutputEncoding = Encoding.UTF8,
|
|
||||||
StandardErrorEncoding = Encoding.UTF8
|
StandardErrorEncoding = Encoding.UTF8
|
||||||
};
|
};
|
||||||
Process process = Process.Start(processStartInfo);
|
Process process = Process.Start(processStartInfo);
|
||||||
|
@ -96,7 +102,10 @@ internal static class SteamCMD
|
||||||
_ = output.Clear();
|
_ = output.Clear();
|
||||||
_ = appInfo.Clear();
|
_ = appInfo.Clear();
|
||||||
}
|
}
|
||||||
else break;
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = Interlocked.Decrement(ref locks[i]);
|
_ = Interlocked.Decrement(ref locks[i]);
|
||||||
|
@ -108,9 +117,6 @@ internal static class SteamCMD
|
||||||
goto wait_for_lock;
|
goto wait_for_lock;
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static readonly string ArchivePath = DirectoryPath + @"\steamcmd.zip";
|
|
||||||
internal static readonly string DllPath = DirectoryPath + @"\steamclient.dll";
|
|
||||||
|
|
||||||
internal static async Task Setup(IProgress<int> progress)
|
internal static async Task Setup(IProgress<int> progress)
|
||||||
{
|
{
|
||||||
await Cleanup();
|
await Cleanup();
|
||||||
|
@ -118,7 +124,8 @@ internal static class SteamCMD
|
||||||
{
|
{
|
||||||
HttpClient httpClient = HttpClientManager.HttpClient;
|
HttpClient httpClient = HttpClientManager.HttpClient;
|
||||||
if (httpClient is null) return;
|
if (httpClient is null) return;
|
||||||
byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
|
byte[] file = await httpClient.GetByteArrayAsync(
|
||||||
|
new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
|
||||||
file.Write(ArchivePath);
|
file.Write(ArchivePath);
|
||||||
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
||||||
File.Delete(ArchivePath);
|
File.Delete(ArchivePath);
|
||||||
|
@ -127,9 +134,7 @@ internal static class SteamCMD
|
||||||
{
|
{
|
||||||
FileSystemWatcher watcher = new(DirectoryPath)
|
FileSystemWatcher watcher = new(DirectoryPath)
|
||||||
{
|
{
|
||||||
Filter = "*",
|
Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true
|
||||||
IncludeSubdirectories = true,
|
|
||||||
EnableRaisingEvents = true
|
|
||||||
};
|
};
|
||||||
if (File.Exists(DllPath)) progress.Report(-15); // update (not used at the moment)
|
if (File.Exists(DllPath)) progress.Report(-15); // update (not used at the moment)
|
||||||
else progress.Report(-1660); // install
|
else progress.Report(-1660); // install
|
||||||
|
@ -141,12 +146,6 @@ internal static class SteamCMD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly string AppCachePath = DirectoryPath + @"\appcache";
|
|
||||||
internal static readonly string ConfigPath = DirectoryPath + @"\config";
|
|
||||||
internal static readonly string DumpsPath = DirectoryPath + @"\dumps";
|
|
||||||
internal static readonly string LogsPath = DirectoryPath + @"\logs";
|
|
||||||
internal static readonly string SteamAppsPath = DirectoryPath + @"\steamapps";
|
|
||||||
|
|
||||||
internal static async Task Cleanup() => await Task.Run(async () =>
|
internal static async Task Cleanup() => await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(DirectoryPath)) return;
|
if (!Directory.Exists(DirectoryPath)) return;
|
||||||
|
@ -165,7 +164,8 @@ internal static class SteamCMD
|
||||||
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.ntfs_transaction_failed"))
|
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.ntfs_transaction_failed"))
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
if (Directory.Exists(AppCachePath))
|
if (Directory.Exists(AppCachePath))
|
||||||
Directory.Delete(AppCachePath, true); // this is definitely needed, so SteamCMD gets the latest information for us
|
Directory.Delete(AppCachePath,
|
||||||
|
true); // this is definitely needed, so SteamCMD gets the latest information for us
|
||||||
if (Directory.Exists(DumpsPath))
|
if (Directory.Exists(DumpsPath))
|
||||||
Directory.Delete(DumpsPath, true);
|
Directory.Delete(DumpsPath, true);
|
||||||
if (Directory.Exists(LogsPath))
|
if (Directory.Exists(LogsPath))
|
||||||
|
@ -181,21 +181,41 @@ internal static class SteamCMD
|
||||||
if (Program.Canceled) return null;
|
if (Program.Canceled) return null;
|
||||||
string output;
|
string output;
|
||||||
string appUpdateFile = $@"{AppInfoPath}\{appId}.vdf";
|
string appUpdateFile = $@"{AppInfoPath}\{appId}.vdf";
|
||||||
restart:
|
restart:
|
||||||
if (Program.Canceled) return null;
|
if (Program.Canceled) return null;
|
||||||
if (File.Exists(appUpdateFile)) output = File.ReadAllText(appUpdateFile, Encoding.UTF8);
|
if (File.Exists(appUpdateFile))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
output = await File.ReadAllTextAsync(appUpdateFile, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output = await Run(appId) ?? "";
|
output = await Run(appId) ?? "";
|
||||||
int openBracket = output.IndexOf("{");
|
int openBracket = output.IndexOf("{", StringComparison.Ordinal);
|
||||||
int closeBracket = output.LastIndexOf("}");
|
int closeBracket = output.LastIndexOf("}", StringComparison.Ordinal);
|
||||||
if (output is not null && openBracket != -1 && closeBracket != -1 && closeBracket > openBracket)
|
if (openBracket != -1 && closeBracket != -1 && closeBracket > openBracket)
|
||||||
{
|
{
|
||||||
output = $"\"{appId}\"\n" + output[openBracket..(1 + closeBracket)];
|
output = $"\"{appId}\"\n" + output[openBracket..(1 + closeBracket)];
|
||||||
output = output.Replace("ERROR! Failed to install app '4' (Invalid platform)", "");
|
output = output.Replace("ERROR! Failed to install app '4' (Invalid platform)", "");
|
||||||
File.WriteAllText(appUpdateFile, output, Encoding.UTF8);
|
try
|
||||||
|
{
|
||||||
|
await File.WriteAllTextAsync(appUpdateFile, output, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto restart;
|
||||||
}
|
}
|
||||||
else goto restart;
|
|
||||||
}
|
}
|
||||||
if (Program.Canceled || output is null) return null;
|
if (Program.Canceled || output is null) return null;
|
||||||
if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue)
|
if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue)
|
||||||
|
@ -207,13 +227,15 @@ internal static class SteamCMD
|
||||||
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
|
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
|
||||||
if (type is null || type.ToString() == "Game")
|
if (type is null || type.ToString() == "Game")
|
||||||
{
|
{
|
||||||
string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch)?.GetChild("buildid")?.ToString();
|
string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch)
|
||||||
|
?.GetChild("buildid")?.ToString();
|
||||||
if (buildid is null && type is not null) return appInfo;
|
if (buildid is null && type is not null) return appInfo;
|
||||||
if (type is null || int.TryParse(buildid, out int gamebuildId) && gamebuildId < buildId)
|
if (type is null || (int.TryParse(buildid, out int gamebuildId) && gamebuildId < buildId))
|
||||||
{
|
{
|
||||||
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||||
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
||||||
if (File.Exists(dlcAppUpdateFile)) File.Delete(dlcAppUpdateFile);
|
if (File.Exists(dlcAppUpdateFile))
|
||||||
|
File.Delete(dlcAppUpdateFile);
|
||||||
if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile);
|
if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile);
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
@ -236,8 +258,10 @@ internal static class SteamCMD
|
||||||
dlcIds.Add("" + appId);
|
dlcIds.Add("" + appId);
|
||||||
VToken depots = appInfo.Value.GetChild("depots");
|
VToken depots = appInfo.Value.GetChild("depots");
|
||||||
if (depots is not null)
|
if (depots is not null)
|
||||||
foreach (VProperty property in depots.Where(p => p is VProperty && int.TryParse((p as VProperty).Key, out int _)))
|
foreach (VProperty property in depots.Where(
|
||||||
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && !dlcIds.Contains("" + appId))
|
p => p is VProperty && int.TryParse((p as VProperty).Key, out int _)))
|
||||||
|
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId)
|
||||||
|
&& !dlcIds.Contains("" + appId))
|
||||||
dlcIds.Add("" + appId);
|
dlcIds.Add("" + appId);
|
||||||
#pragma warning restore IDE0220 // Add explicit cast
|
#pragma warning restore IDE0220 // Add explicit cast
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
using CreamInstaller.Resources;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Gameloop.Vdf.Linq;
|
|
||||||
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Gameloop.Vdf.Linq;
|
||||||
|
using Microsoft.Win32;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Steam;
|
namespace CreamInstaller.Platforms.Steam;
|
||||||
|
@ -18,34 +13,42 @@ namespace CreamInstaller.Platforms.Steam;
|
||||||
internal static class SteamLibrary
|
internal static class SteamLibrary
|
||||||
{
|
{
|
||||||
private static string installPath;
|
private static string installPath;
|
||||||
|
|
||||||
internal static string InstallPath
|
internal static string InstallPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) as string;
|
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath",
|
||||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath", null) as string;
|
null) as string;
|
||||||
|
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath",
|
||||||
|
null) as string;
|
||||||
return installPath.BeautifyPath();
|
return installPath.BeautifyPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
string gameDirectory) =>
|
||||||
|
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||||
|
|
||||||
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames() => await Task.Run(async () =>
|
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>>
|
||||||
|
GetGames() => await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
||||||
List<string> gameLibraryDirectories = await GetLibraryDirectories();
|
List<string> gameLibraryDirectories = await GetLibraryDirectories();
|
||||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return games;
|
if (Program.Canceled) return games;
|
||||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in (await GetGamesFromLibraryDirectory(libraryDirectory))
|
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in
|
||||||
.Where(game => !games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory)))
|
(await GetGamesFromLibraryDirectory(libraryDirectory))
|
||||||
|
.Where(game => !games.Any(_game => _game.appId == game.appId
|
||||||
|
&& _game.gameDirectory == game.gameDirectory)))
|
||||||
games.Add(game);
|
games.Add(game);
|
||||||
}
|
}
|
||||||
return games;
|
return games;
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
|
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>>
|
||||||
|
GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
||||||
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return games;
|
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return games;
|
||||||
|
@ -59,9 +62,9 @@ internal static class SteamLibrary
|
||||||
string name = result.Value.GetChild("name")?.ToString();
|
string name = result.Value.GetChild("name")?.ToString();
|
||||||
string buildId = result.Value.GetChild("buildid")?.ToString();
|
string buildId = result.Value.GetChild("buildid")?.ToString();
|
||||||
if (string.IsNullOrWhiteSpace(appId)
|
if (string.IsNullOrWhiteSpace(appId)
|
||||||
|| string.IsNullOrWhiteSpace(installdir)
|
|| string.IsNullOrWhiteSpace(installdir)
|
||||||
|| string.IsNullOrWhiteSpace(name)
|
|| string.IsNullOrWhiteSpace(name)
|
||||||
|| string.IsNullOrWhiteSpace(buildId))
|
|| string.IsNullOrWhiteSpace(buildId))
|
||||||
continue;
|
continue;
|
||||||
string gameDirectory = (libraryDirectory + @"\common\" + installdir).BeautifyPath();
|
string gameDirectory = (libraryDirectory + @"\common\" + installdir).BeautifyPath();
|
||||||
if (games.Any(g => g.appId == appId && g.gameDirectory == gameDirectory)) continue;
|
if (games.Any(g => g.appId == appId && g.gameDirectory == gameDirectory)) continue;
|
||||||
|
@ -87,9 +90,11 @@ internal static class SteamLibrary
|
||||||
{
|
{
|
||||||
gameDirectories.Add(libraryFolder);
|
gameDirectories.Add(libraryFolder);
|
||||||
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
||||||
if (File.Exists(libraryFolders) && ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
|
if (File.Exists(libraryFolders)
|
||||||
|
&& ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
|
||||||
#pragma warning disable IDE0220 // Add explicit cast
|
#pragma warning disable IDE0220 // Add explicit cast
|
||||||
foreach (VProperty property in result.Value.Where(p => p is VProperty && int.TryParse((p as VProperty).Key, out int _)))
|
foreach (VProperty property in result.Value.Where(
|
||||||
|
p => p is VProperty && int.TryParse((p as VProperty).Key, out int _)))
|
||||||
{
|
{
|
||||||
string path = property.Value.GetChild("path")?.ToString();
|
string path = property.Value.GetChild("path")?.ToString();
|
||||||
if (string.IsNullOrWhiteSpace(path)) continue;
|
if (string.IsNullOrWhiteSpace(path)) continue;
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
using CreamInstaller.Utility;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
using System;
|
using System;
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,6 +14,9 @@ namespace CreamInstaller.Platforms.Steam;
|
||||||
|
|
||||||
internal static class SteamStore
|
internal static class SteamStore
|
||||||
{
|
{
|
||||||
|
private const int COOLDOWN_GAME = 600;
|
||||||
|
private const int COOLDOWN_DLC = 1200;
|
||||||
|
|
||||||
internal static async Task<List<string>> ParseDlcAppIds(AppData appData) => await Task.Run(() =>
|
internal static async Task<List<string>> ParseDlcAppIds(AppData appData) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
List<string> dlcIds = new();
|
List<string> dlcIds = new();
|
||||||
|
@ -25,17 +26,15 @@ internal static class SteamStore
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
});
|
});
|
||||||
|
|
||||||
private const int COOLDOWN_GAME = 600;
|
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false, int attempts = 0)
|
||||||
private const int COOLDOWN_DLC = 1200;
|
|
||||||
|
|
||||||
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false)
|
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return null;
|
if (Program.Canceled) return null;
|
||||||
string cacheFile = ProgramData.AppInfoPath + @$"\{appId}.json";
|
string cacheFile = ProgramData.AppInfoPath + @$"\{appId}.json";
|
||||||
bool cachedExists = File.Exists(cacheFile);
|
bool cachedExists = File.Exists(cacheFile);
|
||||||
if (!cachedExists || ProgramData.CheckCooldown(appId, isDlc ? COOLDOWN_DLC : COOLDOWN_GAME))
|
if (!cachedExists || ProgramData.CheckCooldown(appId, isDlc ? COOLDOWN_DLC : COOLDOWN_GAME))
|
||||||
{
|
{
|
||||||
string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
|
string response
|
||||||
|
= await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
|
||||||
if (response is not null)
|
if (response is not null)
|
||||||
{
|
{
|
||||||
IDictionary<string, JToken> apps = (IDictionary<string, JToken>)JsonConvert.DeserializeObject(response);
|
IDictionary<string, JToken> apps = (IDictionary<string, JToken>)JsonConvert.DeserializeObject(response);
|
||||||
|
@ -50,7 +49,9 @@ internal static class SteamStore
|
||||||
if (!appDetails.success)
|
if (!appDetails.success)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugForm.Current.Log($"Query unsuccessful for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}", LogTextBox.Warning);
|
DebugForm.Current.Log(
|
||||||
|
$"Query unsuccessful for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}",
|
||||||
|
LogTextBox.Warning);
|
||||||
#endif
|
#endif
|
||||||
if (data is null)
|
if (data is null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -59,13 +60,15 @@ internal static class SteamStore
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
|
await File.WriteAllTextAsync(
|
||||||
|
cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
(Exception e)
|
(Exception e)
|
||||||
{
|
{
|
||||||
DebugForm.Current.Log($"Unsuccessful serialization of query for appid {appId}{(isDlc ? " (DLC)" : "")}: {e.GetType()} ({e.Message})");
|
DebugForm.Current.Log(
|
||||||
|
$"Unsuccessful serialization of query for appid {appId}{(isDlc ? " (DLC)" : "")}: {e.GetType()} ({e.Message})");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{ }
|
{ }
|
||||||
|
@ -73,18 +76,24 @@ internal static class SteamStore
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
else DebugForm.Current.Log($"Response data null for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}");
|
DebugForm.Current.Log(
|
||||||
|
$"Response data null for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
else DebugForm.Current.Log($"Response details null for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}");
|
else
|
||||||
|
{
|
||||||
|
DebugForm.Current.Log(
|
||||||
|
$"Response details null for appid {appId}{(isDlc ? " (DLC)" : "")}: {app.Value.ToString(Formatting.None)}");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
(Exception e)
|
(Exception e)
|
||||||
{
|
{
|
||||||
DebugForm.Current.Log($"Unsuccessful deserialization of query for appid {appId}{(isDlc ? " (DLC)" : "")}: {e.GetType()} ({e.Message})");
|
DebugForm.Current.Log(
|
||||||
|
$"Unsuccessful deserialization of query for appid {appId}{(isDlc ? " (DLC)" : "")}: {e.GetType()} ({e.Message})");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{ }
|
{ }
|
||||||
|
@ -93,23 +102,26 @@ internal static class SteamStore
|
||||||
else DebugForm.Current.Log("Response deserialization null for appid " + appId);
|
else DebugForm.Current.Log("Response deserialization null for appid " + appId);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
else DebugForm.Current.Log("Response null for appid " + appId, LogTextBox.Warning);
|
DebugForm.Current.Log("Response null for appid " + appId, LogTextBox.Warning);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cachedExists)
|
if (cachedExists)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject<AppData>(File.ReadAllText(cacheFile));
|
return JsonConvert.DeserializeObject<AppData>(await File.ReadAllTextAsync(cacheFile));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
File.Delete(cacheFile);
|
File.Delete(cacheFile);
|
||||||
}
|
}
|
||||||
if (!isDlc)
|
if (!isDlc && attempts < 10)
|
||||||
{
|
{
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
return await QueryStoreAPI(appId, isDlc);
|
return await QueryStoreAPI(appId, isDlc, ++attempts);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
using CreamInstaller.Resources;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Microsoft.Win32;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller.Platforms.Ubisoft;
|
namespace CreamInstaller.Platforms.Ubisoft;
|
||||||
|
@ -15,6 +11,7 @@ namespace CreamInstaller.Platforms.Ubisoft;
|
||||||
internal static class UbisoftLibrary
|
internal static class UbisoftLibrary
|
||||||
{
|
{
|
||||||
private static RegistryKey installsKey;
|
private static RegistryKey installsKey;
|
||||||
|
|
||||||
internal static RegistryKey InstallsKey
|
internal static RegistryKey InstallsKey
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -25,21 +22,23 @@ internal static class UbisoftLibrary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
string gameDirectory) =>
|
||||||
|
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||||
|
|
||||||
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames() => await Task.Run(() =>
|
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames() => await Task.Run(
|
||||||
{
|
() =>
|
||||||
List<(string gameId, string name, string gameDirectory)> games = new();
|
|
||||||
RegistryKey installsKey = InstallsKey;
|
|
||||||
if (installsKey is null) return games;
|
|
||||||
foreach (string gameId in installsKey.GetSubKeyNames())
|
|
||||||
{
|
{
|
||||||
RegistryKey installKey = installsKey.OpenSubKey(gameId);
|
List<(string gameId, string name, string gameDirectory)> games = new();
|
||||||
string installDir = installKey?.GetValue("InstallDir")?.ToString()?.BeautifyPath();
|
RegistryKey installsKey = InstallsKey;
|
||||||
if (installDir is not null && !games.Any(g => g.gameId == gameId && g.gameDirectory == installDir))
|
if (installsKey is null) return games;
|
||||||
games.Add((gameId, new DirectoryInfo(installDir).Name, installDir));
|
foreach (string gameId in installsKey.GetSubKeyNames())
|
||||||
}
|
{
|
||||||
return games;
|
RegistryKey installKey = installsKey.OpenSubKey(gameId);
|
||||||
});
|
string installDir = installKey?.GetValue("InstallDir")?.ToString()?.BeautifyPath();
|
||||||
|
if (installDir is not null && !games.Any(g => g.gameId == gameId && g.gameDirectory == installDir))
|
||||||
|
games.Add((gameId, new DirectoryInfo(installDir).Name, installDir));
|
||||||
|
}
|
||||||
|
return games;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
using CreamInstaller.Platforms.Steam;
|
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
@ -9,6 +6,9 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Platforms.Steam;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller;
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ internal static class Program
|
||||||
if (ProtectedGames.Contains(name)) return true;
|
if (ProtectedGames.Contains(name)) return true;
|
||||||
if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
|
if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
|
||||||
foreach (string path in ProtectedGameDirectories)
|
foreach (string path in ProtectedGameDirectories)
|
||||||
if (Directory.Exists(directory + path)) return true;
|
if (Directory.Exists(directory + path))
|
||||||
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +57,15 @@ internal static class Program
|
||||||
{
|
{
|
||||||
using DialogForm dialogForm = new(form);
|
using DialogForm dialogForm = new(form);
|
||||||
if (dialogForm.Show(SystemIcons.Error,
|
if (dialogForm.Show(SystemIcons.Error,
|
||||||
$"ERROR: {selection.Name} is currently running!" +
|
$"ERROR: {selection.Name} is currently running!" +
|
||||||
"\n\nPlease close the program/game to continue . . . ",
|
"\n\nPlease close the program/game to continue . . . ",
|
||||||
"Retry", "Cancel") == DialogResult.OK)
|
"Retry", "Cancel") == DialogResult.OK)
|
||||||
return IsProgramRunningDialog(form, selection);
|
return IsProgramRunningDialog(form, selection);
|
||||||
}
|
}
|
||||||
else return true;
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +78,12 @@ internal static class Program
|
||||||
_ = Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
_ = Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
Application.ApplicationExit += new(OnApplicationExit);
|
Application.ApplicationExit += OnApplicationExit;
|
||||||
Application.ThreadException += new((s, e) => e.Exception?.HandleFatalException());
|
Application.ThreadException += (s, e) => e.Exception?.HandleFatalException();
|
||||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||||
AppDomain.CurrentDomain.UnhandledException += new((s, e) => (e.ExceptionObject as Exception)?.HandleFatalException());
|
AppDomain.CurrentDomain.UnhandledException += (s, e)
|
||||||
retry:
|
=> (e.ExceptionObject as Exception)?.HandleFatalException();
|
||||||
|
retry:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClientManager.Setup();
|
HttpClientManager.Setup();
|
||||||
|
@ -99,6 +104,7 @@ internal static class Program
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool Canceled;
|
internal static bool Canceled;
|
||||||
|
|
||||||
internal static async void Cleanup(bool cancel = true)
|
internal static async void Cleanup(bool cancel = true)
|
||||||
{
|
{
|
||||||
Canceled = cancel;
|
Canceled = cancel;
|
||||||
|
|
|
@ -1,28 +1,21 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Resources;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Resources;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller;
|
||||||
|
|
||||||
public enum Platform
|
public enum Platform
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0, Paradox, Steam,
|
||||||
Paradox,
|
Epic, Ubisoft
|
||||||
Steam,
|
|
||||||
Epic,
|
|
||||||
Ubisoft
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DlcType
|
public enum DlcType
|
||||||
{
|
{
|
||||||
Steam,
|
Steam, SteamHidden, EpicCatalogItem,
|
||||||
SteamHidden,
|
|
||||||
EpicCatalogItem,
|
|
||||||
EpicEntitlement
|
EpicEntitlement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,11 +42,17 @@ internal class ProgramSelection
|
||||||
internal List<(string directory, BinaryType binaryType)> ExecutableDirectories;
|
internal List<(string directory, BinaryType binaryType)> ExecutableDirectories;
|
||||||
internal List<string> DllDirectories;
|
internal List<string> DllDirectories;
|
||||||
|
|
||||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc = new(PlatformIdComparer.String);
|
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
|
||||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc = new(PlatformIdComparer.String);
|
= new(PlatformIdComparer.String);
|
||||||
|
|
||||||
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)> ExtraDlc = new(); // for Paradox Launcher
|
internal readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc
|
||||||
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)> ExtraSelectedDlc = new(); // for Paradox Launcher
|
= new(PlatformIdComparer.String);
|
||||||
|
|
||||||
|
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||||
|
ExtraDlc = new(); // for Paradox Launcher
|
||||||
|
|
||||||
|
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||||
|
ExtraSelectedDlc = new(); // for Paradox Launcher
|
||||||
|
|
||||||
internal bool AreDllsLocked
|
internal bool AreDllsLocked
|
||||||
{
|
{
|
||||||
|
@ -63,49 +62,54 @@ internal class ProgramSelection
|
||||||
{
|
{
|
||||||
if (Platform is Platform.Steam or Platform.Paradox)
|
if (Platform is Platform.Steam or Platform.Paradox)
|
||||||
{
|
{
|
||||||
directory.GetCreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetCreamApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
|
out string api64_o, out string config);
|
||||||
if (api32.IsFilePathLocked()
|
if (api32.IsFilePathLocked()
|
||||||
|| api32_o.IsFilePathLocked()
|
|| api32_o.IsFilePathLocked()
|
||||||
|| api64.IsFilePathLocked()
|
|| api64.IsFilePathLocked()
|
||||||
|| api64_o.IsFilePathLocked()
|
|| api64_o.IsFilePathLocked()
|
||||||
|| config.IsFilePathLocked())
|
|| config.IsFilePathLocked())
|
||||||
return true;
|
return true;
|
||||||
directory.GetSmokeApiComponents(out api32, out api32_o, out api64, out api64_o, out config, out string cache);
|
directory.GetSmokeApiComponents(out api32, out api32_o, out api64, out api64_o, out config,
|
||||||
|
out string cache);
|
||||||
if (api32.IsFilePathLocked()
|
if (api32.IsFilePathLocked()
|
||||||
|| api32_o.IsFilePathLocked()
|
|| api32_o.IsFilePathLocked()
|
||||||
|| api64.IsFilePathLocked()
|
|| api64.IsFilePathLocked()
|
||||||
|| api64_o.IsFilePathLocked()
|
|| api64_o.IsFilePathLocked()
|
||||||
|| config.IsFilePathLocked()
|
|| config.IsFilePathLocked()
|
||||||
|| cache.IsFilePathLocked())
|
|| cache.IsFilePathLocked())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Platform is Platform.Epic or Platform.Paradox)
|
if (Platform is Platform.Epic or Platform.Paradox)
|
||||||
{
|
{
|
||||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
|
out string api64_o, out string config);
|
||||||
if (api32.IsFilePathLocked()
|
if (api32.IsFilePathLocked()
|
||||||
|| api32_o.IsFilePathLocked()
|
|| api32_o.IsFilePathLocked()
|
||||||
|| api64.IsFilePathLocked()
|
|| api64.IsFilePathLocked()
|
||||||
|| api64_o.IsFilePathLocked()
|
|| api64_o.IsFilePathLocked()
|
||||||
|| config.IsFilePathLocked())
|
|| config.IsFilePathLocked())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Platform is Platform.Ubisoft)
|
if (Platform is Platform.Ubisoft)
|
||||||
{
|
{
|
||||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
|
||||||
|
out string api64_o, out string config);
|
||||||
if (api32.IsFilePathLocked()
|
if (api32.IsFilePathLocked()
|
||||||
|| api32_o.IsFilePathLocked()
|
|| api32_o.IsFilePathLocked()
|
||||||
|| api64.IsFilePathLocked()
|
|| api64.IsFilePathLocked()
|
||||||
|| api64_o.IsFilePathLocked()
|
|| api64_o.IsFilePathLocked()
|
||||||
|| config.IsFilePathLocked())
|
|| config.IsFilePathLocked())
|
||||||
return true;
|
return true;
|
||||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config);
|
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o,
|
||||||
|
out api64, out api64_o, out config);
|
||||||
if (old_api32.IsFilePathLocked()
|
if (old_api32.IsFilePathLocked()
|
||||||
|| old_api64.IsFilePathLocked()
|
|| old_api64.IsFilePathLocked()
|
||||||
|| api32.IsFilePathLocked()
|
|| api32.IsFilePathLocked()
|
||||||
|| api32_o.IsFilePathLocked()
|
|| api32_o.IsFilePathLocked()
|
||||||
|| api64.IsFilePathLocked()
|
|| api64.IsFilePathLocked()
|
||||||
|| api64_o.IsFilePathLocked()
|
|| api64_o.IsFilePathLocked()
|
||||||
|| config.IsFilePathLocked())
|
|| config.IsFilePathLocked())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +168,8 @@ internal class ProgramSelection
|
||||||
|
|
||||||
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
|
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
|
||||||
|
|
||||||
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan) => AllSafe.ForEach(selection => selection.Validate(programsToScan));
|
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
||||||
|
=> AllSafe.ForEach(selection => selection.Validate(programsToScan));
|
||||||
|
|
||||||
internal static readonly List<ProgramSelection> All = new();
|
internal static readonly List<ProgramSelection> All = new();
|
||||||
|
|
||||||
|
@ -172,12 +177,15 @@ internal class ProgramSelection
|
||||||
|
|
||||||
internal static List<ProgramSelection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
|
internal static List<ProgramSelection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
|
||||||
|
|
||||||
internal static ProgramSelection FromPlatformId(Platform platform, string gameId) => AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
|
internal static ProgramSelection FromPlatformId(Platform platform, string gameId)
|
||||||
|
=> AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
|
||||||
|
|
||||||
internal static (string gameId, (DlcType type, string name, string icon) app)? GetDlcFromPlatformId(Platform platform, string dlcId)
|
internal static (string gameId, (DlcType type, string name, string icon) app)? GetDlcFromPlatformId(
|
||||||
|
Platform platform, string dlcId)
|
||||||
{
|
{
|
||||||
foreach (ProgramSelection selection in AllSafe.Where(s => s.Platform == platform))
|
foreach (ProgramSelection selection in AllSafe.Where(s => s.Platform == platform))
|
||||||
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in selection.AllDlc.Where(p => p.Key == dlcId))
|
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in selection.AllDlc.Where(
|
||||||
|
p => p.Key == dlcId))
|
||||||
return (selection.Id, pair.Value);
|
return (selection.Id, pair.Value);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
40
CreamInstaller/Properties/Resources.Designer.cs
generated
40
CreamInstaller/Properties/Resources.Designer.cs
generated
|
@ -8,10 +8,16 @@
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace CreamInstaller.Properties {
|
namespace CreamInstaller.Properties {
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,27 +25,27 @@ namespace CreamInstaller.Properties {
|
||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[DebuggerNonUserCode()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[CompilerGenerated()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
private static ResourceManager resourceMan;
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
private static CultureInfo resourceCulture;
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
internal Resources() {
|
internal Resources() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
internal static ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
if (ReferenceEquals(resourceMan, null)) {
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CreamInstaller.Properties.Resources", typeof(Resources).Assembly);
|
ResourceManager temp = new ResourceManager("CreamInstaller.Properties.Resources", typeof(Resources).Assembly);
|
||||||
resourceMan = temp;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
|
@ -50,8 +56,8 @@ namespace CreamInstaller.Properties {
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
/// resource lookups using this strongly typed resource class.
|
/// resource lookups using this strongly typed resource class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
internal static CultureInfo Culture {
|
||||||
get {
|
get {
|
||||||
return resourceCulture;
|
return resourceCulture;
|
||||||
}
|
}
|
||||||
|
@ -63,10 +69,10 @@ namespace CreamInstaller.Properties {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static System.Drawing.Icon Icon {
|
internal static Icon Icon {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("Icon", resourceCulture);
|
object obj = ResourceManager.GetObject("Icon", resourceCulture);
|
||||||
return ((System.Drawing.Icon)(obj));
|
return ((Icon)(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class Koaloader
|
internal static class Koaloader
|
||||||
{
|
{
|
||||||
internal static void GetKoaloaderComponents(
|
internal static readonly List<(string unlocker, string dll)> AutoLoadDlls = new()
|
||||||
this string directory,
|
|
||||||
out List<string> proxies,
|
|
||||||
out string config
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
proxies = 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 void GetKoaloaderComponents(
|
||||||
|
this string directory,
|
||||||
|
out List<string> proxies,
|
||||||
|
out string config
|
||||||
|
)
|
||||||
|
{
|
||||||
|
proxies = new List<string>();
|
||||||
foreach (string proxy in EmbeddedResources.Select(proxy =>
|
foreach (string proxy in EmbeddedResources.Select(proxy =>
|
||||||
{
|
{
|
||||||
proxy = proxy[(proxy.IndexOf('.') + 1)..];
|
proxy = proxy[(proxy.IndexOf('.') + 1)..];
|
||||||
|
@ -41,25 +51,20 @@ internal static class Koaloader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void GetProxyInfoFromIdentifier(this string resourceIdentifier, out string proxyName, out BinaryType binaryType)
|
internal static void GetProxyInfoFromIdentifier(this string resourceIdentifier, out string proxyName,
|
||||||
|
out BinaryType binaryType)
|
||||||
{
|
{
|
||||||
string baseIdentifier = resourceIdentifier[(resourceIdentifier.IndexOf('.') + 1)..];
|
string baseIdentifier = resourceIdentifier[(resourceIdentifier.IndexOf('.') + 1)..];
|
||||||
baseIdentifier = baseIdentifier[..baseIdentifier.IndexOf('.')];
|
baseIdentifier = baseIdentifier[..baseIdentifier.IndexOf('.')];
|
||||||
proxyName = baseIdentifier[..baseIdentifier.LastIndexOf('_')];
|
proxyName = baseIdentifier[..baseIdentifier.LastIndexOf('_')];
|
||||||
string bitness = baseIdentifier[(baseIdentifier.LastIndexOf('_') + 1)..];
|
string bitness = baseIdentifier[(baseIdentifier.LastIndexOf('_') + 1)..];
|
||||||
binaryType = bitness == "32" ? BinaryType.BIT32 : bitness == "64" ? BinaryType.BIT64 : BinaryType.Unknown;
|
binaryType = bitness == "32"
|
||||||
|
? BinaryType.BIT32
|
||||||
|
: bitness == "64"
|
||||||
|
? BinaryType.BIT64
|
||||||
|
: BinaryType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
directory.GetKoaloaderComponents(out _, out string config);
|
directory.GetKoaloaderComponents(out _, out string config);
|
||||||
|
@ -78,11 +83,13 @@ internal static class Koaloader
|
||||||
else if (File.Exists(config))
|
else if (File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteConfig(StreamWriter writer, SortedList<string, string> targets, SortedList<string, string> modules, InstallForm installForm = null)
|
internal static void WriteConfig(StreamWriter writer, SortedList<string, string> targets,
|
||||||
|
SortedList<string, string> modules, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
writer.WriteLine(" \"logging\": false,");
|
writer.WriteLine(" \"logging\": false,");
|
||||||
|
@ -96,12 +103,14 @@ internal static class Koaloader
|
||||||
{
|
{
|
||||||
string path = pair.Value;
|
string path = pair.Value;
|
||||||
writer.WriteLine($" \"{path}\"{(pair.Equals(lastTarget) ? "" : ",")}");
|
writer.WriteLine($" \"{path}\"{(pair.Equals(lastTarget) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added target to Koaloader.json with path {path}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added target to Koaloader.json with path {path}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ]");
|
writer.WriteLine(" ]");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"targets\": []");
|
writer.WriteLine(" \"targets\": []");
|
||||||
|
}
|
||||||
if (modules.Any())
|
if (modules.Any())
|
||||||
{
|
{
|
||||||
writer.WriteLine(" \"modules\": [");
|
writer.WriteLine(" \"modules\": [");
|
||||||
|
@ -110,37 +119,41 @@ internal static class Koaloader
|
||||||
{
|
{
|
||||||
string path = pair.Value;
|
string path = pair.Value;
|
||||||
writer.WriteLine(" {");
|
writer.WriteLine(" {");
|
||||||
writer.WriteLine($" \"path\": \"" + path + "\",");
|
writer.WriteLine(" \"path\": \"" + path + "\",");
|
||||||
writer.WriteLine($" \"required\": true");
|
writer.WriteLine(" \"required\": true");
|
||||||
writer.WriteLine(" }" + (pair.Equals(lastModule) ? "" : ","));
|
writer.WriteLine(" }" + (pair.Equals(lastModule) ? "" : ","));
|
||||||
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ]");
|
writer.WriteLine(" ]");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"modules\": []");
|
writer.WriteLine(" \"modules\": []");
|
||||||
|
}
|
||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(async () =>
|
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null,
|
||||||
|
bool deleteConfig = true) => await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||||
foreach (string proxyPath in proxies.Where(proxyPath => File.Exists(proxyPath) && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
|
foreach (string proxyPath in proxies.Where(
|
||||||
|
proxyPath => File.Exists(proxyPath) && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
|
||||||
{
|
{
|
||||||
File.Delete(proxyPath);
|
File.Delete(proxyPath);
|
||||||
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(proxyPath)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(proxyPath)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
foreach ((string unlocker, string path) in AutoLoadDlls
|
foreach ((string unlocker, string path) in AutoLoadDlls
|
||||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||||
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
|
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (deleteConfig && File.Exists(config))
|
if (deleteConfig && File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
await SmokeAPI.Uninstall(directory, installForm, deleteConfig);
|
await SmokeAPI.Uninstall(directory, installForm, deleteConfig);
|
||||||
await ScreamAPI.Uninstall(directory, installForm, deleteConfig);
|
await ScreamAPI.Uninstall(directory, installForm, deleteConfig);
|
||||||
|
@ -150,20 +163,26 @@ internal static class Koaloader
|
||||||
await Uninstall(rootDirectory, null, installForm, deleteConfig);
|
await Uninstall(rootDirectory, null, installForm, deleteConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static async Task Install(string directory, BinaryType binaryType, ProgramSelection selection, string rootDirectory = null, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
|
internal static async Task Install(string directory, BinaryType binaryType, ProgramSelection selection,
|
||||||
|
string rootDirectory = null, InstallForm installForm = null,
|
||||||
|
bool generateConfig = true) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||||
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
||||||
string path = directory + @"\" + proxy + ".dll";
|
string path = directory + @"\" + proxy + ".dll";
|
||||||
foreach (string _path in proxies.Where(p => p != path && File.Exists(p) && p.IsResourceFile(ResourceIdentifier.Koaloader)))
|
foreach (string _path in proxies.Where(p => p != path && File.Exists(p)
|
||||||
|
&& p.IsResourceFile(ResourceIdentifier.Koaloader)))
|
||||||
{
|
{
|
||||||
File.Delete(_path);
|
File.Delete(_path);
|
||||||
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(path) && !path.IsResourceFile(ResourceIdentifier.Koaloader))
|
if (File.Exists(path) && !path.IsResourceFile(ResourceIdentifier.Koaloader))
|
||||||
throw new CustomMessageException("A non-Koaloader DLL named " + proxy + ".dll already exists in this directory!");
|
throw new CustomMessageException("A non-Koaloader DLL named " + proxy
|
||||||
|
+ ".dll already exists in this directory!");
|
||||||
path.WriteProxy(proxy, binaryType);
|
path.WriteProxy(proxy, binaryType);
|
||||||
installForm?.UpdateUser($"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
bool bit32 = false, bit64 = false;
|
bool bit32 = false, bit64 = false;
|
||||||
foreach (string executable in Directory.EnumerateFiles(directory, "*.exe"))
|
foreach (string executable in Directory.EnumerateFiles(directory, "*.exe"))
|
||||||
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
|
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
|
||||||
|
@ -185,12 +204,15 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\SmokeAPI32.dll";
|
path = rootDirectory + @"\SmokeAPI32.dll";
|
||||||
}
|
}
|
||||||
"SmokeAPI.steam_api.dll".Write(path);
|
"SmokeAPI.steam_api.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (bit64)
|
if (bit64)
|
||||||
{
|
{
|
||||||
|
@ -200,12 +222,15 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\SmokeAPI64.dll";
|
path = rootDirectory + @"\SmokeAPI64.dll";
|
||||||
}
|
}
|
||||||
"SmokeAPI.steam_api64.dll".Write(path);
|
"SmokeAPI.steam_api64.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
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);
|
SmokeAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
||||||
}
|
}
|
||||||
|
@ -219,12 +244,15 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\ScreamAPI32.dll";
|
path = rootDirectory + @"\ScreamAPI32.dll";
|
||||||
}
|
}
|
||||||
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(path);
|
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (bit64)
|
if (bit64)
|
||||||
{
|
{
|
||||||
|
@ -234,12 +262,15 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\ScreamAPI64.dll";
|
path = rootDirectory + @"\ScreamAPI64.dll";
|
||||||
}
|
}
|
||||||
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(path);
|
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
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);
|
ScreamAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
||||||
}
|
}
|
||||||
|
@ -253,12 +284,16 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\UplayR1Unlocker32.dll";
|
path = rootDirectory + @"\UplayR1Unlocker32.dll";
|
||||||
}
|
}
|
||||||
"UplayR1.uplay_r1_loader.dll".Write(path);
|
"UplayR1.uplay_r1_loader.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (bit64)
|
if (bit64)
|
||||||
{
|
{
|
||||||
|
@ -268,12 +303,16 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\UplayR1Unlocker64.dll";
|
path = rootDirectory + @"\UplayR1Unlocker64.dll";
|
||||||
}
|
}
|
||||||
"UplayR1.uplay_r1_loader64.dll".Write(path);
|
"UplayR1.uplay_r1_loader64.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
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);
|
UplayR1.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
||||||
if (bit32)
|
if (bit32)
|
||||||
|
@ -284,12 +323,16 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\UplayR2Unlocker32.dll";
|
path = rootDirectory + @"\UplayR2Unlocker32.dll";
|
||||||
}
|
}
|
||||||
"UplayR2.upc_r2_loader.dll".Write(path);
|
"UplayR2.upc_r2_loader.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (bit64)
|
if (bit64)
|
||||||
{
|
{
|
||||||
|
@ -299,12 +342,16 @@ internal static class Koaloader
|
||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser(
|
||||||
|
$"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
path = rootDirectory + @"\UplayR2Unlocker64.dll";
|
path = rootDirectory + @"\UplayR2Unlocker64.dll";
|
||||||
}
|
}
|
||||||
"UplayR2.upc_r2_loader64.dll".Write(path);
|
"UplayR2.upc_r2_loader64.dll".Write(path);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}", LogTextBox.Action, info: false);
|
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);
|
UplayR2.CheckConfig(rootDirectory ?? directory, selection, installForm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using CreamInstaller.Utility;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -9,12 +7,14 @@ using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class Resources
|
internal static class Resources
|
||||||
{
|
{
|
||||||
internal static List<string> embeddedResources;
|
internal static List<string> embeddedResources;
|
||||||
|
|
||||||
internal static List<string> EmbeddedResources
|
internal static List<string> EmbeddedResources
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -22,7 +22,7 @@ internal static class Resources
|
||||||
if (embeddedResources is null)
|
if (embeddedResources is null)
|
||||||
{
|
{
|
||||||
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||||
embeddedResources = new();
|
embeddedResources = new List<string>();
|
||||||
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.")))
|
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.")))
|
||||||
embeddedResources.Add(resourceName[25..]);
|
embeddedResources.Add(resourceName[25..]);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@ internal static class Resources
|
||||||
|
|
||||||
internal static void Write(this string resourceIdentifier, string filePath)
|
internal static void Write(this string resourceIdentifier, string filePath)
|
||||||
{
|
{
|
||||||
using Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("CreamInstaller.Resources." + resourceIdentifier);
|
using Stream resource = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream("CreamInstaller.Resources." + resourceIdentifier);
|
||||||
using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
|
using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
|
||||||
resource.CopyTo(file);
|
resource.CopyTo(file);
|
||||||
}
|
}
|
||||||
|
@ -62,55 +63,59 @@ internal static class Resources
|
||||||
|
|
||||||
internal enum BinaryType
|
internal enum BinaryType
|
||||||
{
|
{
|
||||||
Unknown = -1,
|
Unknown = -1, BIT32 = 0, DOS = 1,
|
||||||
BIT32 = 0,
|
WOW = 2, PIF = 3, POSIX = 4,
|
||||||
DOS = 1,
|
OS216 = 5, BIT64 = 6
|
||||||
WOW = 2,
|
|
||||||
PIF = 3,
|
|
||||||
POSIX = 4,
|
|
||||||
OS216 = 5,
|
|
||||||
BIT64 = 6,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||||
private static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType);
|
private static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType);
|
||||||
internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) => GetBinaryType(path, out binaryType);
|
|
||||||
|
|
||||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false, Func<string, bool> validFunc = null) =>
|
internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType)
|
||||||
await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon: filterCommon, validFunc: validFunc)
|
=> GetBinaryType(path, out binaryType);
|
||||||
?? (filterCommon || validFunc is not null ? await rootDirectory.GetExecutables() : null))?.Select(e =>
|
|
||||||
|
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||||
|
this string rootDirectory, bool filterCommon = false, Func<string, bool> validFunc = null) =>
|
||||||
|
await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon, validFunc)
|
||||||
|
?? (filterCommon || validFunc is not null
|
||||||
|
? await rootDirectory.GetExecutables()
|
||||||
|
: null))?.Select(e =>
|
||||||
{
|
{
|
||||||
e.path = Path.GetDirectoryName(e.path);
|
e.path = Path.GetDirectoryName(e.path);
|
||||||
return e;
|
return e;
|
||||||
})?.DistinctBy(e => e.path).ToList());
|
})?.DistinctBy(e => e.path).ToList());
|
||||||
|
|
||||||
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false, Func<string, bool> validFunc = null) => await Task.Run(() =>
|
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(
|
||||||
{
|
this string rootDirectory, bool filterCommon = false, Func<string, bool> validFunc = null) => await Task.Run(
|
||||||
List<(string path, BinaryType binaryType)> executables = new();
|
() =>
|
||||||
if (Program.Canceled || !Directory.Exists(rootDirectory)) return null;
|
|
||||||
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", new EnumerationOptions() { RecurseSubdirectories = true }))
|
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return null;
|
List<(string path, BinaryType binaryType)> executables = new();
|
||||||
if (!executables.Any(e => e.path == path)
|
if (Program.Canceled || !Directory.Exists(rootDirectory)) return null;
|
||||||
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe",
|
||||||
&& (validFunc is null || validFunc(path))
|
new EnumerationOptions { RecurseSubdirectories = true }))
|
||||||
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64)
|
{
|
||||||
executables.Add((path, binaryType));
|
if (Program.Canceled) return null;
|
||||||
Thread.Sleep(1);
|
if (!executables.Any(e => e.path == path)
|
||||||
}
|
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
||||||
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", new EnumerationOptions() { RecurseSubdirectories = true }))
|
&& (validFunc is null || validFunc(path))
|
||||||
{
|
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64)
|
||||||
if (Program.Canceled) return null;
|
executables.Add((path, binaryType));
|
||||||
if (!executables.Any(e => e.path == path)
|
Thread.Sleep(1);
|
||||||
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
}
|
||||||
&& (validFunc is null || validFunc(path))
|
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe",
|
||||||
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32)
|
new EnumerationOptions { RecurseSubdirectories = true }))
|
||||||
executables.Add((path, binaryType));
|
{
|
||||||
Thread.Sleep(1);
|
if (Program.Canceled) return null;
|
||||||
}
|
if (!executables.Any(e => e.path == path)
|
||||||
return !executables.Any() ? null : executables;
|
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
||||||
});
|
&& (validFunc is null || validFunc(path))
|
||||||
|
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32)
|
||||||
|
executables.Add((path, binaryType));
|
||||||
|
Thread.Sleep(1);
|
||||||
|
}
|
||||||
|
return !executables.Any() ? null : executables;
|
||||||
|
});
|
||||||
|
|
||||||
internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path)
|
internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path)
|
||||||
{
|
{
|
||||||
|
@ -118,69 +123,77 @@ internal static class Resources
|
||||||
return subPath.Contains("SETUP")
|
return subPath.Contains("SETUP")
|
||||||
|| subPath.Contains("REDIST")
|
|| subPath.Contains("REDIST")
|
||||||
|| subPath.Contains("SUPPORT")
|
|| subPath.Contains("SUPPORT")
|
||||||
|| subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT"))
|
|| (subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT")))
|
||||||
|| subPath.Contains("HELPER")
|
|| subPath.Contains("HELPER")
|
||||||
|| subPath.Contains("CEFPROCESS")
|
|| subPath.Contains("CEFPROCESS")
|
||||||
|| subPath.Contains("ZFGAMEBROWSER")
|
|| subPath.Contains("ZFGAMEBROWSER")
|
||||||
|| subPath.Contains("MONO")
|
|| subPath.Contains("MONO")
|
||||||
|| subPath.Contains("PLUGINS")
|
|| subPath.Contains("PLUGINS")
|
||||||
|| subPath.Contains("MODDING")
|
|| subPath.Contains("MODDING")
|
||||||
|| subPath.Contains("MOD") && subPath.Contains("MANAGER")
|
|| (subPath.Contains("MOD") && subPath.Contains("MANAGER"))
|
||||||
|| subPath.Contains("BATTLEYE")
|
|| subPath.Contains("BATTLEYE")
|
||||||
|| subPath.Contains("ANTICHEAT");
|
|| subPath.Contains("ANTICHEAT");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory, Platform platform) => await Task.Run(() =>
|
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(
|
||||||
|
this string gameDirectory, Platform platform) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
List<string> dllDirectories = new();
|
List<string> dllDirectories = new();
|
||||||
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
||||||
foreach (string directory in Directory.EnumerateDirectories(gameDirectory, "*", new EnumerationOptions() { RecurseSubdirectories = true }).Append(gameDirectory))
|
foreach (string directory in Directory
|
||||||
|
.EnumerateDirectories(gameDirectory, "*",
|
||||||
|
new EnumerationOptions { RecurseSubdirectories = true })
|
||||||
|
.Append(gameDirectory))
|
||||||
{
|
{
|
||||||
if (Program.Canceled) return null;
|
if (Program.Canceled) return null;
|
||||||
string subDirectory = directory.BeautifyPath();
|
string subDirectory = directory.BeautifyPath();
|
||||||
if (!dllDirectories.Contains(subDirectory))
|
if (!dllDirectories.Contains(subDirectory))
|
||||||
{
|
{
|
||||||
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
||||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||||
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
||||||
if (platform is Platform.Steam or Platform.Paradox)
|
if (platform is Platform.Steam or Platform.Paradox)
|
||||||
{
|
{
|
||||||
subDirectory.GetSmokeApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string config, out string cache);
|
subDirectory.GetSmokeApiComponents(out string api, out string api_o, out string api64,
|
||||||
|
out string api64_o, out string config, out string cache);
|
||||||
if (File.Exists(api)
|
if (File.Exists(api)
|
||||||
|| File.Exists(api_o)
|
|| File.Exists(api_o)
|
||||||
|| File.Exists(api64)
|
|| File.Exists(api64)
|
||||||
|| File.Exists(api64_o)
|
|| File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled
|
|| (File.Exists(config) && !koaloaderInstalled)
|
||||||
|| File.Exists(cache) && !koaloaderInstalled)
|
|| (File.Exists(cache) && !koaloaderInstalled))
|
||||||
dllDirectories.Add(subDirectory);
|
dllDirectories.Add(subDirectory);
|
||||||
}
|
}
|
||||||
if (platform is Platform.Epic or Platform.Paradox)
|
if (platform is Platform.Epic or Platform.Paradox)
|
||||||
{
|
{
|
||||||
subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
|
||||||
|
out string api64_o, out string config);
|
||||||
if (File.Exists(api32)
|
if (File.Exists(api32)
|
||||||
|| File.Exists(api32_o)
|
|| File.Exists(api32_o)
|
||||||
|| File.Exists(api64)
|
|| File.Exists(api64)
|
||||||
|| File.Exists(api64_o)
|
|| File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled)
|
|| (File.Exists(config) && !koaloaderInstalled))
|
||||||
dllDirectories.Add(subDirectory);
|
dllDirectories.Add(subDirectory);
|
||||||
}
|
}
|
||||||
if (platform is Platform.Ubisoft)
|
if (platform is Platform.Ubisoft)
|
||||||
{
|
{
|
||||||
subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
|
||||||
|
out string api64_o, out string config);
|
||||||
if (File.Exists(api32)
|
if (File.Exists(api32)
|
||||||
|| File.Exists(api32_o)
|
|| File.Exists(api32_o)
|
||||||
|| File.Exists(api64)
|
|| File.Exists(api64)
|
||||||
|| File.Exists(api64_o)
|
|| File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled)
|
|| (File.Exists(config) && !koaloaderInstalled))
|
||||||
dllDirectories.Add(subDirectory);
|
dllDirectories.Add(subDirectory);
|
||||||
subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config);
|
subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32,
|
||||||
|
out api32_o, out api64, out api64_o, out config);
|
||||||
if (File.Exists(old_api32)
|
if (File.Exists(old_api32)
|
||||||
|| File.Exists(old_api64)
|
|| File.Exists(old_api64)
|
||||||
|| File.Exists(api32)
|
|| File.Exists(api32)
|
||||||
|| File.Exists(api32_o)
|
|| File.Exists(api32_o)
|
||||||
|| File.Exists(api64)
|
|| File.Exists(api64)
|
||||||
|| File.Exists(api64_o)
|
|| File.Exists(api64_o)
|
||||||
|| File.Exists(config) && !koaloaderInstalled)
|
|| (File.Exists(config) && !koaloaderInstalled))
|
||||||
dllDirectories.Add(subDirectory);
|
dllDirectories.Add(subDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,10 +202,10 @@ internal static class Resources
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static void GetCreamApiComponents(
|
internal static void GetCreamApiComponents(
|
||||||
this string directory,
|
this string directory,
|
||||||
out string api32, out string api32_o,
|
out string api32, out string api32_o,
|
||||||
out string api64, out string api64_o,
|
out string api64, out string api64_o,
|
||||||
out string config)
|
out string config)
|
||||||
{
|
{
|
||||||
api32 = directory + @"\steam_api.dll";
|
api32 = directory + @"\steam_api.dll";
|
||||||
api32_o = directory + @"\steam_api_o.dll";
|
api32_o = directory + @"\steam_api_o.dll";
|
||||||
|
@ -203,22 +216,15 @@ internal static class Resources
|
||||||
|
|
||||||
internal enum ResourceIdentifier
|
internal enum ResourceIdentifier
|
||||||
{
|
{
|
||||||
Koaloader,
|
Koaloader, Steamworks32, Steamworks64,
|
||||||
Steamworks32,
|
EpicOnlineServices32, EpicOnlineServices64, Uplay32,
|
||||||
Steamworks64,
|
Uplay64, Upc32, Upc64
|
||||||
EpicOnlineServices32,
|
|
||||||
EpicOnlineServices64,
|
|
||||||
Uplay32,
|
|
||||||
Uplay64,
|
|
||||||
Upc32,
|
|
||||||
Upc64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly Dictionary<ResourceIdentifier, IReadOnlyList<string>> ResourceMD5s = new()
|
internal static readonly Dictionary<ResourceIdentifier, IReadOnlyList<string>> ResourceMD5s = new()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Koaloader,
|
ResourceIdentifier.Koaloader, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"8A0958687B5ED7C34DAD037856DD1530", // Koaloader v2.0.0
|
"8A0958687B5ED7C34DAD037856DD1530", // Koaloader v2.0.0
|
||||||
"8FECDEB40980F4E687C10E056232D96B", // Koaloader v2.0.0
|
"8FECDEB40980F4E687C10E056232D96B", // Koaloader v2.0.0
|
||||||
|
@ -463,75 +469,67 @@ internal static class Resources
|
||||||
"76CAB00C7DD33FC19F7CDD1849FF9CA2", // Koaloader v2.4.0
|
"76CAB00C7DD33FC19F7CDD1849FF9CA2", // Koaloader v2.4.0
|
||||||
"DA4D6A7C0872757A74DDAE05A2C1D160", // Koaloader v2.4.0
|
"DA4D6A7C0872757A74DDAE05A2C1D160", // Koaloader v2.4.0
|
||||||
"1F46DE8747C0A157841AFFE6185CE4C9", // Koaloader v2.4.0
|
"1F46DE8747C0A157841AFFE6185CE4C9", // Koaloader v2.4.0
|
||||||
"BE16B588D018D8EFF1F3B6A600F26BED" // Koaloader v2.4.0
|
"BE16B588D018D8EFF1F3B6A600F26BED" // Koaloader v2.4.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.EpicOnlineServices32,
|
ResourceIdentifier.EpicOnlineServices32, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"069A57B1834A960193D2AD6B96926D70", // ScreamAPI v3.0.0
|
"069A57B1834A960193D2AD6B96926D70", // ScreamAPI v3.0.0
|
||||||
"E2FB3A4A9583FDC215832E5F935E4440" // ScreamAPI v3.0.1
|
"E2FB3A4A9583FDC215832E5F935E4440" // ScreamAPI v3.0.1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.EpicOnlineServices64,
|
ResourceIdentifier.EpicOnlineServices64, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"0D62E57139F1A64F807A9934946A9474", // ScreamAPI v3.0.0
|
"0D62E57139F1A64F807A9934946A9474", // ScreamAPI v3.0.0
|
||||||
"3875C7B735EE80C23239CC4749FDCBE6" // ScreamAPI v3.0.1
|
"3875C7B735EE80C23239CC4749FDCBE6" // ScreamAPI v3.0.1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Steamworks32,
|
ResourceIdentifier.Steamworks32, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"02594110FE56B2945955D46670B9A094", // CreamAPI v4.5.0.0 Hotfix
|
"02594110FE56B2945955D46670B9A094", // CreamAPI v4.5.0.0 Hotfix
|
||||||
"B2434578957CBE38BDCE0A671C1262FC", // SmokeAPI v1.0.0
|
"B2434578957CBE38BDCE0A671C1262FC", // SmokeAPI v1.0.0
|
||||||
"973AB1632B747D4BF3B2666F32E34327", // SmokeAPI v1.0.1
|
"973AB1632B747D4BF3B2666F32E34327", // SmokeAPI v1.0.1
|
||||||
"C7E41F569FC6A347D67D2BFB2BD10F25", // SmokeAPI v1.0.2
|
"C7E41F569FC6A347D67D2BFB2BD10F25", // SmokeAPI v1.0.2
|
||||||
"F9E7D5B248B86D1C2F2F2905A9F37755" // SmokeAPI v1.0.3
|
"F9E7D5B248B86D1C2F2F2905A9F37755" // SmokeAPI v1.0.3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Steamworks64,
|
ResourceIdentifier.Steamworks64, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"30091B91923D9583A54A93ED1145554B", // CreamAPI v4.5.0.0 Hotfix
|
"30091B91923D9583A54A93ED1145554B", // CreamAPI v4.5.0.0 Hotfix
|
||||||
"08713035CAD6F52548FF324D0487B88D", // SmokeAPI v1.0.0
|
"08713035CAD6F52548FF324D0487B88D", // SmokeAPI v1.0.0
|
||||||
"D077737B9979D32458AC938A2978FA3C", // SmokeAPI v1.0.1
|
"D077737B9979D32458AC938A2978FA3C", // SmokeAPI v1.0.1
|
||||||
"49122A2E2E51CBB0AE5E1D59B280E4CD", // SmokeAPI v1.0.2
|
"49122A2E2E51CBB0AE5E1D59B280E4CD", // SmokeAPI v1.0.2
|
||||||
"13F3E9476116F7670E21365A400357AC" // SmokeAPI v1.0.3
|
"13F3E9476116F7670E21365A400357AC" // SmokeAPI v1.0.3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Uplay32,
|
ResourceIdentifier.Uplay32, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"1977967B2549A38EC2DB39D4C8ED499B" // Uplay R1 Unlocker v2.0.0
|
"1977967B2549A38EC2DB39D4C8ED499B" // Uplay R1 Unlocker v2.0.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Uplay64,
|
ResourceIdentifier.Uplay64, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"333FEDD9DC2B299419B37ED1624FF8DB" // Uplay R1 Unlocker v2.0.0
|
"333FEDD9DC2B299419B37ED1624FF8DB" // Uplay R1 Unlocker v2.0.0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Upc32,
|
ResourceIdentifier.Upc32, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"C14368BC4EE19FDE8DBAC07E31C67AE4", // Uplay R2 Unlocker v3.0.0
|
"C14368BC4EE19FDE8DBAC07E31C67AE4", // Uplay R2 Unlocker v3.0.0
|
||||||
"DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
|
"DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResourceIdentifier.Upc64,
|
ResourceIdentifier.Upc64, new List<string>
|
||||||
new List<string>()
|
|
||||||
{
|
{
|
||||||
"7D9A4C12972BAABCB6C181920CC0F19B", // Uplay R2 Unlocker v3.0.0
|
"7D9A4C12972BAABCB6C181920CC0F19B", // Uplay R2 Unlocker v3.0.0
|
||||||
"D7FDBFE0FC8D7600FEB8EC0A97713184" // Uplay R2 Unlocker v3.0.1
|
"D7FDBFE0FC8D7600FEB8EC0A97713184" // Uplay R2 Unlocker v3.0.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -547,7 +545,10 @@ internal static class Resources
|
||||||
return BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
|
return BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
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, 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 IsResourceFile(this string filePath) => filePath.ComputeMD5() is string hash
|
||||||
|
&& ResourceMD5s.Values.Any(
|
||||||
|
hashes => hashes.Contains(hash));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class ScreamAPI
|
internal static class ScreamAPI
|
||||||
{
|
{
|
||||||
internal static void GetScreamApiComponents(
|
internal static void GetScreamApiComponents(
|
||||||
this string directory,
|
this string directory,
|
||||||
out string api32, out string api32_o,
|
out string api32, out string api32_o,
|
||||||
out string api64, out string api64_o,
|
out string api64, out string api64_o,
|
||||||
out string config
|
out string config
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
api32 = directory + @"\EOSSDK-Win32-Shipping.dll";
|
api32 = directory + @"\EOSSDK-Win32-Shipping.dll";
|
||||||
api32_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
|
api32_o = directory + @"\EOSSDK-Win32-Shipping_o.dll";
|
||||||
|
@ -28,11 +28,15 @@ internal static class ScreamAPI
|
||||||
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config);
|
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideCatalogItems = selection.AllDlc.Where(pair => pair.Value.type is DlcType.EpicCatalogItem).Except(selection.SelectedDlc);
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideCatalogItems
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
= selection.AllDlc.Where(pair => pair.Value.type is DlcType.EpicCatalogItem).Except(selection.SelectedDlc);
|
||||||
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
overrideCatalogItems = overrideCatalogItems.Except(extraDlc);
|
overrideCatalogItems = overrideCatalogItems.Except(extraDlc);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> entitlements = selection.SelectedDlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement);
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> entitlements
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> _dlc) in selection.ExtraSelectedDlc)
|
= selection.SelectedDlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement);
|
||||||
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> _dlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
entitlements = entitlements.Concat(_dlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement));
|
entitlements = entitlements.Concat(_dlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement));
|
||||||
if (overrideCatalogItems.Any() || entitlements.Any())
|
if (overrideCatalogItems.Any() || entitlements.Any())
|
||||||
{
|
{
|
||||||
|
@ -41,20 +45,27 @@ internal static class ScreamAPI
|
||||||
File.Create(config).Close();
|
File.Create(config).Close();
|
||||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||||
WriteConfig(writer,
|
WriteConfig(writer,
|
||||||
new(overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
new(entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value),
|
||||||
installForm);
|
PlatformIdComparer.String),
|
||||||
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
|
entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||||
|
installForm);
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
writer.Close();
|
writer.Close();
|
||||||
}
|
}
|
||||||
else if (File.Exists(config))
|
else if (File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> overrideCatalogItems, SortedList<string, (DlcType type, string name, string icon)> entitlements, InstallForm installForm = null)
|
internal static void WriteConfig(StreamWriter writer,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> overrideCatalogItems,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> entitlements,
|
||||||
|
InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
writer.WriteLine(" \"version\": 2,");
|
writer.WriteLine(" \"version\": 2,");
|
||||||
|
@ -66,18 +77,22 @@ internal static class ScreamAPI
|
||||||
if (overrideCatalogItems.Any())
|
if (overrideCatalogItems.Any())
|
||||||
{
|
{
|
||||||
writer.WriteLine(" \"override\": [");
|
writer.WriteLine(" \"override\": [");
|
||||||
KeyValuePair<string, (DlcType type, string name, string icon)> lastOverrideCatalogItem = overrideCatalogItems.Last();
|
KeyValuePair<string, (DlcType type, string name, string icon)> lastOverrideCatalogItem
|
||||||
|
= overrideCatalogItems.Last();
|
||||||
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in overrideCatalogItems)
|
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in overrideCatalogItems)
|
||||||
{
|
{
|
||||||
string id = pair.Key;
|
string id = pair.Key;
|
||||||
(_, string name, _) = pair.Value;
|
(_, string name, _) = pair.Value;
|
||||||
writer.WriteLine($" \"{id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
|
writer.WriteLine($" \"{id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added override catalog item to ScreamAPI.json with id {id} ({name})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added override catalog item to ScreamAPI.json with id {id} ({name})",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ]");
|
writer.WriteLine(" ]");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"override\": []");
|
writer.WriteLine(" \"override\": []");
|
||||||
|
}
|
||||||
writer.WriteLine(" },");
|
writer.WriteLine(" },");
|
||||||
writer.WriteLine(" \"entitlements\": {");
|
writer.WriteLine(" \"entitlements\": {");
|
||||||
writer.WriteLine(" \"unlock_all\": true,");
|
writer.WriteLine(" \"unlock_all\": true,");
|
||||||
|
@ -91,68 +106,79 @@ internal static class ScreamAPI
|
||||||
string id = pair.Key;
|
string id = pair.Key;
|
||||||
(_, string name, _) = pair.Value;
|
(_, string name, _) = pair.Value;
|
||||||
writer.WriteLine($" \"{id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
|
writer.WriteLine($" \"{id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added entitlement to ScreamAPI.json with id {id} ({name})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added entitlement to ScreamAPI.json with id {id} ({name})", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ]");
|
writer.WriteLine(" ]");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"inject\": []");
|
writer.WriteLine(" \"inject\": []");
|
||||||
|
}
|
||||||
writer.WriteLine(" }");
|
writer.WriteLine(" }");
|
||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||||
{
|
=> await Task.Run(() =>
|
||||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
|
||||||
if (File.Exists(api32_o))
|
|
||||||
{
|
{
|
||||||
if (File.Exists(api32))
|
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config);
|
||||||
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Delete(api32);
|
if (File.Exists(api32))
|
||||||
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
{
|
||||||
|
File.Delete(api32);
|
||||||
|
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
|
||||||
|
}
|
||||||
|
File.Move(api32_o, api32);
|
||||||
|
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api32_o, api32);
|
if (File.Exists(api64_o))
|
||||||
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
if (File.Exists(api64_o))
|
|
||||||
{
|
|
||||||
if (File.Exists(api64))
|
|
||||||
{
|
{
|
||||||
File.Delete(api64);
|
if (File.Exists(api64))
|
||||||
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
|
File.Delete(api64);
|
||||||
|
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||||
|
}
|
||||||
|
File.Move(api64_o, api64);
|
||||||
|
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api64_o, api64);
|
if (deleteConfig && File.Exists(config))
|
||||||
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
}
|
File.Delete(config);
|
||||||
if (deleteConfig && File.Exists(config))
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
||||||
{
|
}
|
||||||
File.Delete(config);
|
});
|
||||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
|
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null,
|
||||||
|
bool generateConfig = true) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config);
|
||||||
if (File.Exists(api32) && !File.Exists(api32_o))
|
if (File.Exists(api32) && !File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Move(api32, api32_o);
|
File.Move(api32, api32_o);
|
||||||
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api32_o))
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(api32);
|
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(api32);
|
||||||
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64) && !File.Exists(api64_o))
|
if (File.Exists(api64) && !File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
File.Move(api64, api64_o);
|
File.Move(api64, api64_o);
|
||||||
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64_o))
|
if (File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(api64);
|
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(api64);
|
||||||
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (generateConfig)
|
if (generateConfig)
|
||||||
CheckConfig(directory, selection, installForm);
|
CheckConfig(directory, selection, installForm);
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class SmokeAPI
|
internal static class SmokeAPI
|
||||||
{
|
{
|
||||||
internal static void GetSmokeApiComponents(
|
internal static void GetSmokeApiComponents(
|
||||||
this string directory,
|
this string directory,
|
||||||
out string api32, out string api32_o,
|
out string api32, out string api32_o,
|
||||||
out string api64, out string api64_o,
|
out string api64, out string api64_o,
|
||||||
out string config,
|
out string config,
|
||||||
out string cache)
|
out string cache)
|
||||||
{
|
{
|
||||||
api32 = directory + @"\steam_api.dll";
|
api32 = directory + @"\steam_api.dll";
|
||||||
api32_o = directory + @"\steam_api_o.dll";
|
api32_o = directory + @"\steam_api_o.dll";
|
||||||
|
@ -29,14 +29,18 @@ internal static class SmokeAPI
|
||||||
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string config, out _);
|
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string config, out _);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideDlc = selection.AllDlc.Except(selection.SelectedDlc);
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideDlc
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
= selection.AllDlc.Except(selection.SelectedDlc);
|
||||||
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
overrideDlc = overrideDlc.Except(extraDlc);
|
overrideDlc = overrideDlc.Except(extraDlc);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> injectDlc = new List<KeyValuePair<string, (DlcType type, string name, string icon)>>();
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> injectDlc
|
||||||
|
= new List<KeyValuePair<string, (DlcType type, string name, string icon)>>();
|
||||||
if (selection.AllDlc.Count > 64 || selection.ExtraDlc.Any(e => e.dlc.Count > 64))
|
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));
|
injectDlc = injectDlc.Concat(selection.SelectedDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
if (selection.ExtraDlc.Where(e => e.id == id).Single().dlc.Count > 64)
|
if (selection.ExtraDlc.Where(e => e.id == id).Single().dlc.Count > 64)
|
||||||
injectDlc = injectDlc.Concat(extraDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
|
injectDlc = injectDlc.Concat(extraDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
|
||||||
}
|
}
|
||||||
|
@ -47,20 +51,26 @@ internal static class SmokeAPI
|
||||||
File.Create(config).Close();
|
File.Create(config).Close();
|
||||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||||
WriteConfig(writer,
|
WriteConfig(writer,
|
||||||
new(overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
new(injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||||
installForm);
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
|
injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||||
|
installForm);
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
writer.Close();
|
writer.Close();
|
||||||
}
|
}
|
||||||
else if (File.Exists(config))
|
else if (File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> overrideDlc, SortedList<string, (DlcType type, string name, string icon)> injectDlc, InstallForm installForm = null)
|
internal static void WriteConfig(StreamWriter writer,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> overrideDlc,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> injectDlc,
|
||||||
|
InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
writer.WriteLine(" \"$version\": 1,");
|
writer.WriteLine(" \"$version\": 1,");
|
||||||
|
@ -76,12 +86,15 @@ internal static class SmokeAPI
|
||||||
string dlcId = pair.Key;
|
string dlcId = pair.Key;
|
||||||
(_, string dlcName, _) = pair.Value;
|
(_, string dlcName, _) = pair.Value;
|
||||||
writer.WriteLine($" {dlcId}{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
|
writer.WriteLine($" {dlcId}{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added override DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added override DLC to SmokeAPI.json with appid {dlcId} ({dlcName})",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ],");
|
writer.WriteLine(" ],");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"override\": [],");
|
writer.WriteLine(" \"override\": [],");
|
||||||
|
}
|
||||||
if (injectDlc.Count > 0)
|
if (injectDlc.Count > 0)
|
||||||
{
|
{
|
||||||
writer.WriteLine(" \"dlc_ids\": [");
|
writer.WriteLine(" \"dlc_ids\": [");
|
||||||
|
@ -91,86 +104,101 @@ internal static class SmokeAPI
|
||||||
string dlcId = pair.Key;
|
string dlcId = pair.Key;
|
||||||
(_, string dlcName, _) = pair.Value;
|
(_, string dlcName, _) = pair.Value;
|
||||||
writer.WriteLine($" {dlcId}{(pair.Equals(lastInjectDlc) ? "" : ",")}");
|
writer.WriteLine($" {dlcId}{(pair.Equals(lastInjectDlc) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added inject DLC to SmokeAPI.json with appid {dlcId} ({dlcName})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added inject DLC to SmokeAPI.json with appid {dlcId} ({dlcName})",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ],");
|
writer.WriteLine(" ],");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"dlc_ids\": [],");
|
writer.WriteLine(" \"dlc_ids\": [],");
|
||||||
|
}
|
||||||
writer.WriteLine(" \"auto_inject_inventory\": true,");
|
writer.WriteLine(" \"auto_inject_inventory\": true,");
|
||||||
writer.WriteLine(" \"inventory_items\": []");
|
writer.WriteLine(" \"inventory_items\": []");
|
||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||||
{
|
=> await Task.Run(() =>
|
||||||
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
|
|
||||||
if (File.Exists(oldConfig))
|
|
||||||
{
|
{
|
||||||
File.Delete(oldConfig);
|
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
|
||||||
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}", LogTextBox.Action, info: false);
|
if (File.Exists(oldConfig))
|
||||||
}
|
|
||||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string cache);
|
|
||||||
if (File.Exists(api32_o))
|
|
||||||
{
|
|
||||||
if (File.Exists(api32))
|
|
||||||
{
|
{
|
||||||
File.Delete(api32);
|
File.Delete(oldConfig);
|
||||||
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api32_o, api32);
|
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
out string config, out string cache);
|
||||||
}
|
if (File.Exists(api32_o))
|
||||||
if (File.Exists(api64_o))
|
|
||||||
{
|
|
||||||
if (File.Exists(api64))
|
|
||||||
{
|
{
|
||||||
File.Delete(api64);
|
if (File.Exists(api32))
|
||||||
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
|
File.Delete(api32);
|
||||||
|
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
|
||||||
|
}
|
||||||
|
File.Move(api32_o, api32);
|
||||||
|
installForm?.UpdateUser(
|
||||||
|
$"Restored Steamworks: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
File.Move(api64_o, api64);
|
if (File.Exists(api64_o))
|
||||||
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
}
|
if (File.Exists(api64))
|
||||||
if (deleteConfig && File.Exists(config))
|
{
|
||||||
{
|
File.Delete(api64);
|
||||||
File.Delete(config);
|
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
}
|
||||||
}
|
File.Move(api64_o, api64);
|
||||||
if (deleteConfig && File.Exists(cache))
|
installForm?.UpdateUser(
|
||||||
{
|
$"Restored Steamworks: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action,
|
||||||
File.Delete(cache);
|
false);
|
||||||
installForm?.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", LogTextBox.Action, info: false);
|
}
|
||||||
}
|
if (deleteConfig && File.Exists(config))
|
||||||
});
|
{
|
||||||
|
File.Delete(config);
|
||||||
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
||||||
|
}
|
||||||
|
if (deleteConfig && File.Exists(cache))
|
||||||
|
{
|
||||||
|
File.Delete(cache);
|
||||||
|
installForm?.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", LogTextBox.Action, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
|
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);
|
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
|
||||||
if (File.Exists(oldConfig))
|
if (File.Exists(oldConfig))
|
||||||
{
|
{
|
||||||
File.Delete(oldConfig);
|
File.Delete(oldConfig);
|
||||||
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out _);
|
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config, out _);
|
||||||
if (File.Exists(api32) && !File.Exists(api32_o))
|
if (File.Exists(api32) && !File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Move(api32, api32_o);
|
File.Move(api32, api32_o);
|
||||||
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api32_o))
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
"SmokeAPI.steam_api.dll".Write(api32);
|
"SmokeAPI.steam_api.dll".Write(api32);
|
||||||
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64) && !File.Exists(api64_o))
|
if (File.Exists(api64) && !File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
File.Move(api64, api64_o);
|
File.Move(api64, api64_o);
|
||||||
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64_o))
|
if (File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
"SmokeAPI.steam_api64.dll".Write(api64);
|
"SmokeAPI.steam_api64.dll".Write(api64);
|
||||||
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (generateConfig)
|
if (generateConfig)
|
||||||
CheckConfig(directory, selection, installForm);
|
CheckConfig(directory, selection, installForm);
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class UplayR1
|
internal static class UplayR1
|
||||||
{
|
{
|
||||||
internal static void GetUplayR1Components(
|
internal static void GetUplayR1Components(
|
||||||
this string directory,
|
this string directory,
|
||||||
out string api32, out string api32_o,
|
out string api32, out string api32_o,
|
||||||
out string api64, out string api64_o,
|
out string api64, out string api64_o,
|
||||||
out string config
|
out string config
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
api32 = directory + @"\uplay_r1_loader.dll";
|
api32 = directory + @"\uplay_r1_loader.dll";
|
||||||
api32_o = directory + @"\uplay_r1_loader_o.dll";
|
api32_o = directory + @"\uplay_r1_loader_o.dll";
|
||||||
|
@ -28,8 +28,10 @@ internal static class UplayR1
|
||||||
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
directory.GetUplayR1Components(out _, out _, out _, out _, out string config);
|
directory.GetUplayR1Components(out _, out _, out _, out _, out string config);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
= selection.AllDlc.Except(selection.SelectedDlc);
|
||||||
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
blacklistDlc = blacklistDlc.Except(extraDlc);
|
blacklistDlc = blacklistDlc.Except(extraDlc);
|
||||||
if (blacklistDlc.Any())
|
if (blacklistDlc.Any())
|
||||||
{
|
{
|
||||||
|
@ -37,18 +39,24 @@ internal static class UplayR1
|
||||||
installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
|
installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
|
||||||
File.Create(config).Close();
|
File.Create(config).Close();
|
||||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||||
WriteConfig(writer, new(blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
|
WriteConfig(writer,
|
||||||
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
|
blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||||
|
installForm);
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
writer.Close();
|
writer.Close();
|
||||||
}
|
}
|
||||||
else if (File.Exists(config))
|
else if (File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc, InstallForm installForm = null)
|
internal static void WriteConfig(StreamWriter writer,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
|
||||||
|
InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
writer.WriteLine(" \"logging\": false,");
|
writer.WriteLine(" \"logging\": false,");
|
||||||
|
@ -63,67 +71,80 @@ internal static class UplayR1
|
||||||
string dlcId = pair.Key;
|
string dlcId = pair.Key;
|
||||||
(_, string dlcName, _) = pair.Value;
|
(_, string dlcName, _) = pair.Value;
|
||||||
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
|
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {dlcId} ({dlcName})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {dlcId} ({dlcName})",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ],");
|
writer.WriteLine(" ],");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"blacklist\": [],");
|
writer.WriteLine(" \"blacklist\": [],");
|
||||||
|
}
|
||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||||
{
|
=> await Task.Run(() =>
|
||||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
|
||||||
if (File.Exists(api32_o))
|
|
||||||
{
|
{
|
||||||
if (File.Exists(api32))
|
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config);
|
||||||
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Delete(api32);
|
if (File.Exists(api32))
|
||||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
{
|
||||||
|
File.Delete(api32);
|
||||||
|
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
File.Move(api32_o, api32);
|
||||||
|
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api32_o, api32);
|
if (File.Exists(api64_o))
|
||||||
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
if (File.Exists(api64_o))
|
|
||||||
{
|
|
||||||
if (File.Exists(api64))
|
|
||||||
{
|
{
|
||||||
File.Delete(api64);
|
if (File.Exists(api64))
|
||||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
|
File.Delete(api64);
|
||||||
|
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
File.Move(api64_o, api64);
|
||||||
|
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api64_o, api64);
|
if (deleteConfig && File.Exists(config))
|
||||||
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
{
|
||||||
}
|
File.Delete(config);
|
||||||
if (deleteConfig && File.Exists(config))
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
||||||
{
|
}
|
||||||
File.Delete(config);
|
});
|
||||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
|
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null,
|
||||||
|
bool generateConfig = true) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o,
|
||||||
|
out string config);
|
||||||
if (File.Exists(api32) && !File.Exists(api32_o))
|
if (File.Exists(api32) && !File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Move(api32, api32_o);
|
File.Move(api32, api32_o);
|
||||||
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api32_o))
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
"UplayR1.uplay_r1_loader.dll".Write(api32);
|
"UplayR1.uplay_r1_loader.dll".Write(api32);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64) && !File.Exists(api64_o))
|
if (File.Exists(api64) && !File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
File.Move(api64, api64_o);
|
File.Move(api64, api64_o);
|
||||||
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64_o))
|
if (File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
"UplayR1.uplay_r1_loader64.dll".Write(api64);
|
"UplayR1.uplay_r1_loader64.dll".Write(api64);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (generateConfig)
|
if (generateConfig)
|
||||||
CheckConfig(directory, selection, installForm);
|
CheckConfig(directory, selection, installForm);
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
using CreamInstaller.Components;
|
using System.Collections.Generic;
|
||||||
using CreamInstaller.Utility;
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
|
||||||
namespace CreamInstaller.Resources;
|
namespace CreamInstaller.Resources;
|
||||||
|
|
||||||
internal static class UplayR2
|
internal static class UplayR2
|
||||||
{
|
{
|
||||||
internal static void GetUplayR2Components(
|
internal static void GetUplayR2Components(
|
||||||
this string directory,
|
this string directory,
|
||||||
out string old_api32, out string old_api64,
|
out string old_api32, out string old_api64,
|
||||||
out string api32, out string api32_o,
|
out string api32, out string api32_o,
|
||||||
out string api64, out string api64_o,
|
out string api64, out string api64_o,
|
||||||
out string config)
|
out string config)
|
||||||
{
|
{
|
||||||
old_api32 = directory + @"\uplay_r2_loader.dll";
|
old_api32 = directory + @"\uplay_r2_loader.dll";
|
||||||
old_api64 = directory + @"\uplay_r2_loader64.dll";
|
old_api64 = directory + @"\uplay_r2_loader64.dll";
|
||||||
|
@ -30,8 +30,10 @@ internal static class UplayR2
|
||||||
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
directory.GetUplayR2Components(out _, out _, out _, out _, out _, out _, out string config);
|
directory.GetUplayR2Components(out _, out _, out _, out _, out _, out _, out string config);
|
||||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
|
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc
|
||||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
= selection.AllDlc.Except(selection.SelectedDlc);
|
||||||
|
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in
|
||||||
|
selection.ExtraSelectedDlc)
|
||||||
blacklistDlc = blacklistDlc.Except(extraDlc);
|
blacklistDlc = blacklistDlc.Except(extraDlc);
|
||||||
if (blacklistDlc.Any())
|
if (blacklistDlc.Any())
|
||||||
{
|
{
|
||||||
|
@ -39,18 +41,24 @@ internal static class UplayR2
|
||||||
installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
|
installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
|
||||||
File.Create(config).Close();
|
File.Create(config).Close();
|
||||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||||
WriteConfig(writer, new(blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
|
WriteConfig(writer,
|
||||||
|
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||||
|
blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||||
|
installForm);
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
writer.Close();
|
writer.Close();
|
||||||
}
|
}
|
||||||
else if (File.Exists(config))
|
else if (File.Exists(config))
|
||||||
{
|
{
|
||||||
File.Delete(config);
|
File.Delete(config);
|
||||||
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc, InstallForm installForm = null)
|
internal static void WriteConfig(StreamWriter writer,
|
||||||
|
SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
|
||||||
|
InstallForm installForm = null)
|
||||||
{
|
{
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
writer.WriteLine(" \"logging\": false,");
|
writer.WriteLine(" \"logging\": false,");
|
||||||
|
@ -67,71 +75,84 @@ internal static class UplayR2
|
||||||
string dlcId = pair.Key;
|
string dlcId = pair.Key;
|
||||||
(_, string dlcName, _) = pair.Value;
|
(_, string dlcName, _) = pair.Value;
|
||||||
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
|
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
|
||||||
installForm?.UpdateUser($"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {dlcId} ({dlcName})", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {dlcId} ({dlcName})",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
writer.WriteLine(" ],");
|
writer.WriteLine(" ],");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
writer.WriteLine(" \"blacklist\": [],");
|
writer.WriteLine(" \"blacklist\": [],");
|
||||||
|
}
|
||||||
writer.WriteLine("}");
|
writer.WriteLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||||
{
|
=> await Task.Run(() =>
|
||||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
|
||||||
if (File.Exists(api32_o))
|
|
||||||
{
|
{
|
||||||
string api = File.Exists(old_api32) ? old_api32 : api32;
|
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32,
|
||||||
if (File.Exists(api))
|
out string api32_o, out string api64, out string api64_o, out string config);
|
||||||
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Delete(api);
|
string api = File.Exists(old_api32) ? old_api32 : api32;
|
||||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
if (File.Exists(api))
|
||||||
|
{
|
||||||
|
File.Delete(api);
|
||||||
|
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
File.Move(api32_o, api);
|
||||||
|
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api32_o, api);
|
if (File.Exists(api64_o))
|
||||||
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
if (File.Exists(api64_o))
|
|
||||||
{
|
|
||||||
string api = File.Exists(old_api64) ? old_api64 : api64;
|
|
||||||
if (File.Exists(api))
|
|
||||||
{
|
{
|
||||||
File.Delete(api);
|
string api = File.Exists(old_api64) ? old_api64 : api64;
|
||||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
if (File.Exists(api))
|
||||||
|
{
|
||||||
|
File.Delete(api);
|
||||||
|
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
File.Move(api64_o, api);
|
||||||
|
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
File.Move(api64_o, api);
|
if (deleteConfig && File.Exists(config))
|
||||||
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
{
|
||||||
}
|
File.Delete(config);
|
||||||
if (deleteConfig && File.Exists(config))
|
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
|
||||||
{
|
}
|
||||||
File.Delete(config);
|
});
|
||||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() =>
|
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null,
|
||||||
|
bool generateConfig = true) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32, out string api32_o,
|
||||||
|
out string api64, out string api64_o, out string config);
|
||||||
string api = File.Exists(old_api32) ? old_api32 : api32;
|
string api = File.Exists(old_api32) ? old_api32 : api32;
|
||||||
if (File.Exists(api) && !File.Exists(api32_o))
|
if (File.Exists(api) && !File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
File.Move(api, api32_o);
|
File.Move(api, api32_o);
|
||||||
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api32_o))
|
if (File.Exists(api32_o))
|
||||||
{
|
{
|
||||||
"UplayR2.upc_r2_loader.dll".Write(api);
|
"UplayR2.upc_r2_loader.dll".Write(api);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
api = File.Exists(old_api64) ? old_api64 : api64;
|
api = File.Exists(old_api64) ? old_api64 : api64;
|
||||||
if (File.Exists(api) && !File.Exists(api64_o))
|
if (File.Exists(api) && !File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
File.Move(api, api64_o);
|
File.Move(api, api64_o);
|
||||||
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}",
|
||||||
|
LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (File.Exists(api64_o))
|
if (File.Exists(api64_o))
|
||||||
{
|
{
|
||||||
"UplayR2.upc_r2_loader64.dll".Write(api);
|
"UplayR2.upc_r2_loader64.dll".Write(api);
|
||||||
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
|
||||||
}
|
}
|
||||||
if (generateConfig)
|
if (generateConfig)
|
||||||
CheckConfig(directory, selection, installForm);
|
CheckConfig(directory, selection, installForm);
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
using Microsoft.Win32;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace CreamInstaller.Utility;
|
namespace CreamInstaller.Utility;
|
||||||
|
|
||||||
internal static class Diagnostics
|
internal static class Diagnostics
|
||||||
{
|
{
|
||||||
private static string notepadPlusPlusPath;
|
private static string notepadPlusPlusPath;
|
||||||
|
|
||||||
internal static string NotepadPlusPlusPath
|
internal static string NotepadPlusPlusPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
notepadPlusPlusPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Notepad++", "", null) as string;
|
notepadPlusPlusPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Notepad++", "", null) as string;
|
||||||
notepadPlusPlusPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\Notepad++", "", null) as string;
|
notepadPlusPlusPath
|
||||||
|
??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\Notepad++", "", null) as string;
|
||||||
return notepadPlusPlusPath;
|
return notepadPlusPlusPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,29 +35,18 @@ internal static class Diagnostics
|
||||||
OpenFileInWindowsNotepad(path);
|
OpenFileInWindowsNotepad(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OpenFileInNotepadPlusPlus(string npp, string path) => Process.Start(new ProcessStartInfo
|
private static void OpenFileInNotepadPlusPlus(string npp, string path)
|
||||||
{
|
=> Process.Start(new ProcessStartInfo { FileName = npp, Arguments = path });
|
||||||
FileName = npp,
|
|
||||||
Arguments = path
|
|
||||||
});
|
|
||||||
|
|
||||||
private static void OpenFileInWindowsNotepad(string path) => Process.Start(new ProcessStartInfo
|
private static void OpenFileInWindowsNotepad(string path)
|
||||||
{
|
=> Process.Start(new ProcessStartInfo { FileName = "notepad.exe", Arguments = path });
|
||||||
FileName = "notepad.exe",
|
|
||||||
Arguments = path
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static void OpenDirectoryInFileExplorer(string path) => Process.Start(new ProcessStartInfo
|
internal static void OpenDirectoryInFileExplorer(string path)
|
||||||
{
|
=> Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = path });
|
||||||
FileName = "explorer.exe",
|
|
||||||
Arguments = path
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static void OpenUrlInInternetBrowser(string url) => Process.Start(new ProcessStartInfo
|
internal static void OpenUrlInInternetBrowser(string url)
|
||||||
{
|
=> Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true });
|
||||||
FileName = url,
|
|
||||||
UseShellExecute = true
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static string BeautifyPath(this string path) => path is null ? null : Path.TrimEndingDirectorySeparator(Path.GetFullPath(path));
|
internal static string BeautifyPath(this string path)
|
||||||
|
=> path is null ? null : Path.TrimEndingDirectorySeparator(Path.GetFullPath(path));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller.Utility;
|
namespace CreamInstaller.Utility;
|
||||||
|
|
||||||
internal static class ExceptionHandler
|
internal static class ExceptionHandler
|
||||||
{
|
{
|
||||||
internal static bool HandleException(this Exception e, Form form = null, string caption = null, string acceptButtonText = "Retry", string cancelButtonText = "Cancel")
|
internal static bool HandleException(this Exception e, Form form = null, string caption = null,
|
||||||
|
string acceptButtonText = "Retry", string cancelButtonText = "Cancel")
|
||||||
{
|
{
|
||||||
caption ??= Program.Name + " encountered an exception";
|
caption ??= Program.Name + " encountered an exception";
|
||||||
StringBuilder output = new();
|
StringBuilder output = new();
|
||||||
|
@ -21,35 +23,40 @@ internal static class ExceptionHandler
|
||||||
string[] stackTrace = e.StackTrace?.Split('\n');
|
string[] stackTrace = e.StackTrace?.Split('\n');
|
||||||
if (stackTrace is not null && stackTrace.Length > 0)
|
if (stackTrace is not null && stackTrace.Length > 0)
|
||||||
{
|
{
|
||||||
_ = output.Append(e.GetType() + (e.Message is not null ? (": " + e.Message) : ""));
|
_ = output.Append(e.GetType() + (": " + e.Message));
|
||||||
for (int i = 0; i < stackTrace.Length; i++)
|
for (int i = 0; i < stackTrace.Length; i++)
|
||||||
{
|
{
|
||||||
string line = stackTrace[i];
|
string line = stackTrace[i];
|
||||||
int atNum = line.IndexOf("at ");
|
int atNum = line.IndexOf("at ", StringComparison.Ordinal);
|
||||||
int inNum = line.IndexOf("in ");
|
int inNum = line.IndexOf("in ", StringComparison.Ordinal);
|
||||||
int ciNum = line.LastIndexOf(@"CreamInstaller\");
|
int ciNum = line.LastIndexOf(@"CreamInstaller\", StringComparison.Ordinal);
|
||||||
int lineNum = line.LastIndexOf(":line ");
|
int lineNum = line.LastIndexOf(":line ", StringComparison.Ordinal);
|
||||||
if (line is not null && atNum != -1)
|
if (atNum != -1)
|
||||||
_ = output.Append("\n " + (inNum != -1 ? line[atNum..(inNum - 1)] : line[atNum..])
|
_ = output.Append("\n " + (inNum != -1 ? line[atNum..(inNum - 1)] : line[atNum..])
|
||||||
+ (inNum != -1 ? ("\n "
|
+ (inNum != -1
|
||||||
+ (ciNum != -1 ? ("in "
|
? "\n "
|
||||||
+ (lineNum != -1 ? line[ciNum..lineNum]
|
+ (ciNum != -1
|
||||||
+ "\n on " + line[(lineNum + 1)..]
|
? "in "
|
||||||
: line[ciNum..]))
|
+ (lineNum != -1
|
||||||
: line[inNum..]))
|
? line[ciNum..lineNum]
|
||||||
: null));
|
+ "\n on " + line[(lineNum + 1)..]
|
||||||
|
: line[ciNum..])
|
||||||
|
: line[inNum..])
|
||||||
|
: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e = e.InnerException;
|
e = e.InnerException;
|
||||||
stackDepth++;
|
stackDepth++;
|
||||||
}
|
}
|
||||||
using DialogForm dialogForm = new(form ?? Form.ActiveForm);
|
using DialogForm dialogForm = new(form ?? Form.ActiveForm);
|
||||||
return dialogForm.Show(SystemIcons.Error, output.ToString(), acceptButtonText, cancelButtonText, customFormText: caption) == DialogResult.OK;
|
return dialogForm.Show(SystemIcons.Error, output.ToString(), acceptButtonText, cancelButtonText, caption)
|
||||||
|
== DialogResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void HandleFatalException(this Exception e)
|
internal static void HandleFatalException(this Exception e)
|
||||||
{
|
{
|
||||||
bool? restart = e?.HandleException(caption: Program.Name + " encountered a fatal exception", acceptButtonText: "Restart");
|
bool? restart = e?.HandleException(caption: Program.Name + " encountered a fatal exception",
|
||||||
|
acceptButtonText: "Restart");
|
||||||
if (restart.HasValue && restart.Value)
|
if (restart.HasValue && restart.Value)
|
||||||
Application.Restart();
|
Application.Restart();
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
|
@ -58,14 +65,12 @@ internal static class ExceptionHandler
|
||||||
|
|
||||||
public class CustomMessageException : Exception
|
public class CustomMessageException : Exception
|
||||||
{
|
{
|
||||||
private readonly string message;
|
public CustomMessageException() => Message = "CustomMessageException";
|
||||||
public override string Message => message;
|
|
||||||
|
public CustomMessageException(string message) : base(message) => Message = message;
|
||||||
|
|
||||||
|
public CustomMessageException(string message, Exception e) : base(message, e) => Message = message;
|
||||||
|
public override string Message { get; }
|
||||||
|
|
||||||
public override string ToString() => Message;
|
public override string ToString() => Message;
|
||||||
|
|
||||||
public CustomMessageException() : base() => message = "CustomMessageException";
|
|
||||||
|
|
||||||
public CustomMessageException(string message) : base(message) => this.message = message;
|
|
||||||
|
|
||||||
public CustomMessageException(string message, Exception e) : base(message, e) => this.message = message;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
using HtmlAgilityPack;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using HtmlAgilityPack;
|
||||||
|
|
||||||
namespace CreamInstaller.Utility;
|
namespace CreamInstaller.Utility;
|
||||||
|
|
||||||
internal static class HttpClientManager
|
internal static class HttpClientManager
|
||||||
{
|
{
|
||||||
internal static HttpClient HttpClient;
|
internal static HttpClient HttpClient;
|
||||||
|
|
||||||
internal static void Setup()
|
internal static void Setup()
|
||||||
{
|
{
|
||||||
HttpClient = new();
|
HttpClient = new HttpClient();
|
||||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Program.Version.Replace(".", "")}");
|
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Program.Version.Replace(".", "")}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ internal static class HttpClientManager
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
||||||
using HttpResponseMessage response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
using HttpResponseMessage response
|
||||||
|
= await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
_ = response.EnsureSuccessStatusCode();
|
_ = response.EnsureSuccessStatusCode();
|
||||||
return await response.Content.ReadAsStringAsync();
|
return await response.Content.ReadAsStringAsync();
|
||||||
}
|
}
|
||||||
|
@ -31,16 +32,18 @@ internal static class HttpClientManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static HtmlAgilityPack.HtmlDocument ToHtmlDocument(this string html)
|
internal static HtmlDocument ToHtmlDocument(this string html)
|
||||||
{
|
{
|
||||||
HtmlAgilityPack.HtmlDocument document = new();
|
HtmlDocument document = new();
|
||||||
document.LoadHtml(html);
|
document.LoadHtml(html);
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath) => (await EnsureGet(url))?.ToHtmlDocument()?.DocumentNode?.SelectNodes(xpath);
|
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath)
|
||||||
|
=> (await EnsureGet(url))?.ToHtmlDocument()?.DocumentNode?.SelectNodes(xpath);
|
||||||
|
|
||||||
internal static HtmlNodeCollection GetDocumentNodes(this HtmlAgilityPack.HtmlDocument htmlDocument, string xpath) => htmlDocument.DocumentNode?.SelectNodes(xpath);
|
internal static HtmlNodeCollection GetDocumentNodes(this HtmlDocument htmlDocument, string xpath)
|
||||||
|
=> htmlDocument.DocumentNode?.SelectNodes(xpath);
|
||||||
|
|
||||||
internal static async Task<Image> GetImageFromUrl(string url)
|
internal static async Task<Image> GetImageFromUrl(string url)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,17 +12,21 @@ internal static class IconGrabber
|
||||||
return Icon.FromHandle(dialogIconBitmap.GetHicon());
|
return Icon.FromHandle(dialogIconBitmap.GetHicon());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal const string SteamAppImagesPath = "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/";
|
internal const string SteamAppImagesPath
|
||||||
|
= "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/";
|
||||||
|
|
||||||
internal const string GoogleFaviconsApiUrl = "https://www.google.com/s2/favicons";
|
internal const string GoogleFaviconsApiUrl = "https://www.google.com/s2/favicons";
|
||||||
|
|
||||||
internal static string GetDomainFaviconUrl(string domain, int size = 16) => GoogleFaviconsApiUrl + $"?domain={domain}&sz={size}";
|
internal static string GetDomainFaviconUrl(string domain, int size = 16)
|
||||||
|
=> GoogleFaviconsApiUrl + $"?domain={domain}&sz={size}";
|
||||||
|
|
||||||
internal static Image GetFileIconImage(this string path) => File.Exists(path) ? Icon.ExtractAssociatedIcon(path)?.ToBitmap() : null;
|
internal static Image GetFileIconImage(this string path)
|
||||||
|
=> File.Exists(path) ? Icon.ExtractAssociatedIcon(path)?.ToBitmap() : null;
|
||||||
|
|
||||||
internal static Image GetNotepadImage() => GetFileIconImage(Diagnostics.GetNotepadPath());
|
internal static Image GetNotepadImage() => GetFileIconImage(Diagnostics.GetNotepadPath());
|
||||||
|
|
||||||
internal static Image GetCommandPromptImage() => GetFileIconImage(Environment.SystemDirectory + @"\cmd.exe");
|
internal static Image GetCommandPromptImage() => GetFileIconImage(Environment.SystemDirectory + @"\cmd.exe");
|
||||||
|
|
||||||
internal static Image GetFileExplorerImage() => GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\explorer.exe");
|
internal static Image GetFileExplorerImage()
|
||||||
|
=> GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\explorer.exe");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
using Newtonsoft.Json;
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CreamInstaller.Utility;
|
namespace CreamInstaller.Utility;
|
||||||
|
|
||||||
internal static class ProgramData
|
internal static class ProgramData
|
||||||
{
|
{
|
||||||
internal static readonly string DirectoryPathOld = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CreamInstaller";
|
internal static readonly string DirectoryPathOld
|
||||||
internal static readonly string DirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
|
= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CreamInstaller";
|
||||||
|
|
||||||
|
internal static readonly string DirectoryPath
|
||||||
|
= Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
|
||||||
|
|
||||||
internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo";
|
internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo";
|
||||||
internal static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
|
internal static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
|
||||||
|
@ -34,7 +37,9 @@ internal static class ProgramData
|
||||||
Directory.Move(DirectoryPathOld, DirectoryPath);
|
Directory.Move(DirectoryPathOld, DirectoryPath);
|
||||||
}
|
}
|
||||||
if (!Directory.Exists(DirectoryPath)) _ = Directory.CreateDirectory(DirectoryPath);
|
if (!Directory.Exists(DirectoryPath)) _ = Directory.CreateDirectory(DirectoryPath);
|
||||||
if (!File.Exists(AppInfoVersionPath) || !Version.TryParse(File.ReadAllText(AppInfoVersionPath, Encoding.UTF8), out Version version) || version < MinimumAppInfoVersion)
|
if (!File.Exists(AppInfoVersionPath)
|
||||||
|
|| !Version.TryParse(File.ReadAllText(AppInfoVersionPath, Encoding.UTF8), out Version version)
|
||||||
|
|| version < MinimumAppInfoVersion)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(AppInfoPath)) Directory.Delete(AppInfoPath, true);
|
if (Directory.Exists(AppInfoPath)) Directory.Delete(AppInfoPath, true);
|
||||||
_ = Directory.CreateDirectory(AppInfoPath);
|
_ = Directory.CreateDirectory(AppInfoPath);
|
||||||
|
@ -55,23 +60,23 @@ internal static class ProgramData
|
||||||
SetCooldown(identifier, now);
|
SetCooldown(identifier, now);
|
||||||
return cooldownOver;
|
return cooldownOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DateTime? GetCooldown(string identifier)
|
private static DateTime? GetCooldown(string identifier)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(CooldownPath))
|
if (Directory.Exists(CooldownPath))
|
||||||
{
|
{
|
||||||
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
||||||
if (File.Exists(cooldownFile))
|
if (File.Exists(cooldownFile))
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (DateTime.TryParse(File.ReadAllText(cooldownFile), out DateTime cooldown))
|
if (DateTime.TryParse(File.ReadAllText(cooldownFile), out DateTime cooldown))
|
||||||
return cooldown;
|
return cooldown;
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetCooldown(string identifier, DateTime time)
|
private static void SetCooldown(string identifier, DateTime time)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(CooldownPath))
|
if (!Directory.Exists(CooldownPath))
|
||||||
|
@ -79,7 +84,7 @@ internal static class ProgramData
|
||||||
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File.WriteAllText(cooldownFile, time.ToString());
|
File.WriteAllText(cooldownFile, time.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
@ -90,13 +95,15 @@ internal static class ProgramData
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject(File.ReadAllText(ProgramChoicesPath),
|
return JsonConvert.DeserializeObject(File.ReadAllText(ProgramChoicesPath),
|
||||||
typeof(List<(Platform platform, string id)>)) as List<(Platform platform, string id)>;
|
typeof(List<(Platform platform, string id)>)) as
|
||||||
|
List<(Platform platform, string id)>;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return new();
|
return new List<(Platform platform, string id)>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteProgramChoices(List<(Platform platform, string id)> choices)
|
internal static void WriteProgramChoices(List<(Platform platform, string id)> choices)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -115,13 +122,15 @@ internal static class ProgramData
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject(File.ReadAllText(DlcChoicesPath),
|
return JsonConvert.DeserializeObject(File.ReadAllText(DlcChoicesPath),
|
||||||
typeof(List<(Platform platform, string gameId, string dlcId)>)) as List<(Platform platform, string gameId, string dlcId)>;
|
typeof(List<(Platform platform, string gameId, string dlcId)>)) as
|
||||||
|
List<(Platform platform, string gameId, string dlcId)>;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return new();
|
return new List<(Platform platform, string gameId, string dlcId)>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteDlcChoices(List<(Platform platform, string gameId, string dlcId)> choices)
|
internal static void WriteDlcChoices(List<(Platform platform, string gameId, string dlcId)> choices)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -140,15 +149,18 @@ internal static class ProgramData
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject(File.ReadAllText(KoaloaderProxyChoicesPath),
|
return JsonConvert.DeserializeObject(File.ReadAllText(KoaloaderProxyChoicesPath),
|
||||||
typeof(List<(Platform platform, string id, string proxy, bool enabled)>)) as List<(Platform platform, string id, string proxy, bool enabled)>;
|
typeof(
|
||||||
|
List<(Platform platform, string id, string proxy, bool enabled)>))
|
||||||
|
as List<(Platform platform, string id, string proxy, bool enabled)>;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return new();
|
return new List<(Platform platform, string id, string proxy, bool enabled)>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteKoaloaderProxyChoices(List<(Platform platform, string id, string proxy, bool enabled)> choices)
|
internal static void WriteKoaloaderProxyChoices(
|
||||||
|
List<(Platform platform, string id, string proxy, bool enabled)> choices)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue