This commit is contained in:
pointfeev 2023-01-05 13:22:44 -05:00
parent 0e48a18eee
commit 05e2ea5519
32 changed files with 1391 additions and 1735 deletions

View file

@ -21,31 +21,25 @@ internal class ContextMenuItem : ToolStripMenuItem
OnClickEvent = onClick;
}
internal ContextMenuItem(string text, string imageIdentifier, EventHandler onClick = null)
: this(text, onClick) => _ = TryImageIdentifier(this, imageIdentifier);
internal ContextMenuItem(string text, string imageIdentifier, EventHandler onClick = null) : this(text, onClick)
=> _ = TryImageIdentifier(this, imageIdentifier);
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, 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));
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run(
async () =>
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier)
=> await Task.Run(async () =>
{
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null)
{
item.Image = image;
}
else
{
switch (imageIdentifier)
@ -68,28 +62,22 @@ internal class ContextMenuItem : ToolStripMenuItem
image = IconGrabber.GetFileExplorerImage();
break;
case "SteamDB":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("steamdb.info"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("steamdb.info"));
break;
case "Steam Store":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("store.steampowered.com"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("store.steampowered.com"));
break;
case "Steam Community":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("steamcommunity.com"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("steamcommunity.com"));
break;
case "ScreamDB":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("scream-db.web.app"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("scream-db.web.app"));
break;
case "Epic Games":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("epicgames.com"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("epicgames.com"));
break;
case "Ubisoft Store":
image = await HttpClientManager.GetImageFromUrl(
IconGrabber.GetDomainFaviconUrl("store.ubi.com"));
image = await HttpClientManager.GetImageFromUrl(IconGrabber.GetDomainFaviconUrl("store.ubi.com"));
break;
default:
return;
@ -102,16 +90,13 @@ internal class ContextMenuItem : ToolStripMenuItem
}
});
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;
}
else
{
image = await HttpClientManager.GetImageFromUrl(iconUrl);
@ -121,16 +106,15 @@ internal class ContextMenuItem : ToolStripMenuItem
item.Image = image;
}
else if (onFail is not null)
{
onFail();
}
}
});
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
if (OnClickEvent is null) return;
if (OnClickEvent is null)
return;
OnClickEvent.Invoke(this, e);
}
}

View file

@ -60,17 +60,13 @@ internal class CustomForm : Form
_ = 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"
+ "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"
+ "\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"
+ "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"
@ -80,14 +76,11 @@ internal class CustomForm : Form
+ " 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"
+ " 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"
+ " 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"
+ "\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}).");
}
@ -96,8 +89,7 @@ internal class CustomForm : Form
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy,
uint uFlags);
internal static extern void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
internal void BringToFrontWithoutActivation()
{
@ -113,12 +105,13 @@ internal class CustomForm : Form
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 Point(X, Y);
Location = new(X, Y);
}
private void OnKeyPress(object s, KeyPressEventArgs e)
{
if (e.KeyChar != 'S') return; // Shift + S
if (e.KeyChar != 'S')
return; // Shift + S
UpdateBounds();
Rectangle bounds = Bounds;
using Bitmap bitmap = new(Size.Width - 14, Size.Height - 7);
@ -127,8 +120,7 @@ internal class CustomForm : Form
using EncoderParameters encoding = new(1);
using EncoderParameter encoderParam = new(Encoder.Quality, 100L);
encoding.Param[0] = encoderParam;
graphics.CopyFromScreen(new Point(bounds.Left + 7, bounds.Top), Point.Empty,
new Size(Size.Width - 14, Size.Height - 7));
graphics.CopyFromScreen(new(bounds.Left + 7, bounds.Top), Point.Empty, new(Size.Width - 14, Size.Height - 7));
Clipboard.SetImage(bitmap);
e.Handled = true;
}

View file

@ -65,8 +65,7 @@ internal class CustomTreeView : TreeView
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);
@ -88,8 +87,7 @@ internal class CustomTreeView : TreeView
text = platform.ToString();
size = TextRenderer.MeasureText(graphics, text, font);
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
selectionBounds
= new Rectangle(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
selectionBounds = new Rectangle(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
graphics.FillRectangle(brush, bounds);
point = new Point(bounds.Location.X - 1, bounds.Location.Y + 1);
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
@ -104,8 +102,7 @@ internal class CustomTreeView : TreeView
size = TextRenderer.MeasureText(graphics, text, font);
int left = -4;
bounds = bounds with { X = bounds.X + bounds.Width + left, Width = size.Width };
selectionBounds = new Rectangle(selectionBounds.Location,
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
selectionBounds = new Rectangle(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
graphics.FillRectangle(brush, bounds);
point = new Point(bounds.Location.X - 1, bounds.Location.Y + 1);
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
@ -130,8 +127,7 @@ internal class CustomTreeView : TreeView
: CheckBoxState.UncheckedDisabled;
size = CheckBoxRenderer.GetGlyphSize(graphics, checkBoxState);
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
selectionBounds = new Rectangle(selectionBounds.Location,
selectionBounds.Size + bounds.Size with { Height = 0 });
selectionBounds = new Rectangle(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
Rectangle checkBoxBounds = bounds;
graphics.FillRectangle(backBrush, bounds);
point = new Point(bounds.Left, bounds.Top + bounds.Height / 2 - size.Height / 2 - 1);
@ -140,41 +136,31 @@ internal class CustomTreeView : TreeView
size = TextRenderer.MeasureText(graphics, text, font);
int left = 1;
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width + left };
selectionBounds = new Rectangle(selectionBounds.Location,
selectionBounds.Size + bounds.Size with { Height = 0 });
checkBoxBounds = new Rectangle(checkBoxBounds.Location,
checkBoxBounds.Size + bounds.Size with { Height = 0 });
selectionBounds = new Rectangle(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
checkBoxBounds = new Rectangle(checkBoxBounds.Location, checkBoxBounds.Size + bounds.Size with { Height = 0 });
graphics.FillRectangle(backBrush, bounds);
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"),
TextRenderer.DrawText(graphics, text, font, point, 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(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 Rectangle(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width,
bounds.Height - padding);
selectionBounds = new Rectangle(selectionBounds.Location,
selectionBounds.Size + bounds.Size with { Height = 0 });
bounds = new Rectangle(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width, bounds.Height - padding);
selectionBounds = new Rectangle(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
Rectangle comboBoxBounds = bounds;
graphics.FillRectangle(backBrush, bounds);
ComboBoxRenderer.DrawTextBox(graphics, bounds, text, comboBoxFont, comboBoxState);
size = new Size(14, 0);
left = -1;
bounds = bounds with { X = bounds.X + bounds.Width + left, Width = size.Width };
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));
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);
}
@ -215,11 +201,9 @@ internal class CustomTreeView : TreeView
}
else if (pair.Value.Contains(clickPoint))
{
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))
.Select(p =>
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader")).Select(p =>
{
p.GetProxyInfoFromIdentifier(
out string proxyName, out _);
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
return proxyName;
}).Distinct().ToList();
comboBoxDropDown ??= new ToolStripDropDown();
@ -240,8 +224,7 @@ 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 });
}

View file

@ -14,16 +14,16 @@ internal static class PlatformIdComparer
private static NodeNameComparer nodeNameComparer;
private static NodeTextComparer nodeTextComparer;
internal static StringComparer String => stringComparer ??= new StringComparer();
internal static NodeComparer Node => nodeComparer ??= new NodeComparer();
internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer();
internal static NodeTextComparer NodeText => nodeTextComparer ??= new NodeTextComparer();
internal static StringComparer String => stringComparer ??= new();
internal static NodeComparer Node => nodeComparer ??= new();
internal static NodeNameComparer NodeName => nodeNameComparer ??= new();
internal static NodeTextComparer NodeText => nodeTextComparer ??= new();
}
internal class StringComparer : IComparer<string>
{
public int Compare(string a, string b) =>
!int.TryParse(a, out _) && !int.TryParse(b, out _)
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
@ -38,8 +38,8 @@ internal class StringComparer : IComparer<string>
internal class NodeComparer : IComparer<TreeNode>
{
public int Compare(TreeNode a, TreeNode b) =>
a.Tag is not Platform A
public int Compare(TreeNode a, TreeNode b)
=> a.Tag is not Platform A
? 1
: b.Tag is not Platform B
? -1
@ -52,8 +52,8 @@ internal class NodeComparer : IComparer<TreeNode>
internal class NodeNameComparer : IComparer
{
public int Compare(object a, object b) =>
a is not TreeNode A
public int Compare(object a, object b)
=> a is not TreeNode A
? 1
: b is not TreeNode B
? -1
@ -64,8 +64,8 @@ internal class NodeNameComparer : IComparer
internal class NodeTextComparer : IComparer
{
public int Compare(object a, object b) =>
a is not TreeNode A
public int Compare(object a, object b)
=> a is not TreeNode A
? 1
: b is not TreeNode B
? -1

View file

@ -24,7 +24,7 @@ internal partial class DebugForm : CustomForm
{
if (current is not null && (current.Disposing || current.IsDisposed))
current = null;
return current ??= new DebugForm();
return current ??= new();
}
set => current = value;
}
@ -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 Point(attachedForm.Right, attachedForm.Top);
Location = new(attachedForm.Right, attachedForm.Top);
BringToFrontWithoutActivation();
}
}

View file

@ -12,8 +12,8 @@ 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();
@ -32,7 +32,7 @@ internal partial class DialogForm : CustomForm
if (string.IsNullOrWhiteSpace(link))
link = text;
descriptionText = descriptionText.Remove(i, linkRight + 1 - i).Insert(i, text);
links.Add(new LinkLabel.Link(i, text.Length, link));
links.Add(new(i, text.Length, link));
}
}
descriptionLabel.Text = descriptionText;
@ -43,13 +43,9 @@ internal partial class DialogForm : CustomForm
cancelButton.Visible = false;
}
else
{
cancelButton.Text = cancelButtonText;
}
if (customFormText is not null)
{
Text = customFormText;
}
else
{
OnResize(null, null);
@ -61,16 +57,13 @@ 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();
}
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
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.ApplicationName;
}

View file

@ -38,18 +38,21 @@ internal partial class InstallForm : CustomForm
userProgressBar.Invoke(() =>
{
int value = (int)((float)CompleteOperationsCount / OperationsCount * 100) + progress / OperationsCount;
if (value < userProgressBar.Value) return;
if (value < userProgressBar.Value)
return;
userProgressBar.Value = value;
});
}
internal void UpdateUser(string text, Color color, bool info = true, bool log = true)
{
if (info) _ = userInfoLabel.Invoke(() => userInfoLabel.Text = text);
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);
if (logTextBox.Text.Length > 0)
logTextBox.AppendText(Environment.NewLine, color);
logTextBox.AppendText(text, color);
logTextBox.Invalidate();
});
@ -63,12 +66,11 @@ internal partial class InstallForm : CustomForm
UpdateUser("Repairing Paradox Launcher . . . ", LogTextBox.Operation);
_ = await Repair(this, selection);
}
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")}" +
$" {(Uninstalling ? "from" : "for")} " + selection.Name
UpdateUser(
$"{(Uninstalling ? "Uninstalling" : "Installing")}" + $" {(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)))
?.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);
@ -76,16 +78,13 @@ internal partial class InstallForm : CustomForm
if (invalidDirectories is not null)
foreach (string directory in invalidDirectories)
{
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
if (Program.Canceled)
throw new CustomMessageException("The operation was canceled.");
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
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);
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
}
Thread.Sleep(1);
@ -93,15 +92,13 @@ internal partial class InstallForm : CustomForm
if (Uninstalling || !selection.Koaloader)
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
{
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
if (Program.Canceled)
throw new CustomMessageException("The operation was canceled.");
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
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);
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
}
Thread.Sleep(1);
@ -110,17 +107,18 @@ internal partial class InstallForm : CustomForm
int count = selection.DllDirectories.Count, cur = 0;
foreach (string directory in selection.DllDirectories)
{
if (Program.Canceled) throw new CustomMessageException("The operation was canceled.");
if (Program.Canceled)
throw new CustomMessageException("The operation was canceled.");
if (selection.Platform is Platform.Steam or Platform.Paradox)
{
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config, out string cache);
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, 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
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await SmokeAPI.Uninstall(directory, this);
@ -130,14 +128,11 @@ 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
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await ScreamAPI.Uninstall(directory, this);
@ -147,28 +142,24 @@ 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
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" + $" {(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);
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
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await UplayR2.Uninstall(directory, this);
@ -182,9 +173,9 @@ internal partial class InstallForm : CustomForm
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);
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, selection.RootDirectory, this);
Thread.Sleep(1);
}
@ -236,13 +227,12 @@ 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;
@ -262,7 +252,8 @@ internal partial class InstallForm : CustomForm
}
catch (Exception e)
{
if (e.HandleException(this)) goto retry;
if (e.HandleException(this))
goto retry;
Close();
}
}

View file

@ -58,24 +58,18 @@ internal partial class MainForm : CustomForm
updateButton.Click -= OnUpdateCancel;
progressLabel.Text = "Checking for updates . . .";
changelogTreeView.Visible = false;
changelogTreeView.Location = progressLabel.Location with
{
Y = progressLabel.Location.Y + progressLabel.Size.Height + 13
};
changelogTreeView.Location = progressLabel.Location with { Y = 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 UpdateManager(AssemblyMetadata.FromAssembly(Program.EntryAssembly, Program.CurrentProcessFilePath),
resolver, extractor);
updateManager = new(AssemblyMetadata.FromAssembly(Program.EntryAssembly, Program.CurrentProcessFilePath), resolver, extractor);
if (latestVersion is null)
{
CheckForUpdatesResult checkForUpdatesResult = null;
cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource = new();
try
{
checkForUpdatesResult = await updateManager.CheckForUpdatesAsync(cancellationTokenSource.Token);
@ -93,8 +87,7 @@ 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 { }
@ -120,8 +113,7 @@ internal partial class MainForm : CustomForm
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
@ -162,8 +154,7 @@ 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!",
"WARNING: " + Program.ApplicationExecutable + " was renamed!" + "\n\nThis will cause undesirable behavior when updating the program!",
"Ignore", "Abort") == DialogResult.Cancel)
{
Application.Exit();
@ -174,7 +165,8 @@ internal partial class MainForm : CustomForm
}
catch (Exception e)
{
if (e.HandleException(this)) goto retry;
if (e.HandleException(this))
goto retry;
Close();
}
}
@ -188,8 +180,7 @@ internal partial class MainForm : CustomForm
updateButton.Text = "Cancel";
updateButton.Click -= OnUpdate;
updateButton.Click += OnUpdateCancel;
changelogTreeView.Location
= progressBar.Location with { Y = progressBar.Location.Y + progressBar.Size.Height + 6 };
changelogTreeView.Location = progressBar.Location with { Y = progressBar.Location.Y + progressBar.Size.Height + 6 };
Refresh();
Progress<double> progress = new();
progress.ProgressChanged += delegate(object sender, double _progress)
@ -198,7 +189,7 @@ internal partial class MainForm : CustomForm
progressBar.Value = (int)_progress;
};
progressLabel.Text = "Updating . . . ";
cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource = new();
try
{
await updateManager.PrepareUpdateAsync(latestVersion, progress, cancellationTokenSource.Token);
@ -207,8 +198,7 @@ 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 { }

View file

@ -12,10 +12,11 @@ internal partial class SelectDialogForm : CustomForm
private readonly List<(Platform platform, string id, string name)> selected = new();
internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
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;
if (!choices.Any())
return null;
groupBox.Text = groupBoxText;
allCheckBox.Enabled = false;
acceptButton.Enabled = false;
@ -26,7 +27,8 @@ internal partial class SelectDialogForm : CustomForm
OnTreeNodeChecked(node);
_ = selectionTreeView.Nodes.Add(node);
}
if (!selected.Any()) OnLoad(null, null);
if (!selected.Any())
OnLoad(null, null);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = selectionTreeView.Nodes.Cast<TreeNode>().All(n => n.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
@ -59,13 +61,11 @@ internal partial class SelectDialogForm : CustomForm
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
}
private void OnResize(object s, EventArgs e) =>
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
? Program.ApplicationNameShort
: Program.ApplicationName;
private void OnResize(object s, EventArgs e)
=> Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100 ? Program.ApplicationNameShort : Program.ApplicationName;
private void OnSortCheckBoxChanged(object sender, EventArgs e) => selectionTreeView.TreeViewNodeSorter
= sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
private void OnSortCheckBoxChanged(object sender, EventArgs e)
=> selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
private void OnAllCheckBoxChanged(object sender, EventArgs e)
{
@ -85,7 +85,8 @@ internal partial class SelectDialogForm : CustomForm
private void OnLoad(object sender, EventArgs e)
{
List<(Platform platform, string id)> choices = ProgramData.ReadProgramChoices();
if (choices is null) return;
if (choices is null)
return;
foreach (TreeNode node in selectionTreeView.Nodes)
{
node.Checked = choices.Any(n => n.platform == (Platform)node.Tag && n.id == node.Name);

View file

@ -38,23 +38,23 @@ internal partial class SelectForm : CustomForm
Text = Program.ApplicationName;
}
public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new ContextMenuStrip();
public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new();
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("&", "&&")
: "";
private static void UpdateRemaining(Label label, SynchronizedCollection<string> list, string descriptor)
=> label.Text = list.Any() ? $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list).Replace("&", "&&") : "";
private void UpdateRemainingGames() => UpdateRemaining(progressLabelGames, RemainingGames, "games");
private void AddToRemainingGames(string gameName)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
progressLabelGames.Invoke(delegate
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
if (!RemainingGames.Contains(gameName))
RemainingGames.Add(gameName);
UpdateRemainingGames();
@ -63,10 +63,12 @@ internal partial class SelectForm : CustomForm
private void RemoveFromRemainingGames(string gameName)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
progressLabelGames.Invoke(delegate
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
RemainingGames.Remove(gameName);
UpdateRemainingGames();
});
@ -76,10 +78,12 @@ internal partial class SelectForm : CustomForm
private void AddToRemainingDLCs(string dlcId)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
progressLabelDLCs.Invoke(delegate
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
if (!RemainingDLCs.Contains(dlcId))
RemainingDLCs.Add(dlcId);
UpdateRemainingDLCs();
@ -88,10 +92,12 @@ internal partial class SelectForm : CustomForm
private void RemoveFromRemainingDLCs(string dlcId)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
progressLabelDLCs.Invoke(delegate
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
RemainingDLCs.Remove(dlcId);
UpdateRemainingDLCs();
});
@ -99,7 +105,8 @@ internal partial class SelectForm : CustomForm
private async Task GetApplicablePrograms(IProgress<int> progress)
{
if (ProgramsToScan is null || !ProgramsToScan.Any()) return;
if (ProgramsToScan is null || !ProgramsToScan.Any())
return;
int TotalGameCount = 0;
int CompleteGameCount = 0;
void AddToRemainingGames(string gameName)
@ -113,30 +120,30 @@ internal partial class SelectForm : CustomForm
this.RemoveFromRemainingGames(gameName);
progress.Report(Interlocked.Increment(ref CompleteGameCount));
}
if (Program.Canceled) return;
if (Program.Canceled)
return;
List<TreeNode> treeNodes = TreeNodes;
RemainingGames.Clear(); // for display purposes only, otherwise ignorable
RemainingDLCs.Clear(); // for display purposes only, otherwise ignorable
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 ProgramSelection();
if (allCheckBox.Checked) selection.Enabled = true;
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
selection ??= new();
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();
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;
@ -148,14 +155,13 @@ 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.Canceled)
return;
if (Program.IsGameBlocked(name, gameDirectory) || !ProgramsToScan.Any(c => c.platform is Platform.Steam && c.id == appId))
{
Interlocked.Decrement(ref steamGamesToCheck);
continue;
@ -163,9 +169,9 @@ internal partial class SelectForm : CustomForm
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
List<string> dllDirectories
= await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
if (Program.Canceled)
return;
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
if (dllDirectories is null)
{
Interlocked.Decrement(ref steamGamesToCheck);
@ -180,25 +186,30 @@ internal partial class SelectForm : CustomForm
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
if (Program.Canceled)
return;
ConcurrentDictionary<string, (DlcType type, string name, string icon)> dlc = new();
List<Task> dlcTasks = new();
List<string> dlcIds = new();
if (appData is not null) dlcIds.AddRange(await SteamStore.ParseDlcAppIds(appData));
if (appInfo is not null) dlcIds.AddRange(await SteamCMD.ParseDlcAppIds(appInfo));
if (appData is not null)
dlcIds.AddRange(await SteamStore.ParseDlcAppIds(appData));
if (appInfo is not null)
dlcIds.AddRange(await SteamCMD.ParseDlcAppIds(appInfo));
if (dlcIds.Count > 0)
{
foreach (string dlcAppId in dlcIds)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
AddToRemainingDLCs(dlcAppId);
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
do // give games steam store api limit priority
Thread.Sleep(200);
while (!Program.Canceled && steamGamesToCheck > 0);
if (Program.Canceled) return;
if (Program.Canceled)
return;
string dlcName = null;
string dlcIcon = null;
bool onSteamStore = false;
@ -215,18 +226,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;
if (Program.Canceled)
return;
if (string.IsNullOrWhiteSpace(dlcName))
dlcName = "Unknown";
dlc[dlcAppId] = (onSteamStore ? DlcType.Steam : DlcType.SteamHidden, dlcName, dlcIcon);
@ -234,45 +242,43 @@ internal partial class SelectForm : CustomForm
});
dlcTasks.Add(task);
}
}
else
{
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
if (Program.Canceled)
return;
foreach (Task task in dlcTasks)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
await task;
}
steamGamesToCheck = 0;
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;
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.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.Publisher = appData?.publishers[0] ?? appInfo?.Value?.GetChild("extended")?.GetChild("publisher")?.ToString();
selection.WebsiteUrl = appData?.website;
if (Program.Canceled) return;
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();
if (Program.Canceled)
return;
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;
@ -281,13 +287,14 @@ internal partial class SelectForm : CustomForm
_ = selectionTreeView.Nodes.Add(programNode);
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in dlc)
{
if (Program.Canceled || programNode is null) return;
if (Program.Canceled || programNode is null)
return;
string appId = pair.Key;
(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();
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.Tag = selection.Platform;
dlcNode.Name = appId;
dlcNode.Text = dlcApp.name;
@ -296,7 +303,8 @@ internal partial class SelectForm : CustomForm
_ = programNode.Nodes.Add(dlcNode);
}
});
if (Program.Canceled) return;
if (Program.Canceled)
return;
RemoveFromRemainingGames(name);
});
appTasks.Add(task);
@ -310,34 +318,37 @@ internal partial class SelectForm : CustomForm
string @namespace = manifest.CatalogNamespace;
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.Canceled)
return;
if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.platform is Platform.Epic && c.id == @namespace))
continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
List<string> dllDirectories = await directory.GetDllDirectoriesFromGameDirectory(Platform.Epic);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
ConcurrentDictionary<string, (string name, string product, string icon, string developer)>
entitlements = new();
if (Program.Canceled)
return;
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);
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;
if (Program.Canceled)
return;
AddToRemainingDLCs(id);
Task task = Task.Run(() =>
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
entitlements[id] = (name, product, icon, developer);
RemoveFromRemainingDLCs(id);
});
@ -348,37 +359,38 @@ internal partial class SelectForm : CustomForm
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled) return;
if (Program.Canceled)
return;
foreach (Task task in dlcTasks)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
await task;
}
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;
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;
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();
if (Program.Canceled)
return;
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;
@ -400,17 +412,16 @@ 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();
if (allCheckBox.Checked)
selection.SelectedDlc[dlcId] = dlcApp;
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;
@ -419,7 +430,8 @@ internal partial class SelectForm : CustomForm
_ = programNode.Nodes.Add(dlcNode); //entitlementsNode.Nodes.Add(dlcNode);
}
});
if (Program.Canceled) return;
if (Program.Canceled)
return;
RemoveFromRemainingGames(name);
});
appTasks.Add(task);
@ -430,39 +442,39 @@ internal partial class SelectForm : CustomForm
List<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
{
if (Program.Canceled) return;
if (Program.IsGameBlocked(name, gameDirectory)
|| !ProgramsToScan.Any(c => c.platform is Platform.Ubisoft && c.id == gameId)) continue;
if (Program.Canceled)
return;
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);
if (Program.Canceled)
return;
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 ProgramSelection();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any()
|| selection.ExtraSelectedDlc.Any();
if (koaloaderAllCheckBox.Checked) selection.Koaloader = true;
if (Program.Canceled)
return;
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();
if (Program.Canceled)
return;
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;
@ -470,7 +482,8 @@ internal partial class SelectForm : CustomForm
if (programNode.TreeView is null)
_ = selectionTreeView.Nodes.Add(programNode);
});
if (Program.Canceled) return;
if (Program.Canceled)
return;
RemoveFromRemainingGames(name);
});
appTasks.Add(task);
@ -478,7 +491,8 @@ internal partial class SelectForm : CustomForm
}
foreach (Task task in appTasks)
{
if (Program.Canceled) return;
if (Program.Canceled)
return;
await task;
}
steamGamesToCheck = 0;
@ -512,30 +526,24 @@ internal partial class SelectForm : CustomForm
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")));
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)))
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)));
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)))
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)))
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)));
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)
@ -544,15 +552,11 @@ 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;
@ -562,17 +566,17 @@ internal partial class SelectForm : CustomForm
IProgress<int> iProgress = progress;
progress.ProgressChanged += (sender, _progress) =>
{
if (Program.Canceled) return;
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
else curProgress = _progress;
if (Program.Canceled)
return;
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}%"
: $"Gathering and caching your applicable games and their DLCs . . . {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 . . . ";
await SteamCMD.Setup(iProgress);
@ -615,9 +619,11 @@ internal partial class SelectForm : CustomForm
private void OnTreeViewNodeCheckedChanged(object sender, TreeViewEventArgs e)
{
if (e.Action == TreeViewAction.Unknown) return;
if (e.Action == TreeViewAction.Unknown)
return;
TreeNode node = e.Node;
if (node is null) return;
if (node is null)
return;
SyncNode(node);
SyncNodeAncestors(node);
SyncNodeDescendants(node);
@ -640,10 +646,11 @@ internal partial class SelectForm : CustomForm
}
}
private static void SyncNodeDescendants(TreeNode node) =>
node.Nodes.Cast<TreeNode>().ToList().ForEach(childNode =>
private static void SyncNodeDescendants(TreeNode node)
=> node.Nodes.Cast<TreeNode>().ToList().ForEach(childNode =>
{
if (childNode.Text == "Unknown") return;
if (childNode.Text == "Unknown")
return;
childNode.Checked = node.Checked;
SyncNode(childNode);
SyncNodeDescendants(childNode);
@ -653,8 +660,7 @@ 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;
@ -692,10 +698,7 @@ internal partial class SelectForm : CustomForm
progressBar.Visible = true;
programsGroupBox.Size = programsGroupBox.Size with
{
Height = programsGroupBox.Size.Height - 3
- progressLabel.Size.Height
- progressLabelGames.Size.Height
- progressLabelDLCs.Size.Height
Height = programsGroupBox.Size.Height - 3 - progressLabel.Size.Height - progressLabelGames.Size.Height - progressLabelDLCs.Size.Height
- progressBar.Size.Height
};
}
@ -709,15 +712,13 @@ internal partial class SelectForm : CustomForm
progressBar.Visible = false;
programsGroupBox.Size = programsGroupBox.Size with
{
Height = programsGroupBox.Size.Height + 3
+ progressLabel.Size.Height
+ progressLabelGames.Size.Height
+ progressLabelDLCs.Size.Height
Height = programsGroupBox.Size.Height + 3 + progressLabel.Size.Height + progressLabelGames.Size.Height + progressLabelDLCs.Size.Height
+ progressBar.Size.Height
};
}
internal void OnNodeRightClick(TreeNode node, Point location) => Invoke(() =>
internal void OnNodeRightClick(TreeNode node, Point location)
=> Invoke(() =>
{
ContextMenuStrip contextMenuStrip = ContextMenuStrip;
while (ContextMenuStrip.Tag is bool used && used)
@ -738,11 +739,11 @@ internal partial class SelectForm : CustomForm
return;
ContextMenuItem header = null;
if (id == "PL")
header = new ContextMenuItem(node.Text, "Paradox Launcher");
header = new(node.Text, "Paradox Launcher");
else if (selection is not null)
header = new ContextMenuItem(node.Text, (id, selection.IconUrl));
header = new(node.Text, (id, selection.IconUrl));
else if (dlc is not null && dlcParentSelection is not null)
header = new ContextMenuItem(node.Text, (id, dlc.Value.app.icon), (id, dlcParentSelection.IconUrl));
header = new(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";
@ -757,19 +758,16 @@ internal partial class SelectForm : CustomForm
: selection.Platform is Platform.Epic
? "Epic GraphQL "
: "";
queries.Add(new ContextMenuItem($"Open {platformString}Query", "Notepad",
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
queries.Add(new($"Open {platformString}Query", "Notepad", (sender, e) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
}
if (File.Exists(appInfoVDF))
queries.Add(new ContextMenuItem("Open SteamCMD Query", "Notepad",
(sender, e) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
queries.Add(new("Open SteamCMD Query", "Notepad", (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",
(sender, e) =>
items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt", (sender, e) =>
{
try
{
@ -795,109 +793,88 @@ internal partial class SelectForm : CustomForm
if (id == "PL")
{
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Repair", "Command Prompt",
async (sender, e) => await ParadoxLauncher.Repair(this, selection)));
items.Add(new ContextMenuItem("Repair", "Command Prompt", async (sender, e) => await ParadoxLauncher.Repair(this, selection)));
}
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Open Root Directory", "File Explorer",
(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",
(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",
(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",
(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",
(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",
(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",
(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",
(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)));
(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",
(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",
(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",
(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)),
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();
@ -915,7 +892,8 @@ internal partial class SelectForm : CustomForm
}
catch (Exception e)
{
if (e.HandleException(this)) goto retry;
if (e.HandleException(this))
goto retry;
Close();
}
}
@ -927,7 +905,8 @@ internal partial class SelectForm : CustomForm
foreach (ProgramSelection selection in ProgramSelection.AllEnabled)
if (!Program.IsProgramRunningDialog(this, selection))
return;
if (!uninstall && ParadoxLauncher.DlcDialog(this)) return;
if (!uninstall && ParadoxLauncher.DlcDialog(this))
return;
Hide();
#pragma warning disable CA2000 // Dispose objects before losing scope
InstallForm form = new(uninstall);
@ -945,9 +924,7 @@ internal partial class SelectForm : CustomForm
OnLoad();
}
else
{
Close();
}
};
form.Show();
Hide();
@ -982,7 +959,7 @@ internal partial class SelectForm : CustomForm
if (node.Parent is null && node.Checked != shouldCheck)
{
node.Checked = shouldCheck;
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
}
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = shouldCheck;
@ -1009,20 +986,17 @@ 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)>();
?? new List<(Platform platform, string gameId, string dlcId)>();
foreach (TreeNode node in TreeNodes)
if (node.Parent is TreeNode parent && node.Tag is Platform platform)
{
@ -1042,15 +1016,15 @@ internal partial class SelectForm : CustomForm
private void OnLoadDlc(object sender, EventArgs e)
{
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices();
if (choices is null) return;
if (choices is null)
return;
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.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));
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
}
}
@ -1062,7 +1036,7 @@ internal partial class SelectForm : CustomForm
if (node.Parent is not null && node.Tag is Platform)
{
node.Checked = node.Text != "Unknown";
OnTreeViewNodeCheckedChanged(null, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
}
resetButton.Enabled = CanResetDlc();
}
@ -1075,8 +1049,7 @@ 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)
{
@ -1085,12 +1058,9 @@ internal partial class SelectForm : CustomForm
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)
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));
selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy, selection.Koaloader));
}
ProgramData.WriteKoaloaderProxyChoices(choices);
saveKoaloaderButton.Enabled = CanSaveKoaloader();
@ -1102,12 +1072,13 @@ internal partial class SelectForm : CustomForm
private void OnLoadKoaloader(object sender, EventArgs e)
{
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices();
if (choices is null) return;
if (choices is null)
return;
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
{
(Platform platform, string id, string proxy, bool enabled) choice =
choices.First(c => c.platform == selection.Platform && c.id == selection.Id);
(Platform platform, string id, string proxy, bool enabled)
choice = choices.First(c => c.platform == selection.Platform && c.id == selection.Id);
(Platform platform, string id, string proxy, bool enabled) = choice;
string currentProxy = proxy;
if (proxy is not null && proxy.Contains('.')) // convert pre-v4.1.0.0 choices
@ -1115,14 +1086,11 @@ 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
@ -1176,22 +1144,16 @@ 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
= sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
private void OnSortCheckBoxChanged(object sender, EventArgs e)
=> selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
}
#pragma warning restore IDE0058

View file

@ -17,43 +17,36 @@ internal static class EpicLibrary
{
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;
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(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(() =>
internal static async Task<List<Manifest>> GetGames()
=> await Task.Run(() =>
{
List<Manifest> games = new();
string manifests = EpicManifestsPath;
if (!Directory.Exists(manifests)) return games;
if (!Directory.Exists(manifests))
return games;
foreach (string file in Directory.EnumerateFiles(manifests, "*.item"))
{
if (Program.Canceled) return games;
if (Program.Canceled)
return games;
string json = File.ReadAllText(file);
try
{
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))
if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId && !games.Any(g
=> g.CatalogItemId == manifest.CatalogItemId && g.InstallLocation == manifest.InstallLocation))
games.Add(manifest);
}
catch { }

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
using CreamInstaller.Platforms.Epic.GraphQL;
@ -23,8 +22,7 @@ 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";
@ -40,7 +38,6 @@ internal static class EpicStore
catch { }
}
else if (cachedExists)
{
try
{
response = JsonConvert.DeserializeObject<Response>(await File.ReadAllTextAsync(cacheFile));
@ -49,16 +46,13 @@ internal static class EpicStore
{
File.Delete(cacheFile);
}
}
if (response is null)
return dlcIds;
List<Element> searchStore = new(response.Data.Catalog.SearchStore.Elements);
foreach (Element element in searchStore)
{
string title = element.Title;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any()
? element.CatalogNs.Mappings.First().PageSlug
: null;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any() ? element.CatalogNs.Mappings.First().PageSlug : null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{
@ -76,9 +70,7 @@ internal static class EpicStore
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;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any() ? element.CatalogNs.Mappings.First().PageSlug : null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{
@ -95,11 +87,11 @@ internal static class EpicStore
return dlcIds;
}
private static void Populate(
this List<(string id, string name, string product, string icon, string developer)> dlcIds, string id,
string title, string product, string icon, string developer, bool canOverwrite = false)
private static void Populate(this List<(string id, string name, string product, string icon, string developer)> dlcIds, string id, string title,
string product, string icon, string developer, bool canOverwrite = false)
{
if (id == null) return;
if (id == null)
return;
bool found = false;
for (int i = 0; i < dlcIds.Count; i++)
{
@ -113,7 +105,8 @@ internal static class EpicStore
break;
}
}
if (!found) dlcIds.Add((id, title, product, icon, developer));
if (!found)
dlcIds.Add((id, title, product, icon, developer));
}
private static async Task<Response> QueryGraphQL(string categoryNamespace)
@ -124,11 +117,11 @@ internal static class EpicStore
Request request = new(encoded);
string payload = JsonConvert.SerializeObject(request);
using HttpContent content = new StringContent(payload);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType = new("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);
if (client is null)
return null;
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);

View file

@ -9,10 +9,11 @@ namespace CreamInstaller.Platforms.Epic.GraphQL;
internal class Request
{
internal Request(string @namespace) => Vars = new Variables(@namespace);
internal Request(string @namespace) => Vars = new(@namespace);
[JsonProperty(PropertyName = "query")]
private string Query => @"query searchOffers($namespace: String!) {
private string Query
=> @"query searchOffers($namespace: String!) {
Catalog {
searchStore(category: ""*"", namespace: $namespace){
elements {

View file

@ -27,20 +27,16 @@ internal static class ParadoxLauncher
{
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)
{
@ -49,26 +45,24 @@ 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 ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
selection.Id, selection.Name, selection.AllDlc));
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(selection.Id, selection.Name,
selection.AllDlc));
paradoxLauncher.ExtraSelectedDlc.Add(
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
selection.Id, selection.Name, selection.SelectedDlc));
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 ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
selection.Id, selection.Name, selection.AllDlc));
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(selection.Id, selection.Name,
selection.AllDlc));
paradoxLauncher.ExtraSelectedDlc.Add(
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(
selection.Id, selection.Name, selection.AllDlc));
new ValueTuple<string, string, SortedList<string, (DlcType type, string name, string icon)>>(selection.Id, selection.Name,
selection.AllDlc));
}
}
}
@ -84,9 +78,8 @@ 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", "Paradox Launcher") != DialogResult.OK;
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!", "Ignore", "Cancel",
"Paradox Launcher") != DialogResult.OK;
}
}
return false;
@ -96,9 +89,7 @@ internal static class ParadoxLauncher
{
InstallForm installForm = form as InstallForm;
if (!Program.IsProgramRunningDialog(form, selection))
return form is InstallForm
? throw new CustomMessageException("Repair failed! The launcher is currently running!")
: RepairResult.ProgramRunning;
return form is InstallForm ? throw new CustomMessageException("Repair failed! The launcher is currently running!") : RepairResult.ProgramRunning;
bool smokeInstalled = false;
byte[] steamOriginalSdk32 = null;
byte[] steamOriginalSdk64 = null;
@ -107,40 +98,29 @@ internal static class ParadoxLauncher
byte[] epicOriginalSdk64 = null;
foreach (string directory in selection.DllDirectories)
{
bool koaloaderInstalled = Koaloader.AutoLoadDlls
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
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 _);
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));
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);
await SmokeAPI.Uninstall(directory, deleteConfig: false);
if (steamOriginalSdk32 is null && File.Exists(api32)
&& !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
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))
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));
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);
await ScreamAPI.Uninstall(directory, deleteConfig: false);
if (epicOriginalSdk32 is null && File.Exists(api32)
&& !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
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))
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)
@ -181,26 +161,22 @@ 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
_ = dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK",
customFormText: "Paradox Launcher");
_ = 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");
? 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;
}
}

View file

@ -21,8 +21,7 @@ internal static class SteamCMD
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 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];
@ -38,18 +37,22 @@ internal static class SteamCMD
internal static string DirectoryPath => ProgramData.DirectoryPath;
internal static string AppInfoPath => ProgramData.AppInfoPath;
private static string GetArguments(string appId) => AttemptCount.TryGetValue(appId, out int attempts)
private static string GetArguments(string appId)
=> AttemptCount.TryGetValue(appId, out int attempts)
? $@"@ShutdownOnFailedCommand 0 +force_install_dir {DirectoryPath} +login anonymous +app_info_print {appId} "
+ string.Concat(Enumerable.Repeat("+app_update 4 ", attempts)) + "+quit"
: $"+login anonymous +app_info_print {appId} +quit";
internal static async Task<string> Run(string appId) => await Task.Run(() =>
internal static async Task<string> Run(string appId)
=> await Task.Run(() =>
{
wait_for_lock:
if (Program.Canceled) return "";
if (Program.Canceled)
return "";
for (int i = 0; i < locks.Length; i++)
{
if (Program.Canceled) return "";
if (Program.Canceled)
return "";
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
{
if (appId is not null)
@ -57,14 +60,13 @@ internal static class SteamCMD
AttemptCount.TryGetValue(appId, out int count);
AttemptCount[appId] = ++count;
}
if (Program.Canceled) return "";
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,
StandardErrorEncoding = 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);
StringBuilder output = new();
@ -84,7 +86,8 @@ internal static class SteamCMD
{
lastOutput = DateTime.UtcNow;
char ch = (char)c;
if (ch == '{') appInfoStarted = true;
if (ch == '{')
appInfoStarted = true;
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
}
DateTime now = DateTime.UtcNow;
@ -103,11 +106,9 @@ internal static class SteamCMD
_ = appInfo.Clear();
}
else
{
break;
}
}
}
_ = Interlocked.Decrement(ref locks[i]);
return appInfo.ToString();
}
@ -123,21 +124,20 @@ internal static class SteamCMD
if (!File.Exists(FilePath))
{
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"));
if (httpClient is null)
return;
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);
}
if (!File.Exists(DllPath))
{
FileSystemWatcher watcher = new(DirectoryPath)
{
Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true
};
if (File.Exists(DllPath)) progress.Report(-15); // update (not used at the moment)
else progress.Report(-1660); // install
FileSystemWatcher watcher = new(DirectoryPath) { Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true };
if (File.Exists(DllPath))
progress.Report(-15); // update (not used at the moment)
else
progress.Report(-1660); // install
int cur = 0;
progress.Report(cur);
watcher.Changed += (sender, e) => progress.Report(++cur);
@ -146,9 +146,11 @@ internal static class SteamCMD
}
}
internal static async Task Cleanup() => await Task.Run(async () =>
internal static async Task Cleanup()
=> await Task.Run(async () =>
{
if (!Directory.Exists(DirectoryPath)) return;
if (!Directory.Exists(DirectoryPath))
return;
await Kill();
try
{
@ -164,8 +166,7 @@ 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))
@ -178,13 +179,14 @@ internal static class SteamCMD
internal static async Task<VProperty> GetAppInfo(string appId, string branch = "public", int buildId = 0)
{
if (Program.Canceled) return null;
if (Program.Canceled)
return null;
string output;
string appUpdateFile = $@"{AppInfoPath}\{appId}.vdf";
restart:
if (Program.Canceled) return null;
if (Program.Canceled)
return null;
if (File.Exists(appUpdateFile))
{
try
{
output = await File.ReadAllTextAsync(appUpdateFile, Encoding.UTF8);
@ -193,7 +195,6 @@ internal static class SteamCMD
{
goto restart;
}
}
else
{
output = await Run(appId) ?? "";
@ -213,37 +214,40 @@ internal static class SteamCMD
}
}
else
{
goto restart;
}
}
if (Program.Canceled) return null;
if (Program.Canceled)
return null;
if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue)
{
File.Delete(appUpdateFile);
goto restart;
}
if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0) return appInfo;
if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0)
return appInfo;
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
if (type is not null && type.ToString() != "Game")
return appInfo;
string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch)
?.GetChild("buildid")?.ToString();
if (buildid is null && type is not null) return appInfo;
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 not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId))
return appInfo;
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(appUpdateFile)) File.Delete(appUpdateFile);
if (File.Exists(appUpdateFile))
File.Delete(appUpdateFile);
goto restart;
}
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo)
=> await Task.Run(() =>
{
List<string> dlcIds = new();
if (Program.Canceled || appInfo is null) return dlcIds;
if (Program.Canceled || appInfo is null)
return dlcIds;
VToken extended = appInfo.Value.GetChild("extended");
if (extended is not null)
foreach (VToken vToken in extended.Where(p => p is VProperty { Key: "listofdlc" }))
@ -259,8 +263,7 @@ internal static class SteamCMD
foreach (VToken vToken in depots.Where(p => p is VProperty property && int.TryParse(property.Key, out int _)))
{
VProperty property = (VProperty)vToken;
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0
&& !dlcIds.Contains("" + appId))
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
dlcIds.Add("" + appId);
}
return dlcIds;
@ -268,8 +271,7 @@ internal static class SteamCMD
private static async Task Kill()
{
List<Task> tasks = Process.GetProcessesByName("steamcmd")
.Select(process => Task.Run(() =>
List<Task> tasks = Process.GetProcessesByName("steamcmd").Select(process => Task.Run(() =>
{
try
{
@ -278,9 +280,9 @@ internal static class SteamCMD
process.Close();
}
catch { }
}))
.ToList();
foreach (Task task in tasks) await task;
})).ToList();
foreach (Task task in tasks)
await task;
}
internal static void Dispose()

View file

@ -18,70 +18,74 @@ internal static class SteamLibrary
{
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(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;
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)))
(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(() =>
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;
if (Program.Canceled || !Directory.Exists(libraryDirectory))
return games;
foreach (string file in Directory.EnumerateFiles(libraryDirectory, "*.acf"))
{
if (Program.Canceled) return games;
if (Program.Canceled)
return games;
if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
{
string appId = result.Value.GetChild("appid")?.ToString();
string installdir = result.Value.GetChild("installdir")?.ToString();
string name = result.Value.GetChild("name")?.ToString();
string buildId = result.Value.GetChild("buildid")?.ToString();
if (string.IsNullOrWhiteSpace(appId)
|| string.IsNullOrWhiteSpace(installdir)
|| string.IsNullOrWhiteSpace(name)
if (string.IsNullOrWhiteSpace(appId) || 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;
if (!int.TryParse(appId, out int appIdInt)) continue;
if (!int.TryParse(buildId, out int buildIdInt)) continue;
if (games.Any(g => g.appId == appId && g.gameDirectory == gameDirectory))
continue;
if (!int.TryParse(appId, out int appIdInt))
continue;
if (!int.TryParse(buildId, out int buildIdInt))
continue;
string branch = result.Value.GetChild("UserConfig")?.GetChild("betakey")?.ToString();
if (string.IsNullOrWhiteSpace(branch)) branch = "public";
if (string.IsNullOrWhiteSpace(branch))
branch = "public";
games.Add((appId, name, branch, buildIdInt, gameDirectory));
}
}
return games;
});
internal static async Task<List<string>> GetLibraryDirectories() => await Task.Run(() =>
internal static async Task<List<string>> GetLibraryDirectories()
=> await Task.Run(() =>
{
List<string> gameDirectories = new();
if (Program.Canceled) return gameDirectories;
if (Program.Canceled)
return gameDirectories;
string steamInstallPath = InstallPath;
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
{
@ -90,14 +94,13 @@ 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;
if (string.IsNullOrWhiteSpace(path))
continue;
path += @"\steamapps";
if (Directory.Exists(path) && !gameDirectories.Contains(path))
gameDirectories.Add(path);

View file

@ -18,23 +18,25 @@ internal static class SteamStore
private const int COOLDOWN_GAME = 600;
private const int COOLDOWN_DLC = 1200;
internal static async Task<List<string>> ParseDlcAppIds(AppData appData) => await Task.Run(() =>
internal static async Task<List<string>> ParseDlcAppIds(AppData appData)
=> await Task.Run(() =>
{
List<string> dlcIds = new();
if (appData.dlc is null) return dlcIds;
if (appData.dlc is null)
return dlcIds;
dlcIds.AddRange(from appId in appData.dlc where appId > 0 select appId.ToString());
return dlcIds;
});
internal static async Task<AppData> QueryStoreAPI(string appId, bool isDlc = false, int attempts = 0)
{
if (Program.Canceled) return null;
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);
@ -60,8 +62,7 @@ internal static class SteamStore
{
try
{
await File.WriteAllTextAsync(
cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
await File.WriteAllTextAsync(cacheFile, JsonConvert.SerializeObject(data, Formatting.Indented));
}
catch
#if DEBUG
@ -76,16 +77,13 @@ internal static class SteamStore
return data;
}
#if DEBUG
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)}");
}
#endif
}
catch
@ -99,7 +97,8 @@ internal static class SteamStore
{ }
#endif
#if DEBUG
else DebugForm.Current.Log("Response deserialization null for appid " + appId);
else
DebugForm.Current.Log("Response deserialization null for appid " + appId);
#endif
}
else

View file

@ -22,16 +22,16 @@ internal static class UbisoftLibrary
}
}
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 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(
() =>
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;
if (installsKey is null)
return games;
foreach (string gameId in installsKey.GetSubKeyNames())
{
RegistryKey installKey = installsKey.OpenSubKey(gameId);

View file

@ -42,8 +42,10 @@ internal static class Program
internal static bool IsGameBlocked(string name, string directory = null)
{
if (!BlockProtectedGames) return false;
if (ProtectedGames.Contains(name)) return true;
if (!BlockProtectedGames)
return false;
if (ProtectedGames.Contains(name))
return true;
if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
foreach (string path in ProtectedGameDirectories)
if (Directory.Exists(directory + path))
@ -56,16 +58,12 @@ internal static class Program
if (selection.AreDllsLocked)
{
using DialogForm dialogForm = new(form);
if (dialogForm.Show(SystemIcons.Error,
$"ERROR: {selection.Name} is currently running!" +
"\n\nPlease close the program/game to continue . . . ",
if (dialogForm.Show(SystemIcons.Error, $"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;
}
return false;
}
@ -81,8 +79,7 @@ internal static class Program
Application.ApplicationExit += OnApplicationExit;
Application.ThreadException += (s, e) => e.Exception?.HandleFatalException();
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += (s, e)
=> (e.ExceptionObject as Exception)?.HandleFatalException();
AppDomain.CurrentDomain.UnhandledException += (s, e) => (e.ExceptionObject as Exception)?.HandleFatalException();
retry:
try
{
@ -95,7 +92,8 @@ internal static class Program
}
catch (Exception e)
{
if (e.HandleException()) goto retry;
if (e.HandleException())
goto retry;
Application.Exit();
return;
}

View file

@ -25,17 +25,14 @@ internal class ProgramSelection
internal static readonly List<ProgramSelection> All = new();
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
= new(PlatformIdComparer.String);
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc = 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)> 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 SortedList<string, (DlcType type, string name, string icon)> SelectedDlc = new(PlatformIdComparer.String);
internal List<string> DllDirectories;
internal bool Enabled;
@ -67,54 +64,31 @@ 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);
if (api32.IsFilePathLocked()
|| api32_o.IsFilePathLocked()
|| api64.IsFilePathLocked()
|| api64_o.IsFilePathLocked()
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())
return true;
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())
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())
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);
if (api32.IsFilePathLocked()
|| api32_o.IsFilePathLocked()
|| api64.IsFilePathLocked()
|| api64_o.IsFilePathLocked()
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())
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);
if (api32.IsFilePathLocked()
|| api32_o.IsFilePathLocked()
|| api64.IsFilePathLocked()
|| api64_o.IsFilePathLocked()
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())
return true;
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())
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())
return true;
}
}
@ -128,8 +102,10 @@ internal class ProgramSelection
private void Toggle(string dlcAppId, (DlcType type, string name, string icon) dlcApp, bool enabled)
{
if (enabled) SelectedDlc[dlcAppId] = dlcApp;
else _ = SelectedDlc.Remove(dlcAppId);
if (enabled)
SelectedDlc[dlcAppId] = dlcApp;
else
_ = SelectedDlc.Remove(dlcAppId);
}
internal void ToggleDlc(string dlcId, bool enabled)
@ -160,7 +136,8 @@ internal class ProgramSelection
return;
}
_ = DllDirectories.RemoveAll(directory => !Directory.Exists(directory));
if (!DllDirectories.Any()) _ = All.Remove(this);
if (!DllDirectories.Any())
_ = All.Remove(this);
}
internal void Validate(List<(Platform platform, string id, string name)> programsToScan)
@ -178,15 +155,12 @@ internal class ProgramSelection
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
=> AllSafe.ForEach(selection => selection.Validate(programsToScan));
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;
}

View file

@ -14,27 +14,22 @@ internal static class Koaloader
{
internal static readonly List<(string unlocker, string dll)> AutoLoadDlls = new()
{
("Koaloader", "Unlocker.dll"), ("Koaloader", "Unlocker32.dll"), ("Koaloader", "Unlocker64.dll"),
("Lyptus", "Lyptus.dll"), ("Lyptus", "Lyptus32.dll"), ("Lyptus", "Lyptus64.dll"),
("SmokeAPI", "SmokeAPI.dll"), ("SmokeAPI", "SmokeAPI32.dll"), ("SmokeAPI", "SmokeAPI64.dll"),
("ScreamAPI", "ScreamAPI.dll"), ("ScreamAPI", "ScreamAPI32.dll"), ("ScreamAPI", "ScreamAPI64.dll"),
("Uplay R1 Unlocker", "UplayR1Unlocker.dll"), ("Uplay R1 Unlocker", "UplayR1Unlocker32.dll"),
("Uplay R1 Unlocker", "UplayR1Unlocker64.dll"), ("Uplay R2 Unlocker", "UplayR2Unlocker.dll"),
("Uplay R2 Unlocker", "UplayR2Unlocker32.dll"), ("Uplay R2 Unlocker", "UplayR2Unlocker64.dll")
("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
)
internal static void GetKoaloaderComponents(this string directory, out List<string> proxies, out string config)
{
proxies = new List<string>();
proxies = new();
foreach (string proxy in EmbeddedResources.Select(proxy =>
{
proxy = proxy[(proxy.IndexOf('.') + 1)..];
return proxy[(proxy.IndexOf('.') + 1)..];
})) proxies.Add(directory + @"\" + proxy);
}))
proxies.Add(directory + @"\" + proxy);
config = directory + @"\Koaloader.json";
}
@ -51,8 +46,7 @@ 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('.')];
@ -83,13 +77,12 @@ internal static class Koaloader
else if (File.Exists(config))
{
File.Delete(config);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
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,");
@ -108,9 +101,7 @@ internal static class Koaloader
writer.WriteLine(" ]");
}
else
{
writer.WriteLine(" \"targets\": []");
}
if (modules.Any())
{
writer.WriteLine(" \"modules\": [");
@ -127,24 +118,20 @@ internal static class Koaloader
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, false);
}
foreach ((string unlocker, string path) in AutoLoadDlls
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
foreach ((string unlocker, string path) in AutoLoadDlls.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
{
File.Delete(path);
@ -163,26 +150,23 @@ 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, 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, 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))
@ -204,8 +188,7 @@ internal static class Koaloader
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI32.dll";
}
@ -222,8 +205,7 @@ internal static class Koaloader
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI64.dll";
}
@ -244,8 +226,7 @@ internal static class Koaloader
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI32.dll";
}
@ -262,8 +243,7 @@ internal static class Koaloader
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI64.dll";
}
@ -284,9 +264,7 @@ 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, false);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR1Unlocker32.dll";
}
@ -303,9 +281,7 @@ 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, false);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR1Unlocker64.dll";
}
@ -323,9 +299,7 @@ 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, false);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR2Unlocker32.dll";
}
@ -342,9 +316,7 @@ 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, false);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR2Unlocker64.dll";
}

View file

@ -335,7 +335,7 @@ internal static class Resources
if (embeddedResources is null)
{
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
embeddedResources = new List<string>();
embeddedResources = new();
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.")))
embeddedResources.Add(resourceName[25..]);
}
@ -345,8 +345,7 @@ 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);
}
@ -378,45 +377,42 @@ internal static class Resources
[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 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 =>
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(
() =>
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false,
Func<string, bool> validFunc = null)
=> await Task.Run(() =>
{
List<(string path, BinaryType binaryType)> executables = new();
if (Program.Canceled || !Directory.Exists(rootDirectory)) return null;
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe",
new EnumerationOptions { RecurseSubdirectories = true }))
if (Program.Canceled || !Directory.Exists(rootDirectory))
return null;
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", new EnumerationOptions { RecurseSubdirectories = true }))
{
if (Program.Canceled) return null;
if (executables.All(e => e.path != path)
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
&& (validFunc is null || validFunc(path))
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64)
if (Program.Canceled)
return null;
if (executables.All(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 }))
foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", new EnumerationOptions { RecurseSubdirectories = true }))
{
if (Program.Canceled) return null;
if (executables.All(e => e.path != path)
&& (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path))
&& (validFunc is null || validFunc(path))
&& path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32)
if (Program.Canceled)
return null;
if (executables.All(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);
}
@ -426,80 +422,54 @@ internal static class Resources
internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path)
{
string subPath = path[rootDirectory.Length..].ToUpperInvariant().BeautifyPath();
return subPath.Contains("SETUP")
|| subPath.Contains("REDIST")
|| subPath.Contains("SUPPORT")
|| (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("BATTLEYE")
return subPath.Contains("SETUP") || subPath.Contains("REDIST") || subPath.Contains("SUPPORT")
|| 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("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 })
if (Program.Canceled || !Directory.Exists(gameDirectory))
return null;
foreach (string directory in Directory.EnumerateDirectories(gameDirectory, "*", new EnumerationOptions { RecurseSubdirectories = true })
.Append(gameDirectory))
{
if (Program.Canceled) return null;
if (Program.Canceled)
return null;
string subDirectory = directory.BeautifyPath();
if (!dllDirectories.Contains(subDirectory))
{
bool koaloaderInstalled = Koaloader.AutoLoadDlls
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
bool koaloaderInstalled = Koaloader.AutoLoadDlls.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);
if (File.Exists(api)
|| File.Exists(api_o)
|| File.Exists(api64)
|| File.Exists(api64_o)
|| (File.Exists(config) && !koaloaderInstalled)
|| (File.Exists(cache) && !koaloaderInstalled))
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)
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);
if (File.Exists(api32)
|| File.Exists(api32_o)
|| File.Exists(api64)
|| File.Exists(api64_o)
|| (File.Exists(config) && !koaloaderInstalled))
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)
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);
if (File.Exists(api32)
|| File.Exists(api32_o)
|| File.Exists(api64)
|| File.Exists(api64_o)
|| (File.Exists(config) && !koaloaderInstalled))
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)
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);
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))
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)
dllDirectories.Add(subDirectory);
}
}
@ -507,10 +477,7 @@ internal static class Resources
return !dllDirectories.Any() ? null : dllDirectories;
});
internal static void GetCreamApiComponents(
this string directory,
out string api32, out string api32_o,
out string api64, out string api64_o,
internal static void GetCreamApiComponents(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";
@ -522,7 +489,8 @@ internal static class Resources
internal static string ComputeMD5(this string filePath)
{
if (!File.Exists(filePath)) return null;
if (!File.Exists(filePath))
return null;
#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms
using MD5 md5 = MD5.Create();
#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms
@ -534,9 +502,8 @@ internal static class Resources
internal static bool IsResourceFile(this string filePath, ResourceIdentifier identifier)
=> filePath.ComputeMD5() is string hash && ResourceMD5s[identifier].Contains(hash);
internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is string hash
&& ResourceMD5s.Values.Any(
hashes => hashes.Contains(hash));
internal static bool IsResourceFile(this string filePath)
=> filePath.ComputeMD5() is string hash && ResourceMD5s.Values.Any(hashes => hashes.Contains(hash));
internal enum BinaryType
{

View file

@ -11,12 +11,8 @@ 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
)
internal static void GetScreamApiComponents(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";
@ -30,13 +26,11 @@ internal static class ScreamAPI
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)
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)
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())
{
@ -44,28 +38,20 @@ internal static class ScreamAPI
installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
File.Create(config).Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer,
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);
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);
writer.Flush();
writer.Close();
}
else if (File.Exists(config))
{
File.Delete(config);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
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,");
@ -77,22 +63,18 @@ 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, 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,");
@ -106,15 +88,12 @@ 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,
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("}");
}
@ -122,8 +101,7 @@ internal static class ScreamAPI
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);
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
if (File.Exists(api32_o))
{
if (File.Exists(api32))
@ -132,8 +110,7 @@ internal static class ScreamAPI
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);
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
@ -143,8 +120,7 @@ internal static class ScreamAPI
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);
installForm?.UpdateUser($"Restored EOS: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
@ -153,16 +129,14 @@ internal static class ScreamAPI
}
});
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, false);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
@ -172,8 +146,7 @@ internal static class ScreamAPI
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, false);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{

View file

@ -11,12 +11,8 @@ 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)
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)
{
api32 = directory + @"\steam_api.dll";
api32_o = directory + @"\steam_api_o.dll";
@ -29,18 +25,15 @@ 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)>>();
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));
}
@ -50,27 +43,20 @@ internal static class SmokeAPI
installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
File.Create(config).Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer,
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);
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);
writer.Flush();
writer.Close();
}
else if (File.Exists(config))
{
File.Delete(config);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
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,");
@ -86,15 +72,12 @@ 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, 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\": [");
@ -104,15 +87,12 @@ 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, 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("}");
@ -125,11 +105,9 @@ internal static class SmokeAPI
if (File.Exists(oldConfig))
{
File.Delete(oldConfig);
installForm?.UpdateUser($"Deleted old CreamAPI configuration: {Path.GetFileName(oldConfig)}",
LogTextBox.Action, 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 string 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_o))
{
if (File.Exists(api32))
@ -138,9 +116,7 @@ internal static class SmokeAPI
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);
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
@ -150,9 +126,7 @@ internal static class SmokeAPI
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);
installForm?.UpdateUser($"Restored Steamworks: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
@ -166,23 +140,20 @@ internal static class SmokeAPI
}
});
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, 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, false);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
@ -192,8 +163,7 @@ internal static class SmokeAPI
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, false);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{

View file

@ -11,12 +11,8 @@ 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
)
internal static void GetUplayR1Components(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,10 +24,8 @@ 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())
{
@ -39,23 +33,18 @@ 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 SortedList<string, (DlcType type, string name, string icon)>(
blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
installForm);
WriteConfig(writer, new(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,
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,
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
@ -71,46 +60,38 @@ 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, 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);
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
if (File.Exists(api32_o))
{
if (File.Exists(api32))
{
File.Delete(api32);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action,
false);
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);
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
if (File.Exists(api64))
{
File.Delete(api64);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action,
false);
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);
installForm?.UpdateUser($"Restored Uplay R1: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
@ -119,16 +100,14 @@ internal static class UplayR1
}
});
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, false);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
@ -138,8 +117,7 @@ internal static class UplayR1
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, false);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{

View file

@ -11,12 +11,8 @@ 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)
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)
{
old_api32 = directory + @"\uplay_r2_loader.dll";
old_api64 = directory + @"\uplay_r2_loader64.dll";
@ -30,10 +26,8 @@ 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())
{
@ -41,23 +35,18 @@ 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 SortedList<string, (DlcType type, string name, string icon)>(
blacklistDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
installForm);
WriteConfig(writer, new(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,
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,
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
@ -75,35 +64,30 @@ 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, 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);
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32, out string api32_o, out string api64,
out string api64_o, out string config);
if (File.Exists(api32_o))
{
string api = File.Exists(old_api32) ? old_api32 : api32;
if (File.Exists(api))
{
File.Delete(api);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
false);
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);
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api32_o)} -> {Path.GetFileName(api)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
@ -111,12 +95,10 @@ internal static class UplayR2
if (File.Exists(api))
{
File.Delete(api);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
false);
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);
installForm?.UpdateUser($"Restored Uplay R2: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
@ -125,17 +107,16 @@ internal static class UplayR2
}
});
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, false);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
@ -146,8 +127,7 @@ internal static class UplayR2
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, false);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{

View file

@ -14,8 +14,7 @@ internal static class Diagnostics
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;
}
}
@ -35,18 +34,13 @@ 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));
}

View file

@ -8,8 +8,8 @@ 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();
@ -32,15 +32,9 @@ internal static class ExceptionHandler
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..])
_ = 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));
}
@ -49,14 +43,12 @@ internal static class ExceptionHandler
stackDepth++;
}
using DialogForm dialogForm = new(form ?? Form.ActiveForm);
return dialogForm.Show(SystemIcons.Error, output.ToString(), acceptButtonText, cancelButtonText, 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();

View file

@ -12,7 +12,7 @@ internal static class HttpClientManager
internal static void Setup()
{
HttpClient = new HttpClient();
HttpClient = new();
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Program.Version.Replace(".", "")}");
}
@ -21,8 +21,7 @@ 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();
}
@ -42,8 +41,7 @@ internal static class HttpClientManager
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath)
=> (await EnsureGet(url))?.ToHtmlDocument()?.DocumentNode?.SelectNodes(xpath);
internal static HtmlNodeCollection GetDocumentNodes(this 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)
{

View file

@ -6,27 +6,23 @@ namespace CreamInstaller.Utility;
internal static class IconGrabber
{
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 Icon ToIcon(this Image image)
{
using Bitmap dialogIconBitmap = new(image, new Size(image.Width, image.Height));
using Bitmap dialogIconBitmap = new(image, new(image.Width, image.Height));
return Icon.FromHandle(dialogIconBitmap.GetHicon());
}
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");
}

View file

@ -18,9 +18,11 @@ internal static class LogTextBox
textBox.SelectionStart = textBox.TextLength;
textBox.SelectionLength = 0;
textBox.SelectionColor = color;
if (scroll) textBox.ScrollToCaret();
if (scroll)
textBox.ScrollToCaret();
textBox.AppendText(text);
if (scroll) textBox.ScrollToCaret();
if (scroll)
textBox.ScrollToCaret();
textBox.SelectionColor = textBox.ForeColor;
textBox.Invalidate();
}

View file

@ -11,11 +11,9 @@ namespace CreamInstaller.Utility;
internal static class ProgramData
{
internal static readonly string DirectoryPathOld
= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\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 DirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo";
internal static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
@ -29,19 +27,22 @@ internal static class ProgramData
internal static readonly string DlcChoicesPath = DirectoryPath + @"\dlc.json";
internal static readonly string KoaloaderProxyChoicesPath = DirectoryPath + @"\proxies.json";
internal static async Task Setup() => await Task.Run(() =>
internal static async Task Setup()
=> await Task.Run(() =>
{
if (Directory.Exists(DirectoryPathOld))
{
if (Directory.Exists(DirectoryPath)) Directory.Delete(DirectoryPath, true);
if (Directory.Exists(DirectoryPath))
Directory.Delete(DirectoryPath, true);
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)
if (!Directory.Exists(DirectoryPath))
_ = Directory.CreateDirectory(DirectoryPath);
if (!File.Exists(AppInfoVersionPath) || !Version.TryParse(File.ReadAllText(AppInfoVersionPath, Encoding.UTF8), out Version version)
|| version < MinimumAppInfoVersion)
{
if (Directory.Exists(AppInfoPath)) Directory.Delete(AppInfoPath, true);
if (Directory.Exists(AppInfoPath))
Directory.Delete(AppInfoPath, true);
_ = Directory.CreateDirectory(AppInfoPath);
File.WriteAllText(AppInfoVersionPath, Program.Version, Encoding.UTF8);
}
@ -91,16 +92,16 @@ internal static class ProgramData
internal static List<(Platform platform, string id)> ReadProgramChoices()
{
if (!File.Exists(ProgramChoicesPath)) return null;
if (!File.Exists(ProgramChoicesPath))
return null;
try
{
return JsonConvert.DeserializeObject(File.ReadAllText(ProgramChoicesPath),
typeof(List<(Platform platform, string id)>)) as
return JsonConvert.DeserializeObject(File.ReadAllText(ProgramChoicesPath), typeof(List<(Platform platform, string id)>)) as
List<(Platform platform, string id)>;
}
catch
{
return new List<(Platform platform, string id)>();
return new();
}
}
@ -118,16 +119,16 @@ internal static class ProgramData
internal static List<(Platform platform, string gameId, string dlcId)> ReadDlcChoices()
{
if (!File.Exists(DlcChoicesPath)) return null;
if (!File.Exists(DlcChoicesPath))
return null;
try
{
return JsonConvert.DeserializeObject(File.ReadAllText(DlcChoicesPath),
typeof(List<(Platform platform, string gameId, string dlcId)>)) as
return JsonConvert.DeserializeObject(File.ReadAllText(DlcChoicesPath), typeof(List<(Platform platform, string gameId, string dlcId)>)) as
List<(Platform platform, string gameId, string dlcId)>;
}
catch
{
return new List<(Platform platform, string gameId, string dlcId)>();
return new();
}
}
@ -145,22 +146,20 @@ internal static class ProgramData
internal static List<(Platform platform, string id, string proxy, bool enabled)> ReadKoaloaderChoices()
{
if (!File.Exists(KoaloaderProxyChoicesPath)) return null;
if (!File.Exists(KoaloaderProxyChoicesPath))
return null;
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 List<(Platform platform, string id, string proxy, bool enabled)>();
return new();
}
}
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
{