start of v4.9.0

- Large refactoring & optimization
- Fixed & optimized right-click context menu
- Fixed silent HTTP cache concurrency exception
- Added a better SafeIO exception output for anti-virus detections
- Updated the help button dialog
This commit is contained in:
pointfeev 2023-05-27 17:50:03 -04:00
parent 324b0606e5
commit 9318fd7768
23 changed files with 484 additions and 489 deletions

View file

@ -51,14 +51,10 @@ internal class CustomForm : Form
_ = helpDialog.Show(SystemIcons.Information,
"Automatically finds all installed Steam, Epic and Ubisoft games with their respective DLC-related DLL locations on the user's computer,\n"
+ "parses SteamCMD, Steam Store and Epic Games Store for user-selected games' DLCs, then provides a very simple graphical interface\n"
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n" + "\n"
+ "utilizing the gathered information for the maintenance of DLC unlockers.\n\n"
+ $"The program utilizes the latest versions of [Koaloader]({acidicoala}/Koaloader), [SmokeAPI]({acidicoala}/SmokeAPI), [ScreamAPI]({acidicoala}/ScreamAPI), [Uplay R1 Unlocker]({acidicoala}/UplayR1Unlocker) and [Uplay R2 Unlocker]({acidicoala}/UplayR2Unlocker), all by\n"
+ $"the wonderful [acidicoala]({acidicoala}), and all downloaded and embedded into the program itself; no further downloads necessary on your part!\n"
+ "\n" + "NOTE: This program does not automatically download nor install actual DLC files for you. As the title of the program says, it's\n"
+ "only a DLC Unlocker installer. Should the game you wish to unlock DLC for not already come with the DLCs installed (very many\n"
+ "do not), you have to find, download, and install those yourself. Preferably, you should be referring to the proper cs.rin.ru post for\n"
+ "the game(s) you're tinkering with; you'll usually find any answer to your problems there.\n" + "\n" + "USAGE:\n"
+ " 1. Choose which programs and/or games the program should scan for DLC.\n"
+ $"the 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"
@ -69,10 +65,17 @@ internal class CustomForm : Form
+ " If the default \'version.dll\' doesn't work, then see [here](https://cs.rin.ru/forum/viewtopic.php?p=2552172#p2552172) to find one that does.\n"
+ " 6. Click the \"Generate and Install\" button.\n" + " 7. Click the \"OK\" button to close the program.\n"
+ " 8. If any of the DLC unlockers cause problems with any of the games you installed them on, simply go back\n"
+ " to step 5 and select what games you wish you revert changes to, and instead click the \"Uninstall\" button this time.\n" + "\n"
+ $"For reliable and quick assistance, all bugs, crashes and other issues should be referred to the [GitHub Issues]({repository}/issues) page!\n"
+ "\n" + "SteamCMD installation and appinfo cache can be found at [C:\\ProgramData\\CreamInstaller]().\n"
+ $"The program automatically and very quickly updates from [GitHub]({repository}) using [Onova](https://github.com/Tyrrrz/Onova). (updates can be ignored)\n"
+ " 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 template issue corresponding to your problem should one exist! Also, note that the [GitHub Issues]({repository}/issues) page is not\n"
+ "your personal assistance hotline, rather it is for genuine bugs/crashes/issues with the program itself. If you post an issue which has already\n"
+ "been explained within the template issues and/or within this text, I will just close it.\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}).");
}

View file

@ -24,8 +24,8 @@ internal sealed class CustomTreeView : TreeView
private static readonly Color C7 = ColorTranslator.FromHtml("#006900");
private static readonly Color C8 = ColorTranslator.FromHtml("#69AA69");
private readonly Dictionary<ProgramSelection, Rectangle> checkBoxBounds = new();
private readonly Dictionary<ProgramSelection, Rectangle> comboBoxBounds = new();
private readonly Dictionary<Selection, Rectangle> checkBoxBounds = new();
private readonly Dictionary<Selection, Rectangle> comboBoxBounds = new();
private readonly Dictionary<TreeNode, Rectangle> selectionBounds = new();
private SolidBrush backBrush;
@ -110,7 +110,7 @@ internal sealed class CustomTreeView : TreeView
}
if (form is SelectForm)
{
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, platformId);
Selection selection = Selection.FromPlatformId(platform, platformId);
if (selection is not null)
{
if (bounds == node.Bounds)
@ -145,7 +145,7 @@ internal sealed class CustomTreeView : TreeView
{
comboBoxFont ??= new(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet, font.GdiVerticalFont);
ComboBoxState comboBoxState = Enabled ? ComboBoxState.Normal : ComboBoxState.Disabled;
text = (selection.KoaloaderProxy ?? ProgramSelection.DefaultKoaloaderProxy) + ".dll";
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);
@ -186,9 +186,9 @@ internal sealed class CustomTreeView : TreeView
}
if (e.Button is not MouseButtons.Left)
return;
if (comboBoxBounds.Any() && selectForm is not null)
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in comboBoxBounds)
if (!ProgramSelection.All.Contains(pair.Key))
if (comboBoxBounds.Count > 0 && selectForm is not null)
foreach (KeyValuePair<Selection, Rectangle> pair in comboBoxBounds)
if (!Selection.All.Contains(pair.Key))
_ = comboBoxBounds.Remove(pair.Key);
else if (pair.Value.Contains(clickPoint))
{
@ -214,15 +214,15 @@ internal sealed class CustomTreeView : TreeView
if (canUse)
_ = comboBoxDropDown.Items.Add(new ToolStripButton(proxy + ".dll", null, (_, _) =>
{
pair.Key.KoaloaderProxy = proxy == ProgramSelection.DefaultKoaloaderProxy ? null : proxy;
pair.Key.KoaloaderProxy = proxy == Selection.DefaultKoaloaderProxy ? null : proxy;
selectForm.OnKoaloaderChanged();
}) { Font = comboBoxFont });
}
comboBoxDropDown.Show(this, PointToScreen(new(pair.Value.Left, pair.Value.Bottom - 1)));
break;
}
foreach (KeyValuePair<ProgramSelection, Rectangle> pair in checkBoxBounds)
if (!ProgramSelection.All.Contains(pair.Key))
foreach (KeyValuePair<Selection, Rectangle> pair in checkBoxBounds)
if (!Selection.All.Contains(pair.Key))
_ = checkBoxBounds.Remove(pair.Key);
else if (pair.Value.Contains(clickPoint))
{

View file

@ -4,7 +4,7 @@
<TargetFramework>net7.0-windows</TargetFramework>
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<Version>4.8.1</Version>
<Version>4.9.0</Version>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
<Company>CreamInstaller</Company>
<Product>Automatic DLC Unlocker Installer &amp; Configuration Generator</Product>

View file

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CreamInstaller.Components;
@ -52,14 +51,14 @@ internal sealed partial class DialogForm : CustomForm
}
if (customFormIcon is not null)
Icon = customFormIcon;
if (!links.Any())
if (links.Count < 1)
return ShowDialog();
foreach (LinkLabel.Link link in links)
_ = descriptionLabel.Links.Add(link);
descriptionLabel.LinkClicked += (_, e) =>
descriptionLabel.LinkClicked += (s, e) =>
{
if (e.Link != null)
Process.Start(new ProcessStartInfo((string)e.Link.LinkData) { UseShellExecute = true });
_ = Process.Start(new ProcessStartInfo((string)e.Link.LinkData) { UseShellExecute = true });
};
return ShowDialog();
}

View file

@ -15,9 +15,9 @@ namespace CreamInstaller.Forms;
internal sealed partial class InstallForm : CustomForm
{
private readonly List<ProgramSelection> disabledSelections = new();
private readonly List<Selection> disabledSelections = new();
private readonly int programCount = ProgramSelection.AllEnabled.Count;
private readonly int programCount = Selection.AllEnabled.Count;
private readonly bool uninstalling;
private int completeOperationsCount;
@ -58,7 +58,7 @@ internal sealed partial class InstallForm : CustomForm
});
}
private async Task OperateFor(ProgramSelection selection)
private async Task OperateFor(Selection selection)
{
UpdateProgress(0);
if (selection.Id == "PL")
@ -189,10 +189,10 @@ internal sealed partial class InstallForm : CustomForm
private async Task Operate()
{
List<ProgramSelection> programSelections = ProgramSelection.AllEnabled;
List<Selection> programSelections = Selection.AllEnabled;
operationsCount = programSelections.Count;
completeOperationsCount = 0;
foreach (ProgramSelection selection in programSelections)
foreach (Selection selection in programSelections)
{
if (Program.Canceled || !Program.AreDllsLockedDialog(this, selection))
throw new CustomMessageException("The operation was canceled.");
@ -210,13 +210,13 @@ internal sealed partial class InstallForm : CustomForm
++completeOperationsCount;
}
Program.Cleanup();
List<ProgramSelection> failedSelections = ProgramSelection.AllEnabled;
if (failedSelections.Any())
List<Selection> failedSelections = Selection.AllEnabled;
if (failedSelections.Count > 0)
if (failedSelections.Count == 1)
throw new CustomMessageException($"Operation failed for {failedSelections.First().Name}.");
else
throw new CustomMessageException($"Operation failed for {failedSelections.Count} programs.");
foreach (ProgramSelection selection in disabledSelections)
foreach (Selection selection in disabledSelections)
selection.Enabled = true;
disabledSelections.Clear();
}
@ -281,7 +281,7 @@ internal sealed partial class InstallForm : CustomForm
{
Program.Cleanup();
Reselecting = true;
foreach (ProgramSelection selection in disabledSelections)
foreach (Selection selection in disabledSelections)
selection.Enabled = true;
disabledSelections.Clear();
Close();

View file

@ -16,7 +16,7 @@ internal sealed partial class SelectDialogForm : CustomForm
out List<(Platform platform, string id, string name)> choices)
{
choices = null;
if (!potentialChoices.Any())
if (potentialChoices.Count < 1)
return DialogResult.Cancel;
groupBox.Text = groupBoxText;
allCheckBox.Enabled = false;
@ -28,13 +28,13 @@ internal sealed partial class SelectDialogForm : CustomForm
OnTreeNodeChecked(node);
_ = selectionTreeView.Nodes.Add(node);
}
if (!selected.Any())
if (selected.Count < 1)
OnLoad(null, null);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = selectionTreeView.Nodes.Cast<TreeNode>().All(n => n.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
allCheckBox.Enabled = true;
acceptButton.Enabled = selected.Any();
acceptButton.Enabled = selected.Count > 0;
saveButton.Enabled = acceptButton.Enabled;
loadButton.Enabled = ProgramData.ReadProgramChoices() is not null;
OnResize(null, null);
@ -46,7 +46,7 @@ internal sealed partial class SelectDialogForm : CustomForm
private void OnTreeNodeChecked(object sender, TreeViewEventArgs e)
{
OnTreeNodeChecked(e.Node);
acceptButton.Enabled = selected.Any();
acceptButton.Enabled = selected.Count > 0;
saveButton.Enabled = acceptButton.Enabled;
}
@ -85,7 +85,7 @@ internal sealed partial class SelectDialogForm : CustomForm
private void OnLoad(object sender, EventArgs e)
{
List<(Platform platform, string id)> choices = ProgramData.ReadProgramChoices().ToList();
if (!choices.Any())
if (choices.Count < 1)
return;
foreach (TreeNode node in selectionTreeView.Nodes)
{

View file

@ -23,9 +23,9 @@ internal sealed partial class SelectForm : CustomForm
{
private const string HelpButtonListPrefix = "\n • ";
private readonly SynchronizedCollection<string> remainingDLCs = new();
private readonly ConcurrentDictionary<string, string> remainingDLCs = new();
private readonly SynchronizedCollection<string> remainingGames = new();
private readonly ConcurrentDictionary<string, string> remainingGames = new();
private List<(Platform platform, string id, string name)> programsToScan;
@ -39,8 +39,8 @@ internal sealed partial class SelectForm : CustomForm
private List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
private static void UpdateRemaining(Label label, SynchronizedCollection<string> list, string descriptor)
=> label.Text = list.Any() ? $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list).Replace("&", "&&") : "";
private static void UpdateRemaining(Label label, ConcurrentDictionary<string, string> list, string descriptor)
=> label.Text = list.IsEmpty ? "" : $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
private void UpdateRemainingGames() => UpdateRemaining(progressLabelGames, remainingGames, "games");
@ -52,8 +52,7 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
if (!remainingGames.Contains(gameName))
remainingGames.Add(gameName);
remainingGames[gameName] = gameName;
UpdateRemainingGames();
});
}
@ -66,7 +65,7 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
remainingGames.Remove(gameName);
_ = remainingGames.Remove(gameName, out _);
UpdateRemainingGames();
});
}
@ -81,8 +80,7 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
if (!remainingDLCs.Contains(dlcId))
remainingDLCs.Add(dlcId);
remainingDLCs[dlcId] = dlcId;
UpdateRemainingDLCs();
});
}
@ -95,14 +93,14 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
remainingDLCs.Remove(dlcId);
_ = remainingDLCs.Remove(dlcId, out _);
UpdateRemainingDLCs();
});
}
private async Task GetApplicablePrograms(IProgress<int> progress, bool uninstallAll = false)
{
if (!uninstallAll && (programsToScan is null || !programsToScan.Any()))
if (!uninstallAll && (programsToScan is null || programsToScan.Count < 1))
return;
int totalGameCount = 0;
int completeGameCount = 0;
@ -126,12 +124,12 @@ internal sealed partial class SelectForm : CustomForm
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Paradox))
{
AddToRemainingGames("Paradox Launcher");
List<string> dllDirectories = await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
HashSet<string> dllDirectories = await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
if (dllDirectories is not null)
{
if (uninstallAll)
{
ProgramSelection bareSelection = ProgramSelection.FromPlatformId(Platform.Paradox, "PL") ?? new();
Selection bareSelection = Selection.FromPlatformId(Platform.Paradox, "PL") ?? new();
bareSelection.Enabled = true;
bareSelection.Id = "PL";
bareSelection.Name = "Paradox Launcher";
@ -142,7 +140,7 @@ internal sealed partial class SelectForm : CustomForm
}
else
{
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Paradox, "PL") ?? new();
Selection selection = Selection.FromPlatformId(Platform.Paradox, "PL") ?? new();
if (allCheckBox.Checked)
selection.Enabled = true;
if (koaloaderAllCheckBox.Checked)
@ -167,7 +165,7 @@ internal sealed partial class SelectForm : CustomForm
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();
HashSet<(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)
{
@ -175,7 +173,7 @@ internal sealed partial class SelectForm : CustomForm
return;
if (!uninstallAll && (Program.IsGameBlocked(name, gameDirectory) || !programsToScan.Any(c => c.platform is Platform.Steam && c.id == appId)))
{
Interlocked.Decrement(ref steamGamesToCheck);
_ = Interlocked.Decrement(ref steamGamesToCheck);
continue;
}
AddToRemainingGames(name);
@ -183,16 +181,16 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
HashSet<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Steam);
if (dllDirectories is null)
{
Interlocked.Decrement(ref steamGamesToCheck);
_ = Interlocked.Decrement(ref steamGamesToCheck);
RemoveFromRemainingGames(name);
return;
}
if (uninstallAll)
{
ProgramSelection bareSelection = ProgramSelection.FromPlatformId(Platform.Steam, appId) ?? new ProgramSelection();
Selection bareSelection = Selection.FromPlatformId(Platform.Steam, appId) ?? new Selection();
bareSelection.Enabled = true;
bareSelection.Id = appId;
bareSelection.Name = name;
@ -206,7 +204,7 @@ internal sealed partial class SelectForm : CustomForm
if (Program.Canceled)
return;
AppData appData = await SteamStore.QueryStoreAPI(appId);
Interlocked.Decrement(ref steamGamesToCheck);
_ = Interlocked.Decrement(ref steamGamesToCheck);
VProperty appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
if (appData is null && appInfo is null)
{
@ -215,7 +213,7 @@ internal sealed partial class SelectForm : CustomForm
}
if (Program.Canceled)
return;
ConcurrentDictionary<string, (DlcType type, string name, string icon)> dlc = new();
ConcurrentDictionary<string, SelectionDLC> dlc = new();
List<Task> dlcTasks = new();
List<string> dlcIds = new();
if (appData is not null)
@ -292,13 +290,20 @@ internal sealed partial class SelectForm : CustomForm
if (Program.Canceled)
return;
if (!string.IsNullOrWhiteSpace(fullGameName))
dlc[fullGameAppId] = (fullGameOnSteamStore ? DlcType.Steam : DlcType.SteamHidden, fullGameName, fullGameIcon);
dlc[fullGameAppId] = new()
{
Id = fullGameAppId, Type = fullGameOnSteamStore ? DLCType.Steam : DLCType.SteamHidden, Name = fullGameName,
Icon = fullGameIcon
};
}
if (Program.Canceled)
return;
if (string.IsNullOrWhiteSpace(dlcName))
dlcName = "Unknown";
dlc[dlcAppId] = (onSteamStore ? DlcType.Steam : DlcType.SteamHidden, dlcName, dlcIcon);
dlc[dlcAppId] = new()
{
Id = dlcAppId, Type = onSteamStore ? DLCType.Steam : DLCType.SteamHidden, Name = dlcName, Icon = dlcIcon
};
RemoveFromRemainingDLCs(dlcAppId);
});
dlcTasks.Add(task);
@ -317,8 +322,14 @@ internal sealed partial class SelectForm : CustomForm
await task;
}
steamGamesToCheck = 0;
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Steam, appId) ?? new ProgramSelection();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
if (dlc.IsEmpty)
{
RemoveFromRemainingGames(name);
return;
}
Selection selection = Selection.FromPlatformId(Platform.Steam, appId) ?? new Selection();
selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
|| selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
if (koaloaderAllCheckBox.Checked)
selection.Koaloader = true;
selection.Id = appId;
@ -327,12 +338,12 @@ internal sealed partial class SelectForm : CustomForm
selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Steam;
selection.ProductUrl = "https://store.steampowered.com/app/" + appId;
selection.IconUrl = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
selection.SubIconUrl = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
selection.Product = "https://store.steampowered.com/app/" + appId;
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();
selection.WebsiteUrl = appData?.Website;
selection.Website = appData?.Website;
if (Program.Canceled)
return;
selectionTreeView.Invoke(delegate
@ -346,18 +357,17 @@ internal sealed partial class SelectForm : CustomForm
programNode.Checked = selection.Enabled;
if (programNode.TreeView is null)
_ = selectionTreeView.Nodes.Add(programNode);
foreach ((string appId, (DlcType type, string name, string icon) dlcApp) in dlc)
foreach ((_, SelectionDLC dlc) in dlc)
{
if (Program.Canceled)
return;
selection.AllDlc[appId] = dlcApp;
if (allCheckBox.Checked && dlcApp.name != "Unknown")
selection.SelectedDlc[appId] = dlcApp;
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new TreeNode();
dlc.Selection = selection;
dlc.Enabled = dlc.Name != "Unknown" && allCheckBox.Checked;
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == dlc.Id) ?? new TreeNode();
dlcNode.Tag = selection.Platform;
dlcNode.Name = appId;
dlcNode.Text = dlcApp.name;
dlcNode.Checked = selection.SelectedDlc.ContainsKey(appId);
dlcNode.Name = dlc.Id;
dlcNode.Text = dlc.Name;
dlcNode.Checked = dlc.Enabled;
if (dlcNode.Parent is null)
_ = programNode.Nodes.Add(dlcNode);
}
@ -371,7 +381,7 @@ internal sealed partial class SelectForm : CustomForm
}
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Epic))
{
List<Manifest> epicGames = await EpicLibrary.GetGames();
HashSet<Manifest> epicGames = await EpicLibrary.GetGames();
foreach (Manifest manifest in epicGames)
{
string @namespace = manifest.CatalogNamespace;
@ -386,7 +396,7 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
List<string> dllDirectories = await directory.GetDllDirectoriesFromGameDirectory(Platform.Epic);
HashSet<string> dllDirectories = await directory.GetDllDirectoriesFromGameDirectory(Platform.Epic);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
@ -394,7 +404,7 @@ internal sealed partial class SelectForm : CustomForm
}
if (uninstallAll)
{
ProgramSelection bareSelection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace) ?? new ProgramSelection();
Selection bareSelection = Selection.FromPlatformId(Platform.Epic, @namespace) ?? new Selection();
bareSelection.Enabled = true;
bareSelection.Id = @namespace;
bareSelection.Name = name;
@ -407,11 +417,13 @@ internal sealed partial class SelectForm : CustomForm
}
if (Program.Canceled)
return;
ConcurrentDictionary<string, (string name, string product, string icon, string developer)> entitlements = new();
ConcurrentDictionary<string, SelectionDLC> catalogItems = new();
// get catalog items
ConcurrentDictionary<string, SelectionDLC> entitlements = new();
List<Task> dlcTasks = new();
List<(string id, string name, string product, string icon, string developer)> entitlementIds
= await EpicStore.QueryEntitlements(@namespace);
if (entitlementIds.Any())
List<(string id, string name, string product, string icon, string developer)>
entitlementIds = await EpicStore.QueryEntitlements(@namespace);
if (entitlementIds.Count > 0)
foreach ((string id, string name, string product, string icon, string developer) in entitlementIds)
{
if (Program.Canceled)
@ -421,16 +433,15 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
entitlements[id] = (name, product, icon, developer);
entitlements[id] = new()
{
Id = id, Name = name, Product = product, Icon = icon,
Publisher = developer
};
RemoveFromRemainingDLCs(id);
});
dlcTasks.Add(task);
}
if ( /*!catalogItems.Any() && */!entitlements.Any())
{
RemoveFromRemainingGames(name);
return;
}
if (Program.Canceled)
return;
foreach (Task task in dlcTasks)
@ -439,8 +450,14 @@ internal sealed partial class SelectForm : CustomForm
return;
await task;
}
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Epic, @namespace) ?? new ProgramSelection();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
if (catalogItems.IsEmpty && entitlements.IsEmpty)
{
RemoveFromRemainingGames(name);
return;
}
Selection selection = Selection.FromPlatformId(Platform.Epic, @namespace) ?? new Selection();
selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
|| selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
if (koaloaderAllCheckBox.Checked)
selection.Koaloader = true;
selection.Id = @namespace;
@ -449,12 +466,13 @@ internal sealed partial class SelectForm : CustomForm
selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Epic;
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements.Where(p
=> p.Value.name == selection.Name))
foreach (KeyValuePair<string, SelectionDLC> dlc in entitlements.Where(dlc => dlc.Value.Name == selection.Name))
{
selection.ProductUrl = "https://www.epicgames.com/store/product/" + pair.Value.product;
selection.IconUrl = pair.Value.icon;
selection.Publisher = pair.Value.developer;
if (Program.Canceled)
return;
selection.Product = "https://www.epicgames.com/store/product/" + dlc.Value.Product;
selection.Icon = dlc.Value.Icon;
selection.Publisher = dlc.Value.Publisher;
}
if (Program.Canceled)
return;
@ -469,35 +487,49 @@ internal sealed partial class SelectForm : CustomForm
programNode.Checked = selection.Enabled;
if (programNode.TreeView is null)
_ = selectionTreeView.Nodes.Add(programNode);
/*TreeNode catalogItemsNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace + "_catalogItems") ?? new();
catalogItemsNode.Tag = selection.Platform;
catalogItemsNode.Name = @namespace + "_catalogItems";
catalogItemsNode.Text = "Catalog Items";
catalogItemsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.CatalogItem);
if (catalogItemsNode.Parent is null)
programNode.Nodes.Add(catalogItemsNode);*/
if (entitlements.Any())
/*TreeNode entitlementsNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace + "_entitlements") ?? new();
entitlementsNode.Tag = selection.Platform;
entitlementsNode.Name = @namespace + "_entitlements";
entitlementsNode.Text = "Entitlements";
entitlementsNode.Checked = selection.SelectedDlc.Any(pair => pair.Value.type == DlcType.Entitlement);
if (entitlementsNode.Parent is null)
programNode.Nodes.Add(entitlementsNode);*/
foreach ((string dlcId, (string name, string product, string icon, string developer) value) in entitlements)
if (!catalogItems.IsEmpty)
/*TreeNode catalogItemsNode = treeNodes.Find(node => node.Tag is Platform.Epic && node.Name == @namespace + "_catalogItems") ?? new();
catalogItemsNode.Name = @namespace + "_catalogItems";
catalogItemsNode.Text = "Catalog Items";
catalogItemsNode.Checked = selection.DLC.Any(dlc => dlc.Type is DLCType.EpicCatalogItem && dlc.Enabled);
if (catalogItemsNode.Parent is null)
_ = programNode.Nodes.Add(catalogItemsNode);*/
foreach ((_, SelectionDLC dlc) in catalogItems)
{
(DlcType type, string name, string icon) dlcApp = (DlcType.EpicEntitlement, value.name, value.icon);
selection.AllDlc[dlcId] = dlcApp;
if (allCheckBox.Checked)
selection.SelectedDlc[dlcId] = dlcApp;
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == dlcId) ?? new TreeNode();
if (Program.Canceled)
return;
dlc.Selection = selection;
dlc.Enabled = allCheckBox.Checked;
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == dlc.Id) ?? new TreeNode();
dlcNode.Tag = selection.Platform;
dlcNode.Name = dlcId;
dlcNode.Text = dlcApp.name;
dlcNode.Checked = selection.SelectedDlc.ContainsKey(dlcId);
dlcNode.Name = dlc.Id;
dlcNode.Text = dlc.Name;
dlcNode.Checked = dlc.Enabled;
if (dlcNode.Parent is null)
_ = programNode.Nodes.Add(dlcNode); //entitlementsNode.Nodes.Add(dlcNode);
_ = programNode.Nodes.Add(dlcNode); //_ = catalogItemsNode.Nodes.Add(dlcNode);
}
if (entitlements.IsEmpty)
return;
/*TreeNode entitlementsNode = treeNodes.Find(node => node.Tag is Platform.Epic && node.Name == @namespace + "_entitlements") ?? new();
entitlementsNode.Name = @namespace + "_entitlements";
entitlementsNode.Text = "Entitlements";
entitlementsNode.Checked = selection.DLC.Any(dlc => dlc.Type is DLCType.EpicEntitlement && dlc.Enabled);
if (entitlementsNode.Parent is null)
_ = programNode.Nodes.Add(entitlementsNode);*/
foreach ((_, SelectionDLC dlc) in entitlements)
{
if (Program.Canceled)
return;
dlc.Selection = selection;
dlc.Enabled = allCheckBox.Checked;
TreeNode dlcNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == dlc.Id) ?? new TreeNode();
dlcNode.Tag = selection.Platform;
dlcNode.Name = dlc.Id;
dlcNode.Text = dlc.Name;
dlcNode.Checked = dlc.Enabled;
if (dlcNode.Parent is null)
_ = programNode.Nodes.Add(dlcNode); //_ = entitlementsNode.Nodes.Add(dlcNode);
}
});
if (Program.Canceled)
return;
@ -508,7 +540,7 @@ internal sealed partial class SelectForm : CustomForm
}
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Ubisoft))
{
List<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
HashSet<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
{
if (Program.Canceled)
@ -520,7 +552,7 @@ internal sealed partial class SelectForm : CustomForm
{
if (Program.Canceled)
return;
List<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
HashSet<string> dllDirectories = await gameDirectory.GetDllDirectoriesFromGameDirectory(Platform.Ubisoft);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
@ -528,7 +560,7 @@ internal sealed partial class SelectForm : CustomForm
}
if (uninstallAll)
{
ProgramSelection bareSelection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId) ?? new ProgramSelection();
Selection bareSelection = Selection.FromPlatformId(Platform.Ubisoft, gameId) ?? new Selection();
bareSelection.Enabled = true;
bareSelection.Id = gameId;
bareSelection.Name = name;
@ -541,8 +573,9 @@ internal sealed partial class SelectForm : CustomForm
}
if (Program.Canceled)
return;
ProgramSelection selection = ProgramSelection.FromPlatformId(Platform.Ubisoft, gameId) ?? new ProgramSelection();
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraSelectedDlc.Any();
Selection selection = Selection.FromPlatformId(Platform.Ubisoft, gameId) ?? new Selection();
selection.Enabled = allCheckBox.Checked || selection.DLC.Any(dlc => dlc.Enabled)
|| selection.ExtraSelections.Any(extraSelection => extraSelection.DLC.Any(dlc => dlc.Enabled));
if (koaloaderAllCheckBox.Checked)
selection.Koaloader = true;
selection.Id = gameId;
@ -551,7 +584,7 @@ internal sealed partial class SelectForm : CustomForm
selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
selection.DllDirectories = dllDirectories;
selection.Platform = Platform.Ubisoft;
selection.IconUrl = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
selection.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
selectionTreeView.Invoke(delegate
{
if (Program.Canceled)
@ -603,7 +636,7 @@ internal sealed partial class SelectForm : CustomForm
ShowProgressBar();
await ProgramData.Setup(this);
bool scan = forceScan;
if (!scan && (programsToScan is null || !programsToScan.Any() || forceProvideChoices))
if (!scan && (programsToScan is null || programsToScan.Count < 1 || forceProvideChoices))
{
List<(Platform platform, string id, string name, bool alreadySelected)> gameChoices = new();
if (ParadoxLauncher.InstallPath.DirectoryExists())
@ -621,7 +654,7 @@ internal sealed partial class SelectForm : CustomForm
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)));
if (gameChoices.Any())
if (gameChoices.Count > 0)
{
using SelectDialogForm form = new(this);
DialogResult selectResult = form.QueryUser("Choose which programs and/or games to scan:", gameChoices,
@ -649,11 +682,11 @@ internal sealed partial class SelectForm : CustomForm
await GetApplicablePrograms(iProgress, true);
if (!Program.Canceled)
OnUninstall(null, null);
ProgramSelection.All.Clear();
Selection.All.Clear();
programsToScan = null;
}
else
scan = selectResult == DialogResult.OK && choices is not null && choices.Any();
scan = selectResult == DialogResult.OK && choices is not null && choices.Count > 0;
const string retry = "\n\nPress the \"Rescan\" button to re-choose.";
if (scan)
{
@ -696,7 +729,7 @@ internal sealed partial class SelectForm : CustomForm
}
setup = false;
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
ProgramSelection.ValidateAll(programsToScan);
Selection.ValidateAll(programsToScan);
TreeNodes.ForEach(node => node.Remove());
await GetApplicablePrograms(iProgress);
await SteamCMD.Cleanup();
@ -704,11 +737,11 @@ internal sealed partial class SelectForm : CustomForm
OnLoadDlc(null, null);
OnLoadKoaloader(null, null);
HideProgressBar();
selectionTreeView.Enabled = ProgramSelection.All.Any();
selectionTreeView.Enabled = Selection.All.Count > 0;
allCheckBox.Enabled = selectionTreeView.Enabled;
koaloaderAllCheckBox.Enabled = selectionTreeView.Enabled;
noneFoundLabel.Visible = !selectionTreeView.Enabled;
installButton.Enabled = ProgramSelection.AllEnabled.Any();
installButton.Enabled = Selection.AllEnabled.Count > 0;
uninstallButton.Enabled = installButton.Enabled;
saveButton.Enabled = CanSaveDlc();
loadButton.Enabled = CanLoadDlc();
@ -735,7 +768,7 @@ internal sealed partial class SelectForm : CustomForm
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = TreeNodes.TrueForAll(node => node.Text == "Unknown" || node.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
installButton.Enabled = ProgramSelection.AllEnabled.Any();
installButton.Enabled = Selection.AllEnabled.Count > 0;
uninstallButton.Enabled = installButton.Enabled;
saveButton.Enabled = CanSaveDlc();
resetButton.Enabled = CanResetDlc();
@ -770,19 +803,15 @@ internal sealed partial class SelectForm : CustomForm
{
string id = node.Name;
Platform platform = (Platform)node.Tag;
(string gameId, (DlcType type, string name, string icon) app)? dlc = ProgramSelection.GetDlcFromPlatformId(platform, id);
if (dlc.HasValue)
Selection selection = Selection.FromPlatformId(platform, id);
if (selection is not null)
{
(string gameId, _) = dlc.Value;
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, gameId);
selection?.ToggleDlc(node.Name, node.Checked);
}
else
{
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, id);
if (selection is not null)
selection.Enabled = node.Checked;
selection.Enabled = node.Checked;
return;
}
SelectionDLC dlc = SelectionDLC.FromPlatformId(platform, id);
if (dlc is not null)
dlc.Enabled = node.Checked;
}
private static List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
@ -830,31 +859,25 @@ internal sealed partial class SelectForm : CustomForm
internal void OnNodeRightClick(TreeNode node, Point location)
=> Invoke(() =>
{
ContextMenuStrip contextMenuStrip = ContextMenuStrip;
while (ContextMenuStrip.Tag is true)
Thread.Sleep(100);
ContextMenuStrip.Tag = true;
ContextMenuStrip contextMenuStrip = new();
ToolStripItemCollection items = contextMenuStrip.Items;
items.Clear();
string id = node.Name;
Platform platform = (Platform)node.Tag;
ProgramSelection selection = ProgramSelection.FromPlatformId(platform, id);
(string gameAppId, (DlcType type, string name, string icon) app)? dlc = null;
Selection selection = Selection.FromPlatformId(platform, id);
SelectionDLC dlc = null;
if (selection is null)
dlc = ProgramSelection.GetDlcFromPlatformId(platform, id);
ProgramSelection dlcParentSelection = null;
dlc = SelectionDLC.FromPlatformId(platform, id);
Selection dlcParentSelection = null;
if (dlc is not null)
dlcParentSelection = ProgramSelection.FromPlatformId(platform, dlc.Value.gameAppId);
dlcParentSelection = Selection.FromPlatformId(platform, dlc.Selection.Id);
if (selection is null && dlcParentSelection is null)
return;
ContextMenuItem header;
if (id == "PL")
header = new(node.Text, "Paradox Launcher");
else if (selection is not null)
header = new(node.Text, (id, selection.IconUrl));
else
header = new(node.Text, (id, dlc.Value.app.icon), (id, dlcParentSelection.IconUrl));
items.Add(header);
ContextMenuItem header = id == "PL"
? new(node.Text, "Paradox Launcher")
: selection is not null
? new(node.Text, (id, selection.Icon))
: new(node.Text, (id, dlc.Icon), (id, dlcParentSelection.Icon));
_ = items.Add(header);
string appInfoVDF = $@"{SteamCMD.AppInfoPath}\{id}.vdf";
string appInfoJSON = $@"{SteamCMD.AppInfoPath}\{id}.json";
string cooldown = $@"{ProgramData.CooldownPath}\{id}.txt";
@ -872,12 +895,12 @@ internal sealed partial class SelectForm : CustomForm
}
if (appInfoVDF.FileExists())
queries.Add(new("Open SteamCMD Query", "Notepad", (_, _) => Diagnostics.OpenFileInNotepad(appInfoVDF)));
if (queries.Any())
if (queries.Count > 0)
{
items.Add(new ToolStripSeparator());
_ = items.Add(new ToolStripSeparator());
foreach (ContextMenuItem query in queries)
items.Add(query);
items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt", (_, _) =>
_ = items.Add(query);
_ = items.Add(new ContextMenuItem("Refresh Queries", "Command Prompt", (_, _) =>
{
appInfoVDF.DeleteFile();
appInfoJSON.DeleteFile();
@ -890,16 +913,16 @@ internal sealed partial class SelectForm : CustomForm
{
if (id == "PL")
{
items.Add(new ToolStripSeparator());
_ = items.Add(new ToolStripSeparator());
async void EventHandler(object sender, EventArgs e) => await ParadoxLauncher.Repair(this, selection);
items.Add(new ContextMenuItem("Repair", "Command Prompt", EventHandler));
_ = items.Add(new ContextMenuItem("Repair", "Command Prompt", EventHandler));
}
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Open Root Directory", "File Explorer",
_ = 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.ToList())
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)));
List<string> directories = selection.DllDirectories.ToList();
int steam = 0, epic = 0, r1 = 0, r2 = 0;
@ -910,7 +933,7 @@ internal sealed partial class SelectForm : CustomForm
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())
items.Add(new ContextMenuItem($"Open Steamworks Directory #{++steam}", "File Explorer",
_ = items.Add(new ContextMenuItem($"Open Steamworks Directory #{++steam}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
if (selection.Platform is Platform.Epic or Platform.Paradox)
@ -919,7 +942,7 @@ internal sealed partial class SelectForm : CustomForm
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())
items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
_ = items.Add(new ContextMenuItem($"Open EOS Directory #{++epic}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
if (selection.Platform is Platform.Ubisoft)
@ -928,13 +951,13 @@ internal sealed partial class SelectForm : CustomForm
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())
items.Add(new ContextMenuItem($"Open Uplay R1 Directory #{++r1}", "File Explorer",
_ = 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,
out log);
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",
_ = items.Add(new ContextMenuItem($"Open Uplay R2 Directory #{++r2}", "File Explorer",
(_, _) => Diagnostics.OpenDirectoryInFileExplorer(directory)));
}
}
@ -942,39 +965,39 @@ internal sealed partial class SelectForm : CustomForm
{
if (selection?.Platform is Platform.Steam || dlcParentSelection?.Platform is Platform.Steam)
{
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Open SteamDB", "SteamDB", (_, _) => Diagnostics.OpenUrlInInternetBrowser("https://steamdb.info/app/" + id)));
_ = items.Add(new ToolStripSeparator());
_ = 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.ProductUrl)));
items.Add(new ContextMenuItem("Open Steam Community", ("Sub_" + id, selection.SubIconUrl), "Steam Community",
_ = 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)));
break;
case Platform.Epic:
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Open ScreamDB", "ScreamDB",
_ = items.Add(new ToolStripSeparator());
_ = items.Add(new ContextMenuItem("Open ScreamDB", "ScreamDB",
(_, _) => Diagnostics.OpenUrlInInternetBrowser("https://scream-db.web.app/offers/" + id)));
items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.ProductUrl)));
_ = items.Add(new ContextMenuItem("Open Epic Games Store", "Epic Games",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.Product)));
break;
case Platform.Ubisoft:
items.Add(new ToolStripSeparator());
items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
_ = items.Add(new ToolStripSeparator());
_ = items.Add(new ContextMenuItem("Open Ubisoft Store", "Ubisoft Store",
(_, _) => Diagnostics.OpenUrlInInternetBrowser(
"https://store.ubi.com/us/" + selection.Name.Replace(" ", "-").ToLowerInvariant())));
break;
}
}
if (selection?.WebsiteUrl != null)
items.Add(new ContextMenuItem("Open Official Website", ("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.WebsiteUrl)),
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.WebsiteUrl)));
if (selection?.Website is not null)
_ = items.Add(new ContextMenuItem("Open Official Website", ("Web_" + id, IconGrabber.GetDomainFaviconUrl(selection.Website)),
(_, _) => Diagnostics.OpenUrlInInternetBrowser(selection.Website)));
contextMenuStrip.Show(selectionTreeView, location);
contextMenuStrip.Refresh();
ContextMenuStrip.Tag = null;
});
private void OnLoad(object sender, EventArgs _)
@ -996,9 +1019,9 @@ internal sealed partial class SelectForm : CustomForm
private void OnAccept(bool uninstall = false)
{
if (!ProgramSelection.All.Any())
if (Selection.All.Count < 1)
return;
if (ProgramSelection.AllEnabled.Any(selection => !Program.AreDllsLockedDialog(this, selection)))
if (Selection.AllEnabled.Any(selection => !Program.AreDllsLockedDialog(this, selection)))
return;
if (!uninstall && ParadoxLauncher.DlcDialog(this))
return;
@ -1053,8 +1076,8 @@ internal sealed partial class SelectForm : CustomForm
private void OnKoaloaderAllCheckBoxChanged(object sender, EventArgs e)
{
bool shouldCheck = ProgramSelection.AllSafe.Any(selection => !selection.Koaloader);
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
bool shouldCheck = Selection.AllSafe.Any(selection => !selection.Koaloader);
foreach (Selection selection in Selection.AllSafe)
selection.Koaloader = shouldCheck;
selectionTreeView.Invalidate();
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
@ -1076,7 +1099,7 @@ internal sealed partial class SelectForm : CustomForm
if (node.Text == "Unknown" ? node.Checked : !node.Checked)
choices.Add((platform, node.Parent.Name, node.Name));
else
choices.RemoveAll(n => n.platform == platform && n.gameId == parent.Name && n.dlcId == node.Name);
_ = choices.RemoveAll(n => n.platform == platform && n.gameId == parent.Name && n.dlcId == node.Name);
}
choices = choices.Distinct().ToList();
ProgramData.WriteDlcChoices(choices);
@ -1111,19 +1134,19 @@ internal sealed partial class SelectForm : CustomForm
resetButton.Enabled = CanResetDlc();
}
private static bool AreKoaloaderSelectionsDefault() => ProgramSelection.AllSafe.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
private static bool AreKoaloaderSelectionsDefault() => Selection.AllSafe.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
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();
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
foreach (Selection selection in Selection.AllSafe)
{
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
if (selection.KoaloaderProxy is not null and not ProgramSelection.DefaultKoaloaderProxy || !selection.Koaloader)
choices.Add((selection.Platform, selection.Id,
selection.KoaloaderProxy == ProgramSelection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy, selection.Koaloader));
if (selection.KoaloaderProxy is not null and not Selection.DefaultKoaloaderProxy || !selection.Koaloader)
choices.Add((selection.Platform, selection.Id, selection.KoaloaderProxy == Selection.DefaultKoaloaderProxy ? null : selection.KoaloaderProxy,
selection.Koaloader));
}
ProgramData.WriteKoaloaderProxyChoices(choices);
saveKoaloaderButton.Enabled = CanSaveKoaloader();
@ -1135,7 +1158,7 @@ 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();
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
foreach (Selection selection in Selection.AllSafe)
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
{
(Platform platform, string id, string proxy, bool enabled)
@ -1146,12 +1169,12 @@ internal sealed partial class SelectForm : CustomForm
proxy.GetProxyInfoFromIdentifier(out currentProxy, out _);
if (proxy != currentProxy && choices.Remove(choice)) // convert pre-v4.1.0.0 choices
choices.Add((platform, id, currentProxy, enabled));
if (currentProxy is null or ProgramSelection.DefaultKoaloaderProxy && enabled)
if (currentProxy is null or Selection.DefaultKoaloaderProxy && enabled)
_ = choices.RemoveAll(c => c.platform == platform && c.id == id);
else
{
selection.Koaloader = enabled;
selection.KoaloaderProxy = currentProxy == ProgramSelection.DefaultKoaloaderProxy ? currentProxy : proxy;
selection.KoaloaderProxy = currentProxy == Selection.DefaultKoaloaderProxy ? currentProxy : proxy;
}
}
else
@ -1168,7 +1191,7 @@ internal sealed partial class SelectForm : CustomForm
private void OnResetKoaloader(object sender, EventArgs e)
{
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
foreach (Selection selection in Selection.AllSafe)
{
selection.Koaloader = true;
selection.KoaloaderProxy = null;
@ -1182,7 +1205,7 @@ internal sealed partial class SelectForm : CustomForm
saveKoaloaderButton.Enabled = CanSaveKoaloader();
resetKoaloaderButton.Enabled = CanResetKoaloader();
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
koaloaderAllCheckBox.Checked = ProgramSelection.AllSafe.TrueForAll(selection => selection.Koaloader);
koaloaderAllCheckBox.Checked = Selection.AllSafe.TrueForAll(selection => selection.Koaloader);
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
}

View file

@ -27,13 +27,13 @@ internal static class EpicLibrary
}
}
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
internal static async Task<List<Manifest>> GetGames()
internal static async Task<HashSet<Manifest>> GetGames()
=> await Task.Run(() =>
{
List<Manifest> games = new();
HashSet<Manifest> games = new();
string manifests = EpicManifestsPath;
if (!manifests.DirectoryExists())
return games;
@ -47,7 +47,7 @@ internal static class EpicLibrary
Manifest manifest = JsonConvert.DeserializeObject<Manifest>(json);
if (manifest is not null && manifest.CatalogItemId == manifest.MainGameCatalogItemId && !games.Any(g
=> g.CatalogItemId == manifest.CatalogItemId && g.InstallLocation == manifest.InstallLocation))
games.Add(manifest);
_ = games.Add(manifest);
}
catch
{

View file

@ -54,7 +54,7 @@ internal static class EpicStore
foreach (Element element in searchStore)
{
string title = element.Title;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any() ? element.CatalogNs.Mappings.First().PageSlug : null;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0 ? element.CatalogNs.Mappings.First().PageSlug : null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{
@ -71,7 +71,7 @@ internal static class EpicStore
foreach (Element element in catalogOffers)
{
string title = element.Title;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Any() ? element.CatalogNs.Mappings.First().PageSlug : null;
string product = element.CatalogNs is not null && element.CatalogNs.Mappings.Length > 0 ? element.CatalogNs.Mappings.First().PageSlug : null;
string icon = null;
for (int i = 0; i < element.KeyImages?.Length; i++)
{

View file

@ -34,49 +34,39 @@ internal static class ParadoxLauncher
}
}
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
private static void PopulateDlc(ProgramSelection paradoxLauncher = null)
private static void PopulateDlc(Selection paradoxLauncher = null)
{
paradoxLauncher ??= ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
if (paradoxLauncher is not null)
{
paradoxLauncher.ExtraDlc.Clear();
paradoxLauncher.ExtraSelectedDlc.Clear();
foreach (ProgramSelection selection in ProgramSelection.AllEnabled.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
{
paradoxLauncher.ExtraDlc.Add(selection.Id, (selection.Name, selection.AllDlc));
paradoxLauncher.ExtraSelectedDlc.Add(selection.Id, (selection.Name, selection.SelectedDlc));
}
if (!paradoxLauncher.ExtraDlc.Any())
foreach (ProgramSelection selection in ProgramSelection.AllSafe.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
{
paradoxLauncher.ExtraDlc.Add(selection.Id, (selection.Name, selection.AllDlc));
paradoxLauncher.ExtraSelectedDlc.Add(selection.Id, (selection.Name, selection.AllDlc));
}
}
paradoxLauncher ??= Selection.FromPlatformId(Platform.Paradox, "PL");
if (paradoxLauncher is null)
return;
paradoxLauncher.ExtraSelections.Clear();
foreach (Selection selection in Selection.AllEnabled.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
if (paradoxLauncher.ExtraSelections.Count > 0)
return;
foreach (Selection selection in Selection.AllSafe.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
_ = paradoxLauncher.ExtraSelections.Add(selection);
}
internal static bool DlcDialog(Form form)
{
ProgramSelection paradoxLauncher = ProgramSelection.FromPlatformId(Platform.Paradox, "PL");
if (paradoxLauncher is not null && paradoxLauncher.Enabled)
{
PopulateDlc(paradoxLauncher);
if (!paradoxLauncher.ExtraDlc.Any())
{
using DialogForm dialogForm = new(form);
return dialogForm.Show(SystemIcons.Warning,
"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!"
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!", "Ignore", "Cancel",
"Paradox Launcher") != DialogResult.OK;
}
}
return false;
Selection paradoxLauncher = Selection.FromPlatformId(Platform.Paradox, "PL");
if (paradoxLauncher is null || !paradoxLauncher.Enabled)
return false;
PopulateDlc(paradoxLauncher);
if (paradoxLauncher.ExtraSelections.Count > 0)
return false;
using DialogForm dialogForm = new(form);
return dialogForm.Show(SystemIcons.Warning,
"WARNING: There are no scanned games with DLC that can be added to the Paradox Launcher!"
+ "\n\nInstalling DLC unlockers for the Paradox Launcher alone can cause existing configurations to be deleted!", "Ignore", "Cancel",
"Paradox Launcher") != DialogResult.OK;
}
internal static async Task<RepairResult> Repair(Form form, ProgramSelection selection)
internal static async Task<RepairResult> Repair(Form form, Selection selection)
{
InstallForm installForm = form as InstallForm;
if (!Program.AreDllsLockedDialog(form, selection))

View file

@ -22,14 +22,14 @@ internal static class SteamLibrary
}
}
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
internal static async Task<HashSet<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
=> await Task.Run(async () =>
{
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
List<string> gameLibraryDirectories = await GetLibraryDirectories();
HashSet<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
HashSet<string> gameLibraryDirectories = await GetLibraryDirectories();
foreach (string libraryDirectory in gameLibraryDirectories)
{
if (Program.Canceled)
@ -37,7 +37,7 @@ internal static class SteamLibrary
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in
(await GetGamesFromLibraryDirectory(libraryDirectory)).Where(game
=> !games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory)))
games.Add(game);
_ = games.Add(game);
}
return games;
});
@ -85,10 +85,10 @@ internal static class SteamLibrary
return games;
});
private static async Task<List<string>> GetLibraryDirectories()
private static async Task<HashSet<string>> GetLibraryDirectories()
=> await Task.Run(() =>
{
List<string> gameDirectories = new();
HashSet<string> gameDirectories = new();
if (Program.Canceled)
return gameDirectories;
string steamInstallPath = InstallPath;
@ -97,7 +97,7 @@ internal static class SteamLibrary
string libraryFolder = steamInstallPath + @"\steamapps";
if (!libraryFolder.DirectoryExists())
return gameDirectories;
gameDirectories.Add(libraryFolder);
_ = gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
if (!libraryFolders.FileExists() || !ValveDataFile.TryDeserialize(libraryFolders.ReadFile(), out VProperty result))
return gameDirectories;
@ -108,8 +108,8 @@ internal static class SteamLibrary
if (string.IsNullOrWhiteSpace(path))
continue;
path += @"\steamapps";
if (path.DirectoryExists() && !gameDirectories.Contains(path))
gameDirectories.Add(path);
if (path.DirectoryExists())
_ = gameDirectories.Add(path);
}
return gameDirectories;
});

View file

@ -12,7 +12,7 @@ internal static class UbisoftLibrary
{
private static RegistryKey installsKey;
internal static RegistryKey InstallsKey
private static RegistryKey InstallsKey
{
get
{
@ -22,13 +22,13 @@ internal static class UbisoftLibrary
}
}
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames()
internal static async Task<HashSet<(string gameId, string name, string gameDirectory)>> GetGames()
=> await Task.Run(() =>
{
List<(string gameId, string name, string gameDirectory)> games = new();
HashSet<(string gameId, string name, string gameDirectory)> games = new();
RegistryKey installsKey = InstallsKey;
if (installsKey is null)
return games;
@ -37,7 +37,7 @@ internal static class UbisoftLibrary
RegistryKey installKey = installsKey.OpenSubKey(gameId);
string installDir = installKey?.GetValue("InstallDir")?.ToString()?.BeautifyPath();
if (installDir is not null && !games.Any(g => g.gameId == gameId && g.gameDirectory == installDir))
games.Add((gameId, new DirectoryInfo(installDir).Name, installDir));
_ = games.Add((gameId, new DirectoryInfo(installDir).Name, installDir));
}
return games;
});

View file

@ -48,7 +48,7 @@ internal static class Program
return ProtectedGameDirectories.Any(path => (directory + path).DirectoryExists());
}
internal static bool AreDllsLockedDialog(Form form, ProgramSelection selection)
internal static bool AreDllsLockedDialog(Form form, Selection selection)
{
while (true)
{

View file

@ -75,7 +75,7 @@ internal static class Koaloader
}
SortedList<string, string> targets = new(PlatformIdComparer.String);
SortedList<string, string> modules = new(PlatformIdComparer.String);
if (targets.Any() || modules.Any())
if (targets.Count > 0 || modules.Count > 0)
{
/*if (installForm is not null)
installForm.UpdateUser("Generating Koaloader configuration for " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);*/
@ -92,13 +92,13 @@ internal static class Koaloader
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, string> targets, SortedList<string, string> modules, InstallForm installForm = null)
private static void WriteConfig(TextWriter writer, SortedList<string, string> targets, SortedList<string, string> modules, InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
writer.WriteLine(" \"enabled\": true,");
writer.WriteLine(" \"auto_load\": " + (modules.Any() ? "false" : "true") + ",");
if (targets.Any())
writer.WriteLine(" \"auto_load\": " + (modules.Count > 0 ? "false" : "true") + ",");
if (targets.Count > 0)
{
writer.WriteLine(" \"targets\": [");
KeyValuePair<string, string> lastTarget = targets.Last();
@ -112,7 +112,7 @@ internal static class Koaloader
}
else
writer.WriteLine(" \"targets\": []");
if (modules.Any())
if (modules.Count > 0)
{
writer.WriteLine(" \"modules\": [");
KeyValuePair<string, string> lastModule = modules.Last();
@ -166,11 +166,11 @@ internal static class Koaloader
await Uninstall(rootDirectory, null, installForm, deleteConfig);
});
internal static async Task Install(string directory, BinaryType binaryType, ProgramSelection 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 ?? ProgramSelection.DefaultKoaloaderProxy;
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)))
{

View file

@ -483,21 +483,21 @@ internal static class Resources
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,
Func<string, bool> validFunc = null)
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(this string rootDirectory,
bool filterCommon = false, Func<string, bool> validFunc = null)
=> await Task.Run(async ()
=> (await rootDirectory.GetExecutables(filterCommon, validFunc)
?? (filterCommon || validFunc is not null ? await rootDirectory.GetExecutables() : null))?.Select(e =>
{
e.path = Path.GetDirectoryName(e.path);
return e;
}).DistinctBy(e => e.path).ToList());
}).DistinctBy(e => e.path).ToHashSet());
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false,
internal static async Task<HashSet<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false,
Func<string, bool> validFunc = null)
=> await Task.Run(() =>
{
List<(string path, BinaryType binaryType)> executables = new();
HashSet<(string path, BinaryType binaryType)> executables = new();
if (Program.Canceled || !rootDirectory.DirectoryExists())
return null;
foreach (string path in rootDirectory.EnumerateDirectory("*.exe", true))
@ -507,7 +507,7 @@ internal static class Resources
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));
_ = executables.Add((path, binaryType));
Thread.Sleep(1);
}
foreach (string path in rootDirectory.EnumerateDirectory("*.exe", true))
@ -517,10 +517,10 @@ internal static class Resources
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));
_ = executables.Add((path, binaryType));
Thread.Sleep(1);
}
return !executables.Any() ? null : executables;
return executables.Count > 0 ? executables : null;
});
private static bool IsCommonIncorrectExecutable(this string rootDirectory, string path)
@ -533,10 +533,10 @@ internal static class Resources
|| subPath.Contains("ANTICHEAT");
}
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory, Platform platform)
internal static async Task<HashSet<string>> GetDllDirectoriesFromGameDirectory(this string gameDirectory, Platform platform)
=> await Task.Run(() =>
{
List<string> dllDirectories = new();
HashSet<string> dllDirectories = new();
if (Program.Canceled || !gameDirectory.DirectoryExists())
return null;
foreach (string directory in gameDirectory.EnumerateSubdirectories("*", true).Append(gameDirectory))
@ -555,7 +555,7 @@ internal static class Resources
if (api.FileExists() || api_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (old_config.FileExists() || config.FileExists() || old_log.FileExists() || log.FileExists() || cache.FileExists())
&& !koaloaderInstalled)
dllDirectories.Add(subDirectory);
_ = dllDirectories.Add(subDirectory);
}
if (platform is Platform.Epic or Platform.Paradox)
{
@ -563,7 +563,7 @@ internal static class Resources
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
dllDirectories.Add(subDirectory);
_ = dllDirectories.Add(subDirectory);
}
if (platform is Platform.Ubisoft)
{
@ -571,15 +571,15 @@ internal static class Resources
out string log);
if (api32.FileExists() || api32_o.FileExists() || api64.FileExists() || api64_o.FileExists()
|| (config.FileExists() || log.FileExists()) && !koaloaderInstalled)
dllDirectories.Add(subDirectory);
_ = 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,
out log);
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);
_ = dllDirectories.Add(subDirectory);
}
}
return !dllDirectories.Any() ? null : dllDirectories;
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,

View file

@ -22,27 +22,24 @@ internal static class ScreamAPI
log = directory + @"\ScreamAPI.log";
}
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config, out _);
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideCatalogItems
= selection.AllDlc.Where(pair => pair.Value.type is DlcType.EpicCatalogItem).Except(selection.SelectedDlc);
foreach (KeyValuePair<string, (string _, SortedList<string, (DlcType type, string name, string icon)> extraDlc)> pair in selection.ExtraSelectedDlc)
overrideCatalogItems = overrideCatalogItems.Except(pair.Value.extraDlc);
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> entitlements
= selection.SelectedDlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement);
foreach (KeyValuePair<string, (string _, SortedList<string, (DlcType type, string name, string icon)> dlc)> pair in selection.ExtraSelectedDlc)
entitlements = entitlements.Concat(pair.Value.dlc.Where(pair => pair.Value.type == DlcType.EpicEntitlement));
overrideCatalogItems = overrideCatalogItems.ToList();
entitlements = entitlements.ToList();
if (overrideCatalogItems.Any() || entitlements.Any())
List<SelectionDLC> overrideCatalogItems = selection.DLC.Where(dlc => dlc.Type is DLCType.EpicCatalogItem && !dlc.Enabled).ToList();
List<SelectionDLC> overrideEntitlements = selection.DLC.Where(dlc => dlc.Type is DLCType.EpicEntitlement && !dlc.Enabled).ToList();
foreach (Selection extraSelection in selection.ExtraSelections)
{
overrideCatalogItems.AddRange(extraSelection.DLC.Where(dlc => dlc.Type is DLCType.EpicCatalogItem && !dlc.Enabled));
overrideEntitlements.AddRange(extraSelection.DLC.Where(dlc => dlc.Type is DLCType.EpicEntitlement && !dlc.Enabled));
}
if (overrideCatalogItems.Count > 0 || overrideEntitlements.Count > 0)
{
/*if (installForm is not null)
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(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
new(entitlements.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
WriteConfig(writer, new(overrideCatalogItems.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String),
new(overrideEntitlements.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
}
@ -53,8 +50,8 @@ internal static class ScreamAPI
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> overrideCatalogItems,
SortedList<string, (DlcType type, string name, string icon)> entitlements, InstallForm installForm = null)
private static void WriteConfig(TextWriter writer, SortedList<string, SelectionDLC> overrideCatalogItems, SortedList<string, SelectionDLC> entitlements,
InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"version\": 2,");
@ -63,16 +60,16 @@ internal static class ScreamAPI
writer.WriteLine(" \"block_metrics\": false,");
writer.WriteLine(" \"catalog_items\": {");
writer.WriteLine(" \"unlock_all\": true,");
if (overrideCatalogItems.Any())
if (overrideCatalogItems.Count > 0)
{
writer.WriteLine(" \"override\": [");
KeyValuePair<string, (DlcType type, string name, string icon)> lastOverrideCatalogItem = overrideCatalogItems.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in overrideCatalogItems)
KeyValuePair<string, SelectionDLC> lastOverrideCatalogItem = overrideCatalogItems.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in overrideCatalogItems)
{
string id = pair.Key;
(_, string name, _) = pair.Value;
writer.WriteLine($" \"{id}\"{(pair.Equals(lastOverrideCatalogItem) ? "" : ",")}");
installForm?.UpdateUser($"Added override catalog item to ScreamAPI.json with id {id} ({name})", LogTextBox.Action, false);
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,
false);
}
writer.WriteLine(" ]");
}
@ -82,16 +79,16 @@ internal static class ScreamAPI
writer.WriteLine(" \"entitlements\": {");
writer.WriteLine(" \"unlock_all\": true,");
writer.WriteLine(" \"auto_inject\": true,");
if (entitlements.Any())
if (entitlements.Count > 0)
{
writer.WriteLine(" \"inject\": [");
KeyValuePair<string, (DlcType type, string name, string icon)> lastEntitlement = entitlements.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in entitlements)
KeyValuePair<string, SelectionDLC> lastEntitlement = entitlements.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in entitlements)
{
string id = pair.Key;
(_, string name, _) = pair.Value;
writer.WriteLine($" \"{id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
installForm?.UpdateUser($"Added entitlement to ScreamAPI.json with id {id} ({name})", LogTextBox.Action, false);
SelectionDLC selectionDlc = pair.Value;
writer.WriteLine($" \"{selectionDlc.Id}\"{(pair.Equals(lastEntitlement) ? "" : ",")}");
installForm?.UpdateUser($"Added locked entitlement to ScreamAPI.json with id {selectionDlc.Id} ({selectionDlc.Name})", LogTextBox.Action,
false);
}
writer.WriteLine(" ]");
}
@ -139,7 +136,7 @@ internal static class ScreamAPI
}
});
internal static async Task Install(string directory, ProgramSelection 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 _);

View file

@ -25,46 +25,38 @@ internal static class SmokeAPI
cache = directory + @"\SmokeAPI.cache.json";
}
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
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 _);
List<KeyValuePair<string, (DlcType type, string name, string icon)>> overrideDlc = selection.AllDlc.Except(selection.SelectedDlc).ToList();
foreach (KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> dlc)> pair in selection.ExtraDlc)
if (selection.ExtraSelectedDlc.TryGetValue(pair.Key,
out (string name, SortedList<string, (DlcType type, string name, string icon)> dlc) selectedPair))
overrideDlc.AddRange(pair.Value.dlc.Except(selectedPair.dlc));
List<KeyValuePair<string, (DlcType type, string name, string icon)>> injectDlc = new();
if (selection.AllDlc.Count > 64)
injectDlc.AddRange(selection.SelectedDlc.Where(pair => pair.Value.type is DlcType.SteamHidden));
List<KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> injectDlc)>> extraApps = new();
if (selection.ExtraDlc.Any(e => e.Value.dlc.Count > 64))
foreach (KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> injectDlc)> pair in selection
.ExtraSelectedDlc)
if (selection.ExtraDlc.First(e => e.Key == pair.Key).Value.dlc.Count > 64)
{
SortedList<string, (DlcType type, string name, string icon)> extraInjectDlc = new(PlatformIdComparer.String);
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> extraPair in pair.Value.injectDlc.Where(extraPair
=> extraPair.Value.type is DlcType.SteamHidden))
extraInjectDlc.Add(extraPair.Key, extraPair.Value);
KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> injectDlc)> newExtraPair = new(pair.Key,
(pair.Value.name, extraInjectDlc));
extraApps.Add(newExtraPair);
}
injectDlc = injectDlc.ToList();
List<SelectionDLC> overrideDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToList();
foreach (Selection extraSelection in selection.ExtraSelections)
overrideDlc.AddRange(extraSelection.DLC.Where(dlc => !dlc.Enabled));
List<SelectionDLC> injectDlc = new();
if (selection.DLC.Count() > 64)
injectDlc.AddRange(selection.DLC.Where(dlc => dlc.Enabled && dlc.Type is DLCType.SteamHidden));
List<KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)>> extraApps = new();
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))
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);
}
if (selection.ExtraSelectedDlc.Any(p => p.Value.dlc.Any()) || overrideDlc.Any() || injectDlc.Any())
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(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
new(overrideDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String),
new(injectDlc.ToDictionary(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
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();
writer.Close();
}
@ -75,10 +67,8 @@ internal static class SmokeAPI
}
}
private static void WriteConfig(StreamWriter writer, string appId,
SortedList<string, (string name, SortedList<string, (DlcType type, string name, string icon)> injectDlc)> extraApps,
SortedList<string, (DlcType type, string name, string icon)> overrideDlc, SortedList<string, (DlcType type, string name, string icon)> injectDlc,
InstallForm installForm = null)
private static void WriteConfig(TextWriter 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,");
@ -89,13 +79,13 @@ internal static class SmokeAPI
if (overrideDlc.Count > 0)
{
writer.WriteLine(" \"override_dlc_status\": {");
KeyValuePair<string, (DlcType type, string name, string icon)> lastOverrideDlc = overrideDlc.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in overrideDlc)
KeyValuePair<string, SelectionDLC> lastOverrideDlc = overrideDlc.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in overrideDlc)
{
string dlcId = pair.Key;
(_, string dlcName, _) = pair.Value;
writer.WriteLine($" \"{dlcId}\": \"locked\"{(pair.Equals(lastOverrideDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added locked DLC to SmokeAPI.config.json with appid {dlcId} ({dlcName})", LogTextBox.Action, false);
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,
false);
}
writer.WriteLine(" },");
}
@ -110,34 +100,34 @@ internal static class SmokeAPI
{
writer.WriteLine(" \"" + appId + "\": {");
writer.WriteLine(" \"dlcs\": {");
KeyValuePair<string, (DlcType type, string name, string icon)> lastInjectDlc = injectDlc.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in injectDlc)
KeyValuePair<string, SelectionDLC> lastInjectDlc = injectDlc.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in injectDlc)
{
string dlcId = pair.Key;
(_, string dlcName, _) = pair.Value;
writer.WriteLine($" \"{dlcId}\": \"{dlcName}\"{(pair.Equals(lastInjectDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added extra DLC to SmokeAPI.config.json with appid {dlcId} ({dlcName})", LogTextBox.Action, false);
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,
false);
}
writer.WriteLine(" }");
writer.WriteLine(extraApps.Count > 0 ? " }," : " }");
}
if (extraApps.Count > 0)
{
KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> injectDlc)> lastExtraApp = extraApps.Last();
foreach (KeyValuePair<string, (string name, SortedList<string, (DlcType type, string name, string icon)> 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, (DlcType type, string name, string icon)> extraInjectDlc) = pair.Value;
(string _ /*extraAppName*/, SortedList<string, SelectionDLC> extraInjectDlc) = pair.Value;
writer.WriteLine(" \"" + extraAppId + "\": {");
writer.WriteLine(" \"dlcs\": {");
//installForm?.UpdateUser($"Added extra app to SmokeAPI.config.json with appid {extraAppId} ({extraAppName})", LogTextBox.Action, false);
KeyValuePair<string, (DlcType type, string name, string icon)> lastExtraAppDlc = extraInjectDlc.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> extraPair in extraInjectDlc)
KeyValuePair<string, SelectionDLC> lastExtraAppDlc = extraInjectDlc.Last();
foreach (KeyValuePair<string, SelectionDLC> extraPair in extraInjectDlc)
{
string dlcId = extraPair.Key;
(_, string dlcName, _) = extraPair.Value;
writer.WriteLine($" \"{dlcId}\": \"{dlcName}\"{(extraPair.Equals(lastExtraAppDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added extra DLC to SmokeAPI.config.json with appid {dlcId} ({dlcName})", LogTextBox.Action, false);
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})",
LogTextBox.Action, false);
}
writer.WriteLine(" }");
writer.WriteLine(pair.Equals(lastExtraApp) ? " }" : " },");
@ -211,7 +201,7 @@ internal static class SmokeAPI
}
});
internal static async Task Install(string directory, ProgramSelection 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);

View file

@ -22,20 +22,19 @@ internal static class UplayR1
log = directory + @"\UplayR1Unlocker.log";
}
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetUplayR1Components(out _, out _, out _, out _, out string config, out _);
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
foreach (KeyValuePair<string, (string _, SortedList<string, (DlcType type, string name, string icon)> extraDlc)> pair in selection.ExtraSelectedDlc)
blacklistDlc = blacklistDlc.Except(pair.Value.extraDlc);
blacklistDlc = blacklistDlc.ToList();
if (blacklistDlc.Any())
List<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToList();
foreach (Selection extraSelection in selection.ExtraSelections)
blacklistDlc.AddRange(extraSelection.DLC.Where(dlc => !dlc.Enabled));
if (blacklistDlc.Count > 0)
{
/*if (installForm is not null)
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(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
}
@ -46,8 +45,7 @@ internal static class UplayR1
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
private static void WriteConfig(TextWriter writer, SortedList<string, SelectionDLC> blacklistDlc, InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -56,13 +54,13 @@ internal static class UplayR1
if (blacklistDlc.Count > 0)
{
writer.WriteLine(" \"blacklist\": [");
KeyValuePair<string, (DlcType type, string name, string icon)> lastBlacklistDlc = blacklistDlc.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in blacklistDlc)
KeyValuePair<string, SelectionDLC> lastBlacklistDlc = blacklistDlc.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in blacklistDlc)
{
string dlcId = pair.Key;
(_, string dlcName, _) = pair.Value;
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added blacklist DLC to UplayR1Unlocker.jsonc with appid {dlcId} ({dlcName})", LogTextBox.Action, false);
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,
false);
}
writer.WriteLine(" ],");
}
@ -109,7 +107,7 @@ internal static class UplayR1
}
});
internal static async Task Install(string directory, ProgramSelection 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 _);

View file

@ -24,20 +24,19 @@ internal static class UplayR2
log = directory + @"\UplayR2Unlocker.log";
}
internal static void CheckConfig(string directory, ProgramSelection selection, InstallForm installForm = null)
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
{
directory.GetUplayR2Components(out _, out _, out _, out _, out _, out _, out string config, out _);
IEnumerable<KeyValuePair<string, (DlcType type, string name, string icon)>> blacklistDlc = selection.AllDlc.Except(selection.SelectedDlc);
foreach (KeyValuePair<string, (string _, SortedList<string, (DlcType type, string name, string icon)> extraDlc)> pair in selection.ExtraSelectedDlc)
blacklistDlc = blacklistDlc.Except(pair.Value.extraDlc);
blacklistDlc = blacklistDlc.ToList();
if (blacklistDlc.Any())
List<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToList();
foreach (Selection extraSelection in selection.ExtraSelections)
blacklistDlc.AddRange(extraSelection.DLC.Where(dlc => !dlc.Enabled));
if (blacklistDlc.Count > 0)
{
/*if (installForm is not null)
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(pair => pair.Key, pair => pair.Value), PlatformIdComparer.String), installForm);
WriteConfig(writer, new(blacklistDlc.ToDictionary(dlc => dlc.Id, dlc => dlc), PlatformIdComparer.String), installForm);
writer.Flush();
writer.Close();
}
@ -48,8 +47,7 @@ internal static class UplayR2
}
}
private static void WriteConfig(StreamWriter writer, SortedList<string, (DlcType type, string name, string icon)> blacklistDlc,
InstallForm installForm = null)
private static void WriteConfig(TextWriter writer, SortedList<string, SelectionDLC> blacklistDlc, InstallForm installForm = null)
{
writer.WriteLine("{");
writer.WriteLine(" \"logging\": false,");
@ -60,13 +58,13 @@ internal static class UplayR2
if (blacklistDlc.Count > 0)
{
writer.WriteLine(" \"blacklist\": [");
KeyValuePair<string, (DlcType type, string name, string icon)> lastBlacklistDlc = blacklistDlc.Last();
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in blacklistDlc)
KeyValuePair<string, SelectionDLC> lastBlacklistDlc = blacklistDlc.Last();
foreach (KeyValuePair<string, SelectionDLC> pair in blacklistDlc)
{
string dlcId = pair.Key;
(_, string dlcName, _) = pair.Value;
writer.WriteLine($" {dlcId}{(pair.Equals(lastBlacklistDlc) ? "" : ",")}");
installForm?.UpdateUser($"Added blacklist DLC to UplayR2Unlocker.jsonc with appid {dlcId} ({dlcName})", LogTextBox.Action, false);
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,
false);
}
writer.WriteLine(" ],");
}
@ -109,14 +107,13 @@ internal static class UplayR2
config.DeleteFile();
installForm?.UpdateUser($"Deleted configuration: {Path.GetFileName(config)}", LogTextBox.Action, false);
}
if (log.FileExists())
{
log.DeleteFile();
installForm?.UpdateUser($"Deleted log: {Path.GetFileName(log)}", 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, ProgramSelection 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,

View file

@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using CreamInstaller.Components;
using CreamInstaller.Resources;
using CreamInstaller.Utility;
using static CreamInstaller.Resources.Resources;
@ -13,47 +12,31 @@ public enum Platform
Epic, Ubisoft
}
public enum DlcType
{
Steam, SteamHidden, EpicCatalogItem,
EpicEntitlement
}
internal sealed class ProgramSelection
internal sealed class Selection
{
internal const string DefaultKoaloaderProxy = "version";
internal static readonly List<ProgramSelection> All = new();
internal static readonly HashSet<Selection> All = new();
internal readonly HashSet<Selection> ExtraSelections = new();
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc = new(PlatformIdComparer.String);
internal readonly SortedList<string, (string name, SortedList<string, (DlcType type, string name, string icon)> dlc)> ExtraDlc = new();
internal readonly SortedList<string, (string name, SortedList<string, (DlcType type, string name, string icon)> dlc)> ExtraSelectedDlc = new();
internal readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc = new(PlatformIdComparer.String);
internal List<string> DllDirectories;
internal HashSet<string> DllDirectories;
internal bool Enabled;
internal List<(string directory, BinaryType binaryType)> ExecutableDirectories;
internal string IconUrl;
internal HashSet<(string directory, BinaryType binaryType)> ExecutableDirectories;
internal string Icon;
internal string Id = "0";
internal bool Koaloader;
internal string KoaloaderProxy;
internal string Name = "Program";
internal Platform Platform;
internal string ProductUrl;
internal string Product;
internal string Publisher;
internal string RootDirectory;
internal string SubIconUrl;
internal string SubIcon;
internal string Website;
internal string WebsiteUrl;
internal Selection() => All.Add(this);
internal ProgramSelection() => All.Add(this);
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.AllSafe.Where(dlc => dlc.Selection == this);
internal bool AreDllsLocked
{
@ -96,69 +79,41 @@ internal sealed class ProgramSelection
}
}
internal static List<ProgramSelection> AllSafe => All.ToList();
internal static List<Selection> AllSafe => All.ToList();
internal static List<ProgramSelection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
internal static List<Selection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
private void Toggle(string dlcAppId, (DlcType type, string name, string icon) dlcApp, bool enabled)
private void Remove()
{
if (enabled)
SelectedDlc[dlcAppId] = dlcApp;
else
_ = SelectedDlc.Remove(dlcAppId);
}
internal void ToggleDlc(string dlcId, bool enabled)
{
foreach ((string appId, (DlcType type, string name, string icon) dlcApp) in AllDlc)
{
if (appId != dlcId)
continue;
Toggle(appId, dlcApp, enabled);
break;
}
Enabled = SelectedDlc.Any() || ExtraSelectedDlc.Any();
}
private void Validate()
{
if (Program.IsGameBlocked(Name, RootDirectory))
{
_ = All.Remove(this);
return;
}
if (!RootDirectory.DirectoryExists())
{
_ = All.Remove(this);
return;
}
_ = DllDirectories.RemoveAll(directory => !directory.DirectoryExists());
if (!DllDirectories.Any())
_ = All.Remove(this);
_ = All.Remove(this);
foreach (SelectionDLC dlc in DLC)
dlc.Selection = null;
}
private void Validate(List<(Platform platform, string id, string name)> programsToScan)
{
if (programsToScan is null || !programsToScan.Any(p => p.platform == Platform && p.id == Id))
{
_ = All.Remove(this);
Remove();
return;
}
Validate();
if (Program.IsGameBlocked(Name, RootDirectory))
{
Remove();
return;
}
if (!RootDirectory.DirectoryExists())
{
Remove();
return;
}
_ = DllDirectories.RemoveWhere(directory => !directory.DirectoryExists());
if (DllDirectories.Count < 1)
Remove();
}
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
=> AllSafe.ForEach(selection => selection.Validate(programsToScan));
internal static ProgramSelection FromPlatformId(Platform platform, string gameId) => AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
internal static (string gameId, (DlcType type, string name, string icon) app)? GetDlcFromPlatformId(Platform platform, string dlcId)
{
foreach (ProgramSelection selection in AllSafe.Where(s => s.Platform == platform))
foreach (KeyValuePair<string, (DlcType type, string name, string icon)> pair in selection.AllDlc.Where(p => p.Key == dlcId))
return (selection.Id, pair.Value);
return null;
}
internal static Selection FromPlatformId(Platform platform, string gameId) => AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
}

View file

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Linq;
namespace CreamInstaller;
public enum DLCType
{
Steam, SteamHidden, EpicCatalogItem,
EpicEntitlement
}
internal sealed class SelectionDLC
{
private static readonly HashSet<SelectionDLC> All = new();
internal bool Enabled;
internal string Icon;
internal string Id;
internal string Name;
internal string Product;
internal string Publisher;
private Selection selection;
internal DLCType Type;
internal Selection Selection
{
get => selection;
set
{
selection = value;
_ = value is null ? All.Remove(this) : All.Add(this);
}
}
internal static List<SelectionDLC> AllSafe => All.ToList();
internal static SelectionDLC FromPlatformId(Platform platform, string dlcId) => AllSafe.Find(dlc => dlc.Selection.Platform == platform && dlc.Id == dlcId);
}

View file

@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Drawing;
using System.Globalization;
using System.Net;
@ -15,7 +15,7 @@ internal static class HttpClientManager
{
internal static HttpClient HttpClient;
private static readonly Dictionary<string, string> HttpContentCache = new();
private static readonly ConcurrentDictionary<string, string> HttpContentCache = new();
internal static void Setup()
{

View file

@ -36,7 +36,7 @@ internal static class SafeIO
while (!Program.Canceled)
try
{
Directory.CreateDirectory(directoryPath);
_ = Directory.CreateDirectory(directoryPath);
break;
}
catch (Exception e)
@ -251,6 +251,11 @@ internal static class SafeIO
private static DialogResult IOWarnInternal(this string filePath, string message, Exception e, Form form = null)
{
using DialogForm dialogForm = new(form);
return dialogForm.Show(SystemIcons.Warning, message + ": " + filePath.BeautifyPath() + "\n\n" + e.FormatException(), "Retry", "OK");
string description = message + ": " + filePath.BeautifyPath() + "\n\n";
if (e is IOException && (e.HResult & 0x0000FFFF) == 225) // virus or potentially unwanted software
description += "Please resolve your anti-virus and press retry to continue . . . ";
else
description += e.FormatException();
return dialogForm.Show(SystemIcons.Warning, description, "Retry", "OK");
}
}