v4.9.2
- More significant refactoring & optimization - Tethered tree nodes to selection objects for optimization & to further reduce the chance of duplicate nodes - Fixed a minor steam game gathering check that may have been letting through duplicate games - Fixed a few selection form functions from the refactoring & optimization in v4.9.0 - Fixed the Koaloader reset button not updating after toggling the Koaloader all check box
This commit is contained in:
parent
1669f8c887
commit
e333483b8f
11 changed files with 177 additions and 259 deletions
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||||
<Version>4.9.1</Version>
|
<Version>4.9.2</Version>
|
||||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||||
<Company>CreamInstaller</Company>
|
<Company>CreamInstaller</Company>
|
||||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||||
|
|
|
@ -16,7 +16,7 @@ internal sealed partial class InstallForm : CustomForm
|
||||||
{
|
{
|
||||||
private readonly HashSet<Selection> disabledSelections = new();
|
private readonly HashSet<Selection> disabledSelections = new();
|
||||||
|
|
||||||
private readonly int programCount = Selection.AllEnabled.Count;
|
private readonly int programCount = Selection.AllEnabled.Count();
|
||||||
private readonly bool uninstalling;
|
private readonly bool uninstalling;
|
||||||
private int completeOperationsCount;
|
private int completeOperationsCount;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ internal sealed partial class InstallForm : CustomForm
|
||||||
|
|
||||||
private async Task Operate()
|
private async Task Operate()
|
||||||
{
|
{
|
||||||
HashSet<Selection> programSelections = Selection.AllEnabled;
|
HashSet<Selection> programSelections = Selection.AllEnabled.ToHashSet();
|
||||||
operationsCount = programSelections.Count;
|
operationsCount = programSelections.Count;
|
||||||
completeOperationsCount = 0;
|
completeOperationsCount = 0;
|
||||||
foreach (Selection selection in programSelections)
|
foreach (Selection selection in programSelections)
|
||||||
|
@ -205,7 +205,7 @@ internal sealed partial class InstallForm : CustomForm
|
||||||
++completeOperationsCount;
|
++completeOperationsCount;
|
||||||
}
|
}
|
||||||
Program.Cleanup();
|
Program.Cleanup();
|
||||||
HashSet<Selection> failedSelections = Selection.AllEnabled;
|
HashSet<Selection> failedSelections = Selection.AllEnabled.ToHashSet();
|
||||||
if (failedSelections.Count > 0)
|
if (failedSelections.Count > 0)
|
||||||
if (failedSelections.Count == 1)
|
if (failedSelections.Count == 1)
|
||||||
throw new CustomMessageException($"Operation failed for {failedSelections.First().Name}.");
|
throw new CustomMessageException($"Operation failed for {failedSelections.First().Name}.");
|
||||||
|
|
4
CreamInstaller/Forms/SelectForm.Designer.cs
generated
4
CreamInstaller/Forms/SelectForm.Designer.cs
generated
|
@ -447,7 +447,7 @@ namespace CreamInstaller.Forms
|
||||||
private GroupBox programsGroupBox;
|
private GroupBox programsGroupBox;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private Label progressLabel;
|
private Label progressLabel;
|
||||||
private CheckBox allCheckBox;
|
internal CheckBox allCheckBox;
|
||||||
private Button scanButton;
|
private Button scanButton;
|
||||||
private Label noneFoundLabel;
|
private Label noneFoundLabel;
|
||||||
private CustomTreeView selectionTreeView;
|
private CustomTreeView selectionTreeView;
|
||||||
|
@ -460,7 +460,7 @@ namespace CreamInstaller.Forms
|
||||||
private Label progressLabelDLCs;
|
private Label progressLabelDLCs;
|
||||||
private CheckBox sortCheckBox;
|
private CheckBox sortCheckBox;
|
||||||
private FlowLayoutPanel koaloaderFlowPanel;
|
private FlowLayoutPanel koaloaderFlowPanel;
|
||||||
private CheckBox koaloaderAllCheckBox;
|
internal CheckBox koaloaderAllCheckBox;
|
||||||
private Button saveButton;
|
private Button saveButton;
|
||||||
private Button loadButton;
|
private Button loadButton;
|
||||||
private Button resetKoaloaderButton;
|
private Button resetKoaloaderButton;
|
||||||
|
|
|
@ -25,21 +25,29 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
private const string HelpButtonListPrefix = "\n • ";
|
private const string HelpButtonListPrefix = "\n • ";
|
||||||
|
|
||||||
|
private static SelectForm current;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, string> remainingDLCs = new();
|
private readonly ConcurrentDictionary<string, string> remainingDLCs = new();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, string> remainingGames = new();
|
private readonly ConcurrentDictionary<string, string> remainingGames = new();
|
||||||
|
|
||||||
private List<(Platform platform, string id, string name)> programsToScan;
|
private List<(Platform platform, string id, string name)> programsToScan;
|
||||||
|
|
||||||
internal SelectForm()
|
private SelectForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Text = Program.ApplicationName;
|
Text = Program.ApplicationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ContextMenuStrip ContextMenuStrip => base.ContextMenuStrip ??= new();
|
internal static SelectForm Current
|
||||||
|
{
|
||||||
private List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
|
get
|
||||||
|
{
|
||||||
|
if (current is not null && (current.Disposing || current.IsDisposed))
|
||||||
|
current = null;
|
||||||
|
return current ??= new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void UpdateRemaining(Label label, ConcurrentDictionary<string, string> list, string descriptor)
|
private static void UpdateRemaining(Label label, ConcurrentDictionary<string, string> list, string descriptor)
|
||||||
=> label.Text = list.IsEmpty ? "" : $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
|
=> label.Text = list.IsEmpty ? "" : $"Remaining {descriptor} ({list.Count}): " + string.Join(", ", list.Values).Replace("&", "&&");
|
||||||
|
@ -119,7 +127,6 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
List<TreeNode> treeNodes = TreeNodes;
|
|
||||||
remainingGames.Clear(); // for display purposes only, otherwise ignorable
|
remainingGames.Clear(); // for display purposes only, otherwise ignorable
|
||||||
remainingDLCs.Clear(); // for display purposes only, otherwise ignorable
|
remainingDLCs.Clear(); // for display purposes only, otherwise ignorable
|
||||||
List<Task> appTasks = new();
|
List<Task> appTasks = new();
|
||||||
|
@ -133,20 +140,8 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
|
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
|
||||||
if (uninstallAll)
|
if (uninstallAll)
|
||||||
selection.Enabled = true;
|
selection.Enabled = true;
|
||||||
else
|
else if (selection.TreeNode.TreeView is null)
|
||||||
{
|
_ = selectionTreeView.Nodes.Add(selection.TreeNode);
|
||||||
if (allCheckBox.Checked)
|
|
||||||
selection.Enabled = true;
|
|
||||||
if (koaloaderAllCheckBox.Checked)
|
|
||||||
selection.Koaloader = true;
|
|
||||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id) ?? new TreeNode();
|
|
||||||
programNode.Tag = selection.Platform;
|
|
||||||
programNode.Name = selection.Id;
|
|
||||||
programNode.Text = selection.Name;
|
|
||||||
programNode.Checked = selection.Enabled;
|
|
||||||
if (programNode.TreeView is null)
|
|
||||||
_ = selectionTreeView.Nodes.Add(programNode);
|
|
||||||
}
|
|
||||||
RemoveFromRemainingGames("Paradox Launcher");
|
RemoveFromRemainingGames("Paradox Launcher");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,10 +308,6 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name, gameDirectory, dllDirectories,
|
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name, gameDirectory, dllDirectories,
|
||||||
await gameDirectory.GetExecutableDirectories(true));
|
await gameDirectory.GetExecutableDirectories(true));
|
||||||
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.Product = "https://store.steampowered.com/app/" + appId;
|
selection.Product = "https://store.steampowered.com/app/" + appId;
|
||||||
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
|
selection.Icon = IconGrabber.SteamAppImagesPath + @$"\{appId}\{appInfo?.Value.GetChild("common")?.GetChild("icon")}.jpg";
|
||||||
selection.SubIcon = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
|
selection.SubIcon = appData?.HeaderImage ?? IconGrabber.SteamAppImagesPath
|
||||||
|
@ -329,26 +320,13 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == appId) ?? new TreeNode();
|
if (selection.TreeNode.TreeView is null)
|
||||||
programNode.Tag = selection.Platform;
|
_ = selectionTreeView.Nodes.Add(selection.TreeNode);
|
||||||
programNode.Name = appId;
|
|
||||||
programNode.Text = appData?.Name ?? name;
|
|
||||||
programNode.Checked = selection.Enabled;
|
|
||||||
if (programNode.TreeView is null)
|
|
||||||
_ = selectionTreeView.Nodes.Add(programNode);
|
|
||||||
foreach ((SelectionDLC dlc, _) in dlc)
|
foreach ((SelectionDLC dlc, _) in dlc)
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
dlc.Selection = selection;
|
dlc.Selection = selection;
|
||||||
dlc.Enabled = dlc.Name != "Unknown" && allCheckBox.Checked;
|
|
||||||
TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
|
|
||||||
dlcNode.Tag = dlc.Type;
|
|
||||||
dlcNode.Name = dlc.Id;
|
|
||||||
dlcNode.Text = dlc.Name;
|
|
||||||
dlcNode.Checked = dlc.Enabled;
|
|
||||||
if (dlcNode.Parent is null)
|
|
||||||
_ = programNode.Nodes.Add(dlcNode);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
|
@ -431,10 +409,6 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
}
|
}
|
||||||
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
|
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
|
||||||
await directory.GetExecutableDirectories(true));
|
await directory.GetExecutableDirectories(true));
|
||||||
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;
|
|
||||||
foreach ((SelectionDLC dlc, _) in entitlements.Where(dlc => dlc.Key.Name == selection.Name))
|
foreach ((SelectionDLC dlc, _) in entitlements.Where(dlc => dlc.Key.Name == selection.Name))
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
|
@ -449,57 +423,22 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == @namespace) ?? new TreeNode();
|
if (selection.TreeNode.TreeView is null)
|
||||||
programNode.Tag = selection.Platform;
|
_ = selectionTreeView.Nodes.Add(selection.TreeNode);
|
||||||
programNode.Name = @namespace;
|
|
||||||
programNode.Text = name;
|
|
||||||
programNode.Checked = selection.Enabled;
|
|
||||||
if (programNode.TreeView is null)
|
|
||||||
_ = selectionTreeView.Nodes.Add(programNode);
|
|
||||||
if (!catalogItems.IsEmpty)
|
if (!catalogItems.IsEmpty)
|
||||||
/*TreeNode catalogItemsNode = treeNodes.Find(node => (Platform)s.Tag == selection.Platform && node.Name == @namespace + "_catalogItems") ?? new();
|
|
||||||
catalogItemsNode.Tag = selection.Platform;
|
|
||||||
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)
|
foreach ((SelectionDLC dlc, _) in catalogItems)
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
dlc.Selection = selection;
|
dlc.Selection = selection;
|
||||||
dlc.Enabled = allCheckBox.Checked;
|
|
||||||
TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
|
|
||||||
dlcNode.Tag = dlc.Type;
|
|
||||||
dlcNode.Name = dlc.Id;
|
|
||||||
dlcNode.Text = dlc.Name;
|
|
||||||
dlcNode.Checked = dlc.Enabled;
|
|
||||||
if (dlcNode.Parent is null)
|
|
||||||
_ = programNode.Nodes.Add(dlcNode); //_ = catalogItemsNode.Nodes.Add(dlcNode);
|
|
||||||
}
|
}
|
||||||
if (entitlements.IsEmpty)
|
if (entitlements.IsEmpty)
|
||||||
return;
|
return;
|
||||||
/*TreeNode entitlementsNode = treeNodes.Find(node => (Platform)s.Tag == selection.Platform && node.Name == @namespace + "_entitlements") ?? new();
|
|
||||||
entitlementsNode.Name = selection.Platform;
|
|
||||||
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)
|
foreach ((SelectionDLC dlc, _) in entitlements)
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
dlc.Selection = selection;
|
dlc.Selection = selection;
|
||||||
dlc.Enabled = allCheckBox.Checked;
|
|
||||||
TreeNode dlcNode = treeNodes.Find(s => (DLCType)s.Tag == dlc.Type && s.Name == dlc.Id) ?? new TreeNode();
|
|
||||||
dlcNode.Tag = dlc.Type;
|
|
||||||
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)
|
if (Program.Canceled)
|
||||||
|
@ -541,22 +480,13 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
return;
|
return;
|
||||||
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
|
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
|
||||||
await gameDirectory.GetExecutableDirectories(true));
|
await gameDirectory.GetExecutableDirectories(true));
|
||||||
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.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
selection.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
||||||
selectionTreeView.Invoke(delegate
|
selectionTreeView.Invoke(delegate
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == gameId) ?? new TreeNode();
|
if (selection.TreeNode.TreeView is null)
|
||||||
programNode.Tag = selection.Platform;
|
_ = selectionTreeView.Nodes.Add(selection.TreeNode);
|
||||||
programNode.Name = gameId;
|
|
||||||
programNode.Text = name;
|
|
||||||
programNode.Checked = selection.Enabled;
|
|
||||||
if (programNode.TreeView is null)
|
|
||||||
_ = selectionTreeView.Nodes.Add(programNode);
|
|
||||||
});
|
});
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return;
|
return;
|
||||||
|
@ -639,7 +569,8 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
progressBar.Value = p;
|
progressBar.Value = p;
|
||||||
};
|
};
|
||||||
progressLabel.Text = "Quickly gathering games for uninstallation . . . ";
|
progressLabel.Text = "Quickly gathering games for uninstallation . . . ";
|
||||||
TreeNodes.ForEach(node => node.Remove());
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
|
selection.TreeNode.Remove();
|
||||||
await GetApplicablePrograms(iProgress, true);
|
await GetApplicablePrograms(iProgress, true);
|
||||||
if (!Program.Canceled)
|
if (!Program.Canceled)
|
||||||
OnUninstall(null, null);
|
OnUninstall(null, null);
|
||||||
|
@ -691,7 +622,8 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
setup = false;
|
setup = false;
|
||||||
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
||||||
Selection.ValidateAll(programsToScan);
|
Selection.ValidateAll(programsToScan);
|
||||||
TreeNodes.ForEach(node => node.Remove());
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
|
selection.TreeNode.Remove();
|
||||||
await GetApplicablePrograms(iProgress);
|
await GetApplicablePrograms(iProgress);
|
||||||
await SteamCMD.Cleanup();
|
await SteamCMD.Cleanup();
|
||||||
}
|
}
|
||||||
|
@ -702,7 +634,7 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
allCheckBox.Enabled = selectionTreeView.Enabled;
|
allCheckBox.Enabled = selectionTreeView.Enabled;
|
||||||
koaloaderAllCheckBox.Enabled = selectionTreeView.Enabled;
|
koaloaderAllCheckBox.Enabled = selectionTreeView.Enabled;
|
||||||
noneFoundLabel.Visible = !selectionTreeView.Enabled;
|
noneFoundLabel.Visible = !selectionTreeView.Enabled;
|
||||||
installButton.Enabled = Selection.AllEnabled.Count > 0;
|
installButton.Enabled = Selection.AllEnabled.Any();
|
||||||
uninstallButton.Enabled = installButton.Enabled;
|
uninstallButton.Enabled = installButton.Enabled;
|
||||||
saveButton.Enabled = CanSaveDlc();
|
saveButton.Enabled = CanSaveDlc();
|
||||||
loadButton.Enabled = CanLoadDlc();
|
loadButton.Enabled = CanLoadDlc();
|
||||||
|
@ -723,13 +655,12 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
TreeNode node = e.Node;
|
TreeNode node = e.Node;
|
||||||
if (node is null)
|
if (node is null)
|
||||||
return;
|
return;
|
||||||
SyncNode(node);
|
|
||||||
SyncNodeAncestors(node);
|
SyncNodeAncestors(node);
|
||||||
SyncNodeDescendants(node);
|
SyncNodeDescendants(node);
|
||||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||||
allCheckBox.Checked = TreeNodes.TrueForAll(node => node.Text == "Unknown" || node.Checked);
|
allCheckBox.Checked = EnumerateTreeNodes(selectionTreeView.Nodes).All(node => node.Text == "Unknown" || node.Checked);
|
||||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||||
installButton.Enabled = Selection.AllEnabled.Count > 0;
|
installButton.Enabled = Selection.AllEnabled.Any();
|
||||||
uninstallButton.Enabled = installButton.Enabled;
|
uninstallButton.Enabled = installButton.Enabled;
|
||||||
saveButton.Enabled = CanSaveDlc();
|
saveButton.Enabled = CanSaveDlc();
|
||||||
resetButton.Enabled = CanResetDlc();
|
resetButton.Enabled = CanResetDlc();
|
||||||
|
@ -737,17 +668,11 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
|
|
||||||
private static void SyncNodeAncestors(TreeNode node)
|
private static void SyncNodeAncestors(TreeNode node)
|
||||||
{
|
{
|
||||||
while (true)
|
TreeNode parentNode = node.Parent;
|
||||||
{
|
if (parentNode is null)
|
||||||
TreeNode parentNode = node.Parent;
|
return;
|
||||||
if (parentNode is not null)
|
parentNode.Checked = parentNode.Nodes.Cast<TreeNode>().Any(childNode => childNode.Checked);
|
||||||
{
|
SyncNodeAncestors(parentNode);
|
||||||
parentNode.Checked = parentNode.Nodes.Cast<TreeNode>().Any(childNode => childNode.Checked);
|
|
||||||
node = parentNode;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SyncNodeDescendants(TreeNode node)
|
private static void SyncNodeDescendants(TreeNode node)
|
||||||
|
@ -755,38 +680,20 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
foreach (TreeNode childNode in node.Nodes)
|
foreach (TreeNode childNode in node.Nodes)
|
||||||
{
|
{
|
||||||
if (childNode.Text == "Unknown")
|
if (childNode.Text == "Unknown")
|
||||||
return;
|
continue;
|
||||||
childNode.Checked = node.Checked;
|
childNode.Checked = node.Checked;
|
||||||
SyncNode(childNode);
|
|
||||||
SyncNodeDescendants(childNode);
|
SyncNodeDescendants(childNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SyncNode(TreeNode node)
|
private static IEnumerable<TreeNode> EnumerateTreeNodes(TreeNodeCollection nodeCollection)
|
||||||
{
|
{
|
||||||
string id = node.Name;
|
|
||||||
Platform platform = (Platform)node.Tag;
|
|
||||||
Selection selection = Selection.FromPlatformId(platform, id);
|
|
||||||
if (selection is not null)
|
|
||||||
{
|
|
||||||
selection.Enabled = node.Checked;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DLCType type = (DLCType)node.Tag;
|
|
||||||
SelectionDLC dlc = SelectionDLC.FromTypeId(type, id);
|
|
||||||
if (dlc is not null)
|
|
||||||
dlc.Enabled = node.Checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
|
|
||||||
{
|
|
||||||
List<TreeNode> treeNodes = new();
|
|
||||||
foreach (TreeNode rootNode in nodeCollection)
|
foreach (TreeNode rootNode in nodeCollection)
|
||||||
{
|
{
|
||||||
treeNodes.Add(rootNode);
|
yield return rootNode;
|
||||||
treeNodes.AddRange(GatherTreeNodes(rootNode.Nodes));
|
foreach (TreeNode childNode in EnumerateTreeNodes(rootNode.Nodes))
|
||||||
|
yield return childNode;
|
||||||
}
|
}
|
||||||
return treeNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowProgressBar()
|
private void ShowProgressBar()
|
||||||
|
@ -1027,45 +934,44 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
|
|
||||||
private void OnAllCheckBoxChanged(object sender, EventArgs e)
|
private void OnAllCheckBoxChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
bool shouldCheck = TreeNodes.Any(node => node.Parent is null && !node.Checked);
|
bool shouldEnable = Selection.All.Keys.Any(s => !s.Enabled);
|
||||||
foreach (TreeNode node in TreeNodes.Where(node => node.Parent is null && node.Checked != shouldCheck))
|
foreach (Selection selection in Selection.All.Keys.Where(s => s.Enabled != shouldEnable))
|
||||||
{
|
{
|
||||||
node.Checked = shouldCheck;
|
selection.Enabled = shouldEnable;
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
OnTreeViewNodeCheckedChanged(null, new(selection.TreeNode, TreeViewAction.ByMouse));
|
||||||
}
|
}
|
||||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||||
allCheckBox.Checked = shouldCheck;
|
allCheckBox.Checked = shouldEnable;
|
||||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKoaloaderAllCheckBoxChanged(object sender, EventArgs e)
|
private void OnKoaloaderAllCheckBoxChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
bool shouldCheck = Selection.AllSafe.Any(selection => !selection.Koaloader);
|
bool shouldEnable = Selection.All.Keys.Any(selection => !selection.Koaloader);
|
||||||
foreach (Selection selection in Selection.AllSafe)
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
selection.Koaloader = shouldCheck;
|
selection.Koaloader = shouldEnable;
|
||||||
selectionTreeView.Invalidate();
|
selectionTreeView.Invalidate();
|
||||||
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
|
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
|
||||||
koaloaderAllCheckBox.Checked = shouldCheck;
|
koaloaderAllCheckBox.Checked = shouldEnable;
|
||||||
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
|
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
|
||||||
|
resetKoaloaderButton.Enabled = CanResetKoaloader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AreSelectionsDefault()
|
private bool AreSelectionsDefault()
|
||||||
=> TreeNodes.All(node => node.Parent is null || node.Tag is not Platform || (node.Text == "Unknown" ? !node.Checked : node.Checked));
|
=> EnumerateTreeNodes(selectionTreeView.Nodes).All(node
|
||||||
|
=> node.Parent is null || node.Tag is not Platform and not DLCType || (node.Text == "Unknown" ? !node.Checked : node.Checked));
|
||||||
|
|
||||||
private bool CanSaveDlc() => installButton.Enabled && (ProgramData.ReadDlcChoices().Any() || !AreSelectionsDefault());
|
private bool CanSaveDlc() => installButton.Enabled && (ProgramData.ReadDlcChoices().Any() || !AreSelectionsDefault());
|
||||||
|
|
||||||
private void OnSaveDlc(object sender, EventArgs e)
|
private void OnSaveDlc(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
|
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
|
||||||
foreach (TreeNode node in TreeNodes)
|
foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
|
||||||
if (node.Parent is { } parent && node.Tag is Platform platform)
|
if ((dlc.Name == "Unknown" ? dlc.Enabled : !dlc.Enabled)
|
||||||
{
|
&& !choices.Any(c => c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id))
|
||||||
if ((node.Text == "Unknown" ? node.Checked : !node.Checked)
|
choices.Add((dlc.Selection.Platform, dlc.Selection.Id, dlc.Id));
|
||||||
&& !choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name))
|
else
|
||||||
choices.Add((platform, node.Parent.Name, node.Name));
|
_ = choices.RemoveAll(n => n.platform == dlc.Selection.Platform && n.gameId == dlc.Selection.Id && n.dlcId == dlc.Id);
|
||||||
else
|
|
||||||
_ = choices.RemoveAll(n => n.platform == platform && n.gameId == parent.Name && n.dlcId == node.Name);
|
|
||||||
}
|
|
||||||
ProgramData.WriteDlcChoices(choices);
|
ProgramData.WriteDlcChoices(choices);
|
||||||
loadButton.Enabled = CanLoadDlc();
|
loadButton.Enabled = CanLoadDlc();
|
||||||
saveButton.Enabled = CanSaveDlc();
|
saveButton.Enabled = CanSaveDlc();
|
||||||
|
@ -1076,36 +982,35 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
private void OnLoadDlc(object sender, EventArgs e)
|
private void OnLoadDlc(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
|
List<(Platform platform, string gameId, string dlcId)> choices = ProgramData.ReadDlcChoices().ToList();
|
||||||
foreach (TreeNode node in TreeNodes)
|
foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
|
||||||
if (node.Parent is { } parent && node.Tag is Platform platform)
|
{
|
||||||
{
|
dlc.Enabled = choices.Any(c => c.platform == dlc.Selection.Platform && c.gameId == dlc.Selection.Id && c.dlcId == dlc.Id)
|
||||||
node.Checked = choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name)
|
? dlc.Name == "Unknown"
|
||||||
? node.Text == "Unknown"
|
: dlc.Name != "Unknown";
|
||||||
: node.Text != "Unknown";
|
OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanResetDlc() => !AreSelectionsDefault();
|
private bool CanResetDlc() => !AreSelectionsDefault();
|
||||||
|
|
||||||
private void OnResetDlc(object sender, EventArgs e)
|
private void OnResetDlc(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
foreach (TreeNode node in TreeNodes.Where(node => node.Parent is not null && node.Tag is Platform))
|
foreach (SelectionDLC dlc in SelectionDLC.All.Keys)
|
||||||
{
|
{
|
||||||
node.Checked = node.Text != "Unknown";
|
dlc.Enabled = dlc.Name != "Unknown";
|
||||||
OnTreeViewNodeCheckedChanged(null, new(node, TreeViewAction.ByMouse));
|
OnTreeViewNodeCheckedChanged(null, new(dlc.TreeNode, TreeViewAction.ByMouse));
|
||||||
}
|
}
|
||||||
resetButton.Enabled = CanResetDlc();
|
resetButton.Enabled = CanResetDlc();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool AreKoaloaderSelectionsDefault() => Selection.AllSafe.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
|
private static bool AreKoaloaderSelectionsDefault() => Selection.All.Keys.All(selection => selection.Koaloader && selection.KoaloaderProxy is null);
|
||||||
|
|
||||||
private static bool CanSaveKoaloader() => ProgramData.ReadKoaloaderChoices().Any() || !AreKoaloaderSelectionsDefault();
|
private static bool CanSaveKoaloader() => ProgramData.ReadKoaloaderChoices().Any() || !AreKoaloaderSelectionsDefault();
|
||||||
|
|
||||||
private void OnSaveKoaloader(object sender, EventArgs e)
|
private void OnSaveKoaloader(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
|
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
|
||||||
foreach (Selection selection in Selection.AllSafe)
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
{
|
{
|
||||||
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
|
_ = choices.RemoveAll(c => c.platform == selection.Platform && c.id == selection.Id);
|
||||||
if (selection.KoaloaderProxy is not null and not Selection.DefaultKoaloaderProxy || !selection.Koaloader)
|
if (selection.KoaloaderProxy is not null and not Selection.DefaultKoaloaderProxy || !selection.Koaloader)
|
||||||
|
@ -1122,7 +1027,7 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
private void OnLoadKoaloader(object sender, EventArgs e)
|
private void OnLoadKoaloader(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
|
List<(Platform platform, string id, string proxy, bool enabled)> choices = ProgramData.ReadKoaloaderChoices().ToList();
|
||||||
foreach (Selection selection in Selection.AllSafe)
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
|
if (choices.Any(c => c.platform == selection.Platform && c.id == selection.Id))
|
||||||
{
|
{
|
||||||
(Platform platform, string id, string proxy, bool enabled)
|
(Platform platform, string id, string proxy, bool enabled)
|
||||||
|
@ -1155,7 +1060,7 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
|
|
||||||
private void OnResetKoaloader(object sender, EventArgs e)
|
private void OnResetKoaloader(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
foreach (Selection selection in Selection.AllSafe)
|
foreach (Selection selection in Selection.All.Keys)
|
||||||
{
|
{
|
||||||
selection.Koaloader = true;
|
selection.Koaloader = true;
|
||||||
selection.KoaloaderProxy = null;
|
selection.KoaloaderProxy = null;
|
||||||
|
@ -1169,7 +1074,7 @@ internal sealed partial class SelectForm : CustomForm
|
||||||
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
||||||
resetKoaloaderButton.Enabled = CanResetKoaloader();
|
resetKoaloaderButton.Enabled = CanResetKoaloader();
|
||||||
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
|
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
|
||||||
koaloaderAllCheckBox.Checked = Selection.AllSafe.All(selection => selection.Koaloader);
|
koaloaderAllCheckBox.Checked = Selection.All.Keys.All(selection => selection.Koaloader);
|
||||||
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
|
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ internal sealed partial class UpdateForm : CustomForm
|
||||||
|
|
||||||
private void StartProgram()
|
private void StartProgram()
|
||||||
{
|
{
|
||||||
SelectForm form = new();
|
SelectForm form = SelectForm.Current;
|
||||||
form.InheritLocation(this);
|
form.InheritLocation(this);
|
||||||
form.FormClosing += (_, _) => Close();
|
form.FormClosing += (_, _) => Close();
|
||||||
form.Show();
|
form.Show();
|
||||||
|
|
|
@ -35,11 +35,11 @@ internal static class ParadoxLauncher
|
||||||
if (paradoxLauncher is null)
|
if (paradoxLauncher is null)
|
||||||
return;
|
return;
|
||||||
paradoxLauncher.ExtraSelections.Clear();
|
paradoxLauncher.ExtraSelections.Clear();
|
||||||
foreach (Selection selection in Selection.AllEnabled.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
foreach (Selection selection in Selection.AllEnabled.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
|
||||||
_ = paradoxLauncher.ExtraSelections.Add(selection);
|
_ = paradoxLauncher.ExtraSelections.Add(selection);
|
||||||
if (paradoxLauncher.ExtraSelections.Count > 0)
|
if (paradoxLauncher.ExtraSelections.Count > 0)
|
||||||
return;
|
return;
|
||||||
foreach (Selection selection in Selection.AllSafe.Where(s => s != paradoxLauncher && s.Publisher == "Paradox Interactive"))
|
foreach (Selection selection in Selection.All.Keys.Where(s => !s.Equals(paradoxLauncher) && s.Publisher == "Paradox Interactive"))
|
||||||
_ = paradoxLauncher.ExtraSelections.Add(selection);
|
_ = paradoxLauncher.ExtraSelections.Add(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,64 +55,63 @@ internal static class SteamCMD
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return "";
|
return "";
|
||||||
if (Interlocked.CompareExchange(ref Locks[i], 1, 0) == 0)
|
if (Interlocked.CompareExchange(ref Locks[i], 1, 0) != 0)
|
||||||
|
continue;
|
||||||
|
if (appId != null)
|
||||||
|
{
|
||||||
|
_ = AttemptCount.TryGetValue(appId, out int count);
|
||||||
|
AttemptCount[appId] = ++count;
|
||||||
|
}
|
||||||
|
if (Program.Canceled)
|
||||||
|
return "";
|
||||||
|
ProcessStartInfo processStartInfo = new()
|
||||||
|
{
|
||||||
|
FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true,
|
||||||
|
UseShellExecute = false, Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
|
||||||
|
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8
|
||||||
|
};
|
||||||
|
Process process = Process.Start(processStartInfo);
|
||||||
|
StringBuilder output = new();
|
||||||
|
StringBuilder appInfo = new();
|
||||||
|
bool appInfoStarted = false;
|
||||||
|
DateTime lastOutput = DateTime.UtcNow;
|
||||||
|
while (process != null)
|
||||||
{
|
{
|
||||||
if (appId != null)
|
|
||||||
{
|
|
||||||
_ = AttemptCount.TryGetValue(appId, out int count);
|
|
||||||
AttemptCount[appId] = ++count;
|
|
||||||
}
|
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return "";
|
|
||||||
ProcessStartInfo processStartInfo = new()
|
|
||||||
{
|
{
|
||||||
FileName = FilePath, RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true,
|
|
||||||
UseShellExecute = false, Arguments = appId is null ? "+quit" : GetArguments(appId), CreateNoWindow = true,
|
|
||||||
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8
|
|
||||||
};
|
|
||||||
Process process = Process.Start(processStartInfo);
|
|
||||||
StringBuilder output = new();
|
|
||||||
StringBuilder appInfo = new();
|
|
||||||
bool appInfoStarted = false;
|
|
||||||
DateTime lastOutput = DateTime.UtcNow;
|
|
||||||
while (process != null)
|
|
||||||
{
|
|
||||||
if (Program.Canceled)
|
|
||||||
{
|
|
||||||
process.Kill(true);
|
|
||||||
process.Close();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int c = process.StandardOutput.Read();
|
|
||||||
if (c != -1)
|
|
||||||
{
|
|
||||||
lastOutput = DateTime.UtcNow;
|
|
||||||
char ch = (char)c;
|
|
||||||
if (ch == '{')
|
|
||||||
appInfoStarted = true;
|
|
||||||
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
|
|
||||||
}
|
|
||||||
DateTime now = DateTime.UtcNow;
|
|
||||||
TimeSpan timeDiff = now - lastOutput;
|
|
||||||
if (!(timeDiff.TotalSeconds > 0.1))
|
|
||||||
continue;
|
|
||||||
process.Kill(true);
|
process.Kill(true);
|
||||||
process.Close();
|
process.Close();
|
||||||
if (appId != null && output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
|
break;
|
||||||
{
|
|
||||||
AttemptCount[appId]++;
|
|
||||||
processStartInfo.Arguments = GetArguments(appId);
|
|
||||||
process = Process.Start(processStartInfo);
|
|
||||||
appInfoStarted = false;
|
|
||||||
_ = output.Clear();
|
|
||||||
_ = appInfo.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
_ = Interlocked.Decrement(ref Locks[i]);
|
int c = process.StandardOutput.Read();
|
||||||
return appInfo.ToString();
|
if (c != -1)
|
||||||
|
{
|
||||||
|
lastOutput = DateTime.UtcNow;
|
||||||
|
char ch = (char)c;
|
||||||
|
if (ch == '{')
|
||||||
|
appInfoStarted = true;
|
||||||
|
_ = appInfoStarted ? appInfo.Append(ch) : output.Append(ch);
|
||||||
|
}
|
||||||
|
DateTime now = DateTime.UtcNow;
|
||||||
|
TimeSpan timeDiff = now - lastOutput;
|
||||||
|
if (!(timeDiff.TotalSeconds > 0.1))
|
||||||
|
continue;
|
||||||
|
process.Kill(true);
|
||||||
|
process.Close();
|
||||||
|
if (appId != null && output.ToString().Contains($"No app info for AppID {appId} found, requesting..."))
|
||||||
|
{
|
||||||
|
AttemptCount[appId]++;
|
||||||
|
processStartInfo.Arguments = GetArguments(appId);
|
||||||
|
process = Process.Start(processStartInfo);
|
||||||
|
appInfoStarted = false;
|
||||||
|
_ = output.Clear();
|
||||||
|
_ = appInfo.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
_ = Interlocked.Decrement(ref Locks[i]);
|
||||||
|
return appInfo.ToString();
|
||||||
}
|
}
|
||||||
Thread.Sleep(200);
|
Thread.Sleep(200);
|
||||||
goto wait_for_lock;
|
goto wait_for_lock;
|
||||||
|
|
|
@ -30,10 +30,10 @@ internal static class SteamLibrary
|
||||||
{
|
{
|
||||||
if (Program.Canceled)
|
if (Program.Canceled)
|
||||||
return games;
|
return games;
|
||||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in
|
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) game in await GetGamesFromLibraryDirectory(
|
||||||
(await GetGamesFromLibraryDirectory(libraryDirectory)).Where(game
|
libraryDirectory))
|
||||||
=> !games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory)))
|
if (!games.Any(_game => _game.appId == game.appId && _game.gameDirectory == game.gameDirectory))
|
||||||
games.Add(game);
|
games.Add(game);
|
||||||
}
|
}
|
||||||
return games;
|
return games;
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,15 +38,9 @@ internal static class Program
|
||||||
internal static readonly string[] ProtectedGameDirectoryExceptions = Array.Empty<string>();
|
internal static readonly string[] ProtectedGameDirectoryExceptions = Array.Empty<string>();
|
||||||
|
|
||||||
internal static bool IsGameBlocked(string name, string directory = null)
|
internal static bool IsGameBlocked(string name, string directory = null)
|
||||||
{
|
=> BlockProtectedGames && (ProtectedGames.Contains(name) || directory is not null && !ProtectedGameDirectoryExceptions.Contains(name)
|
||||||
if (!BlockProtectedGames)
|
&& ProtectedGameDirectories.Any(path
|
||||||
return false;
|
=> (directory + path).DirectoryExists()));
|
||||||
if (ProtectedGames.Contains(name))
|
|
||||||
return true;
|
|
||||||
if (directory is null || ProtectedGameDirectoryExceptions.Contains(name))
|
|
||||||
return false;
|
|
||||||
return ProtectedGameDirectories.Any(path => (directory + path).DirectoryExists());
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool AreDllsLockedDialog(Form form, Selection selection)
|
internal static bool AreDllsLockedDialog(Form form, Selection selection)
|
||||||
{
|
{
|
||||||
|
@ -57,8 +51,8 @@ internal static class Program
|
||||||
using DialogForm dialogForm = new(form);
|
using DialogForm dialogForm = new(form);
|
||||||
if (dialogForm.Show(SystemIcons.Error,
|
if (dialogForm.Show(SystemIcons.Error,
|
||||||
$"ERROR: One or more DLLs crucial to unlocker installation are locked for {selection.Name}!"
|
$"ERROR: One or more DLLs crucial to unlocker installation are locked for {selection.Name}!"
|
||||||
+ "\n\nThis is commonly caused by the program/game being active or an anti-virus blocking access."
|
+ "\n\nPlease close the program/game or resolve your anti-virus and press retry to continue . . . ", "Retry", "Cancel")
|
||||||
+ "\n\nPlease close the program/game or resolve your anti-virus to continue . . . ", "Retry", "Cancel") == DialogResult.OK)
|
== DialogResult.OK)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Forms;
|
||||||
using CreamInstaller.Resources;
|
using CreamInstaller.Resources;
|
||||||
using CreamInstaller.Utility;
|
using CreamInstaller.Utility;
|
||||||
using static CreamInstaller.Resources.Resources;
|
using static CreamInstaller.Resources.Resources;
|
||||||
|
@ -27,8 +29,7 @@ internal sealed class Selection : IEquatable<Selection>
|
||||||
internal readonly string Name;
|
internal readonly string Name;
|
||||||
internal readonly Platform Platform;
|
internal readonly Platform Platform;
|
||||||
internal readonly string RootDirectory;
|
internal readonly string RootDirectory;
|
||||||
|
internal readonly TreeNode TreeNode;
|
||||||
internal bool Enabled;
|
|
||||||
internal string Icon;
|
internal string Icon;
|
||||||
internal bool Koaloader;
|
internal bool Koaloader;
|
||||||
internal string KoaloaderProxy;
|
internal string KoaloaderProxy;
|
||||||
|
@ -47,9 +48,19 @@ internal sealed class Selection : IEquatable<Selection>
|
||||||
DllDirectories = dllDirectories;
|
DllDirectories = dllDirectories;
|
||||||
ExecutableDirectories = executableDirectories;
|
ExecutableDirectories = executableDirectories;
|
||||||
_ = All.TryAdd(this, default);
|
_ = All.TryAdd(this, default);
|
||||||
|
TreeNode = new() { Tag = Platform, Name = Id, Text = Name };
|
||||||
|
SelectForm selectForm = SelectForm.Current;
|
||||||
|
if (selectForm is null)
|
||||||
|
return;
|
||||||
|
Enabled = selectForm.allCheckBox.Checked;
|
||||||
|
Koaloader = selectForm.koaloaderAllCheckBox.Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.AllSafe.Where(dlc => dlc.Selection.Equals(this));
|
internal static IEnumerable<Selection> AllEnabled => All.Keys.Where(s => s.Enabled);
|
||||||
|
|
||||||
|
internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
|
||||||
|
|
||||||
|
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.All.Keys.Where(dlc => dlc.Selection.Equals(this));
|
||||||
|
|
||||||
internal bool AreDllsLocked
|
internal bool AreDllsLocked
|
||||||
{
|
{
|
||||||
|
@ -92,10 +103,6 @@ internal sealed class Selection : IEquatable<Selection>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static HashSet<Selection> AllSafe => All.Keys.ToHashSet();
|
|
||||||
|
|
||||||
internal static HashSet<Selection> AllEnabled => All.Keys.Where(s => s.Enabled).ToHashSet();
|
|
||||||
|
|
||||||
public bool Equals(Selection other)
|
public bool Equals(Selection other)
|
||||||
=> other is not null && (ReferenceEquals(this, other) || Id == other.Id && Platform == other.Platform && RootDirectory == other.RootDirectory);
|
=> other is not null && (ReferenceEquals(this, other) || Id == other.Id && Platform == other.Platform && RootDirectory == other.RootDirectory);
|
||||||
|
|
||||||
|
@ -106,6 +113,7 @@ internal sealed class Selection : IEquatable<Selection>
|
||||||
private void Remove()
|
private void Remove()
|
||||||
{
|
{
|
||||||
_ = All.TryRemove(this, out _);
|
_ = All.TryRemove(this, out _);
|
||||||
|
TreeNode.Remove();
|
||||||
foreach (SelectionDLC dlc in DLC)
|
foreach (SelectionDLC dlc in DLC)
|
||||||
dlc.Selection = null;
|
dlc.Selection = null;
|
||||||
}
|
}
|
||||||
|
@ -134,11 +142,11 @@ internal sealed class Selection : IEquatable<Selection>
|
||||||
|
|
||||||
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
||||||
{
|
{
|
||||||
foreach (Selection selection in AllSafe)
|
foreach (Selection selection in All.Keys.ToHashSet())
|
||||||
selection.Validate(programsToScan);
|
selection.Validate(programsToScan);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Selection FromPlatformId(Platform platform, string gameId) => AllSafe.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
|
internal static Selection FromPlatformId(Platform platform, string gameId) => All.Keys.FirstOrDefault(s => s.Platform == platform && s.Id == gameId);
|
||||||
|
|
||||||
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is Selection other && Equals(other);
|
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is Selection other && Equals(other);
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace CreamInstaller;
|
namespace CreamInstaller;
|
||||||
|
|
||||||
public enum DLCType
|
public enum DLCType
|
||||||
{
|
{
|
||||||
None = 0, Steam, SteamHidden, EpicCatalogItem,
|
None = 0, Steam, SteamHidden,
|
||||||
EpicEntitlement
|
EpicCatalogItem, EpicEntitlement
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class SelectionDLC : IEquatable<SelectionDLC>
|
internal sealed class SelectionDLC : IEquatable<SelectionDLC>
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<SelectionDLC, byte> All = new();
|
internal static readonly ConcurrentDictionary<SelectionDLC, byte> All = new();
|
||||||
|
|
||||||
internal readonly string Id;
|
internal readonly string Id;
|
||||||
internal readonly string Name;
|
internal readonly string Name;
|
||||||
|
internal readonly TreeNode TreeNode;
|
||||||
internal readonly DLCType Type;
|
internal readonly DLCType Type;
|
||||||
|
|
||||||
internal bool Enabled;
|
|
||||||
internal string Icon;
|
internal string Icon;
|
||||||
internal string Product;
|
internal string Product;
|
||||||
internal string Publisher;
|
internal string Publisher;
|
||||||
|
@ -30,25 +29,38 @@ internal sealed class SelectionDLC : IEquatable<SelectionDLC>
|
||||||
Type = type;
|
Type = type;
|
||||||
Id = id;
|
Id = id;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
TreeNode = new() { Tag = Type, Name = Id, Text = Name };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool Enabled { get => TreeNode.Checked; set => TreeNode.Checked = value; }
|
||||||
|
|
||||||
internal Selection Selection
|
internal Selection Selection
|
||||||
{
|
{
|
||||||
get => selection;
|
get => selection;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
if (ReferenceEquals(selection, value))
|
||||||
|
return;
|
||||||
selection = value;
|
selection = value;
|
||||||
_ = value is null ? All.TryRemove(this, out _) : All.TryAdd(this, default);
|
if (value is null)
|
||||||
|
{
|
||||||
|
_ = All.TryRemove(this, out _);
|
||||||
|
TreeNode.Remove();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_ = All.TryAdd(this, default);
|
||||||
|
_ = value.TreeNode.Nodes.Add(TreeNode);
|
||||||
|
Enabled = Name != "Unknown" && value.Enabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static HashSet<SelectionDLC> AllSafe => All.Keys.ToHashSet();
|
|
||||||
|
|
||||||
public bool Equals(SelectionDLC other) => other is not null && (ReferenceEquals(this, other) || Id == other.Id && Type == other.Type);
|
public bool Equals(SelectionDLC other) => other is not null && (ReferenceEquals(this, other) || Id == other.Id && Type == other.Type);
|
||||||
|
|
||||||
internal static SelectionDLC GetOrCreate(DLCType type, string id, string name) => FromTypeId(type, id) ?? new SelectionDLC(type, id, name);
|
internal static SelectionDLC GetOrCreate(DLCType type, string id, string name) => FromTypeId(type, id) ?? new SelectionDLC(type, id, name);
|
||||||
|
|
||||||
internal static SelectionDLC FromTypeId(DLCType Type, string dlcId) => AllSafe.FirstOrDefault(dlc => dlc.Type == Type && dlc.Id == dlcId);
|
internal static SelectionDLC FromTypeId(DLCType Type, string dlcId) => All.Keys.FirstOrDefault(dlc => dlc.Type == Type && dlc.Id == dlcId);
|
||||||
|
|
||||||
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is SelectionDLC other && Equals(other);
|
public override bool Equals(object obj) => ReferenceEquals(this, obj) || obj is SelectionDLC other && Equals(other);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue