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,35 +90,31 @@ internal class ContextMenuItem : ToolStripMenuItem
}
});
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)
private static async Task TryImageIdentifierInfo(ContextMenuItem item, (string id, string iconUrl) imageIdentifierInfo, Action onFail = null)
=> await Task.Run(async () =>
{
item.Image = image;
}
else
{
image = await HttpClientManager.GetImageFromUrl(iconUrl);
if (image is not null)
{
images[imageIdentifier] = image;
(string id, string iconUrl) = imageIdentifierInfo;
string imageIdentifier = "Icon_" + id;
if (images.TryGetValue(imageIdentifier, out Image image) && image is not null)
item.Image = image;
}
else if (onFail is not null)
else
{
onFail();
image = await HttpClientManager.GetImageFromUrl(iconUrl);
if (image is not null)
{
images[imageIdentifier] = image;
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

@ -58,46 +58,38 @@ internal class CustomForm : Form
string acidicoala = "https://github.com/acidicoala";
string repository = $"https://github.com/{Program.RepositoryOwner}/{Program.RepositoryName}";
_ = helpDialog.Show(SystemIcons.Information,
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n"
+ "\n"
+ $"The program utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [SmokeAPI]({acidicoala}/SmokeAPI), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1 Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by\n"
+ $"the wonderful [acidicoala]({acidicoala}), and all downloaded and embedded into the program itself; no further downloads necessary on your part!\n"
+ "\n"
+ "NOTE: This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's\n"
+ "only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many\n"
+ "do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for\n"
+ "the game(s) you're tinkering with; you'll usually find any answer to your problems there.\n"
+ "\n"
+ "USAGE:\n"
+ " 1. Choose which programs and/or games the program should scan for DLC.\n"
+ " The program automatically gathers all installed games from Steam, Epic and Ubisoft directories.\n"
+ " 2. Wait for the program to download and install SteamCMD (if you chose a Steam game).\n"
+ " 3. Wait for the program to gather and cache the chosen games' information && DLCs.\n"
+ " May take some time on the first run; depends on how many DLCs the games you chose have.\n"
+ " 4. CAREFULLY select which games' DLCs you wish to unlock.\n"
+ " Obviously none of the DLC unlockers are tested for every single game!\n"
+ " 5. Choose whether or not to install with Koaloader, and if so then also pick the proxy DLL to use.\n"
+ " If the default \'version.dll\' doesn't work, then see [here](https://cs.rin.ru/forum/viewtopic.php?p=2552172#p2552172) to find one that does.\n"
+ " 6. Click the \"Generate and Install\" button.\n"
+ " 7. Click the \"OK\" button to close the program.\n"
+ " 8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back\n"
+ " to step 5 and select what games you wish you revert changes to, and instead click the \"Uninstall\" button this time.\n"
+ "\n"
+ $"For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues]({repository}/issues) page!\n"
+ "\n"
+ "SteamCMD installation and appinfo cache can be found at [C:\\ProgramData\\CreamInstaller]().\n"
+ $"The program automatically and very quickly updates from [GitHub]({repository}) using [Onova](https://github.com/Tyrrrz/Onova). (updates can be ignored)\n"
+ $"The program source and other information can be found on [GitHub]({repository}).");
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n" + "\n"
+ $"The program utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [SmokeAPI]({acidicoala}/SmokeAPI), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1 Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by\n"
+ $"the wonderful [acidicoala]({acidicoala}), and all downloaded and embedded into the program itself; no further downloads necessary on your part!\n"
+ "\n" + "NOTE: This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's\n"
+ "only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many\n"
+ "do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for\n"
+ "the game(s) you're tinkering with; you'll usually find any answer to your problems there.\n" + "\n" + "USAGE:\n"
+ " 1. Choose which programs and/or games the program should scan for DLC.\n"
+ " The program automatically gathers all installed games from Steam, Epic and Ubisoft directories.\n"
+ " 2. Wait for the program to download and install SteamCMD (if you chose a Steam game).\n"
+ " 3. Wait for the program to gather and cache the chosen games' information && DLCs.\n"
+ " May take some time on the first run; depends on how many DLCs the games you chose have.\n"
+ " 4. CAREFULLY select which games' DLCs you wish to unlock.\n"
+ " Obviously none of the DLC unlockers are tested for every single game!\n"
+ " 5. Choose whether or not to install with Koaloader, and if so then also pick the proxy DLL to use.\n"
+ " If the default \'version.dll\' doesn't work, then see [here](https://cs.rin.ru/forum/viewtopic.php?p=2552172#p2552172) to find one that does.\n"
+ " 6. Click the \"Generate and Install\" button.\n" + " 7. Click the \"OK\" button to close the program.\n"
+ " 8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back\n"
+ " to step 5 and select what games you wish you revert changes to, and instead click the \"Uninstall\" button this time.\n" + "\n"
+ $"For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues]({repository}/issues) page!\n"
+ "\n" + "SteamCMD installation and appinfo cache can be found at [C:\\ProgramData\\CreamInstaller]().\n"
+ $"The program automatically and very quickly updates from [GitHub]({repository}) using [Onova](https://github.com/Tyrrrz/Onova). (updates can be ignored)\n"
+ $"The program source and other information can be found on [GitHub]({repository}).");
}
internal void OnActivation(object sender, EventArgs args) => Activate();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern void SetWindowPos(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"),
TextFormatFlags.Default);
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,13 +201,11 @@ internal class CustomTreeView : TreeView
}
else if (pair.Value.Contains(clickPoint))
{
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))
.Select(p =>
{
p.GetProxyInfoFromIdentifier(
out string proxyName, out _);
return proxyName;
}).Distinct().ToList();
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader")).Select(p =>
{
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
return proxyName;
}).Distinct().ToList();
comboBoxDropDown ??= new ToolStripDropDown();
comboBoxDropDown.ShowItemToolTips = false;
comboBoxDropDown.Items.Clear();
@ -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
+ $" with root directory \"{selection.RootDirectory}\" . . . ", LogTextBox.Operation);
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,18 +107,19 @@ 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
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await SmokeAPI.Uninstall(directory, this);
else
@ -130,15 +128,12 @@ internal partial class InstallForm : CustomForm
}
if (selection.Platform is Platform.Epic or Platform.Paradox)
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config);
if (uninstallProxy
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config)
: File.Exists(api32) || File.Exists(api64))
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
{
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await ScreamAPI.Uninstall(directory, this);
else
@ -147,29 +142,25 @@ internal partial class InstallForm : CustomForm
}
if (selection.Platform is Platform.Ubisoft)
{
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
out string api64_o, out string config);
if (uninstallProxy
? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config)
: File.Exists(api32) || File.Exists(api64))
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config);
if (uninstallProxy ? File.Exists(api32_o) || File.Exists(api64_o) || File.Exists(config) : File.Exists(api32) || File.Exists(api64))
{
UpdateUser($"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
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
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await UplayR2.Uninstall(directory, this);
else
@ -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,9 +154,8 @@ internal partial class MainForm : CustomForm
{
using DialogForm form = new(this);
if (form.Show(SystemIcons.Warning,
"WARNING: " + Program.ApplicationExecutable + " was renamed!" +
"\n\nThis will cause undesirable behavior when updating the program!",
"Ignore", "Abort") == DialogResult.Cancel)
"WARNING: " + Program.ApplicationExecutable + " was renamed!" + "\n\nThis will cause undesirable behavior when updating the program!",
"Ignore", "Abort") == DialogResult.Cancel)
{
Application.Exit();
return;
@ -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);

File diff suppressed because it is too large Load diff

View file

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

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));
}
}
}
@ -83,10 +77,9 @@ 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;
"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!"
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!", "Ignore", "Cancel",
"Paradox Launcher") != DialogResult.OK;
}
}
return false;
@ -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,84 +37,86 @@ 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)
? $@"@ShutdownOnFailedCommand 0 +force_install_dir {DirectoryPath} +login anonymous +app_info_print {appId} "
+ string.Concat(Enumerable.Repeat("+app_update 4 ", attempts)) + "+quit"
: $"+login anonymous +app_info_print {appId} +quit";
private static 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(() =>
{
wait_for_lock:
if (Program.Canceled) return "";
for (int i = 0; i < locks.Length; i++)
internal static async Task<string> Run(string appId)
=> await Task.Run(() =>
{
if (Program.Canceled) return "";
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
wait_for_lock:
if (Program.Canceled)
return "";
for (int i = 0; i < locks.Length; i++)
{
if (appId is not null)
{
AttemptCount.TryGetValue(appId, out int count);
AttemptCount[appId] = ++count;
}
if (Program.Canceled) return "";
ProcessStartInfo processStartInfo = new()
{
FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true,
RedirectStandardError = true, UseShellExecute = false,
Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
Process process = Process.Start(processStartInfo);
StringBuilder output = new();
StringBuilder appInfo = new();
bool appInfoStarted = false;
DateTime lastOutput = DateTime.UtcNow;
while (true)
if (Program.Canceled)
return "";
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
{
if (appId is not null)
{
AttemptCount.TryGetValue(appId, out int count);
AttemptCount[appId] = ++count;
}
if (Program.Canceled)
return "";
ProcessStartInfo processStartInfo = new()
{
process.Kill(true);
process.Close();
break;
}
int c = process.StandardOutput.Read();
if (c != -1)
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();
StringBuilder appInfo = new();
bool appInfoStarted = false;
DateTime lastOutput = DateTime.UtcNow;
while (true)
{
lastOutput = DateTime.UtcNow;
char ch = (char)c;
if (ch == '{') appInfoStarted = true;
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
}
DateTime now = DateTime.UtcNow;
TimeSpan timeDiff = now - lastOutput;
if (timeDiff.TotalSeconds > 0.1)
{
process.Kill(true);
process.Close();
if (output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
{
AttemptCount[appId]++;
processStartInfo.Arguments = GetArguments(appId);
process = Process.Start(processStartInfo);
appInfoStarted = false;
_ = output.Clear();
_ = appInfo.Clear();
}
else
if (Program.Canceled)
{
process.Kill(true);
process.Close();
break;
}
int c = process.StandardOutput.Read();
if (c != -1)
{
lastOutput = DateTime.UtcNow;
char ch = (char)c;
if (ch == '{')
appInfoStarted = true;
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
}
DateTime now = DateTime.UtcNow;
TimeSpan timeDiff = now - lastOutput;
if (timeDiff.TotalSeconds > 0.1)
{
process.Kill(true);
process.Close();
if (output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
{
AttemptCount[appId]++;
processStartInfo.Arguments = GetArguments(appId);
process = Process.Start(processStartInfo);
appInfoStarted = false;
_ = output.Clear();
_ = appInfo.Clear();
}
else
break;
}
}
_ = Interlocked.Decrement(ref locks[i]);
return appInfo.ToString();
}
_ = Interlocked.Decrement(ref locks[i]);
return appInfo.ToString();
Thread.Sleep(200);
}
Thread.Sleep(200);
}
Thread.Sleep(200);
goto wait_for_lock;
});
goto wait_for_lock;
});
internal static async Task Setup(IProgress<int> progress)
{
@ -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,45 +146,47 @@ internal static class SteamCMD
}
}
internal static async Task Cleanup() => await Task.Run(async () =>
{
if (!Directory.Exists(DirectoryPath)) return;
await Kill();
try
internal static async Task Cleanup()
=> await Task.Run(async () =>
{
if (Directory.Exists(ConfigPath))
foreach (string file in Directory.EnumerateFiles(ConfigPath, "*.tmp"))
if (!Directory.Exists(DirectoryPath))
return;
await Kill();
try
{
if (Directory.Exists(ConfigPath))
foreach (string file in Directory.EnumerateFiles(ConfigPath, "*.tmp"))
File.Delete(file);
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.old"))
File.Delete(file);
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.old"))
File.Delete(file);
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.delete"))
File.Delete(file);
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.crash"))
File.Delete(file);
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
if (Directory.Exists(DumpsPath))
Directory.Delete(DumpsPath, true);
if (Directory.Exists(LogsPath))
Directory.Delete(LogsPath, true);
if (Directory.Exists(SteamAppsPath))
Directory.Delete(SteamAppsPath, true); // this is just a useless folder created from +app_update 4
}
catch { }
});
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.delete"))
File.Delete(file);
foreach (string file in Directory.EnumerateFiles(DirectoryPath, "*.crash"))
File.Delete(file);
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
if (Directory.Exists(DumpsPath))
Directory.Delete(DumpsPath, true);
if (Directory.Exists(LogsPath))
Directory.Delete(LogsPath, true);
if (Directory.Exists(SteamAppsPath))
Directory.Delete(SteamAppsPath, true); // this is just a useless folder created from +app_update 4
}
catch { }
});
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,74 +214,75 @@ 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(() =>
{
List<string> dlcIds = new();
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" }))
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo)
=> await Task.Run(() =>
{
List<string> dlcIds = new();
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" }))
{
VProperty property = (VProperty)vToken;
foreach (string id in property.Value.ToString().Split(","))
if (int.TryParse(id, out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
dlcIds.Add("" + appId);
}
VToken depots = appInfo.Value.GetChild("depots");
if (depots is null)
return dlcIds;
foreach (VToken vToken in depots.Where(p => p is VProperty property && int.TryParse(property.Key, out int _)))
{
VProperty property = (VProperty)vToken;
foreach (string id in property.Value.ToString().Split(","))
if (int.TryParse(id, out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
dlcIds.Add("" + appId);
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
dlcIds.Add("" + appId);
}
VToken depots = appInfo.Value.GetChild("depots");
if (depots is null)
return dlcIds;
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))
dlcIds.Add("" + appId);
}
return dlcIds;
});
});
private static async Task Kill()
{
List<Task> tasks = Process.GetProcessesByName("steamcmd")
.Select(process => Task.Run(() =>
{
try
{
process.Kill(true);
process.WaitForExit();
process.Close();
}
catch { }
}))
.ToList();
foreach (Task task in tasks) await task;
List<Task> tasks = Process.GetProcessesByName("steamcmd").Select(process => Task.Run(() =>
{
try
{
process.Kill(true);
process.WaitForExit();
process.Close();
}
catch { }
})).ToList();
foreach (Task task in tasks)
await task;
}
internal static void Dispose()

View file

@ -18,93 +18,96 @@ 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 () =>
{
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
List<string> gameLibraryDirectories = await GetLibraryDirectories();
foreach (string libraryDirectory in gameLibraryDirectories)
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
=> await Task.Run(async () =>
{
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)))
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(() =>
{
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return games;
foreach (string file in Directory.EnumerateFiles(libraryDirectory, "*.acf"))
{
if (Program.Canceled) return games;
if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
List<string> gameLibraryDirectories = await GetLibraryDirectories();
foreach (string libraryDirectory in gameLibraryDirectories)
{
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)
|| 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;
string branch = result.Value.GetChild("UserConfig")?.GetChild("betakey")?.ToString();
if (string.IsNullOrWhiteSpace(branch)) branch = "public";
games.Add((appId, name, branch, buildIdInt, gameDirectory));
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)))
games.Add(game);
}
}
return games;
});
return games;
});
internal static async Task<List<string>> GetLibraryDirectories() => await Task.Run(() =>
{
List<string> gameDirectories = new();
if (Program.Canceled) return gameDirectories;
string steamInstallPath = InstallPath;
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>>
GetGamesFromLibraryDirectory(string libraryDirectory)
=> await Task.Run(() =>
{
string libraryFolder = steamInstallPath + @"\steamapps";
if (Directory.Exists(libraryFolder))
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
if (Program.Canceled || !Directory.Exists(libraryDirectory))
return games;
foreach (string file in Directory.EnumerateFiles(libraryDirectory, "*.acf"))
{
gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
if (File.Exists(libraryFolders)
&& ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
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)
|| 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;
string branch = result.Value.GetChild("UserConfig")?.GetChild("betakey")?.ToString();
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(() =>
{
List<string> gameDirectories = new();
if (Program.Canceled)
return gameDirectories;
string steamInstallPath = InstallPath;
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
{
string libraryFolder = steamInstallPath + @"\steamapps";
if (Directory.Exists(libraryFolder))
{
gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
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 _)))
{
string path = property.Value.GetChild("path")?.ToString();
if (string.IsNullOrWhiteSpace(path)) continue;
path += @"\steamapps";
if (Directory.Exists(path) && !gameDirectories.Contains(path))
gameDirectories.Add(path);
}
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;
path += @"\steamapps";
if (Directory.Exists(path) && !gameDirectories.Contains(path))
gameDirectories.Add(path);
}
#pragma warning restore IDE0220 // Add explicit cast
}
}
}
return gameDirectories;
});
return gameDirectories;
});
}

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(() =>
{
List<string> dlcIds = new();
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<List<string>> ParseDlcAppIds(AppData appData)
=> await Task.Run(() =>
{
List<string> dlcIds = new();
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 . . . ",
"Retry", "Cancel") == DialogResult.OK)
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,235 +118,216 @@ 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 () =>
{
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
foreach (string proxyPath in proxies.Where(
proxyPath => File.Exists(proxyPath) && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null, bool deleteConfig = true)
=> await Task.Run(async () =>
{
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))
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
File.Delete(config);
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
await SmokeAPI.Uninstall(directory, installForm, deleteConfig);
await ScreamAPI.Uninstall(directory, installForm, deleteConfig);
await UplayR1.Uninstall(directory, installForm, deleteConfig);
await UplayR2.Uninstall(directory, installForm, deleteConfig);
if (rootDirectory is not null && directory != rootDirectory)
await Uninstall(rootDirectory, null, installForm, deleteConfig);
});
directory.GetKoaloaderComponents(out List<string> proxies, out string config);
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))
.Where(pair => File.Exists(pair.path) && pair.path.IsResourceFile()))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
if (deleteConfig && File.Exists(config))
{
File.Delete(config);
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
await SmokeAPI.Uninstall(directory, installForm, deleteConfig);
await ScreamAPI.Uninstall(directory, installForm, deleteConfig);
await UplayR1.Uninstall(directory, installForm, deleteConfig);
await UplayR2.Uninstall(directory, installForm, deleteConfig);
if (rootDirectory is not null && directory != rootDirectory)
await Uninstall(rootDirectory, null, installForm, deleteConfig);
});
internal static async Task Install(string directory, BinaryType binaryType, 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)))
internal static async Task Install(string directory, BinaryType binaryType, ProgramSelection selection, string rootDirectory = null,
InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
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!");
path.WriteProxy(proxy, binaryType);
installForm?.UpdateUser(
$"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}",
LogTextBox.Action, false);
bool bit32 = false, bit64 = false;
foreach (string executable in Directory.EnumerateFiles(directory, "*.exe"))
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
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)))
{
if (binaryType == BinaryType.BIT32)
bit32 = true;
else if (binaryType == BinaryType.BIT64)
bit64 = true;
if (bit32 && bit64)
break;
File.Delete(_path);
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", LogTextBox.Action, false);
}
if (selection.Platform is Platform.Steam or Platform.Paradox)
{
if (bit32)
{
path = directory + @"\SmokeAPI32.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (File.Exists(path) && !path.IsResourceFile(ResourceIdentifier.Koaloader))
throw new CustomMessageException("A non-Koaloader DLL named " + proxy + ".dll already exists in this directory!");
path.WriteProxy(proxy, binaryType);
installForm?.UpdateUser($"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}", LogTextBox.Action,
false);
bool bit32 = false, bit64 = false;
foreach (string executable in Directory.EnumerateFiles(directory, "*.exe"))
if (executable.TryGetFileBinaryType(out BinaryType binaryType))
{
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI32.dll";
if (binaryType == BinaryType.BIT32)
bit32 = true;
else if (binaryType == BinaryType.BIT64)
bit64 = true;
if (bit32 && bit64)
break;
}
"SmokeAPI.steam_api.dll".Write(path);
installForm?.UpdateUser(
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
if (bit64)
if (selection.Platform is Platform.Steam or Platform.Paradox)
{
path = directory + @"\SmokeAPI64.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (bit32)
{
if (File.Exists(path))
path = directory + @"\SmokeAPI32.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI32.dll";
}
path = rootDirectory + @"\SmokeAPI64.dll";
"SmokeAPI.steam_api.dll".Write(path);
installForm?.UpdateUser(
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"SmokeAPI.steam_api64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (bit64)
{
path = directory + @"\SmokeAPI64.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI64.dll";
}
"SmokeAPI.steam_api64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote SmokeAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
SmokeAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
SmokeAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
if (selection.Platform is Platform.Epic or Platform.Paradox)
{
if (bit32)
if (selection.Platform is Platform.Epic or Platform.Paradox)
{
path = directory + @"\ScreamAPI32.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (bit32)
{
if (File.Exists(path))
path = directory + @"\ScreamAPI32.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI32.dll";
}
path = rootDirectory + @"\ScreamAPI32.dll";
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(path);
installForm?.UpdateUser(
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(path);
installForm?.UpdateUser(
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (bit64)
{
path = directory + @"\ScreamAPI64.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI64.dll";
}
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(path);
installForm?.UpdateUser(
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
ScreamAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
if (bit64)
if (selection.Platform is Platform.Ubisoft)
{
path = directory + @"\ScreamAPI64.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (bit32)
{
if (File.Exists(path))
path = directory + @"\UplayR1Unlocker32.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR1Unlocker32.dll";
}
path = rootDirectory + @"\ScreamAPI64.dll";
"UplayR1.uplay_r1_loader.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(path);
installForm?.UpdateUser(
$"Wrote ScreamAPI{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
ScreamAPI.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
if (selection.Platform is Platform.Ubisoft)
{
if (bit32)
{
path = directory + @"\UplayR1Unlocker32.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (bit64)
{
if (File.Exists(path))
path = directory + @"\UplayR1Unlocker64.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser(
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR1Unlocker64.dll";
}
path = rootDirectory + @"\UplayR1Unlocker32.dll";
"UplayR1.uplay_r1_loader64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"UplayR1.uplay_r1_loader.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
if (bit64)
{
path = directory + @"\UplayR1Unlocker64.dll";
if (rootDirectory is not null && directory != rootDirectory)
UplayR1.CheckConfig(rootDirectory ?? directory, selection, installForm);
if (bit32)
{
if (File.Exists(path))
path = directory + @"\UplayR2Unlocker32.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser(
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR2Unlocker32.dll";
}
path = rootDirectory + @"\UplayR1Unlocker64.dll";
"UplayR2.upc_r2_loader.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"UplayR1.uplay_r1_loader64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R1 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
UplayR1.CheckConfig(rootDirectory ?? directory, selection, installForm);
if (bit32)
{
path = directory + @"\UplayR2Unlocker32.dll";
if (rootDirectory is not null && directory != rootDirectory)
if (bit64)
{
if (File.Exists(path))
path = directory + @"\UplayR2Unlocker64.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
File.Delete(path);
installForm?.UpdateUser(
$"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR2Unlocker64.dll";
}
path = rootDirectory + @"\UplayR2Unlocker32.dll";
"UplayR2.upc_r2_loader64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
"UplayR2.upc_r2_loader.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
UplayR2.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
if (bit64)
{
path = directory + @"\UplayR2Unlocker64.dll";
if (rootDirectory is not null && directory != rootDirectory)
{
if (File.Exists(path))
{
File.Delete(path);
installForm?.UpdateUser(
$"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\UplayR2Unlocker64.dll";
}
"UplayR2.upc_r2_loader64.dll".Write(path);
installForm?.UpdateUser(
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
UplayR2.CheckConfig(rootDirectory ?? directory, selection, installForm);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
}

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 =>
{
e.path = Path.GetDirectoryName(e.path);
return e;
})?.DistinctBy(e => e.path).ToList());
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,91 +422,62 @@ 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(() =>
{
List<string> dllDirectories = new();
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
foreach (string directory in Directory
.EnumerateDirectories(gameDirectory, "*",
new EnumerationOptions { RecurseSubdirectories = true })
.Append(gameDirectory))
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory, Platform platform)
=> await Task.Run(() =>
{
if (Program.Canceled) return null;
string subDirectory = directory.BeautifyPath();
if (!dllDirectories.Contains(subDirectory))
List<string> dllDirectories = new();
if (Program.Canceled || !Directory.Exists(gameDirectory))
return null;
foreach (string directory in Directory.EnumerateDirectories(gameDirectory, "*", new EnumerationOptions { RecurseSubdirectories = true })
.Append(gameDirectory))
{
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)
if (Program.Canceled)
return null;
string subDirectory = directory.BeautifyPath();
if (!dllDirectories.Contains(subDirectory))
{
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))
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))
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))
dllDirectories.Add(subDirectory);
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)
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)
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)
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)
dllDirectories.Add(subDirectory);
}
}
}
}
return !dllDirectories.Any() ? null : dllDirectories;
});
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,34 +129,31 @@ internal static class ScreamAPI
}
});
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);
if (File.Exists(api32) && !File.Exists(api32_o))
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
File.Move(api32, api32_o);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(api32);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(api64);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
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);
}
if (File.Exists(api32_o))
{
"ScreamAPI.EOSSDK-Win32-Shipping.dll".Write(api32);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"ScreamAPI.EOSSDK-Win64-Shipping.dll".Write(api64);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
}

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,41 +140,37 @@ internal static class SmokeAPI
}
});
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))
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
File.Delete(oldConfig);
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 _);
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);
}
if (File.Exists(api32_o))
{
"SmokeAPI.steam_api.dll".Write(api32);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"SmokeAPI.steam_api64.dll".Write(api64);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
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);
}
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);
}
if (File.Exists(api32_o))
{
"SmokeAPI.steam_api.dll".Write(api32);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"SmokeAPI.steam_api64.dll".Write(api64);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
}

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,24 +33,19 @@ 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,
InstallForm installForm = null)
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -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,34 +100,31 @@ internal static class UplayR1
}
});
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);
if (File.Exists(api32) && !File.Exists(api32_o))
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
File.Move(api32, api32_o);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
"UplayR1.uplay_r1_loader.dll".Write(api32);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"UplayR1.uplay_r1_loader64.dll".Write(api64);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
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);
}
if (File.Exists(api32_o))
{
"UplayR1.uplay_r1_loader.dll".Write(api32);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"UplayR1.uplay_r1_loader64.dll".Write(api64);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
}

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,24 +35,19 @@ 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,
InstallForm installForm = null)
internal static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -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,36 +107,34 @@ internal static class UplayR2
}
});
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);
string api = File.Exists(old_api32) ? old_api32 : api32;
if (File.Exists(api) && !File.Exists(api32_o))
internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
File.Move(api, api32_o);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api32_o))
{
"UplayR2.upc_r2_loader.dll".Write(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
api = File.Exists(old_api64) ? old_api64 : api64;
if (File.Exists(api) && !File.Exists(api64_o))
{
File.Move(api, api64_o);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"UplayR2.upc_r2_loader64.dll".Write(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
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);
}
if (File.Exists(api32_o))
{
"UplayR2.upc_r2_loader.dll".Write(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
api = File.Exists(old_api64) ? old_api64 : api64;
if (File.Exists(api) && !File.Exists(api64_o))
{
File.Move(api, api64_o);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
}
if (File.Exists(api64_o))
{
"UplayR2.upc_r2_loader64.dll".Write(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});
}

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,31 +32,23 @@ 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..])
: line[inNum..])
: null));
_ = 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));
}
}
e = e.InnerException;
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,27 +27,30 @@ 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(() =>
{
if (Directory.Exists(DirectoryPathOld))
internal static async Task Setup()
=> await Task.Run(() =>
{
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)
|| version < MinimumAppInfoVersion)
{
if (Directory.Exists(AppInfoPath)) Directory.Delete(AppInfoPath, true);
_ = Directory.CreateDirectory(AppInfoPath);
File.WriteAllText(AppInfoVersionPath, Program.Version, Encoding.UTF8);
}
if (!Directory.Exists(CooldownPath))
_ = Directory.CreateDirectory(CooldownPath);
if (File.Exists(OldProgramChoicesPath))
File.Delete(OldProgramChoicesPath);
});
if (Directory.Exists(DirectoryPathOld))
{
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)
|| version < MinimumAppInfoVersion)
{
if (Directory.Exists(AppInfoPath))
Directory.Delete(AppInfoPath, true);
_ = Directory.CreateDirectory(AppInfoPath);
File.WriteAllText(AppInfoVersionPath, Program.Version, Encoding.UTF8);
}
if (!Directory.Exists(CooldownPath))
_ = Directory.CreateDirectory(CooldownPath);
if (File.Exists(OldProgramChoicesPath))
File.Delete(OldProgramChoicesPath);
});
internal static bool CheckCooldown(string identifier, int cooldown)
{
@ -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
{