reformatting
This commit is contained in:
parent
3a2d2f9e01
commit
4927a079c7
35 changed files with 1138 additions and 455 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 & Configuration Generator</Product>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ internal static class ValveDataFile
|
|||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -30,6 +31,7 @@ internal static class ValveDataFile
|
|||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue