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 CreamInstaller.Utility;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Platforms.Paradox;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Components;
|
||||
|
||||
|
@ -14,64 +13,79 @@ internal class ContextMenuItem : ToolStripMenuItem
|
|||
{
|
||||
private static readonly ConcurrentDictionary<string, Image> images = new();
|
||||
|
||||
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
|
||||
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run(
|
||||
async () =>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
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 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
|
||||
{
|
||||
image = await HttpClientManager.GetImageFromUrl(iconUrl);
|
||||
|
@ -81,11 +95,14 @@ internal class ContextMenuItem : ToolStripMenuItem
|
|||
item.Image = image;
|
||||
}
|
||||
else if (onFail is not null)
|
||||
{
|
||||
onFail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
private readonly EventHandler OnClickEvent;
|
||||
|
||||
protected override void OnClick(EventArgs e)
|
||||
{
|
||||
base.OnClick(e);
|
||||
|
@ -105,9 +122,15 @@ internal class ContextMenuItem : ToolStripMenuItem
|
|||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, EventHandler onClick = null)
|
||||
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo);
|
||||
|
||||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, 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 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)
|
||||
: this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, async () => await TryImageIdentifierInfo(this, imageIdentifierInfoFallback));
|
||||
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo,
|
||||
(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.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Forms;
|
||||
|
||||
namespace CreamInstaller.Components;
|
||||
|
||||
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;
|
||||
KeyPreview = true;
|
||||
|
@ -19,47 +28,6 @@ internal class CustomForm : Form
|
|||
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()
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (fromForm is null)
|
||||
return;
|
||||
int X = fromForm.Location.X + fromForm.Size.Width / 2 - Size.Width / 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)
|
||||
|
@ -124,7 +127,8 @@ internal class CustomForm : Form
|
|||
using EncoderParameters encoding = new(1);
|
||||
using EncoderParameter encoderParam = new(Encoder.Quality, 100L);
|
||||
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);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,35 @@
|
|||
using CreamInstaller.Resources;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Resources;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
using TreeView = System.Windows.Forms.TreeView;
|
||||
|
||||
namespace CreamInstaller.Components;
|
||||
|
||||
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 Font comboBoxFont;
|
||||
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)
|
||||
{
|
||||
|
@ -30,14 +40,6 @@ internal class CustomTreeView : TreeView
|
|||
form = FindForm();
|
||||
}
|
||||
|
||||
internal CustomTreeView() : base()
|
||||
{
|
||||
DrawMode = TreeViewDrawMode.OwnerDrawText;
|
||||
DrawNode += new DrawTreeNodeEventHandler(DrawTreeNode);
|
||||
TreeViewNodeSorter = PlatformIdComparer.NodeName;
|
||||
Disposed += OnDisposed;
|
||||
}
|
||||
|
||||
private void OnDisposed(object sender, EventArgs e)
|
||||
{
|
||||
backBrush?.Dispose();
|
||||
|
@ -48,72 +50,68 @@ internal class CustomTreeView : TreeView
|
|||
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)
|
||||
{
|
||||
e.DrawDefault = true;
|
||||
TreeNode node = e.Node;
|
||||
if (!node.IsVisible)
|
||||
return;
|
||||
|
||||
bool highlighted = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected && Focused;
|
||||
|
||||
Graphics graphics = e.Graphics;
|
||||
backBrush ??= new(BackColor);
|
||||
backBrush ??= new SolidBrush(BackColor);
|
||||
Font font = node.NodeFont ?? Font;
|
||||
|
||||
Brush brush = highlighted ? SystemBrushes.Highlight : backBrush;
|
||||
string text;// = e.Node.Text;
|
||||
string text; // = e.Node.Text;
|
||||
Size size;
|
||||
Rectangle bounds = node.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;
|
||||
|
||||
/*Size textSize = TextRenderer.MeasureText(text, font);
|
||||
Point textLoc = new(bounds.X - 1, bounds.Y);
|
||||
bounds = new Rectangle(textLoc, new Size(textSize.Width, bounds.Height));
|
||||
graphics.FillRectangle(brush, bounds);
|
||||
TextRenderer.DrawText(graphics, text, font, bounds, color, TextFormatFlags.Default);*/
|
||||
|
||||
Form form = FindForm();
|
||||
if (form is not SelectForm and not SelectDialogForm)
|
||||
return;
|
||||
|
||||
string platformId = node.Name;
|
||||
Platform platform = (node.Tag as Platform?).GetValueOrDefault(Platform.None);
|
||||
if (string.IsNullOrWhiteSpace(platformId) || platform is Platform.None)
|
||||
return;
|
||||
|
||||
color = highlighted ? ColorTranslator.FromHtml("#FFFF99") : Enabled ? ColorTranslator.FromHtml("#696900") : ColorTranslator.FromHtml("#AAAA69");
|
||||
color = highlighted
|
||||
? ColorTranslator.FromHtml("#FFFF99")
|
||||
: Enabled
|
||||
? ColorTranslator.FromHtml("#696900")
|
||||
: ColorTranslator.FromHtml("#AAAA69");
|
||||
text = platform.ToString();
|
||||
size = TextRenderer.MeasureText(graphics, text, font);
|
||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds
|
||||
= new Rectangle(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
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);
|
||||
|
||||
if (platform is not Platform.Paradox)
|
||||
{
|
||||
color = highlighted ? ColorTranslator.FromHtml("#99FFFF") : Enabled ? ColorTranslator.FromHtml("#006969") : ColorTranslator.FromHtml("#69AAAA");
|
||||
text = platformId.ToString();
|
||||
color = highlighted
|
||||
? ColorTranslator.FromHtml("#99FFFF")
|
||||
: Enabled
|
||||
? ColorTranslator.FromHtml("#006969")
|
||||
: ColorTranslator.FromHtml("#69AAAA");
|
||||
text = platformId;
|
||||
size = TextRenderer.MeasureText(graphics, text, font);
|
||||
int left = -4;
|
||||
bounds = new(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
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);
|
||||
}
|
||||
|
||||
/*if (highlighted)
|
||||
ControlPaint.DrawFocusRectangle(graphics, selectionBounds, color, SystemColors.Highlight);*/
|
||||
|
||||
if (form is SelectForm)
|
||||
{
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, platformId);
|
||||
|
@ -121,64 +119,71 @@ internal class CustomTreeView : TreeView
|
|||
{
|
||||
if (bounds == node.Bounds)
|
||||
{
|
||||
size = new(4, 0);
|
||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
size = new Size(4, 0);
|
||||
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
graphics.FillRectangle(brush, bounds);
|
||||
}
|
||||
|
||||
CheckBoxState checkBoxState = selection.Koaloader
|
||||
? Enabled ? CheckBoxState.CheckedPressed : CheckBoxState.CheckedDisabled
|
||||
: Enabled ? CheckBoxState.UncheckedPressed : CheckBoxState.UncheckedDisabled;
|
||||
: Enabled
|
||||
? CheckBoxState.UncheckedPressed
|
||||
: CheckBoxState.UncheckedDisabled;
|
||||
size = CheckBoxRenderer.GetGlyphSize(graphics, checkBoxState);
|
||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||
selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
Rectangle checkBoxBounds = 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);
|
||||
|
||||
text = koaloaderToggleString;
|
||||
size = TextRenderer.MeasureText(graphics, text, font);
|
||||
int left = 1;
|
||||
bounds = new(bounds.X + bounds.Width, bounds.Y, size.Width + left, bounds.Height);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
checkBoxBounds = new(checkBoxBounds.Location, checkBoxBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y, size.Width + left, bounds.Height);
|
||||
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||
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);
|
||||
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,
|
||||
Enabled ? ColorTranslator.FromHtml("#006900") : ColorTranslator.FromHtml("#69AA69"),
|
||||
TextFormatFlags.Default);
|
||||
|
||||
Enabled
|
||||
? ColorTranslator.FromHtml("#006900")
|
||||
: ColorTranslator.FromHtml("#69AA69"),
|
||||
TextFormatFlags.Default);
|
||||
this.checkBoxBounds[selection] = RectangleToClient(checkBoxBounds);
|
||||
|
||||
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
||||
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;
|
||||
|
||||
text = proxy + ".dll";
|
||||
size = TextRenderer.MeasureText(graphics, text, comboBoxFont) + new Size(6, 0);
|
||||
int padding = 2;
|
||||
bounds = new(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width, bounds.Height - padding);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width,
|
||||
bounds.Height - padding);
|
||||
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||
selectionBounds.Size + new Size(bounds.Size.Width, 0));
|
||||
Rectangle comboBoxBounds = bounds;
|
||||
graphics.FillRectangle(backBrush, bounds);
|
||||
ComboBoxRenderer.DrawTextBox(graphics, bounds, text, comboBoxFont, comboBoxState);
|
||||
|
||||
size = new(14, 0);
|
||||
size = new Size(14, 0);
|
||||
left = -1;
|
||||
bounds = new(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
comboBoxBounds = new(comboBoxBounds.Location, comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
|
||||
bounds = new Rectangle(bounds.X + bounds.Width + left, bounds.Y, size.Width, bounds.Height);
|
||||
selectionBounds = new Rectangle(selectionBounds.Location,
|
||||
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);
|
||||
|
||||
this.comboBoxBounds[selection] = RectangleToClient(comboBoxBounds);
|
||||
}
|
||||
else _ = comboBoxBounds.Remove(selection);
|
||||
else
|
||||
{
|
||||
_ = comboBoxBounds.Remove(selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.selectionBounds[node] = RectangleToClient(selectionBounds);
|
||||
}
|
||||
|
||||
|
@ -189,9 +194,10 @@ internal class CustomTreeView : TreeView
|
|||
Point clickPoint = PointToClient(e.Location);
|
||||
SelectForm selectForm = (form ??= FindForm()) as SelectForm;
|
||||
foreach (KeyValuePair<TreeNode, Rectangle> pair in selectionBounds.ToList())
|
||||
{
|
||||
if (pair.Key.TreeView is null)
|
||||
{
|
||||
_ = selectionBounds.Remove(pair.Key);
|
||||
}
|
||||
else if (pair.Key.IsVisible && pair.Value.Contains(clickPoint))
|
||||
{
|
||||
SelectedNode = pair.Key;
|
||||
|
@ -199,23 +205,24 @@ internal class CustomTreeView : TreeView
|
|||
selectForm.OnNodeRightClick(pair.Key, e.Location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (e.Button is MouseButtons.Left)
|
||||
{
|
||||
if (comboBoxBounds.Any() && selectForm is not null)
|
||||
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in comboBoxBounds.ToList())
|
||||
{
|
||||
if (!ProgramSelection.All.Contains(pair.Key))
|
||||
{
|
||||
_ = comboBoxBounds.Remove(pair.Key);
|
||||
}
|
||||
else if (pair.Value.Contains(clickPoint))
|
||||
{
|
||||
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))
|
||||
.Select(p =>
|
||||
{
|
||||
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
|
||||
return proxyName;
|
||||
}).Distinct().ToList();
|
||||
comboBoxDropDown ??= new();
|
||||
.Select(p =>
|
||||
{
|
||||
p.GetProxyInfoFromIdentifier(
|
||||
out string proxyName, out _);
|
||||
return proxyName;
|
||||
}).Distinct().ToList();
|
||||
comboBoxDropDown ??= new ToolStripDropDown();
|
||||
comboBoxDropDown.ShowItemToolTips = false;
|
||||
comboBoxDropDown.Items.Clear();
|
||||
foreach (string proxy in proxies)
|
||||
|
@ -233,26 +240,25 @@ internal class CustomTreeView : TreeView
|
|||
if (canUse)
|
||||
_ = 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();
|
||||
})
|
||||
{ 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;
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in checkBoxBounds.ToList())
|
||||
{
|
||||
if (!ProgramSelection.All.Contains(pair.Key))
|
||||
{
|
||||
_ = checkBoxBounds.Remove(pair.Key);
|
||||
}
|
||||
else if (pair.Value.Contains(clickPoint))
|
||||
{
|
||||
pair.Key.Koaloader = !pair.Key.Koaloader;
|
||||
selectForm.OnKoaloaderChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,45 +8,68 @@ namespace CreamInstaller.Components;
|
|||
internal static class PlatformIdComparer
|
||||
{
|
||||
private static StringComparer stringComparer;
|
||||
internal static StringComparer String => stringComparer ??= new();
|
||||
internal static StringComparer String => stringComparer ??= new StringComparer();
|
||||
|
||||
private static NodeComparer nodeComparer;
|
||||
internal static NodeComparer Node => nodeComparer ??= new();
|
||||
internal static NodeComparer Node => nodeComparer ??= new NodeComparer();
|
||||
|
||||
private static NodeNameComparer nodeNameComparer;
|
||||
internal static NodeNameComparer NodeName => nodeNameComparer ??= new();
|
||||
internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer();
|
||||
|
||||
private static NodeTextComparer nodeTextComparer;
|
||||
internal static NodeTextComparer NodeText => nodeTextComparer ??= new();
|
||||
internal static NodeTextComparer NodeText => nodeTextComparer ??= new NodeTextComparer();
|
||||
}
|
||||
|
||||
internal class StringComparer : IComparer<string>
|
||||
{
|
||||
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 A) ? 1 : !int.TryParse(b, out int B) ? -1
|
||||
: A > B ? 1 : A < B ? -1 : 0;
|
||||
!int.TryParse(a, out _) && !int.TryParse(b, out _)
|
||||
? string.Compare(a, b, StringComparison.Ordinal)
|
||||
: !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>
|
||||
{
|
||||
public int Compare(TreeNode a, TreeNode b) =>
|
||||
a.Tag is not Platform A ? 1 : b.Tag is not Platform B ? -1
|
||||
: A > B ? 1 : A < B ? -1 : 0;
|
||||
a.Tag is not Platform A
|
||||
? 1
|
||||
: b.Tag is not Platform B
|
||||
? -1
|
||||
: A > B
|
||||
? 1
|
||||
: A < B
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
|
||||
internal class NodeNameComparer : IComparer
|
||||
{
|
||||
public int Compare(object a, object b) =>
|
||||
a is not TreeNode A ? 1 : b is not TreeNode B ? -1
|
||||
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0 ? c
|
||||
: PlatformIdComparer.String.Compare(A.Name, B.Name);
|
||||
a is not TreeNode A
|
||||
? 1
|
||||
: 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
|
||||
{
|
||||
public int Compare(object a, object b) =>
|
||||
a is not TreeNode A ? 1 : b is not TreeNode B ? -1
|
||||
: PlatformIdComparer.Node.Compare(A, B) is int c && c != 0 ? c
|
||||
: PlatformIdComparer.String.Compare(A.Text, B.Text);
|
||||
a is not TreeNode A
|
||||
? 1
|
||||
: 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">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows10.0.22621.0</TargetFramework>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<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>
|
||||
<Company>CreamInstaller</Company>
|
||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||
<StartupObject>CreamInstaller.Program</StartupObject>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<AnalysisLevel>latest-all</AnalysisLevel>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
|
@ -27,6 +26,12 @@
|
|||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<AssemblyName>$(Company)-debug</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Koaloader\audioses-32\audioses.dll" />
|
||||
<None Remove="Resources\Koaloader\audioses-64\audioses.dll" />
|
||||
|
@ -137,10 +142,10 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.45" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Onova" Version="2.6.2" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="6.0.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Onova" Version="2.6.3" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="7.0.0" />
|
||||
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.0" />
|
||||
</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
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
private IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
|
@ -65,5 +68,5 @@ partial class DebugForm
|
|||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.RichTextBox debugTextBox;
|
||||
private RichTextBox debugTextBox;
|
||||
}
|
|
@ -1,32 +1,34 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller;
|
||||
namespace CreamInstaller.Forms;
|
||||
|
||||
internal partial class DebugForm : CustomForm
|
||||
{
|
||||
internal static DebugForm current;
|
||||
|
||||
private Form attachedForm;
|
||||
|
||||
internal DebugForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
debugTextBox.BackColor = LogTextBox.Background;
|
||||
}
|
||||
|
||||
internal static DebugForm Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (current is not null && (current.Disposing || current.IsDisposed))
|
||||
current = null;
|
||||
return current ??= new();
|
||||
return current ??= new DebugForm();
|
||||
}
|
||||
set => current = value;
|
||||
}
|
||||
|
||||
internal DebugForm() : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
debugTextBox.BackColor = LogTextBox.Background;
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message message) // make form immovable by user
|
||||
{
|
||||
if (message.Msg == 0x0112) // WM_SYSCOMMAND
|
||||
|
@ -38,8 +40,6 @@ internal partial class DebugForm : CustomForm
|
|||
base.WndProc(ref message);
|
||||
}
|
||||
|
||||
private Form attachedForm;
|
||||
|
||||
internal void Attach(Form form)
|
||||
{
|
||||
if (attachedForm is not null)
|
||||
|
@ -64,7 +64,7 @@ internal partial class DebugForm : CustomForm
|
|||
if (attachedForm is not null && attachedForm.Visible)
|
||||
{
|
||||
//Size = new(Size.Width, attachedForm.Size.Height);
|
||||
Location = new(attachedForm.Right, attachedForm.Top);
|
||||
Location = new Point(attachedForm.Right, attachedForm.Top);
|
||||
BringToFrontWithoutActivation();
|
||||
}
|
||||
}
|
||||
|
@ -74,13 +74,11 @@ internal partial class DebugForm : CustomForm
|
|||
internal void Log(string text, Color color)
|
||||
{
|
||||
if (!debugTextBox.Disposing && !debugTextBox.IsDisposed)
|
||||
{
|
||||
debugTextBox.Invoke(() =>
|
||||
{
|
||||
if (debugTextBox.Text.Length > 0)
|
||||
debugTextBox.AppendText(Environment.NewLine, color, scroll: true);
|
||||
debugTextBox.AppendText(text, color, scroll: true);
|
||||
debugTextBox.AppendText(Environment.NewLine, color, 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;
|
||||
|
||||
namespace CreamInstaller
|
||||
namespace CreamInstaller.Forms
|
||||
{
|
||||
partial class DialogForm
|
||||
{
|
||||
|
|
|
@ -1,31 +1,30 @@
|
|||
using CreamInstaller.Components;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Components;
|
||||
|
||||
namespace CreamInstaller;
|
||||
namespace CreamInstaller.Forms;
|
||||
|
||||
internal partial class DialogForm : CustomForm
|
||||
{
|
||||
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;
|
||||
icon.Image = descriptionIcon.ToBitmap();
|
||||
List<LinkLabel.Link> links = new();
|
||||
for (int i = 0; i < descriptionText.Length; i++)
|
||||
{
|
||||
if (descriptionText[i] == '[')
|
||||
{
|
||||
int textLeft = descriptionText.IndexOf("[", i);
|
||||
int textRight = descriptionText.IndexOf("]", textLeft == -1 ? i : textLeft);
|
||||
int linkLeft = descriptionText.IndexOf("(", textRight == -1 ? i : textRight);
|
||||
int linkRight = descriptionText.IndexOf(")", linkLeft == -1 ? i : linkLeft);
|
||||
int textLeft = descriptionText.IndexOf("[", i, StringComparison.Ordinal);
|
||||
int textRight = descriptionText.IndexOf("]", textLeft == -1 ? i : textLeft, StringComparison.Ordinal);
|
||||
int linkLeft = descriptionText.IndexOf("(", textRight == -1 ? i : textRight, StringComparison.Ordinal);
|
||||
int linkRight = descriptionText.IndexOf(")", linkLeft == -1 ? i : linkLeft, StringComparison.Ordinal);
|
||||
if (textLeft != -1 && textRight == linkLeft - 1 && linkRight != -1)
|
||||
{
|
||||
string text = descriptionText[(textLeft + 1)..textRight];
|
||||
|
@ -36,7 +35,6 @@ internal partial class DialogForm : CustomForm
|
|||
links.Add(new LinkLabel.Link(i, text.Length, link));
|
||||
}
|
||||
}
|
||||
}
|
||||
descriptionLabel.Text = descriptionText;
|
||||
acceptButton.Text = acceptButtonText;
|
||||
if (cancelButtonText is null)
|
||||
|
@ -44,9 +42,14 @@ internal partial class DialogForm : CustomForm
|
|||
cancelButton.Enabled = false;
|
||||
cancelButton.Visible = false;
|
||||
}
|
||||
else cancelButton.Text = cancelButtonText;
|
||||
else
|
||||
{
|
||||
cancelButton.Text = cancelButtonText;
|
||||
}
|
||||
if (customFormText is not null)
|
||||
{
|
||||
Text = customFormText;
|
||||
}
|
||||
else
|
||||
{
|
||||
OnResize(null, null);
|
||||
|
@ -58,7 +61,8 @@ internal partial class DialogForm : CustomForm
|
|||
{
|
||||
foreach (LinkLabel.Link link in links)
|
||||
_ = 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();
|
||||
}
|
||||
|
@ -66,7 +70,7 @@ internal partial class DialogForm : CustomForm
|
|||
private void OnResize(object s, EventArgs e) =>
|
||||
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
||||
? TextRenderer.MeasureText(Program.ApplicationNameShort, Font).Width > Size.Width - 100
|
||||
? Program.Name
|
||||
: Program.ApplicationNameShort
|
||||
? Program.Name
|
||||
: Program.ApplicationNameShort
|
||||
: 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;
|
||||
|
||||
namespace CreamInstaller
|
||||
namespace CreamInstaller.Forms
|
||||
{
|
||||
partial class InstallForm
|
||||
{
|
||||
|
|
|
@ -1,26 +1,30 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
using static CreamInstaller.Platforms.Paradox.ParadoxLauncher;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller;
|
||||
namespace CreamInstaller.Forms;
|
||||
|
||||
internal partial class InstallForm : CustomForm
|
||||
{
|
||||
internal bool Reselecting;
|
||||
internal readonly bool Uninstalling;
|
||||
private readonly List<ProgramSelection> DisabledSelections = new();
|
||||
|
||||
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();
|
||||
Text = Program.ApplicationName;
|
||||
|
@ -28,9 +32,6 @@ internal partial class InstallForm : CustomForm
|
|||
Uninstalling = uninstall;
|
||||
}
|
||||
|
||||
private int OperationsCount;
|
||||
private int CompleteOperationsCount;
|
||||
|
||||
internal void UpdateProgress(int progress)
|
||||
{
|
||||
if (!userProgressBar.Disposing && !userProgressBar.IsDisposed)
|
||||
|
@ -46,14 +47,12 @@ internal partial class InstallForm : CustomForm
|
|||
{
|
||||
if (info) _ = userInfoLabel.Invoke(() => userInfoLabel.Text = text);
|
||||
if (log && !logTextBox.Disposing && !logTextBox.IsDisposed)
|
||||
{
|
||||
logTextBox.Invoke(() =>
|
||||
{
|
||||
if (logTextBox.Text.Length > 0) logTextBox.AppendText(Environment.NewLine, color);
|
||||
logTextBox.AppendText(text, color);
|
||||
logTextBox.Invalidate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OperateFor(ProgramSelection selection)
|
||||
|
@ -61,14 +60,16 @@ internal partial class InstallForm : CustomForm
|
|||
UpdateProgress(0);
|
||||
if (selection.Id == "PL")
|
||||
{
|
||||
UpdateUser($"Repairing Paradox Launcher . . . ", LogTextBox.Operation);
|
||||
UpdateUser("Repairing Paradox Launcher . . . ", LogTextBox.Operation);
|
||||
_ = await Repair(this, selection);
|
||||
}
|
||||
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())
|
||||
?.Where(d => !selection.ExecutableDirectories.Any(s => s.directory == Path.GetDirectoryName(d.path)))
|
||||
?.Select(d => Path.GetDirectoryName(d.path));
|
||||
?.Where(d => !selection.ExecutableDirectories.Any(
|
||||
s => s.directory == Path.GetDirectoryName(d.path)))
|
||||
?.Select(d => Path.GetDirectoryName(d.path));
|
||||
if (!selection.ExecutableDirectories.Any(s => s.directory == selection.RootDirectory))
|
||||
invalidDirectories = invalidDirectories?.Append(selection.RootDirectory);
|
||||
invalidDirectories = invalidDirectories?.Distinct();
|
||||
|
@ -78,30 +79,33 @@ internal partial class InstallForm : CustomForm
|
|||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
||||
|| directory != selection.RootDirectory && Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
||||
|| File.Exists(config))
|
||||
|| (directory != selection.RootDirectory
|
||||
&& Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll)))
|
||||
|| File.Exists(config))
|
||||
{
|
||||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, rootDirectory: selection.RootDirectory, this);
|
||||
UpdateUser("Uninstalling Koaloader from " + selection.Name
|
||||
+ $" in incorrect directory \"{directory}\" . . . ",
|
||||
LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||
}
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
if (Uninstalling || !selection.Koaloader)
|
||||
{
|
||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||
{
|
||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
|
||||
if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|
||||
|| Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
||||
|| File.Exists(config))
|
||||
|| Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll))
|
||||
|| File.Exists(config))
|
||||
{
|
||||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, rootDirectory: selection.RootDirectory, this);
|
||||
UpdateUser(
|
||||
"Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ",
|
||||
LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||
}
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
bool uninstallProxy = Uninstalling || selection.Koaloader;
|
||||
int count = selection.DllDirectories.Count, cur = 0;
|
||||
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 (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);
|
||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache) : File.Exists(api32) || File.Exists(api64))
|
||||
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
|
||||
out string api64_o, out string config, out string cache);
|
||||
if (uninstallProxy
|
||||
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache)
|
||||
: File.Exists(api32) || File.Exists(api64))
|
||||
{
|
||||
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)
|
||||
await SmokeAPI.Uninstall(directory, this);
|
||||
else
|
||||
|
@ -122,11 +130,15 @@ internal partial class InstallForm : CustomForm
|
|||
}
|
||||
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);
|
||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
|
||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string 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" +
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
if (uninstallProxy)
|
||||
await ScreamAPI.Uninstall(directory, this);
|
||||
else
|
||||
|
@ -135,21 +147,29 @@ internal partial class InstallForm : CustomForm
|
|||
}
|
||||
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);
|
||||
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
|
||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string 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" +
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
if (uninstallProxy)
|
||||
await UplayR1.Uninstall(directory, this);
|
||||
else
|
||||
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);
|
||||
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))
|
||||
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o,
|
||||
out api64, out api64_o, out config);
|
||||
if (uninstallProxy
|
||||
? File.Exists(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" +
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
|
||||
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
if (uninstallProxy)
|
||||
await UplayR2.Uninstall(directory, this);
|
||||
else
|
||||
|
@ -160,20 +180,17 @@ internal partial class InstallForm : CustomForm
|
|||
Thread.Sleep(1);
|
||||
}
|
||||
if (selection.Koaloader && !Uninstalling)
|
||||
{
|
||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||
{
|
||||
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
|
||||
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Install(directory, binaryType, selection, rootDirectory: selection.RootDirectory, this);
|
||||
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ",
|
||||
LogTextBox.Operation);
|
||||
await Koaloader.Install(directory, binaryType, selection, selection.RootDirectory, this);
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
UpdateProgress(100);
|
||||
}
|
||||
|
||||
private readonly List<ProgramSelection> DisabledSelections = new();
|
||||
|
||||
private async Task Operate()
|
||||
{
|
||||
List<ProgramSelection> programSelections = ProgramSelection.AllEnabled;
|
||||
|
@ -181,7 +198,8 @@ internal partial class InstallForm : CustomForm
|
|||
CompleteOperationsCount = 0;
|
||||
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
|
||||
{
|
||||
await OperateFor(selection);
|
||||
|
@ -207,8 +225,6 @@ internal partial class InstallForm : CustomForm
|
|||
DisabledSelections.Clear();
|
||||
}
|
||||
|
||||
private readonly int ProgramCount = ProgramSelection.AllEnabled.Count;
|
||||
|
||||
private async void Start()
|
||||
{
|
||||
Program.Canceled = false;
|
||||
|
@ -220,11 +236,13 @@ internal partial class InstallForm : CustomForm
|
|||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
userProgressBar.Value = userProgressBar.Maximum;
|
||||
|
@ -235,7 +253,7 @@ internal partial class InstallForm : CustomForm
|
|||
|
||||
private void OnLoad(object sender, EventArgs _)
|
||||
{
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
userInfoLabel.Text = "Loading . . . ";
|
||||
|
@ -244,7 +262,7 @@ internal partial class InstallForm : CustomForm
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e.HandleException(form: this)) goto retry;
|
||||
if (e.HandleException(this)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
|
7
CreamInstaller/Forms/MainForm.Designer.cs
generated
7
CreamInstaller/Forms/MainForm.Designer.cs
generated
|
@ -1,11 +1,8 @@
|
|||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Components;
|
||||
|
||||
namespace CreamInstaller
|
||||
namespace CreamInstaller.Forms
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
using Onova;
|
||||
using Onova.Models;
|
||||
using Onova.Services;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
@ -16,19 +7,29 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
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 MainForm() : base()
|
||||
private CancellationTokenSource cancellationTokenSource;
|
||||
private Version latestVersion;
|
||||
|
||||
private UpdateManager updateManager;
|
||||
private IReadOnlyList<Version> versions;
|
||||
|
||||
internal MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
Text = Program.ApplicationNameShort;
|
||||
}
|
||||
|
||||
private CancellationTokenSource cancellationTokenSource;
|
||||
|
||||
private void StartProgram()
|
||||
{
|
||||
if (cancellationTokenSource is not null)
|
||||
|
@ -49,10 +50,6 @@ internal partial class MainForm : CustomForm
|
|||
#endif
|
||||
}
|
||||
|
||||
private UpdateManager updateManager;
|
||||
private Version latestVersion;
|
||||
private IReadOnlyList<Version> versions;
|
||||
|
||||
private async void OnLoad()
|
||||
{
|
||||
progressBar.Visible = false;
|
||||
|
@ -61,18 +58,22 @@ internal partial class MainForm : CustomForm
|
|||
updateButton.Click -= OnUpdateCancel;
|
||||
progressLabel.Text = "Checking for updates . . .";
|
||||
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();
|
||||
#if DEBUG
|
||||
DebugForm.Current.Attach(this);
|
||||
#endif
|
||||
GithubPackageResolver resolver = new(Program.RepositoryOwner, Program.RepositoryName, Program.RepositoryPackage);
|
||||
GithubPackageResolver resolver = new(Program.RepositoryOwner, Program.RepositoryName,
|
||||
Program.RepositoryPackage);
|
||||
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)
|
||||
{
|
||||
CheckForUpdatesResult checkForUpdatesResult = null;
|
||||
cancellationTokenSource = new();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
checkForUpdatesResult = await updateManager.CheckForUpdatesAsync(cancellationTokenSource.Token);
|
||||
|
@ -80,8 +81,8 @@ internal partial class MainForm : CustomForm
|
|||
if (checkForUpdatesResult.CanUpdate)
|
||||
{
|
||||
#endif
|
||||
latestVersion = checkForUpdatesResult.LastVersion;
|
||||
versions = checkForUpdatesResult.Versions;
|
||||
latestVersion = checkForUpdatesResult.LastVersion;
|
||||
versions = checkForUpdatesResult.Versions;
|
||||
#if !DEBUG
|
||||
}
|
||||
#endif
|
||||
|
@ -90,7 +91,8 @@ internal partial class MainForm : CustomForm
|
|||
catch (TaskCanceledException) { }
|
||||
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
|
||||
catch { }
|
||||
|
@ -112,19 +114,17 @@ internal partial class MainForm : CustomForm
|
|||
progressLabel.Text = $"An update is available: v{latestVersion}";
|
||||
ignoreButton.Enabled = true;
|
||||
updateButton.Enabled = true;
|
||||
updateButton.Click += new(OnUpdate);
|
||||
updateButton.Click += OnUpdate;
|
||||
changelogTreeView.Visible = true;
|
||||
Version currentVersion = new(Program.Version);
|
||||
#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
|
||||
foreach (Version version in versions.Where(v => v > currentVersion && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
||||
#endif
|
||||
{
|
||||
TreeNode root = new($"v{version}")
|
||||
{
|
||||
Name = version.ToString()
|
||||
};
|
||||
TreeNode root = new($"v{version}") { Name = version.ToString() };
|
||||
changelogTreeView.Nodes.Add(root);
|
||||
if (changelogTreeView.Nodes.Count > 0)
|
||||
changelogTreeView.Nodes[0].EnsureVisible();
|
||||
|
@ -137,19 +137,14 @@ internal partial class MainForm : CustomForm
|
|||
changelogTreeView.Nodes.Remove(root);
|
||||
else
|
||||
foreach (HtmlNode node in nodes)
|
||||
{
|
||||
changelogTreeView.Invoke(delegate
|
||||
{
|
||||
TreeNode change = new()
|
||||
{
|
||||
Text = HttpUtility.HtmlDecode(node.InnerText)
|
||||
};
|
||||
TreeNode change = new() { Text = HttpUtility.HtmlDecode(node.InnerText) };
|
||||
root.Nodes.Add(change);
|
||||
root.Expand();
|
||||
if (changelogTreeView.Nodes.Count > 0)
|
||||
changelogTreeView.Nodes[0].EnsureVisible();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +152,7 @@ internal partial class MainForm : CustomForm
|
|||
|
||||
private void OnLoad(object sender, EventArgs _)
|
||||
{
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
string FileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
||||
|
@ -165,9 +160,9 @@ internal partial class MainForm : CustomForm
|
|||
{
|
||||
using DialogForm form = new(this);
|
||||
if (form.Show(SystemIcons.Warning,
|
||||
"WARNING: " + Program.ApplicationExecutable + " was renamed!" +
|
||||
"\n\nThis will cause undesirable behavior when updating the program!",
|
||||
"Ignore", "Abort") == DialogResult.Cancel)
|
||||
"WARNING: " + Program.ApplicationExecutable + " was renamed!" +
|
||||
"\n\nThis will cause undesirable behavior when updating the program!",
|
||||
"Ignore", "Abort") == DialogResult.Cancel)
|
||||
{
|
||||
Application.Exit();
|
||||
return;
|
||||
|
@ -177,7 +172,7 @@ internal partial class MainForm : CustomForm
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e.HandleException(form: this)) goto retry;
|
||||
if (e.HandleException(this)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
@ -190,19 +185,18 @@ internal partial class MainForm : CustomForm
|
|||
ignoreButton.Visible = false;
|
||||
updateButton.Text = "Cancel";
|
||||
updateButton.Click -= OnUpdate;
|
||||
updateButton.Click += new(OnUpdateCancel);
|
||||
changelogTreeView.Location = new(progressBar.Location.X, progressBar.Location.Y + progressBar.Size.Height + 6);
|
||||
updateButton.Click += OnUpdateCancel;
|
||||
changelogTreeView.Location
|
||||
= new Point(progressBar.Location.X, progressBar.Location.Y + progressBar.Size.Height + 6);
|
||||
Refresh();
|
||||
|
||||
Progress<double> progress = new();
|
||||
progress.ProgressChanged += new(delegate (object sender, double _progress)
|
||||
progress.ProgressChanged += delegate(object sender, double _progress)
|
||||
{
|
||||
progressLabel.Text = $"Updating . . . {(int)_progress}%";
|
||||
progressBar.Value = (int)_progress;
|
||||
});
|
||||
|
||||
};
|
||||
progressLabel.Text = "Updating . . . ";
|
||||
cancellationTokenSource = new();
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
try
|
||||
{
|
||||
await updateManager.PrepareUpdateAsync(latestVersion, progress, cancellationTokenSource.Token);
|
||||
|
@ -211,7 +205,8 @@ internal partial class MainForm : CustomForm
|
|||
catch (TaskCanceledException) { }
|
||||
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
|
||||
catch { }
|
||||
|
@ -221,14 +216,13 @@ internal partial class MainForm : CustomForm
|
|||
cancellationTokenSource.Dispose();
|
||||
cancellationTokenSource = null;
|
||||
}
|
||||
|
||||
if (updateManager is not null && updateManager.IsUpdatePrepared(latestVersion))
|
||||
{
|
||||
updateManager.LaunchUpdater(latestVersion);
|
||||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
else OnLoad();
|
||||
OnLoad();
|
||||
}
|
||||
|
||||
private void OnUpdateCancel(object sender, EventArgs e)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Components;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CreamInstaller
|
||||
namespace CreamInstaller.Forms
|
||||
{
|
||||
partial class SelectDialogForm
|
||||
{
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller;
|
||||
namespace CreamInstaller.Forms;
|
||||
|
||||
internal partial class SelectDialogForm : CustomForm
|
||||
{
|
||||
private readonly List<(Platform platform, string id, string name)> selected = new();
|
||||
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(string groupBoxText, List<(Platform platform, string id, string name, bool alreadySelected)> choices)
|
||||
internal List<(Platform platform, string id, string name)> QueryUser(
|
||||
string groupBoxText, List<(Platform platform, string id, string name, bool alreadySelected)> choices)
|
||||
{
|
||||
if (!choices.Any()) return null;
|
||||
groupBox.Text = groupBoxText;
|
||||
|
@ -23,13 +22,7 @@ internal partial class SelectDialogForm : CustomForm
|
|||
selectionTreeView.AfterCheck += OnTreeNodeChecked;
|
||||
foreach ((Platform platform, string id, string name, bool alreadySelected) in choices)
|
||||
{
|
||||
TreeNode node = new()
|
||||
{
|
||||
Tag = platform,
|
||||
Name = id,
|
||||
Text = name,
|
||||
Checked = alreadySelected
|
||||
};
|
||||
TreeNode node = new() { Tag = platform, Name = id, Text = name, Checked = alreadySelected };
|
||||
OnTreeNodeChecked(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.Drawing;
|
||||
using System.ComponentModel;
|
||||
using CreamInstaller.Components;
|
||||
|
||||
namespace CreamInstaller
|
||||
namespace CreamInstaller.Forms
|
||||
{
|
||||
partial class SelectForm
|
||||
{
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
#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.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -20,26 +10,45 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
namespace CreamInstaller;
|
||||
namespace CreamInstaller.Forms;
|
||||
|
||||
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();
|
||||
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) =>
|
||||
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 AddToRemainingGames(string gameName)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
|
@ -51,6 +60,7 @@ internal partial class SelectForm : CustomForm
|
|||
UpdateRemainingGames();
|
||||
});
|
||||
}
|
||||
|
||||
private void RemoveFromRemainingGames(string gameName)
|
||||
{
|
||||
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 AddToRemainingDLCs(string dlcId)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
|
@ -75,6 +85,7 @@ internal partial class SelectForm : CustomForm
|
|||
UpdateRemainingDLCs();
|
||||
});
|
||||
}
|
||||
|
||||
private void RemoveFromRemainingDLCs(string dlcId)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
|
@ -109,21 +120,23 @@ internal partial class SelectForm : CustomForm
|
|||
List<Task> appTasks = new();
|
||||
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)
|
||||
{
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
|
||||
selection ??= new();
|
||||
selection ??= new ProgramSelection();
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||
selection.Id = "PL";
|
||||
selection.Name = "Paradox Launcher";
|
||||
selection.RootDirectory = ParadoxLauncher.InstallPath;
|
||||
selection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.ExecutableDirectories
|
||||
= await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Paradox;
|
||||
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id) ?? new();
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id)
|
||||
?? new TreeNode();
|
||||
programNode.Tag = selection.Platform;
|
||||
programNode.Name = selection.Id;
|
||||
programNode.Text = selection.Name;
|
||||
|
@ -135,12 +148,14 @@ internal partial class SelectForm : CustomForm
|
|||
int steamGamesToCheck;
|
||||
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;
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
|
||||
{
|
||||
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);
|
||||
continue;
|
||||
|
@ -149,7 +164,8 @@ internal partial class SelectForm : CustomForm
|
|||
Task task = Task.Run(async () =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
|
||||
List<string> dllDirectories
|
||||
= await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
|
||||
if (dllDirectories is null)
|
||||
{
|
||||
Interlocked.Decrement(ref steamGamesToCheck);
|
||||
|
@ -199,11 +215,15 @@ internal partial class SelectForm : CustomForm
|
|||
if (dlcAppInfo is not null)
|
||||
{
|
||||
dlcName = dlcAppInfo.Value?.GetChild("common")?.GetChild("name")?.ToString();
|
||||
string dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")?.ToString();
|
||||
string dlcIconStaticId = dlcAppInfo.Value?.GetChild("common")?.GetChild("icon")
|
||||
?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo_small")
|
||||
?.ToString();
|
||||
dlcIconStaticId ??= dlcAppInfo.Value?.GetChild("common")?.GetChild("logo")
|
||||
?.ToString();
|
||||
if (dlcIconStaticId is not null)
|
||||
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
||||
dlcIcon = IconGrabber.SteamAppImagesPath
|
||||
+ @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
|
||||
}
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
|
@ -227,27 +247,32 @@ internal partial class SelectForm : CustomForm
|
|||
await task;
|
||||
}
|
||||
steamGamesToCheck = 0;
|
||||
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Steam, appId) ?? new();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Steam, appId)
|
||||
?? new ProgramSelection();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||
|| selection.ExtraSelectedDlc.Any();
|
||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||
selection.Id = appId;
|
||||
selection.Name = appData?.name ?? name;
|
||||
selection.RootDirectory = gameDirectory;
|
||||
selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.ExecutableDirectories
|
||||
= await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Steam;
|
||||
selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
|
||||
selection.IconUrl = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("icon")}.jpg";
|
||||
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.IconUrl = IconGrabber.SteamAppImagesPath
|
||||
+ @$"\{appId}\{appInfo?.Value?.GetChild("common")?.GetChild("icon")}.jpg";
|
||||
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;
|
||||
|
||||
if (Program.Canceled) return;
|
||||
selectionTreeView.Invoke(delegate
|
||||
{
|
||||
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.Name = appId;
|
||||
programNode.Text = appData?.name ?? name;
|
||||
|
@ -261,7 +286,8 @@ internal partial class SelectForm : CustomForm
|
|||
(DlcType type, string name, string icon) dlcApp = pair.Value;
|
||||
selection.AllDlc[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.Name = appId;
|
||||
dlcNode.Text = dlcApp.name;
|
||||
|
@ -285,7 +311,8 @@ internal partial class SelectForm : CustomForm
|
|||
string name = manifest.DisplayName;
|
||||
string directory = manifest.InstallLocation;
|
||||
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);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
|
@ -297,12 +324,14 @@ internal partial class SelectForm : CustomForm
|
|||
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<(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())
|
||||
{
|
||||
foreach ((string id, string name, string product, string icon, string developer) in entitlementIds)
|
||||
foreach ((string id, string name, string product, string icon, string developer) in
|
||||
entitlementIds)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
AddToRemainingDLCs(id);
|
||||
|
@ -314,8 +343,7 @@ internal partial class SelectForm : CustomForm
|
|||
});
|
||||
dlcTasks.Add(task);
|
||||
}
|
||||
}
|
||||
if (/*!catalogItems.Any() && */!entitlements.Any())
|
||||
if ( /*!catalogItems.Any() && */!entitlements.Any())
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
|
@ -326,28 +354,31 @@ internal partial class SelectForm : CustomForm
|
|||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace) ?? new();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace)
|
||||
?? new ProgramSelection();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||
|| selection.ExtraSelectedDlc.Any();
|
||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||
selection.Id = @namespace;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = directory;
|
||||
selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.ExecutableDirectories
|
||||
= await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Epic;
|
||||
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements.Where(p => p.Value.name == selection.Name))
|
||||
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.IconUrl = pair.Value.icon;
|
||||
selection.Publisher = pair.Value.developer;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
selectionTreeView.Invoke(delegate
|
||||
{
|
||||
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.Name = @namespace;
|
||||
programNode.Text = name;
|
||||
|
@ -362,7 +393,6 @@ internal partial class SelectForm : CustomForm
|
|||
if (catalogItemsNode.Parent is null)
|
||||
programNode.Nodes.Add(catalogItemsNode);*/
|
||||
if (entitlements.Any())
|
||||
{
|
||||
/*TreeNode entitlementsNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace + "_entitlements") ?? new();
|
||||
entitlementsNode.Tag = selection.Platform;
|
||||
entitlementsNode.Name = @namespace + "_entitlements";
|
||||
|
@ -370,14 +400,17 @@ internal partial class SelectForm : CustomForm
|
|||
entitlementsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.Entitlement);
|
||||
if (entitlementsNode.Parent is null)
|
||||
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;
|
||||
(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;
|
||||
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.Name = dlcId;
|
||||
dlcNode.Text = dlcApp.name;
|
||||
|
@ -385,7 +418,6 @@ internal partial class SelectForm : CustomForm
|
|||
if (dlcNode.Parent is null)
|
||||
_ = programNode.Nodes.Add(dlcNode); //entitlementsNode.Nodes.Add(dlcNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (Program.Canceled) return;
|
||||
RemoveFromRemainingGames(name);
|
||||
|
@ -399,34 +431,38 @@ internal partial class SelectForm : CustomForm
|
|||
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
|
||||
{
|
||||
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);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
|
||||
List<string> dllDirectories
|
||||
= await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
|
||||
if (dllDirectories is null)
|
||||
{
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId) ?? new();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
|
||||
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId)
|
||||
?? new ProgramSelection();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|
||||
|| selection.ExtraSelectedDlc.Any();
|
||||
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
|
||||
selection.Id = gameId;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = gameDirectory;
|
||||
selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.ExecutableDirectories
|
||||
= await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Ubisoft;
|
||||
selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
||||
|
||||
selectionTreeView.Invoke(delegate
|
||||
{
|
||||
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.Name = gameId;
|
||||
programNode.Text = name;
|
||||
|
@ -448,7 +484,6 @@ internal partial class SelectForm : CustomForm
|
|||
steamGamesToCheck = 0;
|
||||
}
|
||||
|
||||
private List<(Platform platform, string id, string name)> ProgramsToScan;
|
||||
private async void OnLoad(bool forceScan = false, bool forceProvideChoices = false)
|
||||
{
|
||||
Program.Canceled = false;
|
||||
|
@ -470,27 +505,37 @@ internal partial class SelectForm : CustomForm
|
|||
resetKoaloaderButton.Enabled = false;
|
||||
progressLabel.Text = "Waiting for user to select which programs/games to scan . . .";
|
||||
ShowProgressBar();
|
||||
|
||||
await ProgramData.Setup();
|
||||
|
||||
bool scan = forceScan;
|
||||
if (!scan && (ProgramsToScan is null || !ProgramsToScan.Any() || forceProvideChoices))
|
||||
{
|
||||
List<(Platform platform, string id, string name, bool alreadySelected)> gameChoices = new();
|
||||
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))
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in (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)));
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in
|
||||
(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))
|
||||
foreach (Manifest manifest in (await EpicLibrary.GetGames()).Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)))
|
||||
gameChoices.Add((Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName, 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)));
|
||||
foreach (Manifest manifest in (await EpicLibrary.GetGames()).Where(
|
||||
m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)))
|
||||
gameChoices.Add((Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName,
|
||||
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())
|
||||
{
|
||||
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();
|
||||
string retry = "\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
|
||||
if (scan)
|
||||
|
@ -499,12 +544,15 @@ internal partial class SelectForm : CustomForm
|
|||
noneFoundLabel.Text = "None of the chosen programs nor games were applicable!" + retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
noneFoundLabel.Text = "You didn't choose any programs nor games!" + retry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
|
||||
}
|
||||
}
|
||||
|
||||
if (scan)
|
||||
{
|
||||
bool setup = true;
|
||||
|
@ -518,13 +566,15 @@ internal partial class SelectForm : CustomForm
|
|||
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
|
||||
else curProgress = _progress;
|
||||
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}%";
|
||||
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);
|
||||
}
|
||||
setup = false;
|
||||
|
@ -542,10 +592,8 @@ internal partial class SelectForm : CustomForm
|
|||
await GetApplicablePrograms(iProgress);
|
||||
await SteamCMD.Cleanup();
|
||||
}
|
||||
|
||||
OnLoadDlc(null, null);
|
||||
OnLoadKoaloader(null, null);
|
||||
|
||||
HideProgressBar();
|
||||
selectionTreeView.Enabled = ProgramSelection.All.Any();
|
||||
allCheckBox.Enabled = selectionTreeView.Enabled;
|
||||
|
@ -605,7 +653,8 @@ internal partial class SelectForm : CustomForm
|
|||
{
|
||||
string id = node.Name;
|
||||
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)
|
||||
{
|
||||
(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)
|
||||
{
|
||||
List<TreeNode> treeNodes = new();
|
||||
|
@ -642,12 +690,13 @@ internal partial class SelectForm : CustomForm
|
|||
progressLabelDLCs.Text = "";
|
||||
progressLabelDLCs.Visible = true;
|
||||
progressBar.Visible = true;
|
||||
programsGroupBox.Size = new(programsGroupBox.Size.Width, programsGroupBox.Size.Height - 3
|
||||
- progressLabel.Size.Height
|
||||
- progressLabelGames.Size.Height
|
||||
- progressLabelDLCs.Size.Height
|
||||
- progressBar.Size.Height);
|
||||
programsGroupBox.Size = new Size(programsGroupBox.Size.Width, programsGroupBox.Size.Height - 3
|
||||
- progressLabel.Size.Height
|
||||
- progressLabelGames.Size.Height
|
||||
- progressLabelDLCs.Size.Height
|
||||
- progressBar.Size.Height);
|
||||
}
|
||||
|
||||
private void HideProgressBar()
|
||||
{
|
||||
progressBar.Value = 100;
|
||||
|
@ -655,11 +704,11 @@ internal partial class SelectForm : CustomForm
|
|||
progressLabelGames.Visible = false;
|
||||
progressLabelDLCs.Visible = false;
|
||||
progressBar.Visible = false;
|
||||
programsGroupBox.Size = new(programsGroupBox.Size.Width, programsGroupBox.Size.Height + 3
|
||||
+ progressLabel.Size.Height
|
||||
+ progressLabelGames.Size.Height
|
||||
+ progressLabelDLCs.Size.Height
|
||||
+ progressBar.Size.Height);
|
||||
programsGroupBox.Size = new Size(programsGroupBox.Size.Width, programsGroupBox.Size.Height + 3
|
||||
+ progressLabel.Size.Height
|
||||
+ progressLabelGames.Size.Height
|
||||
+ progressLabelDLCs.Size.Height
|
||||
+ progressBar.Size.Height);
|
||||
}
|
||||
|
||||
internal void OnNodeRightClick(TreeNode node, Point location) => Invoke(() =>
|
||||
|
@ -683,11 +732,11 @@ internal partial class SelectForm : CustomForm
|
|||
return;
|
||||
ContextMenuItem header = null;
|
||||
if (id == "PL")
|
||||
header = new(node.Text, "Paradox Launcher");
|
||||
header = new ContextMenuItem(node.Text, "Paradox Launcher");
|
||||
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)
|
||||
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));
|
||||
string appInfoVDF = $@"{SteamCMD.AppInfoPath}\{id}.vdf";
|
||||
string appInfoJSON = $@"{SteamCMD.AppInfoPath}\{id}.json";
|
||||
|
@ -697,39 +746,42 @@ internal partial class SelectForm : CustomForm
|
|||
List<ContextMenuItem> queries = new();
|
||||
if (File.Exists(appInfoJSON))
|
||||
{
|
||||
string platformString = (selection is null || selection.Platform is Platform.Steam) ? "Steam Store "
|
||||
: selection.Platform is Platform.Epic ? "Epic GraphQL " : "";
|
||||
string platformString = selection is null || selection.Platform is Platform.Steam
|
||||
? "Steam Store "
|
||||
: selection.Platform is Platform.Epic
|
||||
? "Epic GraphQL "
|
||||
: "";
|
||||
queries.Add(new ContextMenuItem($"Open {platformString}Query", "Notepad",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON))));
|
||||
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
|
||||
}
|
||||
if (File.Exists(appInfoVDF))
|
||||
queries.Add(new ContextMenuItem("Open SteamCMD Query", "Notepad",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenFileInNotepad(appInfoVDF))));
|
||||
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
|
||||
if (queries.Any())
|
||||
{
|
||||
items.Add(new ToolStripSeparator());
|
||||
foreach (ContextMenuItem query in queries)
|
||||
items.Add(query);
|
||||
items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt",
|
||||
new EventHandler((sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(appInfoVDF);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
File.Delete(appInfoJSON);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
File.Delete(cooldown);
|
||||
}
|
||||
catch { }
|
||||
OnLoad(forceScan: true);
|
||||
})));
|
||||
(sender, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(appInfoVDF);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
File.Delete(appInfoJSON);
|
||||
}
|
||||
catch { }
|
||||
try
|
||||
{
|
||||
File.Delete(cooldown);
|
||||
}
|
||||
catch { }
|
||||
OnLoad(true);
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (selection is not null)
|
||||
|
@ -738,89 +790,109 @@ internal partial class SelectForm : CustomForm
|
|||
{
|
||||
items.Add(new ToolStripSeparator());
|
||||
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 ContextMenuItem("Open Root Directory", "File Explorer",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(selection.RootDirectory))));
|
||||
(sender, e) => Diagnostics.OpenDirectoryInFileExplorer(
|
||||
selection.RootDirectory)));
|
||||
int executables = 0;
|
||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories.ToList())
|
||||
{
|
||||
items.Add(new ContextMenuItem($"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)", "File Explorer",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
||||
}
|
||||
items.Add(new ContextMenuItem(
|
||||
$"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)",
|
||||
"File Explorer",
|
||||
(sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
|
||||
List<string> directories = selection.DllDirectories.ToList();
|
||||
int steam = 0, epic = 0, r1 = 0, r2 = 0;
|
||||
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
||||
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);
|
||||
if (File.Exists(api32) || File.Exists(api32_o) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(config) || File.Exists(cache))
|
||||
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) || 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",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
||||
(sender, e) => Diagnostics
|
||||
.OpenDirectoryInFileExplorer(directory)));
|
||||
}
|
||||
if (selection.Platform is Platform.Epic or Platform.Paradox)
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
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) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(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) || File.Exists(api64) || File.Exists(api64_o)
|
||||
|| File.Exists(config))
|
||||
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)
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
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) || File.Exists(api64) || File.Exists(api64_o) || File.Exists(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) || File.Exists(api64) || File.Exists(api64_o)
|
||||
|| File.Exists(config))
|
||||
items.Add(new ContextMenuItem($"Open Uplay R1 Directory #{++r1}", "File Explorer",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
||||
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))
|
||||
(sender, e) => Diagnostics
|
||||
.OpenDirectoryInFileExplorer(directory)));
|
||||
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",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory))));
|
||||
(sender, e) => Diagnostics
|
||||
.OpenDirectoryInFileExplorer(directory)));
|
||||
}
|
||||
}
|
||||
if (id != "PL")
|
||||
{
|
||||
if (selection is not null && selection.Platform is Platform.Steam
|
||||
|| dlcParentSelection is not null && dlcParentSelection.Platform is Platform.Steam)
|
||||
if ((selection is not null && selection.Platform is Platform.Steam)
|
||||
|| (dlcParentSelection is not null && dlcParentSelection.Platform is Platform.Steam))
|
||||
{
|
||||
items.Add(new ToolStripSeparator());
|
||||
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.Platform is Platform.Steam)
|
||||
{
|
||||
items.Add(new ContextMenuItem("Open Steam Store", "Steam Store",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl))));
|
||||
items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIconUrl), "Steam Community",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + id))));
|
||||
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||
selection.ProductUrl)));
|
||||
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)
|
||||
{
|
||||
items.Add(new ToolStripSeparator());
|
||||
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",
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl))));
|
||||
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(
|
||||
selection.ProductUrl)));
|
||||
}
|
||||
if (selection.Platform is Platform.Ubisoft)
|
||||
{
|
||||
items.Add(new ToolStripSeparator());
|
||||
#pragma warning disable CA1308 // Normalize strings to uppercase
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selection is not null && selection.WebsiteUrl is not null)
|
||||
{
|
||||
items.Add(new ContextMenuItem("Open Official Website", ("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.WebsiteUrl)),
|
||||
new EventHandler((sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.WebsiteUrl))));
|
||||
}
|
||||
items.Add(new ContextMenuItem("Open Official Website",
|
||||
("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.WebsiteUrl)),
|
||||
(sender, e) => Diagnostics.OpenUrlInInternetBrowser(selection.WebsiteUrl)));
|
||||
contextMenuStrip.Show(selectionTreeView, location);
|
||||
contextMenuStrip.Refresh();
|
||||
ContextMenuStrip.Tag = null;
|
||||
|
@ -828,7 +900,7 @@ internal partial class SelectForm : CustomForm
|
|||
|
||||
private void OnLoad(object sender, EventArgs _)
|
||||
{
|
||||
retry:
|
||||
retry:
|
||||
try
|
||||
{
|
||||
HideProgressBar();
|
||||
|
@ -837,7 +909,7 @@ internal partial class SelectForm : CustomForm
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e.HandleException(form: this)) goto retry;
|
||||
if (e.HandleException(this)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
@ -847,7 +919,8 @@ internal partial class SelectForm : CustomForm
|
|||
if (ProgramSelection.All.Any())
|
||||
{
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllEnabled)
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) return;
|
||||
if (!Program.IsProgramRunningDialog(this, selection))
|
||||
return;
|
||||
if (!uninstall && ParadoxLauncher.DlcDialog(this)) return;
|
||||
Hide();
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
|
@ -865,7 +938,10 @@ internal partial class SelectForm : CustomForm
|
|||
#endif
|
||||
OnLoad();
|
||||
}
|
||||
else Close();
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
form.Show();
|
||||
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);
|
||||
|
||||
|
@ -900,7 +976,7 @@ internal partial class SelectForm : CustomForm
|
|||
if (node.Parent is null && node.Checked != shouldCheck)
|
||||
{
|
||||
node.Checked = shouldCheck;
|
||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
||||
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
|
||||
}
|
||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||
allCheckBox.Checked = shouldCheck;
|
||||
|
@ -927,16 +1003,20 @@ internal partial class SelectForm : CustomForm
|
|||
private bool AreSelectionsDefault()
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
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.Text == "Unknown"
|
||||
: node.Text != "Unknown";
|
||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
||||
node.Checked
|
||||
= choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name)
|
||||
? node.Text == "Unknown"
|
||||
: 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)
|
||||
{
|
||||
node.Checked = node.Text != "Unknown";
|
||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
||||
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
|
||||
}
|
||||
resetButton.Enabled = CanResetDlc();
|
||||
}
|
||||
|
@ -988,16 +1069,22 @@ internal partial class SelectForm : CustomForm
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
|
||||
if (selection.KoaloaderProxy is not null and not ProgramSelection.DefaultKoaloaderProxy || !selection.Koaloader)
|
||||
choices.Add((selection.Platform, selection.Id, selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy, selection.Koaloader));
|
||||
if (selection.KoaloaderProxy is not null and not ProgramSelection.DefaultKoaloaderProxy
|
||||
|| !selection.Koaloader)
|
||||
choices.Add((selection.Platform, selection.Id,
|
||||
selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy
|
||||
? null
|
||||
: selection.KoaloaderProxy, selection.Koaloader));
|
||||
}
|
||||
ProgramData.WriteKoaloaderProxyChoices(choices);
|
||||
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
||||
|
@ -1011,7 +1098,6 @@ internal partial class SelectForm : CustomForm
|
|||
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices();
|
||||
if (choices is null) return;
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
|
||||
{
|
||||
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
|
||||
{
|
||||
(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
|
||||
choices.Add((platform, id, currentProxy, enabled));
|
||||
if (currentProxy is null or ProgramSelection.DefaultKoaloaderProxy && enabled)
|
||||
{
|
||||
_ = choices.RemoveAll(c => c.platform == platform && c.id == id);
|
||||
}
|
||||
else
|
||||
{
|
||||
selection.Koaloader = enabled;
|
||||
selection.KoaloaderProxy = currentProxy == ProgramSelection.DefaultKoaloaderProxy ? currentProxy : proxy;
|
||||
selection.KoaloaderProxy
|
||||
= currentProxy == ProgramSelection.DefaultKoaloaderProxy ? currentProxy : proxy;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1035,7 +1124,6 @@ internal partial class SelectForm : CustomForm
|
|||
selection.Koaloader = true;
|
||||
selection.KoaloaderProxy = null;
|
||||
}
|
||||
}
|
||||
ProgramData.WriteKoaloaderProxyChoices(choices);
|
||||
loadKoaloaderButton.Enabled = CanLoadKoaloader();
|
||||
OnKoaloaderChanged();
|
||||
|
@ -1069,7 +1157,6 @@ internal partial class SelectForm : CustomForm
|
|||
OnLoad(forceProvideChoices: true);
|
||||
}
|
||||
|
||||
private readonly string helpButtonListPrefix = "\n • ";
|
||||
private void OnBlockProtectedGamesHelpButtonClicked(object sender, EventArgs e)
|
||||
{
|
||||
StringBuilder blockedGames = new();
|
||||
|
@ -1083,12 +1170,18 @@ internal partial class SelectForm : CustomForm
|
|||
_ = blockedDirectoryExceptions.Append(helpButtonListPrefix + name);
|
||||
using DialogForm form = new(this);
|
||||
_ = form.Show(SystemIcons.Information,
|
||||
"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!" +
|
||||
"\n\nBlocked games: " + (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) +
|
||||
"\n\nBlocked game sub-directories: " + (string.IsNullOrWhiteSpace(blockedDirectories.ToString()) ? "(none)" : blockedDirectories) +
|
||||
"\n\nBlocked game sub-directory exceptions: " + (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString()) ? "(none)" : blockedDirectoryExceptions),
|
||||
"OK", customFormText: "Block Protected Games");
|
||||
"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!" +
|
||||
"\n\nBlocked games: "
|
||||
+ (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) +
|
||||
"\n\nBlocked game sub-directories: " + (string.IsNullOrWhiteSpace(blockedDirectories.ToString())
|
||||
? "(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
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
|
||||
[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 CreamInstaller.Utility;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Utility;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Epic;
|
||||
|
@ -16,21 +12,32 @@ namespace CreamInstaller.Platforms.Epic;
|
|||
internal static class EpicLibrary
|
||||
{
|
||||
private static string epicManifestsPath;
|
||||
|
||||
internal static string EpicManifestsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
epicManifestsPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir", null) as string;
|
||||
epicManifestsPath ??= 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";
|
||||
epicManifestsPath
|
||||
??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir",
|
||||
null) as string;
|
||||
epicManifestsPath
|
||||
??= 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();
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||
|
||||
internal static async Task<List<Manifest>> GetGames() => await Task.Run(() =>
|
||||
{
|
||||
|
@ -45,10 +52,12 @@ internal static class EpicLibrary
|
|||
{
|
||||
Manifest manifest = JsonSerializer.Deserialize<Manifest>(json);
|
||||
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);
|
||||
}
|
||||
catch { };
|
||||
catch { }
|
||||
;
|
||||
}
|
||||
return games;
|
||||
});
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
using CreamInstaller.Platforms.Epic.GraphQL;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -11,6 +6,9 @@ using System.Net.Http;
|
|||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using CreamInstaller.Platforms.Epic.GraphQL;
|
||||
using CreamInstaller.Utility;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Platforms.Epic;
|
||||
|
||||
|
@ -24,7 +22,9 @@ internal static class EpicStore
|
|||
}*/
|
||||
|
||||
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();
|
||||
string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json";
|
||||
|
@ -35,19 +35,21 @@ internal static class EpicStore
|
|||
response = await QueryGraphQL(categoryNamespace);
|
||||
try
|
||||
{
|
||||
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
await File.WriteAllTextAsync(cacheFile, JsonConvert.SerializeObject(response, Formatting.Indented));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else if (cachedExists)
|
||||
{
|
||||
try
|
||||
{
|
||||
response = JsonConvert.DeserializeObject<Response>(File.ReadAllText(cacheFile));
|
||||
response = JsonConvert.DeserializeObject<Response>(await File.ReadAllTextAsync(cacheFile));
|
||||
}
|
||||
catch
|
||||
{
|
||||
File.Delete(cacheFile);
|
||||
}
|
||||
}
|
||||
if (response is null)
|
||||
return dlcIds;
|
||||
List<Element> searchStore = new(response.Data.Catalog.SearchStore.Elements);
|
||||
|
@ -55,7 +57,8 @@ internal static class EpicStore
|
|||
{
|
||||
string title = element.Title;
|
||||
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;
|
||||
for (int i = 0; i < element.KeyImages?.Length; i++)
|
||||
{
|
||||
|
@ -67,14 +70,15 @@ internal static class EpicStore
|
|||
}
|
||||
}
|
||||
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);
|
||||
foreach (Element element in catalogOffers)
|
||||
{
|
||||
string title = element.Title;
|
||||
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;
|
||||
for (int i = 0; i < element.KeyImages?.Length; i++)
|
||||
{
|
||||
|
@ -86,12 +90,14 @@ internal static class EpicStore
|
|||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
bool found = false;
|
||||
|
@ -121,7 +127,8 @@ internal static class EpicStore
|
|||
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
HttpClient client = HttpClientManager.HttpClient;
|
||||
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();
|
||||
string response = await httpResponse.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<Response>(response);
|
||||
|
|
|
@ -64,7 +64,6 @@ internal class Request
|
|||
{
|
||||
[JsonProperty(PropertyName = "Content-Type")]
|
||||
private string ContentType => "application/graphql";
|
||||
|
||||
}
|
||||
|
||||
private class Variables
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
#pragma warning disable CA1819 // Properties should not return arrays
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Platforms.Epic.GraphQL;
|
||||
|
||||
public class Response
|
||||
{
|
||||
[JsonProperty(PropertyName = "data")]
|
||||
public ResponseData Data { get; protected set; }
|
||||
[JsonProperty(PropertyName = "data")] public ResponseData Data { get; protected set; }
|
||||
}
|
||||
|
||||
public class ResponseData
|
||||
|
@ -35,17 +33,14 @@ public class ElementContainer
|
|||
|
||||
public class Element
|
||||
{
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public string Id { get; protected set; }
|
||||
[JsonProperty(PropertyName = "id")] public string Id { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; protected set; }
|
||||
[JsonProperty(PropertyName = "title")] public string Title { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "keyImages")]
|
||||
public KeyImage[] KeyImages { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "items")]
|
||||
public Item[] Items { get; protected set; }
|
||||
[JsonProperty(PropertyName = "items")] public Item[] Items { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "catalogNs")]
|
||||
public CatalogNs CatalogNs { get; protected set; }
|
||||
|
@ -53,11 +48,9 @@ public class Element
|
|||
|
||||
public class Item
|
||||
{
|
||||
[JsonProperty(PropertyName = "id")]
|
||||
public string Id { get; protected set; }
|
||||
[JsonProperty(PropertyName = "id")] public string Id { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; protected set; }
|
||||
[JsonProperty(PropertyName = "title")] public string Title { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "developer")]
|
||||
public string Developer { get; protected set; }
|
||||
|
@ -65,11 +58,9 @@ public class Item
|
|||
|
||||
public class KeyImage
|
||||
{
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public string Type { get; protected set; }
|
||||
[JsonProperty(PropertyName = "type")] public string Type { get; protected set; }
|
||||
|
||||
[JsonProperty(PropertyName = "url")]
|
||||
public Uri Url { get; protected set; }
|
||||
[JsonProperty(PropertyName = "url")] public Uri Url { get; protected set; }
|
||||
}
|
||||
|
||||
public class CatalogNs
|
||||
|
|
|
@ -1,34 +1,46 @@
|
|||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Paradox;
|
||||
|
||||
internal static class ParadoxLauncher
|
||||
{
|
||||
public enum RepairResult
|
||||
{
|
||||
ProgramRunning = -2, Failure, Unnecessary = 0,
|
||||
Success
|
||||
}
|
||||
|
||||
private static string installPath;
|
||||
|
||||
internal static string InstallPath
|
||||
{
|
||||
get
|
||||
{
|
||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Wow6432Node\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2",
|
||||
"LauncherInstallation", null) as string;
|
||||
installPath ??= Registry.GetValue(
|
||||
@"HKEY_CURRENT_USER\Software\Wow6432Node\Paradox Interactive\Paradox Launcher v2",
|
||||
"LauncherInstallation", null) as string;
|
||||
return installPath.BeautifyPath();
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path
|
||||
=> !Path.GetFileName(path)
|
||||
.Contains("bootstrapper")));
|
||||
|
||||
private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
|
||||
{
|
||||
|
@ -37,16 +49,26 @@ internal static class ParadoxLauncher
|
|||
{
|
||||
paradoxLauncher.ExtraDlc.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.ExtraSelectedDlc.Add(new(selection.Id, selection.Name, selection.SelectedDlc));
|
||||
paradoxLauncher.ExtraDlc.Add(
|
||||
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())
|
||||
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.ExtraSelectedDlc.Add(new(selection.Id, selection.Name, selection.AllDlc));
|
||||
paradoxLauncher.ExtraDlc.Add(
|
||||
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);
|
||||
return dialogForm.Show(SystemIcons.Warning,
|
||||
$"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;
|
||||
"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", "Paradox Launcher") != DialogResult.OK;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum RepairResult
|
||||
{
|
||||
ProgramRunning = -2,
|
||||
Failure,
|
||||
Unnecessary = 0,
|
||||
Success
|
||||
}
|
||||
|
||||
internal static async Task<RepairResult> Repair(Form form, ProgramSelection selection)
|
||||
{
|
||||
InstallForm installForm = form as InstallForm;
|
||||
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;
|
||||
bool smokeInstalled = false;
|
||||
byte[] steamOriginalSdk32 = null;
|
||||
|
@ -92,33 +108,39 @@ internal static class ParadoxLauncher
|
|||
foreach (string directory in selection.DllDirectories)
|
||||
{
|
||||
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.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 _);
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.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 _);
|
||||
smokeInstalled = smokeInstalled
|
||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled
|
||||
|| File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.Steamworks32)
|
||||
|| File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.Steamworks64);
|
||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled)
|
||||
|| (File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
||||
|| (File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.Steamworks64));
|
||||
await SmokeAPI.Uninstall(directory, deleteConfig: false);
|
||||
if (steamOriginalSdk32 is null && File.Exists(api32) && !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
||||
steamOriginalSdk32 = File.ReadAllBytes(api32);
|
||||
if (steamOriginalSdk64 is null && File.Exists(api64) && !api64.IsResourceFile(ResourceIdentifier.Steamworks64))
|
||||
steamOriginalSdk64 = File.ReadAllBytes(api64);
|
||||
if (steamOriginalSdk32 is null && File.Exists(api32)
|
||||
&& !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
|
||||
steamOriginalSdk32 = await File.ReadAllBytesAsync(api32);
|
||||
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);
|
||||
screamInstalled = screamInstalled
|
||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled
|
||||
|| File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32)
|
||||
|| File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64);
|
||||
|| File.Exists(api32_o) || File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled)
|
||||
|| (File.Exists(api32) && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
||||
|| (File.Exists(api64) && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64));
|
||||
await ScreamAPI.Uninstall(directory, deleteConfig: false);
|
||||
if (epicOriginalSdk32 is null && File.Exists(api32) && !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
||||
epicOriginalSdk32 = File.ReadAllBytes(api32);
|
||||
if (epicOriginalSdk64 is null && File.Exists(api64) && !api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
|
||||
epicOriginalSdk64 = File.ReadAllBytes(api64);
|
||||
if (epicOriginalSdk32 is null && File.Exists(api32)
|
||||
&& !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
|
||||
epicOriginalSdk32 = await File.ReadAllBytesAsync(api32);
|
||||
if (epicOriginalSdk64 is null && File.Exists(api64)
|
||||
&& !api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
|
||||
epicOriginalSdk64 = await File.ReadAllBytesAsync(api64);
|
||||
}
|
||||
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;
|
||||
foreach (string directory in selection.DllDirectories)
|
||||
|
@ -159,28 +181,26 @@ internal static class ParadoxLauncher
|
|||
if (installForm is not null)
|
||||
installForm.UpdateUser("Paradox Launcher successfully repaired!", LogTextBox.Success);
|
||||
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;
|
||||
}
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser("Paradox Launcher did not need to be repaired.", LogTextBox.Success);
|
||||
else
|
||||
{
|
||||
if (installForm is not null)
|
||||
installForm.UpdateUser("Paradox Launcher did not need to be repaired.", LogTextBox.Success);
|
||||
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;
|
||||
_ = dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK",
|
||||
customFormText: "Paradox Launcher");
|
||||
return RepairResult.Unnecessary;
|
||||
}
|
||||
_ = 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 CreamInstaller.Utility;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -14,6 +9,9 @@ using System.Net.Http;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller.Platforms.Steam;
|
||||
|
||||
|
@ -21,20 +19,33 @@ internal static class SteamCMD
|
|||
{
|
||||
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 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)
|
||||
? $@"@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";
|
||||
|
||||
private static readonly int[] locks = new int[ProcessLimit];
|
||||
internal static async Task<string> Run(string appId) => await Task.Run(() =>
|
||||
{
|
||||
wait_for_lock:
|
||||
wait_for_lock:
|
||||
if (Program.Canceled) return "";
|
||||
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 (appId is not null)
|
||||
if (AttemptCount.ContainsKey(appId))
|
||||
AttemptCount[appId]++;
|
||||
else
|
||||
AttemptCount[appId] = 0;
|
||||
{
|
||||
AttemptCount.TryGetValue(appId, out int count);
|
||||
AttemptCount[appId] = ++count;
|
||||
}
|
||||
if (Program.Canceled) return "";
|
||||
ProcessStartInfo processStartInfo = new()
|
||||
{
|
||||
FileName = FilePath,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
Arguments = appId is null ? "+quit" : GetArguments(appId),
|
||||
CreateNoWindow = true,
|
||||
StandardInputEncoding = Encoding.UTF8,
|
||||
StandardOutputEncoding = Encoding.UTF8,
|
||||
FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true,
|
||||
RedirectStandardError = true, UseShellExecute = false,
|
||||
Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
|
||||
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8,
|
||||
StandardErrorEncoding = Encoding.UTF8
|
||||
};
|
||||
Process process = Process.Start(processStartInfo);
|
||||
|
@ -96,7 +102,10 @@ internal static class SteamCMD
|
|||
_ = output.Clear();
|
||||
_ = appInfo.Clear();
|
||||
}
|
||||
else break;
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ = Interlocked.Decrement(ref locks[i]);
|
||||
|
@ -108,9 +117,6 @@ internal static class SteamCMD
|
|||
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)
|
||||
{
|
||||
await Cleanup();
|
||||
|
@ -118,7 +124,8 @@ internal static class SteamCMD
|
|||
{
|
||||
HttpClient httpClient = HttpClientManager.HttpClient;
|
||||
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);
|
||||
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
||||
File.Delete(ArchivePath);
|
||||
|
@ -127,9 +134,7 @@ internal static class SteamCMD
|
|||
{
|
||||
FileSystemWatcher watcher = new(DirectoryPath)
|
||||
{
|
||||
Filter = "*",
|
||||
IncludeSubdirectories = true,
|
||||
EnableRaisingEvents = true
|
||||
Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true
|
||||
};
|
||||
if (File.Exists(DllPath)) progress.Report(-15); // update (not used at the moment)
|
||||
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 () =>
|
||||
{
|
||||
if (!Directory.Exists(DirectoryPath)) return;
|
||||
|
@ -165,7 +164,8 @@ internal static class SteamCMD
|
|||
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.ntfs_transaction_failed"))
|
||||
File.Delete(file);
|
||||
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))
|
||||
Directory.Delete(DumpsPath, true);
|
||||
if (Directory.Exists(LogsPath))
|
||||
|
@ -181,21 +181,41 @@ internal static class SteamCMD
|
|||
if (Program.Canceled) return null;
|
||||
string output;
|
||||
string appUpdateFile = $@"{AppInfoPath}\{appId}.vdf";
|
||||
restart:
|
||||
restart:
|
||||
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
|
||||
{
|
||||
output = await Run(appId) ?? "";
|
||||
int openBracket = output.IndexOf("{");
|
||||
int closeBracket = output.LastIndexOf("}");
|
||||
if (output is not null && openBracket != -1 && closeBracket != -1 && closeBracket > openBracket)
|
||||
int openBracket = output.IndexOf("{", StringComparison.Ordinal);
|
||||
int closeBracket = output.LastIndexOf("}", StringComparison.Ordinal);
|
||||
if (openBracket != -1 && closeBracket != -1 && closeBracket > openBracket)
|
||||
{
|
||||
output = $"\"{appId}\"\n" + output[openBracket..(1 + closeBracket)];
|
||||
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 (!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");
|
||||
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 (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);
|
||||
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);
|
||||
goto restart;
|
||||
}
|
||||
|
@ -236,8 +258,10 @@ internal static class SteamCMD
|
|||
dlcIds.Add("" + appId);
|
||||
VToken depots = appInfo.Value.GetChild("depots");
|
||||
if (depots is not null)
|
||||
foreach (VProperty property in depots.Where(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))
|
||||
foreach (VProperty property in depots.Where(
|
||||
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);
|
||||
#pragma warning restore IDE0220 // Add explicit cast
|
||||
return dlcIds;
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Utility;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Steam;
|
||||
|
@ -18,34 +13,42 @@ namespace CreamInstaller.Platforms.Steam;
|
|||
internal static class SteamLibrary
|
||||
{
|
||||
private static string installPath;
|
||||
|
||||
internal static string InstallPath
|
||||
{
|
||||
get
|
||||
{
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath", null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath",
|
||||
null) as string;
|
||||
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath",
|
||||
null) as string;
|
||||
return installPath.BeautifyPath();
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
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> gameLibraryDirectories = await GetLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
if (Program.Canceled) return games;
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in (await GetGamesFromLibraryDirectory(libraryDirectory))
|
||||
.Where(game => !games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory)))
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in
|
||||
(await GetGamesFromLibraryDirectory(libraryDirectory))
|
||||
.Where(game => !games.Any(_game => _game.appId == game.appId
|
||||
&& _game.gameDirectory == game.gameDirectory)))
|
||||
games.Add(game);
|
||||
}
|
||||
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();
|
||||
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return games;
|
||||
|
@ -59,9 +62,9 @@ internal static class SteamLibrary
|
|||
string name = result.Value.GetChild("name")?.ToString();
|
||||
string buildId = result.Value.GetChild("buildid")?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(appId)
|
||||
|| string.IsNullOrWhiteSpace(installdir)
|
||||
|| string.IsNullOrWhiteSpace(name)
|
||||
|| string.IsNullOrWhiteSpace(buildId))
|
||||
|| string.IsNullOrWhiteSpace(installdir)
|
||||
|| string.IsNullOrWhiteSpace(name)
|
||||
|| string.IsNullOrWhiteSpace(buildId))
|
||||
continue;
|
||||
string gameDirectory = (libraryDirectory + @"\common\" + installdir).BeautifyPath();
|
||||
if (games.Any(g => g.appId == appId && g.gameDirectory == gameDirectory)) continue;
|
||||
|
@ -87,9 +90,11 @@ internal static class SteamLibrary
|
|||
{
|
||||
gameDirectories.Add(libraryFolder);
|
||||
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
|
||||
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();
|
||||
if (string.IsNullOrWhiteSpace(path)) continue;
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using CreamInstaller.Utility;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
#if DEBUG
|
||||
using System;
|
||||
#endif
|
||||
|
@ -16,6 +14,9 @@ namespace CreamInstaller.Platforms.Steam;
|
|||
|
||||
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(() =>
|
||||
{
|
||||
List<string> dlcIds = new();
|
||||
|
@ -25,17 +26,15 @@ internal static class SteamStore
|
|||
return dlcIds;
|
||||
});
|
||||
|
||||
private const int COOLDOWN_GAME = 600;
|
||||
private const int COOLDOWN_DLC = 1200;
|
||||
|
||||
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false)
|
||||
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false, int attempts = 0)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
string cacheFile = ProgramData.AppInfoPath + @$"\{appId}.json";
|
||||
bool cachedExists = File.Exists(cacheFile);
|
||||
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)
|
||||
{
|
||||
IDictionary<string, JToken> apps = (IDictionary<string, JToken>)JsonConvert.DeserializeObject(response);
|
||||
|
@ -50,7 +49,9 @@ internal static class SteamStore
|
|||
if (!appDetails.success)
|
||||
{
|
||||
#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
|
||||
if (data is null)
|
||||
return null;
|
||||
|
@ -59,13 +60,15 @@ internal static class SteamStore
|
|||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
|
||||
await File.WriteAllTextAsync(
|
||||
cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
|
||||
}
|
||||
catch
|
||||
#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
|
||||
{ }
|
||||
|
@ -73,18 +76,24 @@ internal static class SteamStore
|
|||
return data;
|
||||
}
|
||||
#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
|
||||
}
|
||||
#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
|
||||
}
|
||||
catch
|
||||
#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
|
||||
{ }
|
||||
|
@ -93,23 +102,26 @@ internal static class SteamStore
|
|||
else DebugForm.Current.Log("Response deserialization null for appid " + appId);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
else DebugForm.Current.Log("Response null for appid " + appId, LogTextBox.Warning);
|
||||
DebugForm.Current.Log("Response null for appid " + appId, LogTextBox.Warning);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (cachedExists)
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<AppData>(File.ReadAllText(cacheFile));
|
||||
return JsonConvert.DeserializeObject<AppData>(await File.ReadAllTextAsync(cacheFile));
|
||||
}
|
||||
catch
|
||||
{
|
||||
File.Delete(cacheFile);
|
||||
}
|
||||
if (!isDlc)
|
||||
if (!isDlc && attempts < 10)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
return await QueryStoreAPI(appId, isDlc);
|
||||
return await QueryStoreAPI(appId, isDlc, ++attempts);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Utility;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Ubisoft;
|
||||
|
@ -15,6 +11,7 @@ namespace CreamInstaller.Platforms.Ubisoft;
|
|||
internal static class UbisoftLibrary
|
||||
{
|
||||
private static RegistryKey installsKey;
|
||||
|
||||
internal static RegistryKey InstallsKey
|
||||
{
|
||||
get
|
||||
|
@ -25,21 +22,23 @@ internal static class UbisoftLibrary
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory) =>
|
||||
await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true));
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
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(() =>
|
||||
{
|
||||
List<(string gameId, string name, string gameDirectory)> games = new();
|
||||
RegistryKey installsKey = InstallsKey;
|
||||
if (installsKey is null) return games;
|
||||
foreach (string gameId in installsKey.GetSubKeyNames())
|
||||
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames() => await Task.Run(
|
||||
() =>
|
||||
{
|
||||
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;
|
||||
});
|
||||
List<(string gameId, string name, string gameDirectory)> games = new();
|
||||
RegistryKey installsKey = InstallsKey;
|
||||
if (installsKey is null) return games;
|
||||
foreach (string gameId in installsKey.GetSubKeyNames())
|
||||
{
|
||||
RegistryKey installKey = installsKey.OpenSubKey(gameId);
|
||||
string installDir = installKey?.GetValue("InstallDir")?.ToString()?.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.Diagnostics;
|
||||
using System.Drawing;
|
||||
|
@ -9,6 +6,9 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Platforms.Steam;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
|
@ -46,7 +46,8 @@ internal static class Program
|
|||
if (ProtectedGames.Contains(name)) return true;
|
||||
if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
|
||||
foreach (string path in ProtectedGameDirectories)
|
||||
if (Directory.Exists(directory + path)) return true;
|
||||
if (Directory.Exists(directory + path))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -56,12 +57,15 @@ internal static class Program
|
|||
{
|
||||
using DialogForm dialogForm = new(form);
|
||||
if (dialogForm.Show(SystemIcons.Error,
|
||||
$"ERROR: {selection.Name} is currently running!" +
|
||||
"\n\nPlease close the program/game to continue . . . ",
|
||||
"Retry", "Cancel") == DialogResult.OK)
|
||||
$"ERROR: {selection.Name} is currently running!" +
|
||||
"\n\nPlease close the program/game to continue . . . ",
|
||||
"Retry", "Cancel") == DialogResult.OK)
|
||||
return IsProgramRunningDialog(form, selection);
|
||||
}
|
||||
else return true;
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -74,11 +78,12 @@ internal static class Program
|
|||
_ = Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.ApplicationExit += new(OnApplicationExit);
|
||||
Application.ThreadException += new((s, e) => e.Exception?.HandleFatalException());
|
||||
Application.ApplicationExit += OnApplicationExit;
|
||||
Application.ThreadException += (s, e) => e.Exception?.HandleFatalException();
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
AppDomain.CurrentDomain.UnhandledException += new((s, e) => (e.ExceptionObject as Exception)?.HandleFatalException());
|
||||
retry:
|
||||
AppDomain.CurrentDomain.UnhandledException += (s, e)
|
||||
=> (e.ExceptionObject as Exception)?.HandleFatalException();
|
||||
retry:
|
||||
try
|
||||
{
|
||||
HttpClientManager.Setup();
|
||||
|
@ -99,6 +104,7 @@ internal static class Program
|
|||
}
|
||||
|
||||
internal static bool Canceled;
|
||||
|
||||
internal static async void Cleanup(bool cancel = true)
|
||||
{
|
||||
Canceled = cancel;
|
||||
|
|
|
@ -1,28 +1,21 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Resources;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Resources;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
public enum Platform
|
||||
{
|
||||
None = 0,
|
||||
Paradox,
|
||||
Steam,
|
||||
Epic,
|
||||
Ubisoft
|
||||
None = 0, Paradox, Steam,
|
||||
Epic, Ubisoft
|
||||
}
|
||||
|
||||
public enum DlcType
|
||||
{
|
||||
Steam,
|
||||
SteamHidden,
|
||||
EpicCatalogItem,
|
||||
Steam, SteamHidden, EpicCatalogItem,
|
||||
EpicEntitlement
|
||||
}
|
||||
|
||||
|
@ -49,11 +42,17 @@ internal class ProgramSelection
|
|||
internal List<(string directory, BinaryType binaryType)> ExecutableDirectories;
|
||||
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)> SelectedDlc = new(PlatformIdComparer.String);
|
||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
|
||||
= 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 readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc
|
||||
= 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
|
||||
{
|
||||
|
@ -63,49 +62,54 @@ internal class ProgramSelection
|
|||
{
|
||||
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()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
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()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked()
|
||||
|| cache.IsFilePathLocked())
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked()
|
||||
|| cache.IsFilePathLocked())
|
||||
return true;
|
||||
}
|
||||
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()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
return true;
|
||||
}
|
||||
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()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
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()
|
||||
|| old_api64.IsFilePathLocked()
|
||||
|| api32.IsFilePathLocked()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
|| old_api64.IsFilePathLocked()
|
||||
|| api32.IsFilePathLocked()
|
||||
|| api32_o.IsFilePathLocked()
|
||||
|| api64.IsFilePathLocked()
|
||||
|| api64_o.IsFilePathLocked()
|
||||
|| config.IsFilePathLocked())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +168,8 @@ internal class ProgramSelection
|
|||
|
||||
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();
|
||||
|
||||
|
@ -172,12 +177,15 @@ internal class ProgramSelection
|
|||
|
||||
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 (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 null;
|
||||
}
|
||||
|
|
40
CreamInstaller/Properties/Resources.Designer.cs
generated
40
CreamInstaller/Properties/Resources.Designer.cs
generated
|
@ -8,10 +8,16 @@
|
|||
// </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 {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
|
@ -19,27 +25,27 @@ namespace CreamInstaller.Properties {
|
|||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[DebuggerNonUserCode()]
|
||||
[CompilerGenerated()]
|
||||
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() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
internal static ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CreamInstaller.Properties.Resources", typeof(Resources).Assembly);
|
||||
if (ReferenceEquals(resourceMan, null)) {
|
||||
ResourceManager temp = new ResourceManager("CreamInstaller.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
|
@ -50,8 +56,8 @@ namespace CreamInstaller.Properties {
|
|||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
internal static CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
|
@ -63,10 +69,10 @@ namespace CreamInstaller.Properties {
|
|||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon Icon {
|
||||
internal static Icon Icon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("Icon", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
return ((Icon)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,35 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class Koaloader
|
||||
{
|
||||
internal static void GetKoaloaderComponents(
|
||||
this string directory,
|
||||
out List<string> proxies,
|
||||
out string config
|
||||
)
|
||||
internal static readonly List<(string unlocker, string dll)> AutoLoadDlls = new()
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
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)..];
|
||||
baseIdentifier = baseIdentifier[..baseIdentifier.IndexOf('.')];
|
||||
proxyName = baseIdentifier[..baseIdentifier.LastIndexOf('_')];
|
||||
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)
|
||||
{
|
||||
directory.GetKoaloaderComponents(out _, out string config);
|
||||
|
@ -78,11 +83,13 @@ internal static class Koaloader
|
|||
else if (File.Exists(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(" \"logging\": false,");
|
||||
|
@ -96,12 +103,14 @@ internal static class Koaloader
|
|||
{
|
||||
string path = pair.Value;
|
||||
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(" ]");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"targets\": []");
|
||||
}
|
||||
if (modules.Any())
|
||||
{
|
||||
writer.WriteLine(" \"modules\": [");
|
||||
|
@ -110,37 +119,41 @@ internal static class Koaloader
|
|||
{
|
||||
string path = pair.Value;
|
||||
writer.WriteLine(" {");
|
||||
writer.WriteLine($" \"path\": \"" + path + "\",");
|
||||
writer.WriteLine($" \"required\": true");
|
||||
writer.WriteLine(" \"path\": \"" + path + "\",");
|
||||
writer.WriteLine(" \"required\": true");
|
||||
writer.WriteLine(" }" + (pair.Equals(lastModule) ? "" : ","));
|
||||
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, info: false);
|
||||
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, false);
|
||||
}
|
||||
writer.WriteLine(" ]");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"modules\": []");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(async () =>
|
||||
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);
|
||||
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);
|
||||
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
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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 ScreamAPI.Uninstall(directory, installForm, deleteConfig);
|
||||
|
@ -150,20 +163,26 @@ internal static class Koaloader
|
|||
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);
|
||||
string proxy = selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy;
|
||||
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);
|
||||
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))
|
||||
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);
|
||||
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;
|
||||
foreach (string executable in Directory.EnumerateFiles(directory, "*.exe"))
|
||||
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
|
||||
|
@ -185,12 +204,15 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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)
|
||||
{
|
||||
|
@ -200,12 +222,15 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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);
|
||||
}
|
||||
|
@ -219,12 +244,15 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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)
|
||||
{
|
||||
|
@ -234,12 +262,15 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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);
|
||||
}
|
||||
|
@ -253,12 +284,16 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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)
|
||||
{
|
||||
|
@ -268,12 +303,16 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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);
|
||||
if (bit32)
|
||||
|
@ -284,12 +323,16 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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)
|
||||
{
|
||||
|
@ -299,12 +342,16 @@ internal static class Koaloader
|
|||
if (File.Exists(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";
|
||||
}
|
||||
"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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using CreamInstaller.Utility;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -9,12 +7,14 @@ using System.Runtime.InteropServices;
|
|||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
internal static List<string> embeddedResources;
|
||||
|
||||
internal static List<string> EmbeddedResources
|
||||
{
|
||||
get
|
||||
|
@ -22,7 +22,7 @@ internal static class Resources
|
|||
if (embeddedResources is null)
|
||||
{
|
||||
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
embeddedResources = new();
|
||||
embeddedResources = new List<string>();
|
||||
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.")))
|
||||
embeddedResources.Add(resourceName[25..]);
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ internal static class Resources
|
|||
|
||||
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);
|
||||
resource.CopyTo(file);
|
||||
}
|
||||
|
@ -62,55 +63,59 @@ internal static class Resources
|
|||
|
||||
internal enum BinaryType
|
||||
{
|
||||
Unknown = -1,
|
||||
BIT32 = 0,
|
||||
DOS = 1,
|
||||
WOW = 2,
|
||||
PIF = 3,
|
||||
POSIX = 4,
|
||||
OS216 = 5,
|
||||
BIT64 = 6,
|
||||
Unknown = -1, BIT32 = 0, DOS = 1,
|
||||
WOW = 2, PIF = 3, POSIX = 4,
|
||||
OS216 = 5, BIT64 = 6
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
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) =>
|
||||
await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon: filterCommon, validFunc: validFunc)
|
||||
?? (filterCommon || validFunc is not null ? await rootDirectory.GetExecutables() : null))?.Select(e =>
|
||||
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) =>
|
||||
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);
|
||||
return e;
|
||||
})?.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(() =>
|
||||
{
|
||||
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 }))
|
||||
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(
|
||||
this string rootDirectory, bool filterCommon = false, Func<string, bool> validFunc = null) => await Task.Run(
|
||||
() =>
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
if (!executables.Any(e => e.path == path)
|
||||
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
||||
&& (validFunc is null || validFunc(path))
|
||||
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64)
|
||||
executables.Add((path, binaryType));
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", new EnumerationOptions() { RecurseSubdirectories = true }))
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
if (!executables.Any(e => e.path == path)
|
||||
&& (!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;
|
||||
});
|
||||
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;
|
||||
if (!executables.Any(e => e.path == path)
|
||||
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
|
||||
&& (validFunc is null || validFunc(path))
|
||||
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64)
|
||||
executables.Add((path, binaryType));
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe",
|
||||
new EnumerationOptions { RecurseSubdirectories = true }))
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
if (!executables.Any(e => e.path == path)
|
||||
&& (!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)
|
||||
{
|
||||
|
@ -118,69 +123,77 @@ internal static class Resources
|
|||
return subPath.Contains("SETUP")
|
||||
|| subPath.Contains("REDIST")
|
||||
|| 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("CEFPROCESS")
|
||||
|| subPath.Contains("ZFGAMEBROWSER")
|
||||
|| subPath.Contains("MONO")
|
||||
|| subPath.Contains("PLUGINS")
|
||||
|| subPath.Contains("MODDING")
|
||||
|| subPath.Contains("MOD") && subPath.Contains("MANAGER")
|
||||
|| (subPath.Contains("MOD") && subPath.Contains("MANAGER"))
|
||||
|| subPath.Contains("BATTLEYE")
|
||||
|| 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();
|
||||
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;
|
||||
string subDirectory = directory.BeautifyPath();
|
||||
if (!dllDirectories.Contains(subDirectory))
|
||||
{
|
||||
bool koaloaderInstalled = Koaloader.AutoLoadDlls
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
||||
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
|
||||
.Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile());
|
||||
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)
|
||||
|| File.Exists(api_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled
|
||||
|| File.Exists(cache) && !koaloaderInstalled)
|
||||
|| File.Exists(api_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled)
|
||||
|| (File.Exists(cache) && !koaloaderInstalled))
|
||||
dllDirectories.Add(subDirectory);
|
||||
}
|
||||
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)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled))
|
||||
dllDirectories.Add(subDirectory);
|
||||
}
|
||||
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)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled))
|
||||
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)
|
||||
|| File.Exists(old_api64)
|
||||
|| File.Exists(api32)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| File.Exists(config) && !koaloaderInstalled)
|
||||
|| File.Exists(old_api64)
|
||||
|| File.Exists(api32)
|
||||
|| File.Exists(api32_o)
|
||||
|| File.Exists(api64)
|
||||
|| File.Exists(api64_o)
|
||||
|| (File.Exists(config) && !koaloaderInstalled))
|
||||
dllDirectories.Add(subDirectory);
|
||||
}
|
||||
}
|
||||
|
@ -189,10 +202,10 @@ internal static class Resources
|
|||
});
|
||||
|
||||
internal static void GetCreamApiComponents(
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config)
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config)
|
||||
{
|
||||
api32 = directory + @"\steam_api.dll";
|
||||
api32_o = directory + @"\steam_api_o.dll";
|
||||
|
@ -203,22 +216,15 @@ internal static class Resources
|
|||
|
||||
internal enum ResourceIdentifier
|
||||
{
|
||||
Koaloader,
|
||||
Steamworks32,
|
||||
Steamworks64,
|
||||
EpicOnlineServices32,
|
||||
EpicOnlineServices64,
|
||||
Uplay32,
|
||||
Uplay64,
|
||||
Upc32,
|
||||
Upc64,
|
||||
Koaloader, Steamworks32, Steamworks64,
|
||||
EpicOnlineServices32, EpicOnlineServices64, Uplay32,
|
||||
Uplay64, Upc32, Upc64
|
||||
}
|
||||
|
||||
internal static readonly Dictionary<ResourceIdentifier, IReadOnlyList<string>> ResourceMD5s = new()
|
||||
{
|
||||
{
|
||||
ResourceIdentifier.Koaloader,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Koaloader, new List<string>
|
||||
{
|
||||
"8A0958687B5ED7C34DAD037856DD1530", // Koaloader v2.0.0
|
||||
"8FECDEB40980F4E687C10E056232D96B", // Koaloader v2.0.0
|
||||
|
@ -463,75 +469,67 @@ internal static class Resources
|
|||
"76CAB00C7DD33FC19F7CDD1849FF9CA2", // Koaloader v2.4.0
|
||||
"DA4D6A7C0872757A74DDAE05A2C1D160", // Koaloader v2.4.0
|
||||
"1F46DE8747C0A157841AFFE6185CE4C9", // Koaloader v2.4.0
|
||||
"BE16B588D018D8EFF1F3B6A600F26BED" // Koaloader v2.4.0
|
||||
"BE16B588D018D8EFF1F3B6A600F26BED" // Koaloader v2.4.0
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.EpicOnlineServices32,
|
||||
new List<string>()
|
||||
ResourceIdentifier.EpicOnlineServices32, new List<string>
|
||||
{
|
||||
"069A57B1834A960193D2AD6B96926D70", // ScreamAPI v3.0.0
|
||||
"E2FB3A4A9583FDC215832E5F935E4440" // ScreamAPI v3.0.1
|
||||
"E2FB3A4A9583FDC215832E5F935E4440" // ScreamAPI v3.0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.EpicOnlineServices64,
|
||||
new List<string>()
|
||||
ResourceIdentifier.EpicOnlineServices64, new List<string>
|
||||
{
|
||||
"0D62E57139F1A64F807A9934946A9474", // ScreamAPI v3.0.0
|
||||
"3875C7B735EE80C23239CC4749FDCBE6" // ScreamAPI v3.0.1
|
||||
"3875C7B735EE80C23239CC4749FDCBE6" // ScreamAPI v3.0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Steamworks32,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Steamworks32, new List<string>
|
||||
{
|
||||
"02594110FE56B2945955D46670B9A094", // CreamAPI v4.5.0.0 Hotfix
|
||||
"B2434578957CBE38BDCE0A671C1262FC", // SmokeAPI v1.0.0
|
||||
"973AB1632B747D4BF3B2666F32E34327", // SmokeAPI v1.0.1
|
||||
"C7E41F569FC6A347D67D2BFB2BD10F25", // SmokeAPI v1.0.2
|
||||
"F9E7D5B248B86D1C2F2F2905A9F37755" // SmokeAPI v1.0.3
|
||||
"F9E7D5B248B86D1C2F2F2905A9F37755" // SmokeAPI v1.0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Steamworks64,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Steamworks64, new List<string>
|
||||
{
|
||||
"30091B91923D9583A54A93ED1145554B", // CreamAPI v4.5.0.0 Hotfix
|
||||
"08713035CAD6F52548FF324D0487B88D", // SmokeAPI v1.0.0
|
||||
"D077737B9979D32458AC938A2978FA3C", // SmokeAPI v1.0.1
|
||||
"49122A2E2E51CBB0AE5E1D59B280E4CD", // SmokeAPI v1.0.2
|
||||
"13F3E9476116F7670E21365A400357AC" // SmokeAPI v1.0.3
|
||||
"13F3E9476116F7670E21365A400357AC" // SmokeAPI v1.0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Uplay32,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Uplay32, new List<string>
|
||||
{
|
||||
"1977967B2549A38EC2DB39D4C8ED499B" // Uplay R1 Unlocker v2.0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Uplay64,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Uplay64, new List<string>
|
||||
{
|
||||
"333FEDD9DC2B299419B37ED1624FF8DB" // Uplay R1 Unlocker v2.0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Upc32,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Upc32, new List<string>
|
||||
{
|
||||
"C14368BC4EE19FDE8DBAC07E31C67AE4", // Uplay R2 Unlocker v3.0.0
|
||||
"DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
|
||||
"DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Upc64,
|
||||
new List<string>()
|
||||
ResourceIdentifier.Upc64, new List<string>
|
||||
{
|
||||
"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();
|
||||
}
|
||||
|
||||
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 CreamInstaller.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class ScreamAPI
|
||||
{
|
||||
internal static void GetScreamApiComponents(
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config
|
||||
)
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config
|
||||
)
|
||||
{
|
||||
api32 = directory + @"\EOSSDK-Win32-Shipping.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)
|
||||
{
|
||||
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);
|
||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideCatalogItems
|
||||
= 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);
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> entitlements = 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)
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> entitlements
|
||||
= 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));
|
||||
if (overrideCatalogItems.Any() || entitlements.Any())
|
||||
{
|
||||
|
@ -41,20 +45,27 @@ internal static class ScreamAPI
|
|||
File.Create(config).Close();
|
||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||
WriteConfig(writer,
|
||||
new(overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
new(entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
installForm);
|
||||
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||
overrideCatalogItems.ToDictionary(pair => pair.Key, pair => pair.Value),
|
||||
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.Close();
|
||||
}
|
||||
else if (File.Exists(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(" \"version\": 2,");
|
||||
|
@ -66,18 +77,22 @@ internal static class ScreamAPI
|
|||
if (overrideCatalogItems.Any())
|
||||
{
|
||||
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)
|
||||
{
|
||||
string id = pair.Key;
|
||||
(_, string name, _) = pair.Value;
|
||||
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(" ]");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"override\": []");
|
||||
}
|
||||
writer.WriteLine(" },");
|
||||
writer.WriteLine(" \"entitlements\": {");
|
||||
writer.WriteLine(" \"unlock_all\": true,");
|
||||
|
@ -91,68 +106,79 @@ internal static class ScreamAPI
|
|||
string id = pair.Key;
|
||||
(_, string name, _) = pair.Value;
|
||||
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(" ]");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"inject\": []");
|
||||
}
|
||||
writer.WriteLine(" }");
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
||||
if (File.Exists(api32_o))
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
||||
if (File.Exists(api32))
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
if (File.Exists(api64))
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
File.Delete(api64);
|
||||
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
if (File.Exists(api64))
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
});
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", 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.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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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)
|
||||
CheckConfig(directory, selection, installForm);
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class SmokeAPI
|
||||
{
|
||||
internal static void GetSmokeApiComponents(
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config,
|
||||
out string cache)
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config,
|
||||
out string cache)
|
||||
{
|
||||
api32 = directory + @"\steam_api.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)
|
||||
{
|
||||
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);
|
||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideDlc
|
||||
= 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);
|
||||
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))
|
||||
{
|
||||
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)
|
||||
injectDlc = injectDlc.Concat(extraDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
|
||||
}
|
||||
|
@ -47,20 +51,26 @@ internal static class SmokeAPI
|
|||
File.Create(config).Close();
|
||||
StreamWriter writer = new(config, true, Encoding.UTF8);
|
||||
WriteConfig(writer,
|
||||
new(overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
new(injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
installForm);
|
||||
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||
overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
new SortedList<string, (DlcType type, string name, string icon)>(
|
||||
injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
|
||||
installForm);
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
else if (File.Exists(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(" \"$version\": 1,");
|
||||
|
@ -76,12 +86,15 @@ internal static class SmokeAPI
|
|||
string dlcId = pair.Key;
|
||||
(_, string dlcName, _) = pair.Value;
|
||||
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(" ],");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"override\": [],");
|
||||
}
|
||||
if (injectDlc.Count > 0)
|
||||
{
|
||||
writer.WriteLine(" \"dlc_ids\": [");
|
||||
|
@ -91,86 +104,101 @@ internal static class SmokeAPI
|
|||
string dlcId = pair.Key;
|
||||
(_, string dlcName, _) = pair.Value;
|
||||
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(" ],");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"dlc_ids\": [],");
|
||||
}
|
||||
writer.WriteLine(" \"auto_inject_inventory\": true,");
|
||||
writer.WriteLine(" \"inventory_items\": []");
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
|
||||
if (File.Exists(oldConfig))
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
File.Delete(oldConfig);
|
||||
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
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))
|
||||
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
|
||||
if (File.Exists(oldConfig))
|
||||
{
|
||||
File.Delete(api32);
|
||||
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
||||
File.Delete(oldConfig);
|
||||
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}",
|
||||
LogTextBox.Action, false);
|
||||
}
|
||||
File.Move(api32_o, api32);
|
||||
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
if (File.Exists(api64))
|
||||
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))
|
||||
{
|
||||
File.Delete(api64);
|
||||
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
if (File.Exists(api32))
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (deleteConfig && File.Exists(cache))
|
||||
{
|
||||
File.Delete(cache);
|
||||
installForm?.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
});
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
if (File.Exists(api64))
|
||||
{
|
||||
File.Delete(api64);
|
||||
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
|
||||
}
|
||||
File.Move(api64_o, api64);
|
||||
installForm?.UpdateUser(
|
||||
$"Restored Steamworks: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action,
|
||||
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);
|
||||
if (File.Exists(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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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)
|
||||
CheckConfig(directory, selection, installForm);
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class UplayR1
|
||||
{
|
||||
internal static void GetUplayR1Components(
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config
|
||||
)
|
||||
this string directory,
|
||||
out string api32, out string api32_o,
|
||||
out string api64, out string api64_o,
|
||||
out string config
|
||||
)
|
||||
{
|
||||
api32 = directory + @"\uplay_r1_loader.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)
|
||||
{
|
||||
directory.GetUplayR1Components(out _, out _, out _, out _, out string config);
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
|
||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc
|
||||
= 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);
|
||||
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);*/
|
||||
File.Create(config).Close();
|
||||
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.Close();
|
||||
}
|
||||
else if (File.Exists(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(" \"logging\": false,");
|
||||
|
@ -63,67 +71,80 @@ internal static class UplayR1
|
|||
string dlcId = pair.Key;
|
||||
(_, string dlcName, _) = pair.Value;
|
||||
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(" ],");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"blacklist\": [],");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
|
||||
if (File.Exists(api32_o))
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, info: false);
|
||||
if (File.Exists(api32))
|
||||
{
|
||||
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);
|
||||
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))
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
File.Delete(api64);
|
||||
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
if (File.Exists(api64))
|
||||
{
|
||||
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);
|
||||
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
});
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", 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.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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
"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)
|
||||
CheckConfig(directory, selection, installForm);
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
|
||||
namespace CreamInstaller.Resources;
|
||||
|
||||
internal static class UplayR2
|
||||
{
|
||||
internal static void GetUplayR2Components(
|
||||
this string directory,
|
||||
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)
|
||||
this string directory,
|
||||
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)
|
||||
{
|
||||
old_api32 = directory + @"\uplay_r2_loader.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)
|
||||
{
|
||||
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);
|
||||
foreach ((string id, string name, SortedList<string, (DlcType type, string name, string icon)> extraDlc) in selection.ExtraSelectedDlc)
|
||||
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc
|
||||
= 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);
|
||||
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);*/
|
||||
File.Create(config).Close();
|
||||
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.Close();
|
||||
}
|
||||
else if (File.Exists(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(" \"logging\": false,");
|
||||
|
@ -67,71 +75,84 @@ internal static class UplayR2
|
|||
string dlcId = pair.Key;
|
||||
(_, string dlcName, _) = pair.Value;
|
||||
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(" ],");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine(" \"blacklist\": [],");
|
||||
}
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true) => await Task.Run(() =>
|
||||
{
|
||||
directory.GetUplayR2Components(out string old_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))
|
||||
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteConfig = true)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
string api = File.Exists(old_api32) ? old_api32 : api32;
|
||||
if (File.Exists(api))
|
||||
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))
|
||||
{
|
||||
File.Delete(api);
|
||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
||||
string api = File.Exists(old_api32) ? old_api32 : api32;
|
||||
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);
|
||||
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))
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
File.Delete(api);
|
||||
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
||||
string api = File.Exists(old_api64) ? old_api64 : api64;
|
||||
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);
|
||||
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, info: false);
|
||||
}
|
||||
});
|
||||
if (deleteConfig && File.Exists(config))
|
||||
{
|
||||
File.Delete(config);
|
||||
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", 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.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;
|
||||
if (File.Exists(api) && !File.Exists(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))
|
||||
{
|
||||
"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;
|
||||
if (File.Exists(api) && !File.Exists(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))
|
||||
{
|
||||
"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)
|
||||
CheckConfig(directory, selection, installForm);
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
using Microsoft.Win32;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class Diagnostics
|
||||
{
|
||||
private static string notepadPlusPlusPath;
|
||||
|
||||
internal static string NotepadPlusPlusPath
|
||||
{
|
||||
get
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -34,29 +35,18 @@ internal static class Diagnostics
|
|||
OpenFileInWindowsNotepad(path);
|
||||
}
|
||||
|
||||
private static void OpenFileInNotepadPlusPlus(string npp, string path) => Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = npp,
|
||||
Arguments = path
|
||||
});
|
||||
private static void OpenFileInNotepadPlusPlus(string npp, string path)
|
||||
=> Process.Start(new ProcessStartInfo { FileName = npp, Arguments = path });
|
||||
|
||||
private static void OpenFileInWindowsNotepad(string path) => Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "notepad.exe",
|
||||
Arguments = path
|
||||
});
|
||||
private static void OpenFileInWindowsNotepad(string path)
|
||||
=> Process.Start(new ProcessStartInfo { FileName = "notepad.exe", Arguments = path });
|
||||
|
||||
internal static void OpenDirectoryInFileExplorer(string path) => Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "explorer.exe",
|
||||
Arguments = path
|
||||
});
|
||||
internal static void OpenDirectoryInFileExplorer(string path)
|
||||
=> Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = path });
|
||||
|
||||
internal static void OpenUrlInInternetBrowser(string url) => Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = url,
|
||||
UseShellExecute = true
|
||||
});
|
||||
internal static void OpenUrlInInternetBrowser(string url)
|
||||
=> Process.Start(new ProcessStartInfo { 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.Text;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Forms;
|
||||
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
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";
|
||||
StringBuilder output = new();
|
||||
|
@ -21,35 +23,40 @@ internal static class ExceptionHandler
|
|||
string[] stackTrace = e.StackTrace?.Split('\n');
|
||||
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++)
|
||||
{
|
||||
string line = stackTrace[i];
|
||||
int atNum = line.IndexOf("at ");
|
||||
int inNum = line.IndexOf("in ");
|
||||
int ciNum = line.LastIndexOf(@"CreamInstaller\");
|
||||
int lineNum = line.LastIndexOf(":line ");
|
||||
if (line is not null && atNum != -1)
|
||||
int atNum = line.IndexOf("at ", StringComparison.Ordinal);
|
||||
int inNum = line.IndexOf("in ", StringComparison.Ordinal);
|
||||
int ciNum = line.LastIndexOf(@"CreamInstaller\", StringComparison.Ordinal);
|
||||
int lineNum = line.LastIndexOf(":line ", StringComparison.Ordinal);
|
||||
if (atNum != -1)
|
||||
_ = output.Append("\n " + (inNum != -1 ? line[atNum..(inNum - 1)] : line[atNum..])
|
||||
+ (inNum != -1 ? ("\n "
|
||||
+ (ciNum != -1 ? ("in "
|
||||
+ (lineNum != -1 ? line[ciNum..lineNum]
|
||||
+ "\n on " + line[(lineNum + 1)..]
|
||||
: line[ciNum..]))
|
||||
: line[inNum..]))
|
||||
: null));
|
||||
+ (inNum != -1
|
||||
? "\n "
|
||||
+ (ciNum != -1
|
||||
? "in "
|
||||
+ (lineNum != -1
|
||||
? line[ciNum..lineNum]
|
||||
+ "\n on " + line[(lineNum + 1)..]
|
||||
: line[ciNum..])
|
||||
: line[inNum..])
|
||||
: null));
|
||||
}
|
||||
}
|
||||
e = e.InnerException;
|
||||
stackDepth++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
Application.Restart();
|
||||
Application.Exit();
|
||||
|
@ -58,14 +65,12 @@ internal static class ExceptionHandler
|
|||
|
||||
public class CustomMessageException : Exception
|
||||
{
|
||||
private readonly string message;
|
||||
public override string Message => message;
|
||||
public CustomMessageException() => Message = "CustomMessageException";
|
||||
|
||||
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 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.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using HtmlAgilityPack;
|
||||
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class HttpClientManager
|
||||
{
|
||||
internal static HttpClient HttpClient;
|
||||
|
||||
internal static void Setup()
|
||||
{
|
||||
HttpClient = new();
|
||||
HttpClient = new HttpClient();
|
||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Program.Version.Replace(".", "")}");
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ internal static class HttpClientManager
|
|||
try
|
||||
{
|
||||
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();
|
||||
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);
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -12,17 +12,21 @@ internal static class IconGrabber
|
|||
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 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 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.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CreamInstaller.Utility;
|
||||
|
||||
internal static class ProgramData
|
||||
{
|
||||
internal static readonly string DirectoryPathOld = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CreamInstaller";
|
||||
internal static readonly string DirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
|
||||
internal static readonly string DirectoryPathOld
|
||||
= 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 AppInfoVersionPath = AppInfoPath + @"\version.txt";
|
||||
|
@ -34,7 +37,9 @@ internal static class ProgramData
|
|||
Directory.Move(DirectoryPathOld, 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);
|
||||
_ = Directory.CreateDirectory(AppInfoPath);
|
||||
|
@ -55,23 +60,23 @@ internal static class ProgramData
|
|||
SetCooldown(identifier, now);
|
||||
return cooldownOver;
|
||||
}
|
||||
|
||||
private static DateTime? GetCooldown(string identifier)
|
||||
{
|
||||
if (Directory.Exists(CooldownPath))
|
||||
{
|
||||
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
||||
if (File.Exists(cooldownFile))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DateTime.TryParse(File.ReadAllText(cooldownFile), out DateTime cooldown))
|
||||
return cooldown;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void SetCooldown(string identifier, DateTime time)
|
||||
{
|
||||
if (!Directory.Exists(CooldownPath))
|
||||
|
@ -79,7 +84,7 @@ internal static class ProgramData
|
|||
string cooldownFile = CooldownPath + @$"\{identifier}.txt";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(cooldownFile, time.ToString());
|
||||
File.WriteAllText(cooldownFile, time.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
@ -90,13 +95,15 @@ internal static class ProgramData
|
|||
try
|
||||
{
|
||||
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
|
||||
{
|
||||
return new();
|
||||
return new List<(Platform platform, string id)>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteProgramChoices(List<(Platform platform, string id)> choices)
|
||||
{
|
||||
try
|
||||
|
@ -115,13 +122,15 @@ internal static class ProgramData
|
|||
try
|
||||
{
|
||||
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
|
||||
{
|
||||
return new();
|
||||
return new List<(Platform platform, string gameId, string dlcId)>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteDlcChoices(List<(Platform platform, string gameId, string dlcId)> choices)
|
||||
{
|
||||
try
|
||||
|
@ -140,15 +149,18 @@ internal static class ProgramData
|
|||
try
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue