reformatting

This commit is contained in:
pointfeev 2024-04-20 17:16:29 -04:00
parent 3a2d2f9e01
commit 4927a079c7
35 changed files with 1138 additions and 455 deletions

View file

@ -23,17 +23,20 @@ internal sealed class ContextMenuItem : ToolStripMenuItem
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)
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) :
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo,
string imageIdentifierFallback, EventHandler onClick = null) :
this(text, onClick)
{
async void OnFail() => await TryImageIdentifier(this, imageIdentifierFallback);
_ = TryImageIdentifierInfo(this, imageIdentifierInfo, OnFail);
}
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, (string id, string iconUrl) imageIdentifierInfoFallback,
internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo,
(string id, string iconUrl) imageIdentifierInfoFallback,
EventHandler onClick = null) : this(text, onClick)
{
async void OnFail() => await TryImageIdentifierInfo(this, imageIdentifierInfoFallback);
@ -56,6 +59,7 @@ internal sealed class ContextMenuItem : ToolStripMenuItem
image = file.GetFileIconImage();
break;
}
break;
case "Notepad":
image = IconGrabber.GetNotepadImage();
@ -67,26 +71,33 @@ internal sealed 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;
}
if (image is not null)
{
Images[imageIdentifier] = image;
@ -95,7 +106,8 @@ internal sealed class ContextMenuItem : ToolStripMenuItem
}
});
private static async Task TryImageIdentifierInfo(ContextMenuItem item, (string id, string iconUrl) imageIdentifierInfo, Action onFail = null)
private static async Task TryImageIdentifierInfo(ContextMenuItem item,
(string id, string iconUrl) imageIdentifierInfo, Action onFail = null)
=> await Task.Run(async () =>
{
try

View file

@ -50,33 +50,34 @@ internal class CustomForm : Form
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"
+ "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"
+ "NOTE: This program does not automatically download nor install actual DLC files for you; as the title of the program states, this program\n"
+ "is only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed, as is the case with\n"
+ "a good majority of games, you must find, download and install those to the game yourself. This process includes manually installing new\n"
+ "DLCs and manually updating the previously manually installed DLCs after game updates.\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"
+ $"HOWEVER: Please read the [FAQ entry]({repository}#faq--common-issues) and/or [template issue]({repository}/issues/new/choose) corresponding to your problem should one exist! Also, note that the [GitHub Issues]({repository}/issues)\n"
+ "page is not your personal assistance hotline, rather it is for genuine bugs/crashes/issues with the program itself. If you post an issue which\n"
+ "has already been explained within the FAQ, template issues, and/or within this text in general, I will just close it and you will be ignored.\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}) by choice of the user through a dialog on startup.\n"
+ $"The program source and other information can be found on [GitHub]({repository}).");
+ "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"
+ "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"
+ "NOTE: This program does not automatically download nor install actual DLC files for you; as the title of the program states, this program\n"
+ "is only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed, as is the case with\n"
+ "a good majority of games, you must find, download and install those to the game yourself. This process includes manually installing new\n"
+ "DLCs and manually updating the previously manually installed DLCs after game updates.\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"
+ $"HOWEVER: Please read the [FAQ entry]({repository}#faq--common-issues) and/or [template issue]({repository}/issues/new/choose) corresponding to your problem should one exist! Also, note that the [GitHub Issues]({repository}/issues)\n"
+ "page is not your personal assistance hotline, rather it is for genuine bugs/crashes/issues with the program itself. If you post an issue which\n"
+ "has already been explained within the FAQ, template issues, and/or within this text in general, I will just close it and you will be ignored.\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}) by choice of the user through a dialog on startup.\n"
+ $"The program source and other information can be found on [GitHub]({repository}).");
}
private void OnActivation(object sender, EventArgs args) => Activate();
@ -85,10 +86,12 @@ internal class CustomForm : Form
{
bool topMost = TopMost;
NativeImports.SetWindowPos(Handle, NativeImports.HWND_TOPMOST, 0, 0, 0, 0,
NativeImports.SWP_NOACTIVATE | NativeImports.SWP_SHOWWINDOW | NativeImports.SWP_NOMOVE | NativeImports.SWP_NOSIZE);
NativeImports.SWP_NOACTIVATE | NativeImports.SWP_SHOWWINDOW | NativeImports.SWP_NOMOVE |
NativeImports.SWP_NOSIZE);
if (!topMost)
NativeImports.SetWindowPos(Handle, NativeImports.HWND_NOTOPMOST, 0, 0, 0, 0,
NativeImports.SWP_NOACTIVATE | NativeImports.SWP_SHOWWINDOW | NativeImports.SWP_NOMOVE | NativeImports.SWP_NOSIZE);
NativeImports.SWP_NOACTIVATE | NativeImports.SWP_SHOWWINDOW | NativeImports.SWP_NOMOVE |
NativeImports.SWP_NOSIZE);
}
internal void InheritLocation(Form fromForm)

View file

@ -94,6 +94,7 @@ internal sealed class CustomTreeView : TreeView
}
else
text = platform.ToString();
Size size = TextRenderer.MeasureText(graphics, text, font);
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
@ -111,11 +112,13 @@ internal sealed class CustomTreeView : TreeView
size = TextRenderer.MeasureText(graphics, text, font);
const int left = -4;
bounds = bounds with { X = bounds.X + bounds.Width + left, Width = size.Width };
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
selectionBounds = new(selectionBounds.Location,
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
graphics.FillRectangle(brush, bounds);
point = new(bounds.Location.X - 1, bounds.Location.Y + 1);
TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default);
}
if (form is SelectForm)
{
Selection selection = Selection.FromId(platform, id);
@ -127,6 +130,7 @@ internal sealed class CustomTreeView : TreeView
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
graphics.FillRectangle(brush, bounds);
}
CheckBoxState checkBoxState = selection.Koaloader
? Enabled ? CheckBoxState.CheckedPressed : CheckBoxState.CheckedDisabled
: Enabled
@ -151,21 +155,25 @@ internal sealed class CustomTreeView : TreeView
this.checkBoxBounds[selection] = RectangleToClient(checkBoxBounds);
if (selection.Koaloader)
{
comboBoxFont ??= new(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet, font.GdiVerticalFont);
comboBoxFont ??= new(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet,
font.GdiVerticalFont);
ComboBoxState comboBoxState = Enabled ? ComboBoxState.Normal : ComboBoxState.Disabled;
text = (selection.KoaloaderProxy ?? Selection.DefaultKoaloaderProxy) + ".dll";
size = TextRenderer.MeasureText(graphics, text, comboBoxFont) + new Size(6, 0);
const int padding = 2;
bounds = new(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width, bounds.Height - padding);
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
selectionBounds = new(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(14, 0);
left = -1;
bounds = bounds with { X = bounds.X + bounds.Width + left, Width = size.Width };
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
comboBoxBounds = new(comboBoxBounds.Location, comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
selectionBounds = new(selectionBounds.Location,
selectionBounds.Size + new Size(bounds.Size.Width + left, 0));
comboBoxBounds = new(comboBoxBounds.Location,
comboBoxBounds.Size + new Size(bounds.Size.Width + left, 0));
ComboBoxRenderer.DrawDropDownButton(graphics, bounds, comboBoxState);
this.comboBoxBounds[selection] = RectangleToClient(comboBoxBounds);
}
@ -173,6 +181,7 @@ internal sealed class CustomTreeView : TreeView
_ = comboBoxBounds.Remove(selection);
}
}
this.selectionBounds[node] = RectangleToClient(selectionBounds);
}
@ -192,6 +201,7 @@ internal sealed class CustomTreeView : TreeView
selectForm.OnNodeRightClick(pair.Key, e.Location);
break;
}
if (e.Button is not MouseButtons.Left)
return;
if (comboBoxBounds.Count > 0 && selectForm is not null)
@ -200,11 +210,12 @@ internal sealed class CustomTreeView : TreeView
_ = comboBoxBounds.Remove(pair.Key);
else if (pair.Value.Contains(clickPoint))
{
HashSet<string> proxies = EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)).Select(p =>
{
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
return proxyName;
}).ToHashSet();
HashSet<string> proxies = EmbeddedResources
.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)).Select(p =>
{
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
return proxyName;
}).ToHashSet();
comboBoxDropDown ??= new();
comboBoxDropDown.ShowItemToolTips = false;
comboBoxDropDown.Items.Clear();
@ -219,6 +230,7 @@ internal sealed class CustomTreeView : TreeView
canUse = false;
break;
}
if (canUse)
_ = comboBoxDropDown.Items.Add(new ToolStripButton(proxy + ".dll", null, (_, _) =>
{
@ -226,9 +238,11 @@ internal sealed class CustomTreeView : TreeView
selectForm.OnKoaloaderChanged();
}) { Font = comboBoxFont });
}
comboBoxDropDown.Show(this, PointToScreen(new(pair.Value.Left, pair.Value.Bottom - 1)));
break;
}
foreach (KeyValuePair<Selection, Rectangle> pair in checkBoxBounds)
if (!Selection.All.ContainsKey(pair.Key))
_ = checkBoxBounds.Remove(pair.Key);

View file

@ -4,7 +4,7 @@
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\program.ico</ApplicationIcon>
<Version>4.10.1</Version>
<Version>4.10.2</Version>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
<Company>CreamInstaller</Company>
<Product>Automatic DLC Unlocker Installer &amp; Configuration Generator</Product>

View file

@ -36,6 +36,7 @@ internal sealed partial class DebugForm : CustomForm
if (command == 0xF010) // SC_MOVE
return;
}
base.WndProc(ref message);
}
@ -48,6 +49,7 @@ internal sealed partial class DebugForm : CustomForm
attachedForm.SizeChanged -= OnChange;
attachedForm.VisibleChanged -= OnChange;
}
attachedForm = form;
attachedForm.Activated += OnChange;
attachedForm.LocationChanged += OnChange;

View file

@ -11,7 +11,8 @@ internal sealed partial class DialogForm : CustomForm
{
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText = "OK", string cancelButtonText = null,
internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText = "OK",
string cancelButtonText = null,
string customFormText = null, Icon customFormIcon = null)
{
descriptionIcon ??= Icon;
@ -33,6 +34,7 @@ internal sealed partial class DialogForm : CustomForm
descriptionText = descriptionText.Remove(i, linkRight + 1 - i).Insert(i, text);
links.Add(new(i, text.Length, link));
}
descriptionLabel.Text = descriptionText;
acceptButton.Text = acceptButtonText;
if (cancelButtonText is null)
@ -42,6 +44,7 @@ internal sealed partial class DialogForm : CustomForm
}
else
cancelButton.Text = cancelButtonText;
if (customFormText is not null)
Text = customFormText;
else
@ -49,6 +52,7 @@ internal sealed partial class DialogForm : CustomForm
OnResize(null, null);
Resize += OnResize;
}
if (customFormIcon is not null)
Icon = customFormIcon;
if (links.Count < 1)
@ -65,6 +69,8 @@ internal sealed partial class DialogForm : CustomForm
private void OnResize(object s, EventArgs e)
=> Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
? TextRenderer.MeasureText(Program.ApplicationNameShort, Font).Width > Size.Width - 100 ? Program.Name : Program.ApplicationNameShort
? TextRenderer.MeasureText(Program.ApplicationNameShort, Font).Width > Size.Width - 100
? Program.Name
: Program.ApplicationNameShort
: Program.ApplicationName;
}

View file

@ -63,11 +63,14 @@ internal sealed 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);
$"{(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.All(s => s.directory != Path.GetDirectoryName(d.path))).Select(d => Path.GetDirectoryName(d.path));
?.Where(d => selection.ExecutableDirectories.All(s => s.directory != Path.GetDirectoryName(d.path)))
.Select(d => Path.GetDirectoryName(d.path));
if (selection.ExecutableDirectories.All(s => s.directory != selection.RootDirectory))
invalidDirectories = invalidDirectories?.Append(selection.RootDirectory);
invalidDirectories = invalidDirectories?.Distinct();
@ -77,27 +80,37 @@ internal sealed partial class InstallForm : CustomForm
if (Program.Canceled)
return;
directory.GetKoaloaderComponents(out string old_config, out string config);
if (directory.GetKoaloaderProxies().Any(proxy => proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| directory != selection.RootDirectory && Koaloader.AutoLoadDLLs.Any(pair => (directory + @"\" + pair.dll).FileExists())
|| old_config.FileExists() || config.FileExists())
if (directory.GetKoaloaderProxies().Any(proxy =>
proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| directory != selection.RootDirectory &&
Koaloader.AutoLoadDLLs.Any(pair => (directory + @"\" + pair.dll).FileExists())
|| old_config.FileExists() || config.FileExists())
{
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);
}
}
if (uninstalling || !selection.Koaloader)
foreach ((string directory, BinaryType _) in selection.ExecutableDirectories)
{
if (Program.Canceled)
return;
directory.GetKoaloaderComponents(out string old_config, out string config);
if (directory.GetKoaloaderProxies().Any(proxy => proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| Koaloader.AutoLoadDLLs.Any(pair => (directory + @"\" + pair.dll).FileExists()) || old_config.FileExists() || config.FileExists())
if (directory.GetKoaloaderProxies().Any(proxy =>
proxy.FileExists() && proxy.IsResourceFile(ResourceIdentifier.Koaloader))
|| Koaloader.AutoLoadDLLs.Any(pair => (directory + @"\" + pair.dll).FileExists()) ||
old_config.FileExists() || config.FileExists())
{
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);
}
}
bool uninstallProxy = uninstalling || selection.Koaloader;
int count = selection.DllDirectories.Count, cur = 0;
foreach (string directory in selection.DllDirectories)
@ -106,77 +119,93 @@ internal sealed partial class InstallForm : CustomForm
return;
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 old_config,
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string old_config,
out string config, out string old_log, out string log, out string cache);
if (uninstallProxy
? api32_o.FileExists() || api64_o.FileExists() || old_config.FileExists() || config.FileExists() || old_log.FileExists() || log.FileExists()
|| cache.FileExists()
: api32.FileExists() || api64.FileExists())
? api32_o.FileExists() || api64_o.FileExists() || old_config.FileExists() ||
config.FileExists() || old_log.FileExists() || log.FileExists()
|| cache.FileExists()
: api32.FileExists() || api64.FileExists())
{
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
$"{(uninstallProxy ? "Uninstalling" : "Installing")} SmokeAPI" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await SmokeAPI.Uninstall(directory, this);
else
await SmokeAPI.Install(directory, selection, this);
}
}
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, out string log);
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config, out string log);
if (uninstallProxy
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: api32.FileExists() || api64.FileExists())
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: api32.FileExists() || api64.FileExists())
{
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
$"{(uninstallProxy ? "Uninstalling" : "Installing")} ScreamAPI" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await ScreamAPI.Uninstall(directory, this);
else
await ScreamAPI.Install(directory, selection, this);
}
}
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, out string log);
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
out string api64_o, out string config, out string log);
if (uninstallProxy
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: api32.FileExists() || api64.FileExists())
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: api32.FileExists() || api64.FileExists())
{
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R1 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
$"{(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, out log);
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o,
out api64, out api64_o, out config, out log);
if (uninstallProxy
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() || api64.FileExists())
? api32_o.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists()
: old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() || api64.FileExists())
{
UpdateUser(
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" + $" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
$"{(uninstallProxy ? "Uninstalling" : "Installing")} Uplay R2 Unlocker" +
$" {(uninstallProxy ? "from" : "for")} " + selection.Name
+ $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
if (uninstallProxy)
await UplayR2.Uninstall(directory, this);
else
await UplayR2.Install(directory, selection, this);
}
}
UpdateProgress(++cur / count * 100);
}
if (selection.Koaloader && !uninstalling)
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
{
if (Program.Canceled)
return;
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ",
LogTextBox.Operation);
await Koaloader.Install(directory, binaryType, selection, selection.RootDirectory, this);
}
UpdateProgress(100);
}
@ -200,8 +229,10 @@ internal sealed partial class InstallForm : CustomForm
{
UpdateUser($"Operation failed for {selection.Name}: " + exception, LogTextBox.Error);
}
++completeOperationsCount;
}
Program.Cleanup();
int activeCount = activeSelections.Count;
if (activeCount > 0)
@ -222,14 +253,19 @@ internal sealed partial class InstallForm : CustomForm
try
{
await Operate();
UpdateUser($"DLC unlocker(s) successfully {(uninstalling ? "uninstalled" : "installed and generated")} for " + selectionCount + " program(s).",
UpdateUser(
$"DLC unlocker(s) successfully {(uninstalling ? "uninstalled" : "installed and generated")} for " +
selectionCount + " 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;
acceptButton.Enabled = true;
cancelButton.Enabled = false;
@ -238,7 +274,7 @@ internal sealed partial class InstallForm : CustomForm
private void OnLoad(object sender, EventArgs a)
{
retry:
retry:
try
{
userInfoLabel.Text = "Loading . . . ";
@ -249,6 +285,7 @@ internal sealed partial class InstallForm : CustomForm
selectionCount++;
_ = activeSelections.Add(selection);
}
Start();
}
catch (Exception e)

View file

@ -12,7 +12,8 @@ internal sealed partial class SelectDialogForm : CustomForm
private readonly List<(Platform platform, string id, string name)> selected = new();
internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
internal DialogResult QueryUser(string groupBoxText, List<(Platform platform, string id, string name, bool alreadySelected)> potentialChoices,
internal DialogResult QueryUser(string groupBoxText,
List<(Platform platform, string id, string name, bool alreadySelected)> potentialChoices,
out List<(Platform platform, string id, string name)> choices)
{
choices = null;
@ -28,6 +29,7 @@ internal sealed partial class SelectDialogForm : CustomForm
OnTreeNodeChecked(node);
_ = selectionTreeView.Nodes.Add(node);
}
if (selected.Count < 1)
OnLoad(null, null);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
@ -64,10 +66,13 @@ internal sealed partial class SelectDialogForm : CustomForm
}
private void OnResize(object s, EventArgs e)
=> Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100 ? Program.ApplicationNameShort : Program.ApplicationName;
=> 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;
=> selectionTreeView.TreeViewNodeSorter =
sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
private void OnAllCheckBoxChanged(object sender, EventArgs e)
{
@ -77,6 +82,7 @@ internal sealed partial class SelectDialogForm : CustomForm
node.Checked = shouldCheck;
OnTreeNodeChecked(node);
}
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = shouldCheck;
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
@ -96,7 +102,8 @@ internal sealed partial class SelectDialogForm : CustomForm
private void OnSave(object sender, EventArgs e)
{
ProgramData.WriteProgramChoices(selectionTreeView.Nodes.Cast<TreeNode>().Where(n => n.Checked).Select(node => ((Platform)node.Tag, node.Name)));
ProgramData.WriteProgramChoices(selectionTreeView.Nodes.Cast<TreeNode>().Where(n => n.Checked)
.Select(node => ((Platform)node.Tag, node.Name)));
loadButton.Enabled = ProgramData.ReadProgramChoices() is not null;
}
}

View file

@ -50,7 +50,9 @@ internal sealed partial class SelectForm : CustomForm
}
private static void UpdateRemaining(Label label, ConcurrentDictionary<string, string> list, string descriptor)
=> label.Text = list.IsEmpty ? "" : $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
=> label.Text = list.IsEmpty
? ""
: $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
private void UpdateRemainingGames() => UpdateRemaining(progressLabelGames, remainingGames, "games");
@ -114,17 +116,20 @@ internal sealed partial class SelectForm : CustomForm
return;
int totalGameCount = 0;
int completeGameCount = 0;
void AddToRemainingGames(string gameName)
{
this.AddToRemainingGames(gameName);
progress.Report(-Interlocked.Increment(ref totalGameCount));
progress.Report(completeGameCount);
}
void RemoveFromRemainingGames(string gameName)
{
this.RemoveFromRemainingGames(gameName);
progress.Report(Interlocked.Increment(ref completeGameCount));
}
if (Program.Canceled)
return;
remainingGames.Clear(); // for display purposes only, otherwise ignorable
@ -133,11 +138,14 @@ internal sealed partial class SelectForm : CustomForm
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Paradox))
{
AddToRemainingGames("Paradox Launcher");
HashSet<string> dllDirectories = await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
HashSet<string> dllDirectories =
await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
if (dllDirectories is not null)
{
Selection selection = Selection.GetOrCreate(Platform.Paradox, "PL", "Paradox Launcher", ParadoxLauncher.InstallPath, dllDirectories,
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
Selection selection = Selection.GetOrCreate(Platform.Paradox, "PL", "Paradox Launcher",
ParadoxLauncher.InstallPath, dllDirectories,
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path =>
!Path.GetFileName(path).Contains("bootstrapper")));
if (uninstallAll)
selection.Enabled = true;
else if (selection.TreeNode.TreeView is null)
@ -145,40 +153,48 @@ internal sealed partial class SelectForm : CustomForm
RemoveFromRemainingGames("Paradox Launcher");
}
}
int steamGamesToCheck;
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Steam))
{
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames = await SteamLibrary.GetGames();
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames =
await SteamLibrary.GetGames();
steamGamesToCheck = steamGames.Count;
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
{
if (Program.Canceled)
return;
if (!uninstallAll && (Program.IsGameBlocked(name, gameDirectory) || !programsToScan.Any(c => c.platform is Platform.Steam && c.id == appId)))
if (!uninstallAll && (Program.IsGameBlocked(name, gameDirectory) ||
!programsToScan.Any(c => c.platform is Platform.Steam && c.id == appId)))
{
_ = Interlocked.Decrement(ref steamGamesToCheck);
continue;
}
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
if (Program.Canceled)
return;
HashSet<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
HashSet<string> dllDirectories =
await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
if (dllDirectories is null)
{
_ = Interlocked.Decrement(ref steamGamesToCheck);
RemoveFromRemainingGames(name);
return;
}
if (uninstallAll)
{
Selection bareSelection = Selection.GetOrCreate(Platform.Steam, appId, name, gameDirectory, dllDirectories,
Selection bareSelection = Selection.GetOrCreate(Platform.Steam, appId, name, gameDirectory,
dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
bareSelection.Enabled = true;
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
AppData appData = await SteamStore.QueryStoreAPI(appId);
@ -189,6 +205,7 @@ internal sealed partial class SelectForm : CustomForm
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
ConcurrentDictionary<SelectionDLC, byte> dlc = new();
@ -233,14 +250,20 @@ internal sealed partial class SelectForm : CustomForm
if (dlcAppInfo is not null)
{
dlcName = dlcAppInfo.Value.GetChild("common")?.GetChild("name")?.ToString();
string dlcIconStaticId = dlcAppInfo.Value.GetChild("common")?.GetChild("icon")?.ToString();
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo_small")?.ToString();
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo")?.ToString();
string dlcIconStaticId = dlcAppInfo.Value.GetChild("common")?.GetChild("icon")
?.ToString();
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo_small")
?.ToString();
dlcIconStaticId ??= dlcAppInfo.Value.GetChild("common")?.GetChild("logo")
?.ToString();
if (dlcIconStaticId is not null)
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{dlcAppId}\{dlcIconStaticId}.jpg";
fullGameAppId = dlcAppInfo.Value.GetChild("common")?.GetChild("parent")?.ToString();
dlcIcon = IconGrabber.SteamAppImagesPath +
@$"\{dlcAppId}\{dlcIconStaticId}.jpg";
fullGameAppId = dlcAppInfo.Value.GetChild("common")?.GetChild("parent")
?.ToString();
}
}
if (fullGameAppId != null && fullGameAppId != appId)
{
string fullGameName = null;
@ -258,29 +281,38 @@ internal sealed partial class SelectForm : CustomForm
VProperty fullGameAppInfo = await SteamCMD.GetAppInfo(fullGameAppId);
if (fullGameAppInfo is not null)
{
fullGameName = fullGameAppInfo.Value.GetChild("common")?.GetChild("name")?.ToString();
string fullGameIconStaticId = fullGameAppInfo.Value.GetChild("common")?.GetChild("icon")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")?.GetChild("logo_small")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")?.GetChild("logo")?.ToString();
fullGameName = fullGameAppInfo.Value.GetChild("common")?.GetChild("name")
?.ToString();
string fullGameIconStaticId = fullGameAppInfo.Value.GetChild("common")
?.GetChild("icon")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")
?.GetChild("logo_small")?.ToString();
fullGameIconStaticId ??= fullGameAppInfo.Value.GetChild("common")
?.GetChild("logo")?.ToString();
if (fullGameIconStaticId is not null)
dlcIcon = IconGrabber.SteamAppImagesPath + @$"\{fullGameAppId}\{fullGameIconStaticId}.jpg";
dlcIcon = IconGrabber.SteamAppImagesPath +
@$"\{fullGameAppId}\{fullGameIconStaticId}.jpg";
}
}
if (Program.Canceled)
return;
if (!string.IsNullOrWhiteSpace(fullGameName))
{
SelectionDLC fullGameDlc = SelectionDLC.GetOrCreate(fullGameOnSteamStore ? DLCType.Steam : DLCType.SteamHidden, appId,
SelectionDLC fullGameDlc = SelectionDLC.GetOrCreate(
fullGameOnSteamStore ? DLCType.Steam : DLCType.SteamHidden, appId,
fullGameAppId, fullGameName);
fullGameDlc.Icon = fullGameIcon;
_ = dlc.TryAdd(fullGameDlc, default);
}
}
if (Program.Canceled)
return;
if (string.IsNullOrWhiteSpace(dlcName))
dlcName = "Unknown";
SelectionDLC _dlc = SelectionDLC.GetOrCreate(onSteamStore ? DLCType.Steam : DLCType.SteamHidden, appId, dlcAppId, dlcName);
SelectionDLC _dlc = SelectionDLC.GetOrCreate(
onSteamStore ? DLCType.Steam : DLCType.SteamHidden, appId, dlcAppId, dlcName);
_dlc.Icon = dlcIcon;
_ = dlc.TryAdd(_dlc, default);
RemoveFromRemainingDLCs(dlcAppId);
@ -292,6 +324,7 @@ internal sealed partial class SelectForm : CustomForm
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
foreach (Task task in dlcTasks)
@ -300,19 +333,24 @@ internal sealed partial class SelectForm : CustomForm
return;
await task;
}
steamGamesToCheck = 0;
if (dlc.IsEmpty)
{
RemoveFromRemainingGames(name);
return;
}
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name, gameDirectory, dllDirectories,
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name,
gameDirectory, dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
selection.Product = "https://store.steampowered.com/app/" + appId;
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
selection.Icon = IconGrabber.SteamAppImagesPath +
@$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
selection.SubIcon = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
+ @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("clienticon")}.ico";
selection.Publisher = appData?.Publishers[0] ?? appInfo?.Value.GetChild("extended")?.GetChild("publisher")?.ToString();
+ @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("clienticon")}.ico";
selection.Publisher = appData?.Publishers[0] ??
appInfo?.Value.GetChild("extended")?.GetChild("publisher")?.ToString();
selection.Website = appData?.Website;
if (Program.Canceled)
return;
@ -336,6 +374,7 @@ internal sealed partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Epic))
{
List<Manifest> epicGames = await EpicLibrary.GetGames();
@ -346,7 +385,8 @@ internal sealed partial class SelectForm : CustomForm
string directory = manifest.InstallLocation;
if (Program.Canceled)
return;
if (!uninstallAll && (Program.IsGameBlocked(name, directory) || !programsToScan.Any(c => c.platform is Platform.Epic && c.id == @namespace)))
if (!uninstallAll && (Program.IsGameBlocked(name, directory) ||
!programsToScan.Any(c => c.platform is Platform.Epic && c.id == @namespace)))
continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
@ -359,19 +399,23 @@ internal sealed partial class SelectForm : CustomForm
RemoveFromRemainingGames(name);
return;
}
if (uninstallAll)
{
Selection bareSelection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
Selection bareSelection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory,
dllDirectories,
await directory.GetExecutableDirectories(true));
bareSelection.Enabled = true;
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
List<Task> dlcTasks = new();
ConcurrentDictionary<SelectionDLC, byte> catalogItems = new();
List<(string id, string name, string product, string icon, string developer)> catalogIds = await EpicStore.QueryCatalog(@namespace);
List<(string id, string name, string product, string icon, string developer)> catalogIds =
await EpicStore.QueryCatalog(@namespace);
if (catalogIds.Count > 0)
foreach ((string id, string name, string product, string icon, string developer) in catalogIds)
{
@ -391,6 +435,7 @@ internal sealed partial class SelectForm : CustomForm
});
dlcTasks.Add(task);
}
if (Program.Canceled)
return;
foreach (Task task in dlcTasks)
@ -399,12 +444,15 @@ internal sealed partial class SelectForm : CustomForm
return;
await task;
}
if (catalogItems.IsEmpty)
{
RemoveFromRemainingGames(name);
return;
}
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory,
dllDirectories,
await directory.GetExecutableDirectories(true));
foreach ((SelectionDLC dlc, _) in catalogItems.Where(dlc => dlc.Key.Name == selection.Name))
{
@ -414,6 +462,7 @@ internal sealed partial class SelectForm : CustomForm
selection.Icon = dlc.Icon;
selection.Publisher = dlc.Publisher;
}
if (Program.Canceled)
return;
Invoke(delegate
@ -438,6 +487,7 @@ internal sealed partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Ubisoft))
{
List<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
@ -445,30 +495,36 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
if (!uninstallAll && (Program.IsGameBlocked(name, gameDirectory) || !programsToScan.Any(c => c.platform is Platform.Ubisoft && c.id == gameId)))
if (!uninstallAll && (Program.IsGameBlocked(name, gameDirectory) ||
!programsToScan.Any(c => c.platform is Platform.Ubisoft && c.id == gameId)))
continue;
AddToRemainingGames(name);
Task task = Task.Run(async () =>
{
if (Program.Canceled)
return;
HashSet<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
HashSet<string> dllDirectories =
await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
return;
}
if (uninstallAll)
{
Selection bareSelection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
Selection bareSelection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory,
dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
bareSelection.Enabled = true;
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory,
dllDirectories,
await gameDirectory.GetExecutableDirectories(true));
selection.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
Invoke(delegate
@ -485,12 +541,14 @@ internal sealed partial class SelectForm : CustomForm
appTasks.Add(task);
}
}
foreach (Task task in appTasks)
{
if (Program.Canceled)
return;
await task;
}
steamGamesToCheck = 0;
}
@ -522,19 +580,26 @@ internal sealed partial class SelectForm : CustomForm
List<(Platform platform, string id, string name, bool alreadySelected)> gameChoices = new();
if (ParadoxLauncher.InstallPath.DirectoryExists())
gameChoices.Add((Platform.Paradox, "PL", "Paradox Launcher",
programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Paradox && p.id == "PL")));
programsToScan is not null &&
programsToScan.Any(p => p.platform is Platform.Paradox && p.id == "PL")));
if (SteamLibrary.InstallPath.DirectoryExists())
foreach ((string appId, string name, string _, int _, string _) in (await SteamLibrary.GetGames()).Where(g
=> !Program.IsGameBlocked(g.name, g.gameDirectory)))
foreach ((string appId, string name, string _, int _, string _) in
(await SteamLibrary.GetGames()).Where(g
=> !Program.IsGameBlocked(g.name, g.gameDirectory)))
gameChoices.Add((Platform.Steam, appId, name,
programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Steam && p.id == appId)));
programsToScan is not null &&
programsToScan.Any(p => p.platform is Platform.Steam && p.id == appId)));
if (EpicLibrary.EpicManifestsPath.DirectoryExists() || HeroicLibrary.HeroicLibraryPath.DirectoryExists())
gameChoices.AddRange((await EpicLibrary.GetGames()).Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)).Select(manifest
=> (Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName,
programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Epic && p.id == manifest.CatalogNamespace))));
foreach ((string gameId, string name, string _) in (await UbisoftLibrary.GetGames()).Where(g => !Program.IsGameBlocked(g.name, g.gameDirectory)))
gameChoices.AddRange((await EpicLibrary.GetGames())
.Where(m => !Program.IsGameBlocked(m.DisplayName, m.InstallLocation)).Select(manifest
=> (Platform.Epic, manifest.CatalogNamespace, manifest.DisplayName,
programsToScan is not null && programsToScan.Any(p =>
p.platform is Platform.Epic && p.id == manifest.CatalogNamespace))));
foreach ((string gameId, string name, string _) in (await UbisoftLibrary.GetGames()).Where(g =>
!Program.IsGameBlocked(g.name, g.gameDirectory)))
gameChoices.Add((Platform.Ubisoft, gameId, name,
programsToScan is not null && programsToScan.Any(p => p.platform is Platform.Ubisoft && p.id == gameId)));
programsToScan is not null &&
programsToScan.Any(p => p.platform is Platform.Ubisoft && p.id == gameId)));
if (gameChoices.Count > 0)
{
using SelectDialogForm form = new(this);
@ -569,6 +634,7 @@ internal sealed partial class SelectForm : CustomForm
}
else
scan = selectResult == DialogResult.OK && choices is not null && choices.Count > 0;
const string retry = "\n\nPress the \"Rescan\" button to re-choose.";
if (scan)
{
@ -581,6 +647,7 @@ internal sealed partial class SelectForm : CustomForm
else
noneFoundLabel.Text = "No applicable programs nor games were found on your computer!";
}
if (scan)
{
bool setup = true;
@ -597,10 +664,14 @@ internal sealed partial class SelectForm : CustomForm
else
curProgress = _progress;
int p = Math.Max(Math.Min((int)((float)curProgress / maxProgress * 100), 100), 0);
progressLabel.Text = setup ? $"Setting up SteamCMD . . . {p}%" : $"Gathering and caching your applicable games and their DLCs . . . {p}%";
progressLabel.Text =
setup
? $"Setting up SteamCMD . . . {p}%"
: $"Gathering and caching your applicable games and their DLCs . . . {p}%";
progressBar.Value = p;
};
if (SteamLibrary.InstallPath.DirectoryExists() && programsToScan is not null && programsToScan.Any(c => c.platform is Platform.Steam))
if (SteamLibrary.InstallPath.DirectoryExists() && programsToScan is not null &&
programsToScan.Any(c => c.platform is Platform.Steam))
{
progressLabel.Text = "Setting up SteamCMD . . . ";
if (!await SteamCMD.Setup(iProgress))
@ -610,6 +681,7 @@ internal sealed partial class SelectForm : CustomForm
return;
}
}
setup = false;
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
Selection.ValidateAll(programsToScan);
@ -618,6 +690,7 @@ internal sealed partial class SelectForm : CustomForm
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
}
OnLoadDlc(null, null);
OnLoadKoaloader(null, null);
HideProgressBar();
@ -649,7 +722,8 @@ internal sealed partial class SelectForm : CustomForm
SyncNodeAncestors(node);
SyncNodeDescendants(node);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = EnumerateTreeNodes(selectionTreeView.Nodes).All(node => node.Text == "Unknown" || node.Checked);
allCheckBox.Checked = EnumerateTreeNodes(selectionTreeView.Nodes)
.All(node => node.Text == "Unknown" || node.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
installButton.Enabled = Selection.AllEnabled.Any();
uninstallButton.Enabled = installButton.Enabled;
@ -699,8 +773,9 @@ internal sealed partial class SelectForm : CustomForm
progressBar.Visible = true;
programsGroupBox.Size = programsGroupBox.Size with
{
Height = programsGroupBox.Size.Height - 3 - progressLabel.Size.Height - progressLabelGames.Size.Height - progressLabelDLCs.Size.Height
- progressBar.Size.Height
Height = programsGroupBox.Size.Height - 3 - progressLabel.Size.Height - progressLabelGames.Size.Height -
progressLabelDLCs.Size.Height
- progressBar.Size.Height
};
}
@ -713,8 +788,9 @@ internal sealed partial class SelectForm : CustomForm
progressBar.Visible = false;
programsGroupBox.Size = programsGroupBox.Size with
{
Height = programsGroupBox.Size.Height + 3 + progressLabel.Size.Height + progressLabelGames.Size.Height + progressLabelDLCs.Size.Height
+ progressBar.Size.Height
Height = programsGroupBox.Size.Height + 3 + progressLabel.Size.Height + progressLabelGames.Size.Height +
progressLabelDLCs.Size.Height
+ progressBar.Size.Height
};
}
@ -753,10 +829,13 @@ internal sealed partial class SelectForm : CustomForm
: selection.Platform is Platform.Epic
? "Epic GraphQL "
: "";
queries.Add(new($"Open {platformString}Query", "Notepad", (_, _) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
queries.Add(new($"Open {platformString}Query", "Notepad",
(_, _) => Diagnostics.OpenFileInNotepad(appInfoJSON)));
}
if (appInfoVDF.FileExists())
queries.Add(new("Open SteamCMD Query", "Notepad", (_, _) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
queries.Add(new("Open SteamCMD Query", "Notepad",
(_, _) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
if (queries.Count > 0)
{
_ = items.Add(new ToolStripSeparator());
@ -774,62 +853,78 @@ internal sealed partial class SelectForm : CustomForm
}));
}
}
if (selection is not null)
{
if (id == "PL")
{
_ = items.Add(new ToolStripSeparator());
async void EventHandler(object sender, EventArgs e)
{
_ = await ParadoxLauncher.Repair(this, selection);
Program.Canceled = false;
}
_ = items.Add(new ContextMenuItem("Repair", "Command Prompt", EventHandler));
}
_ = items.Add(new ToolStripSeparator());
_ = items.Add(new ContextMenuItem("Open Root Directory", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(selection.RootDirectory)));
int executables = 0;
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
_ = items.Add(new ContextMenuItem($"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)",
_ = items.Add(new ContextMenuItem(
$"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)",
"File Explorer", (_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
HashSet<string> directories = selection.DllDirectories;
int steam = 0, epic = 0, r1 = 0, r2 = 0;
if (selection.Platform is Platform.Steam or Platform.Paradox)
foreach (string directory in directories)
{
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string old_config,
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string old_config,
out string config, out string old_log, out string log, out string cache);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() || old_config.FileExists()
|| config.FileExists() || old_log.FileExists() || log.FileExists() || cache.FileExists())
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() ||
old_config.FileExists()
|| config.FileExists() || old_log.FileExists() || log.FileExists() || cache.FileExists())
_ = items.Add(new ContextMenuItem($"Open Steamworks Directory #{++steam}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
if (selection.Platform is Platform.Epic or Platform.Paradox)
foreach (string directory in directories)
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config,
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists())
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() ||
config.FileExists() || log.FileExists())
_ = items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
if (selection.Platform is Platform.Ubisoft)
foreach (string directory in directories)
{
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config,
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() || config.FileExists() || log.FileExists())
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists() ||
config.FileExists() || log.FileExists())
_ = items.Add(new ContextMenuItem($"Open Uplay R1 Directory #{++r1}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config,
directory.GetUplayR2Components(out string old_api32, out string old_api64, out api32,
out api32_o, out api64, out api64_o, out config,
out log);
if (old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() || api32_o.FileExists() || api64.FileExists()
|| api64_o.FileExists() || config.FileExists() || log.FileExists())
if (old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() ||
api32_o.FileExists() || api64.FileExists()
|| api64_o.FileExists() || config.FileExists() || log.FileExists())
_ = items.Add(new ContextMenuItem($"Open Uplay R2 Directory #{++r2}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
}
if (id != "PL")
{
if (selection?.Platform is Platform.Steam || dlcParentSelection?.Platform is Platform.Steam)
@ -838,19 +933,23 @@ internal sealed partial class SelectForm : CustomForm
_ = items.Add(new ContextMenuItem("Open SteamDB", "SteamDB",
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://steamdb.info/app/" + id)));
}
if (selection is not null)
switch (selection.Platform)
{
case Platform.Steam:
_ = items.Add(new ContextMenuItem("Open Steam Store", "Steam Store",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.Product)));
_ = items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIcon), "Steam Community",
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + id)));
_ = items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIcon),
"Steam Community",
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" +
id)));
break;
case Platform.Epic:
_ = items.Add(new ToolStripSeparator());
_ = items.Add(new ContextMenuItem("Open ScreamDB", "ScreamDB",
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://scream-db.web.app/offers/" + id)));
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://scream-db.web.app/offers/" +
id)));
_ = items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.Product)));
break;
@ -858,12 +957,15 @@ internal sealed partial class SelectForm : CustomForm
_ = items.Add(new ToolStripSeparator());
_ = items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(
"https://store.ubi.com/us/" + selection.Name.Replace(" ", "-").ToLowerInvariant())));
"https://store.ubi.com/us/" +
selection.Name.Replace(" ", "-").ToLowerInvariant())));
break;
}
}
if (selection?.Website is not null)
_ = items.Add(new ContextMenuItem("Open Official Website", ("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.Website)),
_ = items.Add(new ContextMenuItem("Open Official Website",
("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.Website)),
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.Website)));
contextMenuStrip.Show(selectionTreeView, location);
contextMenuStrip.Refresh();
@ -871,7 +973,7 @@ internal sealed partial class SelectForm : CustomForm
private void OnLoad(object sender, EventArgs _)
{
retry:
retry:
try
{
HideProgressBar();
@ -934,6 +1036,7 @@ internal sealed partial class SelectForm : CustomForm
selection.Enabled = shouldEnable;
OnTreeViewNodeCheckedChanged(null, new(selection.TreeNode, TreeViewAction.ByMouse));
}
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = shouldEnable;
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
@ -953,19 +1056,23 @@ internal sealed partial class SelectForm : CustomForm
private bool AreSelectionsDefault()
=> EnumerateTreeNodes(selectionTreeView.Nodes).All(node
=> node.Parent is null || node.Tag is not Platform and not DLCType || (node.Text == "Unknown" ? !node.Checked : node.Checked));
=> node.Parent is null || node.Tag is not Platform and not DLCType ||
(node.Text == "Unknown" ? !node.Checked : node.Checked));
private bool CanSaveDlc() => installButton.Enabled && (ProgramData.ReadDlcChoices().Any() || !AreSelectionsDefault());
private bool CanSaveDlc() =>
installButton.Enabled && (ProgramData.ReadDlcChoices().Any() || !AreSelectionsDefault());
private void OnSaveDlc(object sender, EventArgs e)
{
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
if ((dlc.Name == "Unknown" ? dlc.Enabled : !dlc.Enabled)
&& !choices.Any(c => c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id))
&& !choices.Any(c =>
c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id))
choices.Add((dlc.Selection.Platform, dlc.Selection.Id, dlc.Id));
else
_ = choices.RemoveAll(n => n.platform == dlc.Selection.Platform && n.gameId == dlc.Selection.Id && n.dlcId == dlc.Id);
_ = choices.RemoveAll(n =>
n.platform == dlc.Selection.Platform && n.gameId == dlc.Selection.Id && n.dlcId == dlc.Id);
ProgramData.WriteDlcChoices(choices);
loadButton.Enabled = CanLoadDlc();
saveButton.Enabled = CanSaveDlc();
@ -978,7 +1085,8 @@ internal sealed partial class SelectForm : CustomForm
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
{
dlc.Enabled = choices.Any(c => c.platform == dlc.Selection?.Platform && c.gameId == dlc.Selection?.Id && c.dlcId == dlc.Id)
dlc.Enabled = choices.Any(c =>
c.platform == dlc.Selection?.Platform && c.gameId == dlc.Selection?.Id && c.dlcId == dlc.Id)
? dlc.Name == "Unknown"
: dlc.Name != "Unknown";
OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
@ -994,23 +1102,29 @@ internal sealed partial class SelectForm : CustomForm
dlc.Enabled = dlc.Name != "Unknown";
OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
}
resetButton.Enabled = CanResetDlc();
}
private static bool AreKoaloaderSelectionsDefault() => Selection.All.Keys.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
private static bool AreKoaloaderSelectionsDefault() =>
Selection.All.Keys.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
private static bool CanSaveKoaloader() => ProgramData.ReadKoaloaderChoices().Any() || !AreKoaloaderSelectionsDefault();
private static bool CanSaveKoaloader() =>
ProgramData.ReadKoaloaderChoices().Any() || !AreKoaloaderSelectionsDefault();
private void OnSaveKoaloader(object sender, EventArgs e)
{
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
List<(Platform platform, string id, string proxy, bool enabled)> choices =
ProgramData.ReadKoaloaderChoices().ToList();
foreach (Selection selection in Selection.All.Keys)
{
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
if (selection.KoaloaderProxy is not null and not Selection.DefaultKoaloaderProxy || !selection.Koaloader)
choices.Add((selection.Platform, selection.Id, selection.KoaloaderProxy == Selection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy,
choices.Add((selection.Platform, selection.Id,
selection.KoaloaderProxy == Selection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy,
selection.Koaloader));
}
ProgramData.WriteKoaloaderProxyChoices(choices);
saveKoaloaderButton.Enabled = CanSaveKoaloader();
loadKoaloaderButton.Enabled = CanLoadKoaloader();
@ -1020,7 +1134,8 @@ internal sealed partial class SelectForm : CustomForm
private void OnLoadKoaloader(object sender, EventArgs e)
{
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
List<(Platform platform, string id, string proxy, bool enabled)> choices =
ProgramData.ReadKoaloaderChoices().ToList();
foreach (Selection selection in Selection.All.Keys)
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
{
@ -1045,6 +1160,7 @@ internal sealed partial class SelectForm : CustomForm
selection.Koaloader = true;
selection.KoaloaderProxy = null;
}
ProgramData.WriteKoaloaderProxyChoices(choices);
loadKoaloaderButton.Enabled = CanLoadKoaloader();
OnKoaloaderChanged();
@ -1059,6 +1175,7 @@ internal sealed partial class SelectForm : CustomForm
selection.Koaloader = true;
selection.KoaloaderProxy = null;
}
OnKoaloaderChanged();
}
@ -1092,13 +1209,19 @@ internal sealed partial class SelectForm : CustomForm
using DialogForm form = new(this);
_ = form.Show(SystemIcons.Information,
"Blocks the program from caching and displaying games protected by anti-cheats."
+ "\nYou disable this option and install DLC unlockers to protected games at your own risk!" + "\n\nBlocked games: "
+ (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) + "\n\nBlocked game sub-directories: "
+ (string.IsNullOrWhiteSpace(blockedDirectories.ToString()) ? "(none)" : blockedDirectories) + "\n\nBlocked game sub-directory exceptions: "
+ (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString()) ? "(none)" : blockedDirectoryExceptions),
+ "\nYou disable this option and install DLC unlockers to protected games at your own risk!" +
"\n\nBlocked games: "
+ (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) +
"\n\nBlocked game sub-directories: "
+ (string.IsNullOrWhiteSpace(blockedDirectories.ToString()) ? "(none)" : blockedDirectories) +
"\n\nBlocked game sub-directory exceptions: "
+ (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString())
? "(none)"
: blockedDirectoryExceptions),
customFormText: "Block Protected Games");
}
private void OnSortCheckBoxChanged(object sender, EventArgs e)
=> selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
=> selectionTreeView.TreeViewNodeSorter =
sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName;
}

View file

@ -50,16 +50,21 @@ internal sealed partial class UpdateForm : 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
Version currentVersion = new(Program.Version);
#endif
List<ProgramRelease> releases = null;
string response = await HttpClientManager.EnsureGet($"https://api.github.com/repos/{Program.RepositoryOwner}/{Program.RepositoryName}/releases");
string response =
await HttpClientManager.EnsureGet(
$"https://api.github.com/repos/{Program.RepositoryOwner}/{Program.RepositoryName}/releases");
if (response is not null)
releases = JsonConvert.DeserializeObject<List<ProgramRelease>>(response)
?.Where(release => !release.Draft && !release.Prerelease && release.Asset is not null).ToList();
?.Where(release => !release.Draft && !release.Prerelease && release.Asset is not null).ToList();
latestRelease = releases?.FirstOrDefault();
#if DEBUG
if (latestRelease?.Version is not { } latestVersion)
@ -101,7 +106,7 @@ internal sealed partial class UpdateForm : CustomForm
private void OnLoad(object sender, EventArgs _)
{
retry:
retry:
try
{
UpdaterPath.DeleteFile();
@ -125,7 +130,8 @@ internal sealed partial class UpdateForm : 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<int> progress = new();
IProgress<int> iProgress = progress;
@ -144,7 +150,8 @@ internal sealed partial class UpdateForm : CustomForm
{
if (cancellation is null || Program.Canceled)
throw new TaskCanceledException();
using HttpResponseMessage response = await HttpClientManager.HttpClient.GetAsync(latestRelease.Asset.BrowserDownloadUrl,
using HttpResponseMessage response = await HttpClientManager.HttpClient.GetAsync(
latestRelease.Asset.BrowserDownloadUrl,
HttpCompletionOption.ResponseHeadersRead, cancellation.Token);
_ = response.EnsureSuccessStatusCode();
if (cancellation is null || Program.Canceled)
@ -155,7 +162,8 @@ internal sealed partial class UpdateForm : CustomForm
long bytesRead = 0;
int newBytes;
while (cancellation is not null && !Program.Canceled
&& (newBytes = await download.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellation.Token)) != 0)
&& (newBytes = await download.ReadAsync(buffer.AsMemory(0, buffer.Length),
cancellation.Token)) != 0)
{
if (cancellation is null || Program.Canceled)
throw new TaskCanceledException();
@ -166,6 +174,7 @@ internal sealed partial class UpdateForm : CustomForm
continue;
iProgress.Report(report);
}
iProgress.Report((int)(bytesRead / bytes * 100));
if (cancellation is null || Program.Canceled)
throw new TaskCanceledException();
@ -179,6 +188,7 @@ internal sealed partial class UpdateForm : CustomForm
retry = ex.HandleException(this, Program.Name + " encountered an exception while updating");
success = false;
}
cancellation?.Dispose();
cancellation = null;
await update.DisposeAsync();
@ -209,13 +219,15 @@ internal sealed partial class UpdateForm : CustomForm
Process process = new();
ProcessStartInfo startInfo = new()
{
WorkingDirectory = ProgramData.DirectoryPath, FileName = "cmd.exe", Arguments = $"/C START \"UPDATER\" /B {Path.GetFileName(UpdaterPath)}",
WorkingDirectory = ProgramData.DirectoryPath, FileName = "cmd.exe",
Arguments = $"/C START \"UPDATER\" /B {Path.GetFileName(UpdaterPath)}",
CreateNoWindow = true
};
process.StartInfo = startInfo;
_ = process.Start();
return;
}
if (!retry)
StartProgram();
else

View file

@ -17,8 +17,11 @@ internal static class EpicLibrary
{
get
{
epicManifestsPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\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_CURRENT_USER\Software\Epic Games\EOS", "ModSdkMetadataDir", null) as string;
epicManifestsPath ??=
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Epic Games\EpicGamesLauncher", "AppDataPath",
null) as string;
if (epicManifestsPath is not null && epicManifestsPath.EndsWith(@"\Data", StringComparison.Ordinal))
epicManifestsPath += @"\Manifests";
return epicManifestsPath.ResolvePath();
@ -39,8 +42,9 @@ internal static class EpicLibrary
try
{
Manifest manifest = JsonConvert.DeserializeObject<Manifest>(json);
if (manifest is not null && (manifest.InstallLocation = manifest.InstallLocation.ResolvePath()) is not null
&& games.All(g => g.CatalogNamespace != manifest.CatalogNamespace))
if (manifest is not null && (manifest.InstallLocation = manifest.InstallLocation.ResolvePath())
is not null
&& games.All(g => g.CatalogNamespace != manifest.CatalogNamespace))
games.Add(manifest);
}
catch
@ -48,6 +52,7 @@ internal static class EpicLibrary
// ignored
}
}
if (Program.Canceled)
return games;
await HeroicLibrary.GetGames(games);

View file

@ -14,7 +14,8 @@ internal static class EpicStore
{
private const int Cooldown = 600;
internal static async Task<List<(string id, string name, string product, string icon, string developer)>> QueryCatalog(string categoryNamespace)
internal static async Task<List<(string id, string name, string product, string icon, string developer)>>
QueryCatalog(string categoryNamespace)
{
List<(string id, string name, string product, string icon, string developer)> dlcIds = [];
string cacheFile = ProgramData.AppInfoPath + @$"\{categoryNamespace}.json";
@ -41,13 +42,16 @@ internal static class EpicStore
{
cacheFile.DeleteFile();
}
if (response is null)
return dlcIds;
List<Element> searchStore = [..response.Data.Catalog.SearchStore.Elements];
foreach (Element element in searchStore)
{
string title = element.Title;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0 ? element.CatalogNs.Mappings.First().PageSlug : null;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0
? element.CatalogNs.Mappings.First().PageSlug
: null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{
@ -57,14 +61,18 @@ internal static class EpicStore
icon = keyImage.Url.ToString();
break;
}
foreach (Item item in element.Items)
dlcIds.Populate(item.Id, title, product, icon, null, element.Items.Length == 1);
}
List<Element> catalogOffers = [..response.Data.Catalog.CatalogOffers.Elements];
foreach (Element element in catalogOffers)
{
string title = element.Title;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0 ? element.CatalogNs.Mappings.First().PageSlug : null;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0
? element.CatalogNs.Mappings.First().PageSlug
: null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{
@ -74,13 +82,17 @@ internal static class EpicStore
icon = keyImage.Url.ToString();
break;
}
foreach (Item item in element.Items)
dlcIds.Populate(item.Id, title, product, icon, item.Developer, element.Items.Length == 1);
}
return dlcIds;
}
private static void Populate(this List<(string id, string name, string product, string icon, string developer)> dlcIds, string id, string title,
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)
@ -97,6 +109,7 @@ internal static class EpicStore
: (app.id, app.name ?? title, app.product ?? product, app.icon ?? icon, app.developer ?? developer);
break;
}
if (!found)
dlcIds.Add((id, title, product, icon, developer));
}
@ -113,7 +126,8 @@ internal static class EpicStore
HttpClient client = HttpClientManager.HttpClient;
if (client is null)
return null;
HttpResponseMessage httpResponse = await client.PostAsync(new Uri("https://graphql.epicgames.com/graphql"), content);
HttpResponseMessage httpResponse =
await client.PostAsync(new Uri("https://graphql.epicgames.com/graphql"), content);
_ = httpResponse.EnsureSuccessStatusCode();
string response = await httpResponse.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Response>(response);

View file

@ -10,7 +10,8 @@ namespace CreamInstaller.Platforms.Epic.Heroic;
internal static class HeroicLibrary
{
internal static readonly string HeroicLibraryPath
= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\heroic\store_cache\legendary_library.json";
= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
@"\heroic\store_cache\legendary_library.json";
internal static async Task GetGames(List<Manifest> games)
=> await Task.Run(() =>
@ -28,11 +29,13 @@ internal static class HeroicLibrary
try
{
HeroicAppData appData = token.ToObject<HeroicAppData>();
if (appData is null || string.IsNullOrWhiteSpace(appData.Install.InstallPath = appData.Install.InstallPath.ResolvePath()))
if (appData is null || string.IsNullOrWhiteSpace(appData.Install.InstallPath =
appData.Install.InstallPath.ResolvePath()))
continue;
Manifest manifest = new()
{
DisplayName = appData.Title, CatalogNamespace = appData.Namespace, InstallLocation = appData.Install.InstallPath
DisplayName = appData.Title, CatalogNamespace = appData.Namespace,
InstallLocation = appData.Install.InstallPath
};
if (games.All(g => g.CatalogNamespace != manifest.CatalogNamespace))
games.Add(manifest);

View file

@ -13,7 +13,12 @@ namespace CreamInstaller.Platforms.Paradox;
internal static class ParadoxLauncher
{
public enum RepairResult { Failure = -1, Unnecessary = 0, Success }
public enum RepairResult
{
Failure = -1,
Unnecessary = 0,
Success
}
private static string installPath;
@ -21,7 +26,8 @@ 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\Paradox Interactive\Paradox Launcher v2",
"LauncherInstallation", null) as string;
return installPath.ResolvePath();
}
}
@ -32,11 +38,13 @@ internal static class ParadoxLauncher
if (paradoxLauncher is null)
return;
paradoxLauncher.ExtraSelections.Clear();
foreach (Selection selection in Selection.AllEnabled.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
foreach (Selection selection in Selection.AllEnabled.Where(s =>
!s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
if (paradoxLauncher.ExtraSelections.Count > 0)
return;
foreach (Selection selection in Selection.All.Keys.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
foreach (Selection selection in Selection.All.Keys.Where(s =>
!s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
}
@ -51,7 +59,8 @@ internal static class ParadoxLauncher
using DialogForm dialogForm = new(form);
return dialogForm.Show(SystemIcons.Warning,
"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!"
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!", "Ignore", "Cancel",
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!",
"Ignore", "Cancel",
"Paradox Launcher") != DialogResult.OK;
}
@ -64,6 +73,7 @@ internal static class ParadoxLauncher
Program.Canceled = false;
dialogText = new();
}
using DialogForm dialogForm = new(form);
bool smokeInstalled = false;
byte[] steamOriginalSdk32 = null;
@ -73,36 +83,46 @@ internal static class ParadoxLauncher
byte[] epicOriginalSdk64 = null;
foreach (string directory in selection.DllDirectories.TakeWhile(_ => !Program.Canceled))
{
bool koaloaderInstalled = Koaloader.AutoLoadDLLs.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Any(pair => pair.path.FileExists() && pair.path.IsResourceFile());
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string old_config,
bool koaloaderInstalled = Koaloader.AutoLoadDLLs
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Any(pair => pair.path.FileExists() && pair.path.IsResourceFile());
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out string old_config,
out string config, out _, out _, out _);
smokeInstalled = smokeInstalled || api32_o.FileExists() || api64_o.FileExists()
|| (old_config.FileExists() || config.FileExists()) && !koaloaderInstalled
|| api32.FileExists() && api32.IsResourceFile(ResourceIdentifier.Steamworks32)
|| api64.FileExists() && api64.IsResourceFile(ResourceIdentifier.Steamworks64);
|| (old_config.FileExists() || config.FileExists()) && !koaloaderInstalled
|| api32.FileExists() && api32.IsResourceFile(ResourceIdentifier.Steamworks32)
|| api64.FileExists() && api64.IsResourceFile(ResourceIdentifier.Steamworks64);
await SmokeAPI.Uninstall(directory, deleteOthers: false);
if (steamOriginalSdk32 is null && api32.FileExists() && !api32.IsResourceFile(ResourceIdentifier.Steamworks32))
if (steamOriginalSdk32 is null && api32.FileExists() &&
!api32.IsResourceFile(ResourceIdentifier.Steamworks32))
steamOriginalSdk32 = api32.ReadFileBytes(true);
if (steamOriginalSdk64 is null && api64.FileExists() && !api64.IsResourceFile(ResourceIdentifier.Steamworks64))
if (steamOriginalSdk64 is null && api64.FileExists() &&
!api64.IsResourceFile(ResourceIdentifier.Steamworks64))
steamOriginalSdk64 = api64.ReadFileBytes(true);
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out config, out string log);
directory.GetScreamApiComponents(out api32, out api32_o, out api64, out api64_o, out config,
out string log);
screamInstalled = screamInstalled || api32_o.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled
|| api32.FileExists() && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32)
|| api64.FileExists() && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64);
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled
|| api32.FileExists() && api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32)
|| api64.FileExists() && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64);
await ScreamAPI.Uninstall(directory, deleteOthers: false);
if (epicOriginalSdk32 is null && api32.FileExists() && !api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
if (epicOriginalSdk32 is null && api32.FileExists() &&
!api32.IsResourceFile(ResourceIdentifier.EpicOnlineServices32))
epicOriginalSdk32 = api32.ReadFileBytes(true);
if (epicOriginalSdk64 is null && api64.FileExists() && !api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
if (epicOriginalSdk64 is null && api64.FileExists() &&
!api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
epicOriginalSdk64 = api64.ReadFileBytes(true);
}
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.TakeWhile(_ => !Program.Canceled))
{
directory.GetSmokeApiComponents(out string api32, out _, out string api64, out _, out _, out _, out _, out _, out _);
directory.GetSmokeApiComponents(out string api32, out _, out string api64, out _, out _, out _, out _,
out _, out _);
if (steamOriginalSdk32 is not null && api32.IsResourceFile(ResourceIdentifier.Steamworks32))
{
steamOriginalSdk32.WriteResource(api32);
@ -112,6 +132,7 @@ internal static class ParadoxLauncher
dialogText.AppendLine("Corrected Steamworks: " + api32);
neededRepair = true;
}
if (steamOriginalSdk64 is not null && api64.IsResourceFile(ResourceIdentifier.Steamworks64))
{
steamOriginalSdk64.WriteResource(api64);
@ -121,6 +142,7 @@ internal static class ParadoxLauncher
dialogText.AppendLine("Corrected Steamworks: " + api64);
neededRepair = true;
}
if (smokeInstalled)
await SmokeAPI.Install(directory, selection, generateConfig: false);
directory.GetScreamApiComponents(out api32, out _, out api64, out _, out _, out _);
@ -133,6 +155,7 @@ internal static class ParadoxLauncher
dialogText.AppendLine("Corrected Epic Online Services: " + api32);
neededRepair = true;
}
if (epicOriginalSdk64 is not null && api64.IsResourceFile(ResourceIdentifier.EpicOnlineServices64))
{
epicOriginalSdk64.WriteResource(api64);
@ -142,9 +165,11 @@ internal static class ParadoxLauncher
dialogText.AppendLine("Corrected Epic Online Services: " + api64);
neededRepair = true;
}
if (screamInstalled)
await ScreamAPI.Install(directory, selection, generateConfig: false);
}
if (!Program.Canceled)
{
if (neededRepair)
@ -156,28 +181,36 @@ internal static class ParadoxLauncher
dialogText.AppendLine("\nParadox Launcher successfully repaired!");
_ = dialogForm.Show(form.Icon, dialogText.ToString(), 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.", customFormText: "Paradox Launcher");
_ = dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.",
customFormText: "Paradox Launcher");
return RepairResult.Unnecessary;
}
}
if (Program.Canceled)
{
_ = form is InstallForm
? throw new CustomMessageException("Repair failed! The operation was canceled.")
: dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed! The operation was canceled.", customFormText: "Paradox Launcher");
: dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed! The operation was canceled.",
customFormText: "Paradox Launcher");
return RepairResult.Failure;
}
_ = form is InstallForm
? throw new CustomMessageException("Repair failed! " + "An original Steamworks and/or Epic Online Services file could not be found. "
+ "You will likely have to reinstall Paradox Launcher to fix this issue.")
? 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.", customFormText: "Paradox Launcher");
+ "\nYou will likely have to reinstall Paradox Launcher to fix this issue.",
customFormText: "Paradox Launcher");
return RepairResult.Failure;
}
}

View file

@ -23,7 +23,8 @@ internal static class SteamCMD
private 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];
@ -42,13 +43,13 @@ internal static class SteamCMD
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"
+ string.Concat(Enumerable.Repeat("+app_update 4 ", attempts)) + "+quit"
: $"+login anonymous +app_info_print {appId} +quit";
private static async Task<string> Run(string appId)
=> await Task.Run(() =>
{
wait_for_lock:
wait_for_lock:
if (Program.Canceled)
return "";
for (int i = 0; i < Locks.Length; i++)
@ -62,13 +63,17 @@ internal static class SteamCMD
_ = 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
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();
@ -83,6 +88,7 @@ internal static class SteamCMD
process.Close();
break;
}
int c = process.StandardOutput.Read();
if (c != -1)
{
@ -92,13 +98,15 @@ internal static class SteamCMD
appInfoStarted = true;
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
}
DateTime now = DateTime.UtcNow;
TimeSpan timeDiff = now - lastOutput;
if (!(timeDiff.TotalSeconds > 0.1))
continue;
process.Kill(true);
process.Close();
if (appId != null && output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
if (appId != null &&
output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
{
AttemptCount[appId]++;
processStartInfo.Arguments = GetArguments(appId);
@ -110,9 +118,11 @@ internal static class SteamCMD
else
break;
}
_ = Interlocked.Decrement(ref Locks[i]);
return appInfo.ToString();
}
Thread.Sleep(200);
goto wait_for_lock;
});
@ -122,14 +132,16 @@ internal static class SteamCMD
await Cleanup();
if (!FilePath.FileExists())
{
retryDownload:
retryDownload:
HttpClient httpClient = HttpClientManager.HttpClient;
if (httpClient is null)
return false;
while (!Program.Canceled)
try
{
byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
byte[] file =
await httpClient.GetByteArrayAsync(
new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
_ = file.WriteResource(ArchivePath);
ArchivePath.ExtractZip(DirectoryPath);
ArchivePath.DeleteFile();
@ -142,9 +154,11 @@ internal static class SteamCMD
return false;
}
}
if (DllPath.FileExists())
return true;
FileSystemWatcher watcher = new(DirectoryPath) { Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true };
FileSystemWatcher watcher = new(DirectoryPath)
{ Filter = "*", IncludeSubdirectories = true, EnableRaisingEvents = true };
if (DllPath.FileExists())
progress.Report(-15); // update (not used at the moment)
else
@ -176,7 +190,8 @@ internal static class SteamCMD
file.DeleteFile();
foreach (string file in DirectoryPath.EnumerateDirectory("*.ntfs_transaction_failed"))
file.DeleteFile();
AppCachePath.DeleteDirectory(); // this is definitely needed, so SteamCMD gets the latest information for us
AppCachePath
.DeleteDirectory(); // this is definitely needed, so SteamCMD gets the latest information for us
DumpsPath.DeleteDirectory();
LogsPath.DeleteDirectory();
SteamAppsPath.DeleteDirectory(); // this is just a useless folder created from +app_update 4
@ -196,10 +211,12 @@ internal static class SteamCMD
if (attempts > 10)
{
#if DEBUG
DebugForm.Current.Log("Failed to query SteamCMD after 10 tries: " + appId + " (" + branch + ")", LogTextBox.Warning);
DebugForm.Current.Log("Failed to query SteamCMD after 10 tries: " + appId + " (" + branch + ")",
LogTextBox.Warning);
#endif
break;
}
string appUpdateFile = $@"{AppInfoPath}\{appId}.vdf";
string output = appUpdateFile.ReadFile();
if (output is null)
@ -216,27 +233,34 @@ internal static class SteamCMD
else
{
#if DEBUG
DebugForm.Current.Log("SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch + "): Bad output",
DebugForm.Current.Log(
"SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch +
"): Bad output",
LogTextBox.Warning);
#endif
continue;
}
}
if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue)
{
appUpdateFile.DeleteFile();
#if DEBUG
DebugForm.Current.Log("SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch + "): Deserialization failed",
DebugForm.Current.Log(
"SteamCMD query failed on attempt #" + attempts + " for " + appId + " (" + branch +
"): Deserialization failed",
LogTextBox.Warning);
#endif
continue;
}
if (!appInfo.Value.Children().Any())
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();
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))
@ -246,9 +270,12 @@ internal static class SteamCMD
dlcAppUpdateFile.DeleteFile();
appUpdateFile.DeleteFile();
#if DEBUG
DebugForm.Current.Log("SteamCMD query skipped on attempt #" + attempts + " for " + appId + " (" + branch + "): Outdated cache", LogTextBox.Warning);
DebugForm.Current.Log(
"SteamCMD query skipped on attempt #" + attempts + " for " + appId + " (" + branch +
"): Outdated cache", LogTextBox.Warning);
#endif
}
return null;
}
@ -267,15 +294,18 @@ internal static class SteamCMD
if (int.TryParse(id, out int appId) && appId > 0)
_ = 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 _)))
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.Add("" + appId);
}
return dlcIds;
});

View file

@ -16,12 +16,14 @@ internal static class SteamLibrary
get
{
installPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Valve\Steam", "SteamPath", null) as string;
installPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) as string;
installPath ??=
Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam", "InstallPath", null) as string;
return installPath.ResolvePath();
}
}
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
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();
@ -30,10 +32,12 @@ internal static class SteamLibrary
{
if (Program.Canceled)
return games;
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in (await GetGamesFromLibraryDirectory(
libraryDirectory)).Where(game => games.All(_game => _game.appId != game.appId)))
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in (await
GetGamesFromLibraryDirectory(
libraryDirectory)).Where(game => games.All(_game => _game.appId != game.appId)))
games.Add(game);
}
return games;
});
@ -54,11 +58,13 @@ internal static class SteamLibrary
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))
if (string.IsNullOrWhiteSpace(appId) || string.IsNullOrWhiteSpace(installdir) ||
string.IsNullOrWhiteSpace(name)
|| string.IsNullOrWhiteSpace(buildId))
continue;
string gameDirectory = (libraryDirectory + @"\common\" + installdir).ResolvePath();
if (gameDirectory is null || !int.TryParse(appId, out int _) || !int.TryParse(buildId, out int buildIdInt) || games.Any(g => g.appId == appId))
if (gameDirectory is null || !int.TryParse(appId, out int _) ||
!int.TryParse(buildId, out int buildIdInt) || games.Any(g => g.appId == appId))
continue;
VToken userConfig = result.Value.GetChild("UserConfig");
string branch = userConfig?.GetChild("BetaKey")?.ToString();
@ -69,10 +75,12 @@ internal static class SteamLibrary
branch = mountedConfig?.GetChild("BetaKey")?.ToString();
branch ??= mountedConfig?.GetChild("betakey")?.ToString();
}
if (string.IsNullOrWhiteSpace(branch))
branch = "public";
games.Add((appId, name, branch, buildIdInt, gameDirectory));
}
return games;
});
@ -90,9 +98,11 @@ internal static class SteamLibrary
return libraryDirectories;
_ = libraryDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
if (!libraryFolders.FileExists() || !ValveDataFile.TryDeserialize(libraryFolders.ReadFile(), out VProperty result))
if (!libraryFolders.FileExists() ||
!ValveDataFile.TryDeserialize(libraryFolders.ReadFile(), out VProperty result))
return libraryDirectories;
foreach (VToken vToken in result.Value.Where(p => p is VProperty property && int.TryParse(property.Key, out int _)))
foreach (VToken vToken in result.Value.Where(p =>
p is VProperty property && int.TryParse(property.Key, out int _)))
{
VProperty property = (VProperty)vToken;
string path = property.Value.GetChild("path")?.ToString();
@ -102,6 +112,7 @@ internal static class SteamLibrary
if (path.DirectoryExists())
_ = libraryDirectories.Add(path);
}
return libraryDirectories;
});
}

View file

@ -24,7 +24,9 @@ internal static class SteamStore
HashSet<string> dlcIds = new();
if (appData.DLC is null)
return dlcIds;
foreach (string dlcId in from appId in appData.DLC where appId > 0 select appId.ToString(CultureInfo.InvariantCulture))
foreach (string dlcId in from appId in appData.DLC
where appId > 0
select appId.ToString(CultureInfo.InvariantCulture))
_ = dlcIds.Add(dlcId);
return dlcIds;
});
@ -38,10 +40,12 @@ internal static class SteamStore
bool cachedExists = cacheFile.FileExists();
if (!cachedExists || ProgramData.CheckCooldown(appId, isDlc ? CooldownDlc : CooldownGame))
{
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)
{
Dictionary<string, JToken> apps = JsonConvert.DeserializeObject<Dictionary<string, JToken>>(response);
Dictionary<string, JToken> apps =
JsonConvert.DeserializeObject<Dictionary<string, JToken>>(response);
if (apps is not null)
foreach (KeyValuePair<string, JToken> app in apps)
try
@ -54,12 +58,15 @@ internal static class SteamStore
{
#if DEBUG
DebugForm.Current.Log(
"Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Query unsuccessful (" + app.Value.ToString(Formatting.None) + ")", LogTextBox.Warning);
"Steam store query failed on attempt #" + attempts + " for " + appId +
(isDlc ? " (DLC)" : "")
+ ": Query unsuccessful (" + app.Value.ToString(Formatting.None) + ")",
LogTextBox.Warning);
#endif
if (data is null)
return null;
}
if (data is not null)
{
try
@ -70,8 +77,9 @@ internal static class SteamStore
#if DEBUG
(Exception e)
{
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Unsuccessful serialization (" + e.Message + ")");
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts +
" for " + appId + (isDlc ? " (DLC)" : "")
+ ": Unsuccessful serialization (" + e.Message + ")");
}
#else
{
@ -81,22 +89,27 @@ internal static class SteamStore
return data;
}
#if DEBUG
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Response data null (" + app.Value.ToString(Formatting.None) + ")");
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " +
appId + (isDlc ? " (DLC)" : "")
+ ": Response data null (" +
app.Value.ToString(Formatting.None) + ")");
#endif
}
#if DEBUG
else
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Response details null (" + app.Value.ToString(Formatting.None) + ")");
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " +
appId + (isDlc ? " (DLC)" : "")
+ ": Response details null (" +
app.Value.ToString(Formatting.None) + ")");
#endif
}
catch
#if DEBUG
(Exception e)
{
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Unsuccessful deserialization (" + e.Message + ")");
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " +
appId + (isDlc ? " (DLC)" : "")
+ ": Unsuccessful deserialization (" + e.Message + ")");
}
#else
{
@ -105,18 +118,22 @@ internal static class SteamStore
#endif
#if DEBUG
else
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "")
+ ": Response deserialization null");
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId +
(isDlc ? " (DLC)" : "")
+ ": Response deserialization null");
#endif
}
else
{
#if DEBUG
DebugForm.Current.Log("Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "") + ": Response null",
DebugForm.Current.Log(
"Steam store query failed on attempt #" + attempts + " for " + appId + (isDlc ? " (DLC)" : "") +
": Response null",
LogTextBox.Warning);
#endif
}
}
if (cachedExists)
try
{
@ -126,6 +143,7 @@ internal static class SteamStore
{
cacheFile.DeleteFile();
}
if (isDlc)
break;
if (attempts > 10)
@ -135,8 +153,10 @@ internal static class SteamStore
#endif
break;
}
Thread.Sleep(1000);
}
return null;
}
}

View file

@ -17,6 +17,7 @@ internal static class ValveDataFile
{
// ignored
}
return false;
}
@ -30,6 +31,7 @@ internal static class ValveDataFile
{
// ignored
}
return null;
}
}

View file

@ -34,6 +34,7 @@ internal static class UbisoftLibrary
if (installDir is not null && games.All(g => g.gameId != gameId))
games.Add((gameId, new DirectoryInfo(installDir).Name, installDir));
}
return games;
});
}

View file

@ -13,7 +13,11 @@ internal static class Program
{
internal static readonly string Name = Application.CompanyName;
private static readonly string Description = Application.ProductName;
internal static readonly string Version = Application.ProductVersion[..(Application.ProductVersion.IndexOf('+') is var index && index != -1 ? index : Application.ProductVersion.Length)];
internal static readonly string Version = Application.ProductVersion[
..(Application.ProductVersion.IndexOf('+') is var index && index != -1
? index
: Application.ProductVersion.Length)];
internal const string RepositoryOwner = "pointfeev";
internal static readonly string RepositoryName = Name;
@ -37,8 +41,9 @@ internal static class Program
internal static readonly string[] ProtectedGameDirectoryExceptions = [];
internal static bool IsGameBlocked(string name, string directory = null)
=> BlockProtectedGames && (ProtectedGames.Contains(name) || directory is not null && !ProtectedGameDirectoryExceptions.Contains(name)
&& ProtectedGameDirectories.Any(path => (directory + path).DirectoryExists()));
=> BlockProtectedGames && (ProtectedGames.Contains(name) || directory is not null &&
!ProtectedGameDirectoryExceptions.Contains(name)
&& ProtectedGameDirectories.Any(path => (directory + path).DirectoryExists()));
[STAThread]
private static void Main()
@ -52,8 +57,9 @@ internal static class Program
Application.ApplicationExit += OnApplicationExit;
Application.ThreadException += (_, e) => e.Exception.HandleFatalException();
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException += (_, e) => (e.ExceptionObject as Exception)?.HandleFatalException();
retry:
AppDomain.CurrentDomain.UnhandledException +=
(_, e) => (e.ExceptionObject as Exception)?.HandleFatalException();
retry:
try
{
HttpClientManager.Setup();
@ -71,6 +77,7 @@ internal static class Program
return;
}
}
mutex.Close();
}

View file

@ -15,11 +15,16 @@ internal static class Koaloader
{
internal static readonly List<(string unlocker, string dll)> AutoLoadDLLs =
[
("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 IEnumerable<string> GetKoaloaderProxies(this string directory)
@ -38,7 +43,8 @@ internal static class Koaloader
private static void WriteProxy(this string path, string proxyName, BinaryType binaryType)
{
foreach (string resourceIdentifier in EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)))
foreach (string resourceIdentifier in EmbeddedResources.Where(r =>
r.StartsWith("Koaloader", StringComparison.Ordinal)))
{
resourceIdentifier.GetProxyInfoFromIdentifier(out string _proxyName, out BinaryType _binaryType);
if (_proxyName != proxyName || _binaryType != binaryType)
@ -48,7 +54,8 @@ 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('.')];
@ -65,14 +72,18 @@ internal static class Koaloader
if (!config.FileExists())
{
old_config.MoveFile(config!);
installForm?.UpdateUser($"Converted old configuration: {Path.GetFileName(old_config)} -> {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser(
$"Converted old configuration: {Path.GetFileName(old_config)} -> {Path.GetFileName(config)}",
LogTextBox.Action, false);
}
else
{
old_config.DeleteFile();
installForm?.UpdateUser($"Deleted old configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted old configuration: {Path.GetFileName(old_config)}", LogTextBox.Action,
false);
}
}
SortedList<string, string> targets = new(PlatformIdComparer.String);
SortedList<string, string> modules = new(PlatformIdComparer.String);
if (targets.Count > 0 || modules.Count > 0)
@ -88,11 +99,13 @@ internal static class Koaloader
else if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, string> targets, SortedList<string, string> modules, InstallForm installForm = null)
private static void WriteConfig(StreamWriter writer, SortedList<string, string> targets,
SortedList<string, string> modules, InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -108,10 +121,12 @@ internal static class Koaloader
writer.WriteLine($" \"{path}\"{(pair.Equals(lastTarget) ? "" : ",")}");
installForm?.UpdateUser($"Added target to Koaloader.json with path {path}", LogTextBox.Action, false);
}
writer.WriteLine(" ]");
}
else
writer.WriteLine(" \"targets\": []");
if (modules.Count > 0)
{
writer.WriteLine(" \"modules\": [");
@ -125,39 +140,48 @@ internal static class Koaloader
writer.WriteLine(" }" + (pair.Equals(lastModule) ? "" : ","));
installForm?.UpdateUser($"Added module to Koaloader.json with path {path}", LogTextBox.Action, false);
}
writer.WriteLine(" ]");
}
else
writer.WriteLine(" \"modules\": []");
writer.WriteLine("}");
}
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null, bool deleteConfig = true)
internal static async Task Uninstall(string directory, string rootDirectory = null, InstallForm installForm = null,
bool deleteConfig = true)
=> await Task.Run(async () =>
{
directory.GetKoaloaderComponents(out string old_config, out string config);
foreach (string proxyPath in directory.GetKoaloaderProxies().Where(proxyPath
=> proxyPath.FileExists() && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
=> proxyPath.FileExists() && proxyPath.IsResourceFile(ResourceIdentifier.Koaloader)))
{
proxyPath.DeleteFile(true);
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 => pair.path.FileExists() && pair.path.IsResourceFile()))
foreach ((string unlocker, string path) in AutoLoadDLLs
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Where(pair => pair.path.FileExists() && pair.path.IsResourceFile()))
{
path.DeleteFile(true);
installForm?.UpdateUser($"Deleted {unlocker}: {Path.GetFileName(path)}", LogTextBox.Action, false);
}
if (deleteConfig && old_config.FileExists())
{
old_config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(old_config)}", LogTextBox.Action,
false);
}
if (deleteConfig && config.FileExists())
{
config.DeleteFile();
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);
@ -166,21 +190,27 @@ internal static class Koaloader
await Uninstall(rootDirectory, null, installForm, deleteConfig);
});
internal static async Task Install(string directory, BinaryType binaryType, Selection selection, string rootDirectory = null,
internal static async Task Install(string directory, BinaryType binaryType, Selection selection,
string rootDirectory = null,
InstallForm installForm = null, bool generateConfig = true)
=> await Task.Run(() =>
{
string proxy = selection.KoaloaderProxy ?? Selection.DefaultKoaloaderProxy;
string path = directory + @"\" + proxy + ".dll";
foreach (string _path in directory.GetKoaloaderProxies().Where(p => p != path && p.FileExists() && p.IsResourceFile(ResourceIdentifier.Koaloader)))
foreach (string _path in directory.GetKoaloaderProxies().Where(p =>
p != path && p.FileExists() && p.IsResourceFile(ResourceIdentifier.Koaloader)))
{
_path.DeleteFile(true);
installForm?.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", LogTextBox.Action, false);
}
if (path.FileExists() && !path.IsResourceFile(ResourceIdentifier.Koaloader))
throw new CustomMessageException("A non-Koaloader DLL named " + proxy + ".dll already exists in this directory!");
throw new CustomMessageException("A non-Koaloader DLL named " + proxy +
".dll already exists in this directory!");
path.WriteProxy(proxy, binaryType);
installForm?.UpdateUser($"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}", LogTextBox.Action,
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.EnumerateDirectory("*.exe"))
@ -195,9 +225,11 @@ internal static class Koaloader
bit64 = true;
break;
}
if (bit32 && bit64)
break;
}
if (selection.Platform is Platform.Steam or Platform.Paradox)
{
if (bit32)
@ -208,15 +240,20 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
installForm?.UpdateUser(
$"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI32.dll";
}
"SmokeAPI.steam_api.dll".WriteManifestResource(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";
@ -225,17 +262,23 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
installForm?.UpdateUser(
$"Deleted SmokeAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\SmokeAPI64.dll";
}
"SmokeAPI.steam_api64.dll".WriteManifestResource(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);
}
switch (selection.Platform)
{
case Platform.Epic or Platform.Paradox:
@ -248,15 +291,20 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
installForm?.UpdateUser(
$"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI32.dll";
}
"ScreamAPI.EOSSDK-Win32-Shipping.dll".WriteManifestResource(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";
@ -265,15 +313,20 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action, false);
installForm?.UpdateUser(
$"Deleted ScreamAPI from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
path = rootDirectory + @"\ScreamAPI64.dll";
}
"ScreamAPI.EOSSDK-Win64-Shipping.dll".WriteManifestResource(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);
break;
}
@ -287,16 +340,21 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
installForm?.UpdateUser(
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action,
false);
}
path = rootDirectory + @"\UplayR1Unlocker32.dll";
}
"UplayR1.uplay_r1_loader.dll".WriteManifestResource(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";
@ -305,16 +363,21 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
installForm?.UpdateUser(
$"Deleted Uplay R1 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action,
false);
}
path = rootDirectory + @"\UplayR1Unlocker64.dll";
}
"UplayR1.uplay_r1_loader64.dll".WriteManifestResource(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)
{
@ -324,16 +387,21 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
installForm?.UpdateUser(
$"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}",
LogTextBox.Action,
false);
}
path = rootDirectory + @"\UplayR2Unlocker32.dll";
}
"UplayR2.upc_r2_loader.dll".WriteManifestResource(path);
installForm?.UpdateUser(
$"Wrote Uplay R2 Unlocker{(rootDirectory is not null && directory != rootDirectory ? " to root directory" : "")}: {Path.GetFileName(path)}",
LogTextBox.Action, false);
}
if (bit64)
{
path = directory + @"\UplayR2Unlocker64.dll";
@ -342,20 +410,26 @@ internal static class Koaloader
if (path.FileExists())
{
path.DeleteFile();
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker from non-root directory: {Path.GetFileName(path)}", LogTextBox.Action,
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".WriteManifestResource(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);
break;
}
}
if (generateConfig)
CheckConfig(directory, installForm);
});

View file

@ -432,7 +432,8 @@ internal static class Resources
return embeddedResources;
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
embeddedResources = [];
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.", StringComparison.Ordinal)))
foreach (string resourceName in names.Where(n =>
n.StartsWith("CreamInstaller.Resources.", StringComparison.Ordinal)))
_ = embeddedResources.Add(resourceName[25..]);
return embeddedResources;
}
@ -443,14 +444,16 @@ internal static class Resources
while (!Program.Canceled)
try
{
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);
break;
}
catch (Exception e)
{
if (filePath.IOWarn("Failed to write a crucial manifest resource (" + resourceIdentifier + ")", e) is not DialogResult.OK)
if (filePath.IOWarn("Failed to write a crucial manifest resource (" + resourceIdentifier + ")", e) is
not DialogResult.OK)
break;
}
}
@ -469,22 +472,26 @@ internal static class Resources
if (filePath.IOWarn("Failed to write a crucial resource", e) is not DialogResult.OK)
break;
}
return false;
}
internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) => NativeImports.GetBinaryType(path, out binaryType);
internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) =>
NativeImports.GetBinaryType(path, out binaryType);
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false,
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 =>
?? (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,
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory,
bool filterCommon = false,
Func<string, bool> validFunc = null)
=> await Task.Run(() =>
{
@ -495,18 +502,26 @@ internal static class Resources
{
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 (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));
}
foreach (string path in rootDirectory.EnumerateDirectory("*.exe", 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 (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));
}
return executables.Count > 0 ? executables : null;
});
@ -514,12 +529,16 @@ internal static class Resources
{
string subPath = path[rootDirectory.Length..].ToUpperInvariant();
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");
|| 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<HashSet<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory, Platform platform)
internal static async Task<HashSet<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory,
Platform platform)
=> await Task.Run(() =>
{
HashSet<string> dllDirectories = [];
@ -532,43 +551,54 @@ internal static class Resources
string subDirectory = directory.ResolvePath();
if (subDirectory is null || dllDirectories.Contains(subDirectory))
continue;
bool koaloaderInstalled = Koaloader.AutoLoadDLLs.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Any(pair => pair.path.FileExists() && pair.path.IsResourceFile());
bool koaloaderInstalled = Koaloader.AutoLoadDLLs
.Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll))
.Any(pair => pair.path.FileExists() && 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 old_config,
subDirectory.GetSmokeApiComponents(out string api, out string api_o, out string api64,
out string api64_o, out string old_config,
out string config, out string old_log, out string log, out string cache);
if (api.FileExists() || api_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (old_config.FileExists() || config.FileExists() || old_log.FileExists() || log.FileExists() || cache.FileExists())
&& !koaloaderInstalled)
|| (old_config.FileExists() || config.FileExists() || old_log.FileExists() ||
log.FileExists() || cache.FileExists())
&& !koaloaderInstalled)
_ = dllDirectories.Add(subDirectory);
}
if (platform is Platform.Epic or Platform.Paradox)
{
subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config,
subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
_ = dllDirectories.Add(subDirectory);
}
if (platform is Platform.Ubisoft)
{
subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config,
subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64,
out string api64_o, out string config,
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
_ = dllDirectories.Add(subDirectory);
subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, out api32_o, out api64, out api64_o, out config,
subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32,
out api32_o, out api64, out api64_o, out config,
out log);
if (old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() || api32_o.FileExists() || api64.FileExists()
|| api64_o.FileExists() || (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
if (old_api32.FileExists() || old_api64.FileExists() || api32.FileExists() ||
api32_o.FileExists() || api64.FileExists()
|| api64_o.FileExists() || (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
_ = dllDirectories.Add(subDirectory);
}
}
return dllDirectories.Count > 0 ? dllDirectories : null;
});
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";
@ -588,14 +618,27 @@ internal static class Resources
internal static bool IsResourceFile(this string filePath, ResourceIdentifier identifier)
=> filePath.ComputeMD5() is { } hash && ResourceMD5s[identifier].Contains(hash);
internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is { } hash && ResourceMD5s.Values.Any(hashes => hashes.Contains(hash));
internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is { } hash &&
ResourceMD5s.Values.Any(
hashes => hashes.Contains(hash));
internal enum BinaryType { Unknown = -1, BIT32 = 0, BIT64 = 6 }
internal enum BinaryType
{
Unknown = -1,
BIT32 = 0,
BIT64 = 6
}
internal enum ResourceIdentifier
{
Koaloader, Steamworks32, Steamworks64,
EpicOnlineServices32, EpicOnlineServices64, Uplay32,
Uplay64, Upc32, Upc64
Koaloader,
Steamworks32,
Steamworks64,
EpicOnlineServices32,
EpicOnlineServices64,
Uplay32,
Uplay64,
Upc32,
Upc64
}
}

View file

@ -11,7 +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,
internal static void GetScreamApiComponents(this string directory, out string api32, out string api32_o,
out string api64, out string api64_o,
out string config, out string log)
{
api32 = directory + @"\EOSSDK-Win32-Shipping.dll";
@ -25,7 +26,8 @@ internal static class ScreamAPI
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config, out _);
HashSet<SelectionDLC> overrideCatalogItems = selection.DLC.Where(dlc => dlc.Type is DLCType.Epic && !dlc.Enabled).ToHashSet();
HashSet<SelectionDLC> overrideCatalogItems =
selection.DLC.Where(dlc => dlc.Type is DLCType.Epic && !dlc.Enabled).ToHashSet();
int entitlementCount = 0;
HashSet<SelectionDLC> injectedEntitlements = [];
foreach (SelectionDLC dlc in selection.DLC.Where(dlc => dlc.Type is DLCType.EpicEntitlement))
@ -34,6 +36,7 @@ internal static class ScreamAPI
_ = injectedEntitlements.Add(dlc);
entitlementCount++;
}
foreach (Selection extraSelection in selection.ExtraSelections)
{
foreach (SelectionDLC extraDlc in extraSelection.DLC.Where(dlc => dlc.Type is DLCType.Epic && !dlc.Enabled))
@ -45,6 +48,7 @@ internal static class ScreamAPI
entitlementCount++;
}
}
if (injectedEntitlements.Count == entitlementCount)
injectedEntitlements.Clear();
if (overrideCatalogItems.Count > 0 || injectedEntitlements.Count > 0)
@ -53,15 +57,18 @@ internal static class ScreamAPI
installForm.UpdateUser("Generating ScreamAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(overrideCatalogItems.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectedEntitlements.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
WriteConfig(writer,
new(overrideCatalogItems.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectedEntitlements.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
}
@ -83,13 +90,17 @@ internal static class ScreamAPI
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
installForm?.UpdateUser($"Added locked catalog item to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
installForm?.UpdateUser(
$"Added locked catalog item to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" ]");
}
else
writer.WriteLine(" \"override\": []");
writer.WriteLine(" },");
writer.WriteLine(" \"entitlements\": {");
if (injectedEntitlements.Count > 0)
@ -102,9 +113,12 @@ internal static class ScreamAPI
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
installForm?.UpdateUser($"Added injected entitlement to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
installForm?.UpdateUser(
$"Added injected entitlement to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" ]");
}
else
@ -113,6 +127,7 @@ internal static class ScreamAPI
writer.WriteLine(" \"auto_inject\": true,");
writer.WriteLine(" \"inject\": []");
}
writer.WriteLine(" }");
writer.WriteLine("}");
}
@ -120,7 +135,8 @@ internal static class ScreamAPI
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteOthers = true)
=> await Task.Run(() =>
{
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string log);
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out string config, out string log);
if (api32_o.FileExists())
{
if (api32.FileExists())
@ -128,9 +144,12 @@ internal static class ScreamAPI
api32.DeleteFile(true);
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
api32_o.MoveFile(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 (api64_o.FileExists())
{
if (api64.FileExists())
@ -138,9 +157,12 @@ internal static class ScreamAPI
api64.DeleteFile(true);
installForm?.UpdateUser($"Deleted ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
api64_o.MoveFile(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 (!deleteOthers)
return;
if (config.FileExists())
@ -148,6 +170,7 @@ internal static class ScreamAPI
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
if (log.FileExists())
{
log.DeleteFile();
@ -155,30 +178,38 @@ internal static class ScreamAPI
}
});
internal static async Task Install(string directory, Selection selection, InstallForm installForm = null, bool generateConfig = true)
internal static async Task Install(string directory, Selection 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 _, out _);
directory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out _, out _);
if (api32.FileExists() && !api32_o.FileExists())
{
api32.MoveFile(api32_o!, true);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (api32_o.FileExists())
{
"ScreamAPI.EOSSDK-Win32-Shipping.dll".WriteManifestResource(api32);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (api64.FileExists() && !api64_o.FileExists())
{
api64.MoveFile(api64_o!, true);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed EOS: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (api64_o.FileExists())
{
"ScreamAPI.EOSSDK-Win64-Shipping.dll".WriteManifestResource(api64);
installForm?.UpdateUser($"Wrote ScreamAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});

View file

@ -11,7 +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,
internal static void GetSmokeApiComponents(this string directory, out string api32, out string api32_o,
out string api64, out string api64_o,
out string old_config, out string config, out string old_log, out string log, out string cache)
{
api32 = directory + @"\steam_api.dll";
@ -27,35 +28,46 @@ internal static class SmokeAPI
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _, out _, out _);
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _,
out _, out _);
HashSet<SelectionDLC> overrideDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection =>
extraSelection.DLC.Where(dlc => !dlc.Enabled)))
_ = overrideDlc.Add(extraDlc);
HashSet<SelectionDLC> injectDlc = [];
if (selection.DLC.Count() > 64)
foreach (SelectionDLC hiddenDlc in selection.DLC.Where(dlc => dlc.Enabled && dlc.Type is DLCType.SteamHidden))
foreach (SelectionDLC hiddenDlc in selection.DLC.Where(
dlc => dlc.Enabled && dlc.Type is DLCType.SteamHidden))
_ = injectDlc.Add(hiddenDlc);
List<KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)>> extraApps = [];
foreach (Selection extraSelection in selection.ExtraSelections.Where(extraSelection => extraSelection.DLC.Count() > 64))
foreach (Selection extraSelection in selection.ExtraSelections.Where(extraSelection =>
extraSelection.DLC.Count() > 64))
{
SortedList<string, SelectionDLC> extraInjectDlc = new(PlatformIdComparer.String);
foreach (SelectionDLC extraDlc in extraSelection.DLC.Where(extraDlc => extraDlc.Enabled && extraDlc.Type is DLCType.SteamHidden))
foreach (SelectionDLC extraDlc in extraSelection.DLC.Where(extraDlc =>
extraDlc.Enabled && extraDlc.Type is DLCType.SteamHidden))
extraInjectDlc.Add(extraDlc.Id, extraDlc);
if (extraInjectDlc.Count > 0)
extraApps.Add(new(extraSelection.Id, (extraSelection.Name, extraInjectDlc)));
}
if (old_config.FileExists())
{
old_config.DeleteFile();
installForm?.UpdateUser($"Deleted old configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted old configuration: {Path.GetFileName(old_config)}", LogTextBox.Action,
false);
}
if (selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any()) || overrideDlc.Count > 0 || injectDlc.Count > 0)
if (selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any()) || overrideDlc.Count > 0 ||
injectDlc.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating SmokeAPI configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, selection.Id, new(extraApps.ToDictionary(extraApp => extraApp.Key, extraApp => extraApp.Value), PlatformIdComparer.String),
WriteConfig(writer, selection.Id,
new(extraApps.ToDictionary(extraApp => extraApp.Key, extraApp => extraApp.Value),
PlatformIdComparer.String),
new(overrideDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(injectDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
@ -64,12 +76,15 @@ internal static class SmokeAPI
else if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
}
private static void WriteConfig(StreamWriter writer, string appId, SortedList<string, (string name, SortedList<string, SelectionDLC> injectDlc)> extraApps,
SortedList<string, SelectionDLC> overrideDlc, SortedList<string, SelectionDLC> injectDlc, InstallForm installForm = null)
private static void WriteConfig(StreamWriter writer, string appId,
SortedList<string, (string name, SortedList<string, SelectionDLC> injectDlc)> extraApps,
SortedList<string, SelectionDLC> overrideDlc, SortedList<string, SelectionDLC> injectDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"$version\": 2,");
@ -85,13 +100,17 @@ internal static class SmokeAPI
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\": \"locked\"{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added locked DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
installForm?.UpdateUser(
$"Added locked DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" },");
}
else
writer.WriteLine(" \"override_dlc_status\": {},");
writer.WriteLine(" \"auto_inject_inventory\": true,");
writer.WriteLine(" \"extra_inventory_items\": [],");
if (injectDlc.Count > 0 || extraApps.Count > 0)
@ -105,17 +124,24 @@ internal static class SmokeAPI
foreach (KeyValuePair<string, SelectionDLC> pair in injectDlc)
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\": \"{selectionDlc.Name}\"{(pair.Equals(lastInjectDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added extra DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
writer.WriteLine(
$" \"{selectionDlc.Id}\": \"{selectionDlc.Name}\"{(pair.Equals(lastInjectDlc) ? "" : ",")}");
installForm?.UpdateUser(
$"Added extra DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" }");
writer.WriteLine(extraApps.Count > 0 ? " }," : " }");
}
if (extraApps.Count > 0)
{
KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)> lastExtraApp = extraApps.Last();
foreach (KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)> pair in extraApps)
KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)> lastExtraApp =
extraApps.Last();
foreach (KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)> pair in
extraApps)
{
string extraAppId = pair.Key;
(string _ /*extraAppName*/, SortedList<string, SelectionDLC> extraInjectDlc) = pair.Value;
@ -126,18 +152,23 @@ internal static class SmokeAPI
foreach (KeyValuePair<string, SelectionDLC> extraPair in extraInjectDlc)
{
SelectionDLC selectionDlc = extraPair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\": \"{selectionDlc.Name}\"{(extraPair.Equals(lastExtraAppDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added extra DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})",
writer.WriteLine(
$" \"{selectionDlc.Id}\": \"{selectionDlc.Name}\"{(extraPair.Equals(lastExtraAppDlc) ? "" : ",")}");
installForm?.UpdateUser(
$"Added extra DLC to SmokeAPI.config.json with appid {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action, false);
}
writer.WriteLine(" }");
writer.WriteLine(pair.Equals(lastExtraApp) ? " }" : " },");
}
}
writer.WriteLine(" },");
}
else
writer.WriteLine(" \"extra_dlcs\": {},");
writer.WriteLine(" \"store_config\": null");
writer.WriteLine("}");
}
@ -149,9 +180,12 @@ internal static class SmokeAPI
if (oldConfig.FileExists())
{
oldConfig.DeleteFile();
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 old_config,
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out string old_config,
out string config, out string old_log, out string log, out string cache);
if (api32_o.FileExists())
{
@ -160,9 +194,13 @@ internal static class SmokeAPI
api32.DeleteFile(true);
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
api32_o.MoveFile(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 (api64_o.FileExists())
{
if (api64.FileExists())
@ -170,31 +208,40 @@ internal static class SmokeAPI
api64.DeleteFile(true);
installForm?.UpdateUser($"Deleted SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
api64_o.MoveFile(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 (!deleteOthers)
return;
if (old_config.FileExists())
{
old_config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(old_config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(old_config)}", LogTextBox.Action,
false);
}
if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
if (cache.FileExists())
{
cache.DeleteFile();
installForm?.UpdateUser($"Deleted cache: {Path.GetFileName(cache)}", LogTextBox.Action, false);
}
if (old_log.FileExists())
{
old_log.DeleteFile();
installForm?.UpdateUser($"Deleted log: {Path.GetFileName(old_log)}", LogTextBox.Action, false);
}
if (log.FileExists())
{
log.DeleteFile();
@ -202,36 +249,46 @@ internal static class SmokeAPI
}
});
internal static async Task Install(string directory, Selection selection, InstallForm installForm = null, bool generateConfig = true)
internal static async Task Install(string directory, Selection selection, InstallForm installForm = null,
bool generateConfig = true)
=> await Task.Run(() =>
{
directory.GetCreamApiComponents(out _, out _, out _, out _, out string oldConfig);
if (oldConfig.FileExists())
{
oldConfig.DeleteFile();
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 _, out _, out _, out _, out _);
directory.GetSmokeApiComponents(out string api32, out string api32_o, out string api64, out string api64_o,
out _, out _, out _, out _, out _);
if (api32.FileExists() && !api32_o.FileExists())
{
api32.MoveFile(api32_o!, true);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (api32_o.FileExists())
{
"SmokeAPI.steam_api.dll".WriteManifestResource(api32);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api32)}", LogTextBox.Action, false);
}
if (api64.FileExists() && !api64_o.FileExists())
{
api64.MoveFile(api64_o!, true);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Steamworks: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (api64_o.FileExists())
{
"SmokeAPI.steam_api64.dll".WriteManifestResource(api64);
installForm?.UpdateUser($"Wrote SmokeAPI: {Path.GetFileName(api64)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});

View file

@ -11,7 +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,
internal static void GetUplayR1Components(this string directory, out string api32, out string api32_o,
out string api64, out string api64_o,
out string config, out string log)
{
api32 = directory + @"\uplay_r1_loader.dll";
@ -26,7 +27,8 @@ internal static class UplayR1
{
directory.GetUplayR1Components(out _, out _, out _, out _, out string config, out _);
HashSet<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection =>
extraSelection.DLC.Where(dlc => !dlc.Enabled)))
_ = blacklistDlc.Add(extraDlc);
if (blacklistDlc.Count > 0)
{
@ -34,18 +36,21 @@ internal static class UplayR1
installForm.UpdateUser("Generating Uplay R1 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc, InstallForm installForm = null)
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -59,40 +64,53 @@ internal static class UplayR1
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" {selectionDlc.Id}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
installForm?.UpdateUser(
$"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" ],");
}
else
writer.WriteLine(" \"blacklist\": [],");
writer.WriteLine("}");
}
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteOthers = true)
=> await Task.Run(() =>
{
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o, out string config, out string log);
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o,
out string config, out string log);
if (api32_o.FileExists())
{
if (api32.FileExists())
{
api32.DeleteFile(true);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action,
false);
}
api32_o.MoveFile(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 (api64_o.FileExists())
{
if (api64.FileExists())
{
api64.DeleteFile(true);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action,
false);
}
api64_o.MoveFile(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 (!deleteOthers)
return;
if (config.FileExists())
@ -100,36 +118,47 @@ internal static class UplayR1
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
if (!log.FileExists())
return;
log.DeleteFile();
installForm?.UpdateUser($"Deleted log: {Path.GetFileName(log)}", LogTextBox.Action, false);
});
internal static async Task Install(string directory, Selection selection, InstallForm installForm = null, bool generateConfig = true)
internal static async Task Install(string directory, Selection 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 _, out _);
directory.GetUplayR1Components(out string api32, out string api32_o, out string api64, out string api64_o,
out _, out _);
if (api32.FileExists() && !api32_o.FileExists())
{
api32.MoveFile(api32_o!, true);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api32)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (api32_o.FileExists())
{
"UplayR1.uplay_r1_loader.dll".WriteManifestResource(api32);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api32)}", LogTextBox.Action,
false);
}
if (api64.FileExists() && !api64_o.FileExists())
{
api64.MoveFile(api64_o!, true);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Uplay R1: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (api64_o.FileExists())
{
"UplayR1.uplay_r1_loader64.dll".WriteManifestResource(api64);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Wrote Uplay R1 Unlocker: {Path.GetFileName(api64)}", LogTextBox.Action,
false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});

View file

@ -11,7 +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,
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, out string log)
{
old_api32 = directory + @"\uplay_r2_loader.dll";
@ -28,7 +29,8 @@ internal static class UplayR2
{
directory.GetUplayR2Components(out _, out _, out _, out _, out _, out _, out string config, out _);
HashSet<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection =>
extraSelection.DLC.Where(dlc => !dlc.Enabled)))
_ = blacklistDlc.Add(extraDlc);
if (blacklistDlc.Count > 0)
{
@ -36,18 +38,21 @@ internal static class UplayR2
installForm.UpdateUser("Generating Uplay R2 Unlocker configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
config.CreateFile(true, installForm)?.Close();
StreamWriter writer = new(config, true, Encoding.UTF8);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
installForm);
writer.Flush();
writer.Close();
}
else if (config.FileExists())
{
config.DeleteFile();
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted unnecessary configuration: {Path.GetFileName(config)}", LogTextBox.Action,
false);
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc, InstallForm installForm = null)
private static void WriteConfig(StreamWriter writer, SortedList<string, SelectionDLC> blacklistDlc,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -63,20 +68,25 @@ internal static class UplayR2
{
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" {selectionDlc.Id}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
installForm?.UpdateUser(
$"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {selectionDlc.Id} ({selectionDlc.Name})",
LogTextBox.Action,
false);
}
writer.WriteLine(" ],");
}
else
writer.WriteLine(" \"blacklist\": [],");
writer.WriteLine("}");
}
internal static async Task Uninstall(string directory, InstallForm installForm = null, bool deleteOthers = true)
=> await Task.Run(() =>
{
directory.GetUplayR2Components(out string old_api32, out string old_api64, out string api32, out string api32_o, out string api64,
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, out string log);
if (api32_o.FileExists())
{
@ -84,22 +94,30 @@ internal static class UplayR2
if (api.FileExists())
{
api.DeleteFile(true);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
false);
}
api32_o.MoveFile(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 (api64_o.FileExists())
{
string api = old_api64.FileExists() ? old_api64 : api64;
if (api.FileExists())
{
api.DeleteFile(true);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Deleted Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action,
false);
}
api64_o.MoveFile(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 (!deleteOthers)
return;
if (config.FileExists())
@ -107,39 +125,48 @@ internal static class UplayR2
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
if (!log.FileExists())
return;
log.DeleteFile();
installForm?.UpdateUser($"Deleted log: {Path.GetFileName(log)}", LogTextBox.Action, false);
});
internal static async Task Install(string directory, Selection selection, InstallForm installForm = null, bool generateConfig = true)
internal static async Task Install(string directory, Selection 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,
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 _, out _);
string api = old_api32.FileExists() ? old_api32 : api32;
if (api.FileExists() && !api32_o.FileExists())
{
api.MoveFile(api32_o!, true);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api32_o)}",
LogTextBox.Action, false);
}
if (api32_o.FileExists())
{
"UplayR2.upc_r2_loader.dll".WriteManifestResource(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
api = old_api64.FileExists() ? old_api64 : api64;
if (api.FileExists() && !api64_o.FileExists())
{
api.MoveFile(api64_o!, true);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}", LogTextBox.Action, false);
installForm?.UpdateUser($"Renamed Uplay R2: {Path.GetFileName(api)} -> {Path.GetFileName(api64_o)}",
LogTextBox.Action, false);
}
if (api64_o.FileExists())
{
"UplayR2.upc_r2_loader64.dll".WriteManifestResource(api);
installForm?.UpdateUser($"Wrote Uplay R2 Unlocker: {Path.GetFileName(api)}", LogTextBox.Action, false);
}
if (generateConfig)
CheckConfig(directory, selection, installForm);
});

View file

@ -11,8 +11,11 @@ namespace CreamInstaller;
public enum Platform
{
None = 0, Paradox, Steam,
Epic, Ubisoft
None = 0,
Paradox,
Steam,
Epic,
Ubisoft
}
internal sealed class Selection : IEquatable<Selection>
@ -57,15 +60,23 @@ internal sealed class Selection : IEquatable<Selection>
internal static IEnumerable<Selection> AllEnabled => All.Keys.Where(s => s.Enabled);
internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
internal bool Enabled
{
get => TreeNode.Checked;
set => TreeNode.Checked = value;
}
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.All.Keys.Where(dlc => Equals(dlc.Selection, this));
public bool Equals(Selection other) => other is not null && (ReferenceEquals(this, other) || Id == other.Id && Platform == other.Platform);
public bool Equals(Selection other) => other is not null &&
(ReferenceEquals(this, other) ||
Id == other.Id && Platform == other.Platform);
internal static Selection GetOrCreate(Platform platform, string id, string name, string rootDirectory, HashSet<string> dllDirectories,
internal static Selection GetOrCreate(Platform platform, string id, string name, string rootDirectory,
HashSet<string> dllDirectories,
List<(string directory, BinaryType binaryType)> executableDirectories)
=> FromId(platform, id) ?? new Selection(platform, id, name, rootDirectory, dllDirectories, executableDirectories);
=> FromId(platform, id) ??
new Selection(platform, id, name, rootDirectory, dllDirectories, executableDirectories);
internal void Remove()
{
@ -82,16 +93,19 @@ internal sealed class Selection : IEquatable<Selection>
Remove();
return;
}
if (Program.IsGameBlocked(Name, RootDirectory))
{
Remove();
return;
}
if (!RootDirectory.DirectoryExists())
{
Remove();
return;
}
_ = DllDirectories.RemoveWhere(directory => !directory.DirectoryExists());
if (DllDirectories.Count < 1)
Remove();
@ -103,7 +117,8 @@ internal sealed class Selection : IEquatable<Selection>
selection.Validate(programsToScan);
}
internal static Selection FromId(Platform platform, string gameId) => All.Keys.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
internal static Selection FromId(Platform platform, string gameId) =>
All.Keys.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is Selection other && Equals(other);

View file

@ -7,8 +7,11 @@ namespace CreamInstaller;
public enum DLCType
{
None = 0, Steam, SteamHidden,
Epic, EpicEntitlement
None = 0,
Steam,
SteamHidden,
Epic,
EpicEntitlement
}
internal sealed class SelectionDLC : IEquatable<SelectionDLC>
@ -32,7 +35,11 @@ internal sealed class SelectionDLC : IEquatable<SelectionDLC>
TreeNode = new() { Tag = Type, Name = Id, Text = Name };
}
internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
internal bool Enabled
{
get => TreeNode.Checked;
set => TreeNode.Checked = value;
}
internal Selection Selection
{
@ -57,7 +64,8 @@ internal sealed class SelectionDLC : IEquatable<SelectionDLC>
}
public bool Equals(SelectionDLC other)
=> other is not null && (ReferenceEquals(this, other) || Type == other.Type && Selection?.Id == other.Selection?.Id && Id == other.Id);
=> other is not null && (ReferenceEquals(this, other) ||
Type == other.Type && Selection?.Id == other.Selection?.Id && Id == other.Id);
internal static SelectionDLC GetOrCreate(DLCType type, string gameId, string id, string name)
=> FromId(type, gameId, id) ?? new SelectionDLC(type, id, name);

View file

@ -34,13 +34,17 @@ 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 ResolvePath(this string path)
{

View file

@ -30,20 +30,27 @@ 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++;
}
return output.ToString();
}
internal static bool HandleException(this Exception e, Form form = null, string caption = null, string acceptButtonText = "Retry",
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";
@ -51,12 +58,14 @@ internal static class ExceptionHandler
if (string.IsNullOrWhiteSpace(outputString))
outputString = e?.ToString() ?? "Unknown exception";
using DialogForm dialogForm = new(form ?? Form.ActiveForm);
return dialogForm.Show(SystemIcons.Error, outputString, acceptButtonText, cancelButtonText, caption) is DialogResult.OK;
return dialogForm.Show(SystemIcons.Error, outputString, acceptButtonText, cancelButtonText, caption) is
DialogResult.OK;
}
internal static void HandleFatalException(this Exception e)
{
e.HandleException(caption: Program.Name + " encountered a fatal exception", acceptButtonText: "OK", cancelButtonText: null);
e.HandleException(caption: Program.Name + " encountered a fatal exception", acceptButtonText: "OK",
cancelButtonText: null);
Application.Exit();
}
}

View file

@ -29,8 +29,10 @@ internal static class HttpClientManager
try
{
using HttpRequestMessage request = new(HttpMethod.Get, url);
using HttpResponseMessage response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (response.StatusCode is HttpStatusCode.NotModified && HttpContentCache.TryGetValue(url, out string content))
using HttpResponseMessage response =
await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (response.StatusCode is HttpStatusCode.NotModified &&
HttpContentCache.TryGetValue(url, out string content))
return content;
_ = response.EnsureSuccessStatusCode();
content = await response.Content.ReadAsStringAsync();

View file

@ -5,7 +5,8 @@ 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/";
private const string GoogleFaviconsApiUrl = "https://www.google.com/s2/favicons";
@ -15,13 +16,16 @@ internal static class IconGrabber
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) => path.FileExists() ? Icon.ExtractAssociatedIcon(path)?.ToBitmap() : null;
internal static Image GetFileIconImage(this string path) =>
path.FileExists() ? 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

@ -15,8 +15,10 @@ internal static partial class NativeImports
[LibraryImport("kernel32.dll", SetLastError = true), DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool GetBinaryType([MarshalAs(UnmanagedType.LPStr)] string lpApplicationName, out BinaryType lpBinaryType);
internal static partial bool GetBinaryType([MarshalAs(UnmanagedType.LPStr)] string lpApplicationName,
out BinaryType lpBinaryType);
[LibraryImport("user32.dll", SetLastError = true), DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static partial void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
internal static partial void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy,
uint uFlags);
}

View file

@ -10,8 +10,11 @@ namespace CreamInstaller.Utility;
internal static class ProgramData
{
private static readonly string DirectoryPathOld = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CreamInstaller";
internal static readonly string DirectoryPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
private static readonly string DirectoryPathOld =
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\CreamInstaller";
internal static readonly string DirectoryPath =
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\CreamInstaller";
internal static readonly string AppInfoPath = DirectoryPath + @"\appinfo";
private static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
@ -33,13 +36,17 @@ internal static class ProgramData
DirectoryPath.DeleteDirectory();
DirectoryPathOld.MoveDirectory(DirectoryPath, true, form);
}
DirectoryPath.CreateDirectory();
if (!AppInfoVersionPath.FileExists() || !Version.TryParse(AppInfoVersionPath.ReadFile(), out Version version) || version < MinimumAppInfoVersion)
if (!AppInfoVersionPath.FileExists() ||
!Version.TryParse(AppInfoVersionPath.ReadFile(), out Version version) ||
version < MinimumAppInfoVersion)
{
AppInfoPath.DeleteDirectory();
AppInfoPath.CreateDirectory();
AppInfoVersionPath.WriteFile(Program.Version);
}
CooldownPath.CreateDirectory();
if (OldProgramChoicesPath.FileExists())
OldProgramChoicesPath.DeleteFile();
@ -71,6 +78,7 @@ internal static class ProgramData
{
// ignored
}
return null;
}
@ -93,7 +101,8 @@ internal static class ProgramData
if (ProgramChoicesPath.FileExists())
try
{
if (JsonConvert.DeserializeObject(ProgramChoicesPath.ReadFile(), typeof(List<(Platform platform, string id)>)) is
if (JsonConvert.DeserializeObject(ProgramChoicesPath.ReadFile(),
typeof(List<(Platform platform, string id)>)) is
List<(Platform platform, string id)> choices)
return choices;
}
@ -101,6 +110,7 @@ internal static class ProgramData
{
// ignored
}
return Enumerable.Empty<(Platform platform, string id)>();
}
@ -124,7 +134,8 @@ internal static class ProgramData
if (DlcChoicesPath.FileExists())
try
{
if (JsonConvert.DeserializeObject(DlcChoicesPath.ReadFile(), typeof(IEnumerable<(Platform platform, string gameId, string dlcId)>)) is
if (JsonConvert.DeserializeObject(DlcChoicesPath.ReadFile(),
typeof(IEnumerable<(Platform platform, string gameId, string dlcId)>)) is
IEnumerable<(Platform platform, string gameId, string dlcId)> choices)
return choices;
}
@ -132,6 +143,7 @@ internal static class ProgramData
{
// ignored
}
return Enumerable.Empty<(Platform platform, string gameId, string dlcId)>();
}
@ -164,10 +176,12 @@ internal static class ProgramData
{
// ignored
}
return Enumerable.Empty<(Platform platform, string id, string proxy, bool enabled)>();
}
internal static void WriteKoaloaderProxyChoices(IEnumerable<(Platform platform, string id, string proxy, bool enabled)> choices)
internal static void WriteKoaloaderProxyChoices(
IEnumerable<(Platform platform, string id, string proxy, bool enabled)> choices)
{
try
{

View file

@ -26,12 +26,14 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || directoryPath.DirectoryExists() || directoryPath.IOWarn("Failed to create a crucial directory", e, form) is not DialogResult.OK)
if (!crucial || directoryPath.DirectoryExists() ||
directoryPath.IOWarn("Failed to create a crucial directory", e, form) is not DialogResult.OK)
break;
}
}
internal static void MoveDirectory(this string directoryPath, string newDirectoryPath, bool crucial = false, Form form = null)
internal static void MoveDirectory(this string directoryPath, string newDirectoryPath, bool crucial = false,
Form form = null)
{
if (!directoryPath.DirectoryExists())
return;
@ -43,7 +45,8 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !directoryPath.DirectoryExists() || directoryPath.IOWarn("Failed to move a crucial directory", e, form) is not DialogResult.OK)
if (!crucial || !directoryPath.DirectoryExists() ||
directoryPath.IOWarn("Failed to move a crucial directory", e, form) is not DialogResult.OK)
break;
}
}
@ -61,12 +64,14 @@ internal static class SafeIO
catch (Exception e)
{
if (!crucial || !directoryPath.DirectoryExists()
|| directoryPath.IOWarn("Failed to delete a crucial directory", e, form) is not DialogResult.OK)
|| directoryPath.IOWarn("Failed to delete a crucial directory", e, form) is not
DialogResult.OK)
break;
}
}
internal static IEnumerable<string> EnumerateDirectory(this string directoryPath, string filePattern, bool subdirectories = false, bool crucial = false,
internal static IEnumerable<string> EnumerateDirectory(this string directoryPath, string filePattern,
bool subdirectories = false, bool crucial = false,
Form form = null)
{
if (!directoryPath.DirectoryExists())
@ -75,19 +80,23 @@ internal static class SafeIO
try
{
return subdirectories
? Directory.EnumerateFiles(directoryPath, filePattern, new EnumerationOptions { RecurseSubdirectories = true })
? Directory.EnumerateFiles(directoryPath, filePattern,
new EnumerationOptions { RecurseSubdirectories = true })
: Directory.EnumerateFiles(directoryPath, filePattern);
}
catch (Exception e)
{
if (!crucial || !directoryPath.DirectoryExists()
|| directoryPath.IOWarn("Failed to enumerate a crucial directory's files", e, form) is not DialogResult.OK)
|| directoryPath.IOWarn("Failed to enumerate a crucial directory's files", e, form) is not
DialogResult.OK)
break;
}
return Enumerable.Empty<string>();
}
internal static IEnumerable<string> EnumerateSubdirectories(this string directoryPath, string directoryPattern, bool subdirectories = false,
internal static IEnumerable<string> EnumerateSubdirectories(this string directoryPath, string directoryPattern,
bool subdirectories = false,
bool crucial = false, Form form = null)
{
if (!directoryPath.DirectoryExists())
@ -96,15 +105,18 @@ internal static class SafeIO
try
{
return subdirectories
? Directory.EnumerateDirectories(directoryPath, directoryPattern, new EnumerationOptions { RecurseSubdirectories = true })
? Directory.EnumerateDirectories(directoryPath, directoryPattern,
new EnumerationOptions { RecurseSubdirectories = true })
: Directory.EnumerateDirectories(directoryPath, directoryPattern);
}
catch (Exception e)
{
if (!crucial || !directoryPath.DirectoryExists()
|| directoryPath.IOWarn("Failed to enumerate a crucial directory's subdirectories", e, form) is not DialogResult.OK)
|| directoryPath.IOWarn("Failed to enumerate a crucial directory's subdirectories", e,
form) is not DialogResult.OK)
break;
}
return Enumerable.Empty<string>();
}
@ -122,6 +134,7 @@ internal static class SafeIO
if (!crucial || filePath.IOWarn("Failed to create a crucial file", e, form) is not DialogResult.OK)
break;
}
return null;
}
@ -137,7 +150,8 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !filePath.FileExists() || filePath.IOWarn("Failed to move a crucial file", e, form) is not DialogResult.OK)
if (!crucial || !filePath.FileExists() ||
filePath.IOWarn("Failed to move a crucial file", e, form) is not DialogResult.OK)
break;
}
}
@ -154,7 +168,8 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !filePath.FileExists() || filePath.IOWarn("Failed to delete a crucial file", e, form) is not DialogResult.OK)
if (!crucial || !filePath.FileExists() ||
filePath.IOWarn("Failed to delete a crucial file", e, form) is not DialogResult.OK)
break;
}
}
@ -170,9 +185,11 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !filePath.FileExists() || filePath.IOWarn("Failed to read a crucial file", e, form) is not DialogResult.OK)
if (!crucial || !filePath.FileExists() ||
filePath.IOWarn("Failed to read a crucial file", e, form) is not DialogResult.OK)
break;
}
return null;
}
@ -187,9 +204,11 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !filePath.FileExists() || filePath.IOWarn("Failed to read a crucial file", e, form) is not DialogResult.OK)
if (!crucial || !filePath.FileExists() ||
filePath.IOWarn("Failed to read a crucial file", e, form) is not DialogResult.OK)
break;
}
return null;
}
@ -208,7 +227,8 @@ internal static class SafeIO
}
}
internal static void ExtractZip(this string archivePath, string destinationPath, bool crucial = false, Form form = null)
internal static void ExtractZip(this string archivePath, string destinationPath, bool crucial = false,
Form form = null)
{
if (!archivePath.FileExists())
return;
@ -220,7 +240,8 @@ internal static class SafeIO
}
catch (Exception e)
{
if (!crucial || !archivePath.FileExists() || archivePath.IOWarn("Failed to extract a crucial zip file", e, form) is not DialogResult.OK)
if (!crucial || !archivePath.FileExists() ||
archivePath.IOWarn("Failed to extract a crucial zip file", e, form) is not DialogResult.OK)
break;
}
}
@ -255,6 +276,7 @@ internal static class SafeIO
description += e.FormatException();
break;
}
DialogResult result = dialogForm.Show(SystemIcons.Warning, description, "Retry", "Cancel");
if (result is not DialogResult.OK)
Program.Canceled = true;