v4.9.1
- Hash & concurrency fixes to stop duplicate games & DLC - Threading fixes for significantly faster operations - More significant refactoring to prevent possible issues
This commit is contained in:
parent
0974f78889
commit
1669f8c887
22 changed files with 263 additions and 272 deletions
|
@ -76,16 +76,24 @@ internal sealed class CustomTreeView : TreeView
|
|||
Form form = FindForm();
|
||||
if (form is not SelectForm and not SelectDialogForm)
|
||||
return;
|
||||
string platformId = node.Name;
|
||||
string id = node.Name;
|
||||
Platform platform = (node.Tag as Platform?).GetValueOrDefault(Platform.None);
|
||||
if (string.IsNullOrWhiteSpace(platformId) || platform is Platform.None)
|
||||
DLCType dlcType = (node.Tag as DLCType?).GetValueOrDefault(DLCType.None);
|
||||
if (string.IsNullOrWhiteSpace(id) || platform is Platform.None && dlcType is DLCType.None)
|
||||
return;
|
||||
Color color = highlighted
|
||||
? C1
|
||||
: Enabled
|
||||
? C2
|
||||
: C3;
|
||||
string text = platform.ToString();
|
||||
string text;
|
||||
if (dlcType is not DLCType.None)
|
||||
{
|
||||
SelectionDLC dlc = SelectionDLC.FromTypeId(dlcType, id);
|
||||
text = dlc is not null ? dlc.Selection.Platform.ToString() : dlcType.ToString();
|
||||
}
|
||||
else
|
||||
text = platform.ToString();
|
||||
Size size = TextRenderer.MeasureText(graphics, text, font);
|
||||
bounds = bounds with { X = bounds.X + bounds.Width, Width = size.Width };
|
||||
selectionBounds = new(selectionBounds.Location, selectionBounds.Size + bounds.Size with { Height = 0 });
|
||||
|
@ -99,7 +107,7 @@ internal sealed class CustomTreeView : TreeView
|
|||
: Enabled
|
||||
? C5
|
||||
: C6;
|
||||
text = platformId;
|
||||
text = id;
|
||||
size = TextRenderer.MeasureText(graphics, text, font);
|
||||
const int left = -4;
|
||||
bounds = bounds with { X = bounds.X + bounds.Width + left, Width = size.Width };
|
||||
|
@ -110,7 +118,7 @@ internal sealed class CustomTreeView : TreeView
|
|||
}
|
||||
if (form is SelectForm)
|
||||
{
|
||||
Selection selection = Selection.FromPlatformId(platform, platformId);
|
||||
Selection selection = Selection.FromPlatformId(platform, id);
|
||||
if (selection is not null)
|
||||
{
|
||||
if (bounds == node.Bounds)
|
||||
|
@ -188,15 +196,15 @@ internal sealed class CustomTreeView : TreeView
|
|||
return;
|
||||
if (comboBoxBounds.Count > 0 && selectForm is not null)
|
||||
foreach (KeyValuePair<Selection, Rectangle> pair in comboBoxBounds)
|
||||
if (!Selection.All.Contains(pair.Key))
|
||||
if (!Selection.All.ContainsKey(pair.Key))
|
||||
_ = comboBoxBounds.Remove(pair.Key);
|
||||
else if (pair.Value.Contains(clickPoint))
|
||||
{
|
||||
List<string> proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader", StringComparison.Ordinal)).Select(p =>
|
||||
HashSet<string> proxies = EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)).Select(p =>
|
||||
{
|
||||
p.GetProxyInfoFromIdentifier(out string proxyName, out _);
|
||||
return proxyName;
|
||||
}).Distinct().ToList();
|
||||
}).ToHashSet();
|
||||
comboBoxDropDown ??= new();
|
||||
comboBoxDropDown.ShowItemToolTips = false;
|
||||
comboBoxDropDown.Items.Clear();
|
||||
|
@ -222,7 +230,7 @@ internal sealed class CustomTreeView : TreeView
|
|||
break;
|
||||
}
|
||||
foreach (KeyValuePair<Selection, Rectangle> pair in checkBoxBounds)
|
||||
if (!Selection.All.Contains(pair.Key))
|
||||
if (!Selection.All.ContainsKey(pair.Key))
|
||||
_ = checkBoxBounds.Remove(pair.Key);
|
||||
else if (pair.Value.Contains(clickPoint))
|
||||
{
|
||||
|
|
|
@ -8,12 +8,10 @@ namespace CreamInstaller.Components;
|
|||
internal static class PlatformIdComparer
|
||||
{
|
||||
private static StringComparer stringComparer;
|
||||
|
||||
private static NodeComparer nodeComparer;
|
||||
|
||||
private static NodeNameComparer nodeNameComparer;
|
||||
|
||||
private static NodeTextComparer nodeTextComparer;
|
||||
|
||||
internal static StringComparer String => stringComparer ??= new();
|
||||
internal static NodeComparer Node => nodeComparer ??= new();
|
||||
internal static NodeNameComparer NodeName => nodeNameComparer ??= new();
|
||||
|
@ -39,15 +37,17 @@ internal sealed class StringComparer : IComparer<string>
|
|||
internal sealed class NodeComparer : IComparer<TreeNode>
|
||||
{
|
||||
public int Compare(TreeNode a, TreeNode b)
|
||||
=> a?.Tag is not Platform A
|
||||
=> a is null
|
||||
? 1
|
||||
: b?.Tag is not Platform B
|
||||
: b is null
|
||||
? -1
|
||||
: A > B
|
||||
? 1
|
||||
: A < B
|
||||
? -1
|
||||
: 0;
|
||||
: a.Tag is not Platform pA || b.Tag is not Platform pB
|
||||
? 0
|
||||
: pA > pB
|
||||
? 1
|
||||
: pA < pB
|
||||
? -1
|
||||
: 0;
|
||||
}
|
||||
|
||||
internal sealed class NodeNameComparer : IComparer
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||
<Version>4.9.0</Version>
|
||||
<Version>4.9.1</Version>
|
||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||
<Company>CreamInstaller</Company>
|
||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Components;
|
||||
using CreamInstaller.Resources;
|
||||
|
@ -15,7 +14,7 @@ namespace CreamInstaller.Forms;
|
|||
|
||||
internal sealed partial class InstallForm : CustomForm
|
||||
{
|
||||
private readonly List<Selection> disabledSelections = new();
|
||||
private readonly HashSet<Selection> disabledSelections = new();
|
||||
|
||||
private readonly int programCount = Selection.AllEnabled.Count;
|
||||
private readonly bool uninstalling;
|
||||
|
@ -87,7 +86,6 @@ internal sealed partial class InstallForm : CustomForm
|
|||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in incorrect directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||
}
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
if (uninstalling || !selection.Koaloader)
|
||||
foreach ((string directory, BinaryType _) in selection.ExecutableDirectories)
|
||||
|
@ -101,7 +99,6 @@ internal sealed partial class InstallForm : CustomForm
|
|||
UpdateUser("Uninstalling Koaloader from " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Uninstall(directory, selection.RootDirectory, this);
|
||||
}
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
bool uninstallProxy = uninstalling || selection.Koaloader;
|
||||
int count = selection.DllDirectories.Count, cur = 0;
|
||||
|
@ -173,7 +170,6 @@ internal sealed partial class InstallForm : CustomForm
|
|||
}
|
||||
}
|
||||
UpdateProgress(++cur / count * 100);
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
if (selection.Koaloader && !uninstalling)
|
||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||
|
@ -182,14 +178,13 @@ internal sealed partial class InstallForm : CustomForm
|
|||
throw new CustomMessageException("The operation was canceled.");
|
||||
UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ", LogTextBox.Operation);
|
||||
await Koaloader.Install(directory, binaryType, selection, selection.RootDirectory, this);
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
UpdateProgress(100);
|
||||
}
|
||||
|
||||
private async Task Operate()
|
||||
{
|
||||
List<Selection> programSelections = Selection.AllEnabled;
|
||||
HashSet<Selection> programSelections = Selection.AllEnabled;
|
||||
operationsCount = programSelections.Count;
|
||||
completeOperationsCount = 0;
|
||||
foreach (Selection selection in programSelections)
|
||||
|
@ -201,7 +196,7 @@ internal sealed partial class InstallForm : CustomForm
|
|||
await OperateFor(selection);
|
||||
UpdateUser($"Operation succeeded for {selection.Name}.", LogTextBox.Success);
|
||||
selection.Enabled = false;
|
||||
disabledSelections.Add(selection);
|
||||
_ = disabledSelections.Add(selection);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
@ -210,7 +205,7 @@ internal sealed partial class InstallForm : CustomForm
|
|||
++completeOperationsCount;
|
||||
}
|
||||
Program.Cleanup();
|
||||
List<Selection> failedSelections = Selection.AllEnabled;
|
||||
HashSet<Selection> failedSelections = Selection.AllEnabled;
|
||||
if (failedSelections.Count > 0)
|
||||
if (failedSelections.Count == 1)
|
||||
throw new CustomMessageException($"Operation failed for {failedSelections.First().Name}.");
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
@ -128,30 +129,16 @@ internal sealed partial class SelectForm : CustomForm
|
|||
HashSet<string> dllDirectories = await ParadoxLauncher.InstallPath.GetDllDirectoriesFromGameDirectory(Platform.Paradox);
|
||||
if (dllDirectories is not null)
|
||||
{
|
||||
Selection selection = Selection.GetOrCreate(Platform.Paradox, "PL", "Paradox Launcher", ParadoxLauncher.InstallPath, dllDirectories,
|
||||
await ParadoxLauncher.InstallPath.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper")));
|
||||
if (uninstallAll)
|
||||
{
|
||||
Selection bareSelection = Selection.FromPlatformId(Platform.Paradox, "PL") ?? new();
|
||||
bareSelection.Enabled = true;
|
||||
bareSelection.Id = "PL";
|
||||
bareSelection.Name = "Paradox Launcher";
|
||||
bareSelection.RootDirectory = ParadoxLauncher.InstallPath;
|
||||
bareSelection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(bareSelection.RootDirectory);
|
||||
bareSelection.DllDirectories = dllDirectories;
|
||||
bareSelection.Platform = Platform.Paradox;
|
||||
}
|
||||
selection.Enabled = true;
|
||||
else
|
||||
{
|
||||
Selection selection = Selection.FromPlatformId(Platform.Paradox, "PL") ?? new();
|
||||
if (allCheckBox.Checked)
|
||||
selection.Enabled = true;
|
||||
if (koaloaderAllCheckBox.Checked)
|
||||
selection.Koaloader = true;
|
||||
selection.Id = "PL";
|
||||
selection.Name = "Paradox Launcher";
|
||||
selection.RootDirectory = ParadoxLauncher.InstallPath;
|
||||
selection.ExecutableDirectories = await ParadoxLauncher.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Paradox;
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Paradox && s.Name == selection.Id) ?? new TreeNode();
|
||||
programNode.Tag = selection.Platform;
|
||||
programNode.Name = selection.Id;
|
||||
|
@ -166,7 +153,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
int steamGamesToCheck;
|
||||
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Steam))
|
||||
{
|
||||
HashSet<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames = await SteamLibrary.GetGames();
|
||||
List<(string appId, string name, string branch, int buildId, string gameDirectory)> steamGames = await SteamLibrary.GetGames();
|
||||
steamGamesToCheck = steamGames.Count;
|
||||
foreach ((string appId, string name, string branch, int buildId, string gameDirectory) in steamGames)
|
||||
{
|
||||
|
@ -191,14 +178,9 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (uninstallAll)
|
||||
{
|
||||
Selection bareSelection = Selection.FromPlatformId(Platform.Steam, appId) ?? new Selection();
|
||||
Selection bareSelection = Selection.GetOrCreate(Platform.Steam, appId, name, gameDirectory, dllDirectories,
|
||||
await gameDirectory.GetExecutableDirectories(true));
|
||||
bareSelection.Enabled = true;
|
||||
bareSelection.Id = appId;
|
||||
bareSelection.Name = name;
|
||||
bareSelection.RootDirectory = gameDirectory;
|
||||
bareSelection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(bareSelection.RootDirectory);
|
||||
bareSelection.DllDirectories = dllDirectories;
|
||||
bareSelection.Platform = Platform.Steam;
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
|
@ -214,14 +196,15 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
ConcurrentDictionary<string, SelectionDLC> dlc = new();
|
||||
ConcurrentDictionary<SelectionDLC, byte> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<string> dlcIds = new();
|
||||
HashSet<string> dlcIds = new();
|
||||
if (appData is not null)
|
||||
dlcIds.AddRange(await SteamStore.ParseDlcAppIds(appData));
|
||||
foreach (string dlcId in await SteamStore.ParseDlcAppIds(appData))
|
||||
_ = dlcIds.Add(dlcId);
|
||||
if (appInfo is not null)
|
||||
dlcIds.AddRange(await SteamCMD.ParseDlcAppIds(appInfo));
|
||||
dlcIds = dlcIds.Distinct().ToList();
|
||||
foreach (string dlcId in await SteamCMD.ParseDlcAppIds(appInfo))
|
||||
_ = dlcIds.Add(dlcId);
|
||||
if (dlcIds.Count > 0)
|
||||
foreach (string dlcAppId in dlcIds)
|
||||
{
|
||||
|
@ -291,20 +274,20 @@ internal sealed partial class SelectForm : CustomForm
|
|||
if (Program.Canceled)
|
||||
return;
|
||||
if (!string.IsNullOrWhiteSpace(fullGameName))
|
||||
dlc[fullGameAppId] = new()
|
||||
{
|
||||
Id = fullGameAppId, Type = fullGameOnSteamStore ? DLCType.Steam : DLCType.SteamHidden, Name = fullGameName,
|
||||
Icon = fullGameIcon
|
||||
};
|
||||
{
|
||||
SelectionDLC fullGameDlc = SelectionDLC.GetOrCreate(fullGameOnSteamStore ? DLCType.Steam : DLCType.SteamHidden,
|
||||
fullGameAppId, fullGameName);
|
||||
fullGameDlc.Icon = fullGameIcon;
|
||||
_ = dlc.TryAdd(fullGameDlc, default);
|
||||
}
|
||||
}
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(dlcName))
|
||||
dlcName = "Unknown";
|
||||
dlc[dlcAppId] = new()
|
||||
{
|
||||
Id = dlcAppId, Type = onSteamStore ? DLCType.Steam : DLCType.SteamHidden, Name = dlcName, Icon = dlcIcon
|
||||
};
|
||||
SelectionDLC _dlc = SelectionDLC.GetOrCreate(onSteamStore ? DLCType.Steam : DLCType.SteamHidden, dlcAppId, dlcName);
|
||||
_dlc.Icon = dlcIcon;
|
||||
_ = dlc.TryAdd(_dlc, default);
|
||||
RemoveFromRemainingDLCs(dlcAppId);
|
||||
});
|
||||
dlcTasks.Add(task);
|
||||
|
@ -328,17 +311,12 @@ internal sealed partial class SelectForm : CustomForm
|
|||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
Selection selection = Selection.FromPlatformId(Platform.Steam, appId) ?? new Selection();
|
||||
Selection selection = Selection.GetOrCreate(Platform.Steam, appId, appData?.Name ?? name, gameDirectory, dllDirectories,
|
||||
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.Id = appId;
|
||||
selection.Name = appData?.Name ?? name;
|
||||
selection.RootDirectory = gameDirectory;
|
||||
selection.ExecutableDirectories = await SteamLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Steam;
|
||||
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
|
||||
|
@ -351,21 +329,21 @@ internal sealed partial class SelectForm : CustomForm
|
|||
{
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Steam && s.Name == appId) ?? new TreeNode();
|
||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == appId) ?? new TreeNode();
|
||||
programNode.Tag = selection.Platform;
|
||||
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)
|
||||
return;
|
||||
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;
|
||||
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;
|
||||
|
@ -382,7 +360,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Epic))
|
||||
{
|
||||
HashSet<Manifest> epicGames = await EpicLibrary.GetGames();
|
||||
List<Manifest> epicGames = await EpicLibrary.GetGames();
|
||||
foreach (Manifest manifest in epicGames)
|
||||
{
|
||||
string @namespace = manifest.CatalogNamespace;
|
||||
|
@ -405,22 +383,17 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (uninstallAll)
|
||||
{
|
||||
Selection bareSelection = Selection.FromPlatformId(Platform.Epic, @namespace) ?? new Selection();
|
||||
Selection bareSelection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
|
||||
await directory.GetExecutableDirectories(true));
|
||||
bareSelection.Enabled = true;
|
||||
bareSelection.Id = @namespace;
|
||||
bareSelection.Name = name;
|
||||
bareSelection.RootDirectory = directory;
|
||||
bareSelection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(bareSelection.RootDirectory);
|
||||
bareSelection.DllDirectories = dllDirectories;
|
||||
bareSelection.Platform = Platform.Epic;
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
ConcurrentDictionary<string, SelectionDLC> catalogItems = new();
|
||||
ConcurrentDictionary<SelectionDLC, byte> catalogItems = new();
|
||||
// get catalog items
|
||||
ConcurrentDictionary<string, SelectionDLC> entitlements = new();
|
||||
ConcurrentDictionary<SelectionDLC, byte> entitlements = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<(string id, string name, string product, string icon, string developer)>
|
||||
entitlementIds = await EpicStore.QueryEntitlements(@namespace);
|
||||
|
@ -434,11 +407,11 @@ internal sealed partial class SelectForm : CustomForm
|
|||
{
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
entitlements[id] = new()
|
||||
{
|
||||
Id = id, Name = name, Product = product, Icon = icon,
|
||||
Publisher = developer
|
||||
};
|
||||
SelectionDLC entitlement = SelectionDLC.GetOrCreate(DLCType.EpicEntitlement, id, name);
|
||||
entitlement.Icon = icon;
|
||||
entitlement.Product = product;
|
||||
entitlement.Publisher = developer;
|
||||
_ = entitlements.TryAdd(entitlement, default);
|
||||
RemoveFromRemainingDLCs(id);
|
||||
});
|
||||
dlcTasks.Add(task);
|
||||
|
@ -456,24 +429,19 @@ internal sealed partial class SelectForm : CustomForm
|
|||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
Selection selection = Selection.FromPlatformId(Platform.Epic, @namespace) ?? new Selection();
|
||||
Selection selection = Selection.GetOrCreate(Platform.Epic, @namespace, name, directory, dllDirectories,
|
||||
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;
|
||||
selection.Id = @namespace;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = directory;
|
||||
selection.ExecutableDirectories = await EpicLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Epic;
|
||||
foreach (KeyValuePair<string, SelectionDLC> dlc in entitlements.Where(dlc => dlc.Value.Name == selection.Name))
|
||||
foreach ((SelectionDLC dlc, _) in entitlements.Where(dlc => dlc.Key.Name == selection.Name))
|
||||
{
|
||||
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;
|
||||
selection.Product = "https://www.epicgames.com/store/product/" + dlc.Product;
|
||||
selection.Icon = dlc.Icon;
|
||||
selection.Publisher = dlc.Publisher;
|
||||
}
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
|
@ -481,7 +449,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
{
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Epic && s.Name == @namespace) ?? new TreeNode();
|
||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == @namespace) ?? new TreeNode();
|
||||
programNode.Tag = selection.Platform;
|
||||
programNode.Name = @namespace;
|
||||
programNode.Text = name;
|
||||
|
@ -489,20 +457,21 @@ internal sealed partial class SelectForm : CustomForm
|
|||
if (programNode.TreeView is null)
|
||||
_ = selectionTreeView.Nodes.Add(programNode);
|
||||
if (!catalogItems.IsEmpty)
|
||||
/*TreeNode catalogItemsNode = treeNodes.Find(node => node.Tag is Platform.Epic && node.Name == @namespace + "_catalogItems") ?? new();
|
||||
/*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)
|
||||
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;
|
||||
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;
|
||||
|
@ -511,20 +480,21 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (entitlements.IsEmpty)
|
||||
return;
|
||||
/*TreeNode entitlementsNode = treeNodes.Find(node => node.Tag is Platform.Epic && node.Name == @namespace + "_entitlements") ?? new();
|
||||
/*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)
|
||||
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;
|
||||
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;
|
||||
|
@ -541,7 +511,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (uninstallAll || programsToScan.Any(c => c.platform is Platform.Ubisoft))
|
||||
{
|
||||
HashSet<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
|
||||
List<(string gameId, string name, string gameDirectory)> ubisoftGames = await UbisoftLibrary.GetGames();
|
||||
foreach ((string gameId, string name, string gameDirectory) in ubisoftGames)
|
||||
{
|
||||
if (Program.Canceled)
|
||||
|
@ -561,36 +531,26 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
if (uninstallAll)
|
||||
{
|
||||
Selection bareSelection = Selection.FromPlatformId(Platform.Ubisoft, gameId) ?? new Selection();
|
||||
Selection bareSelection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
|
||||
await gameDirectory.GetExecutableDirectories(true));
|
||||
bareSelection.Enabled = true;
|
||||
bareSelection.Id = gameId;
|
||||
bareSelection.Name = name;
|
||||
bareSelection.RootDirectory = gameDirectory;
|
||||
bareSelection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(bareSelection.RootDirectory);
|
||||
bareSelection.DllDirectories = dllDirectories;
|
||||
bareSelection.Platform = Platform.Ubisoft;
|
||||
RemoveFromRemainingGames(name);
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
Selection selection = Selection.FromPlatformId(Platform.Ubisoft, gameId) ?? new Selection();
|
||||
Selection selection = Selection.GetOrCreate(Platform.Ubisoft, gameId, name, gameDirectory, dllDirectories,
|
||||
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.Id = gameId;
|
||||
selection.Name = name;
|
||||
selection.RootDirectory = gameDirectory;
|
||||
selection.ExecutableDirectories = await UbisoftLibrary.GetExecutableDirectories(selection.RootDirectory);
|
||||
selection.DllDirectories = dllDirectories;
|
||||
selection.Platform = Platform.Ubisoft;
|
||||
selection.Icon = IconGrabber.GetDomainFaviconUrl("store.ubi.com");
|
||||
selectionTreeView.Invoke(delegate
|
||||
{
|
||||
if (Program.Canceled)
|
||||
return;
|
||||
TreeNode programNode = treeNodes.Find(s => s.Tag is Platform.Ubisoft && s.Name == gameId) ?? new TreeNode();
|
||||
TreeNode programNode = treeNodes.Find(s => (Platform)s.Tag == selection.Platform && s.Name == gameId) ?? new TreeNode();
|
||||
programNode.Tag = selection.Platform;
|
||||
programNode.Name = gameId;
|
||||
programNode.Text = name;
|
||||
|
@ -738,7 +698,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
OnLoadDlc(null, null);
|
||||
OnLoadKoaloader(null, null);
|
||||
HideProgressBar();
|
||||
selectionTreeView.Enabled = Selection.All.Count > 0;
|
||||
selectionTreeView.Enabled = !Selection.All.IsEmpty;
|
||||
allCheckBox.Enabled = selectionTreeView.Enabled;
|
||||
koaloaderAllCheckBox.Enabled = selectionTreeView.Enabled;
|
||||
noneFoundLabel.Visible = !selectionTreeView.Enabled;
|
||||
|
@ -791,14 +751,16 @@ internal sealed partial class SelectForm : CustomForm
|
|||
}
|
||||
|
||||
private static void SyncNodeDescendants(TreeNode node)
|
||||
=> node.Nodes.Cast<TreeNode>().ToList().ForEach(childNode =>
|
||||
{
|
||||
foreach (TreeNode childNode in node.Nodes)
|
||||
{
|
||||
if (childNode.Text == "Unknown")
|
||||
return;
|
||||
childNode.Checked = node.Checked;
|
||||
SyncNode(childNode);
|
||||
SyncNodeDescendants(childNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void SyncNode(TreeNode node)
|
||||
{
|
||||
|
@ -810,7 +772,8 @@ internal sealed partial class SelectForm : CustomForm
|
|||
selection.Enabled = node.Checked;
|
||||
return;
|
||||
}
|
||||
SelectionDLC dlc = SelectionDLC.FromPlatformId(platform, id);
|
||||
DLCType type = (DLCType)node.Tag;
|
||||
SelectionDLC dlc = SelectionDLC.FromTypeId(type, id);
|
||||
if (dlc is not null)
|
||||
dlc.Enabled = node.Checked;
|
||||
}
|
||||
|
@ -867,10 +830,10 @@ internal sealed partial class SelectForm : CustomForm
|
|||
Selection selection = Selection.FromPlatformId(platform, id);
|
||||
SelectionDLC dlc = null;
|
||||
if (selection is null)
|
||||
dlc = SelectionDLC.FromPlatformId(platform, id);
|
||||
dlc = SelectionDLC.FromTypeId((DLCType)node.Tag, id);
|
||||
Selection dlcParentSelection = null;
|
||||
if (dlc is not null)
|
||||
dlcParentSelection = Selection.FromPlatformId(platform, dlc.Selection.Id);
|
||||
dlcParentSelection = dlc.Selection;
|
||||
if (selection is null && dlcParentSelection is null)
|
||||
return;
|
||||
ContextMenuItem header = id == "PL"
|
||||
|
@ -922,10 +885,10 @@ internal sealed partial class SelectForm : CustomForm
|
|||
_ = 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())
|
||||
foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories)
|
||||
_ = 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();
|
||||
HashSet<string> directories = selection.DllDirectories;
|
||||
int steam = 0, epic = 0, r1 = 0, r2 = 0;
|
||||
if (selection.Platform is Platform.Steam or Platform.Paradox)
|
||||
foreach (string directory in directories)
|
||||
|
@ -1020,7 +983,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
|
||||
private void OnAccept(bool uninstall = false)
|
||||
{
|
||||
if (Selection.All.Count < 1)
|
||||
if (Selection.All.IsEmpty)
|
||||
return;
|
||||
if (Selection.AllEnabled.Any(selection => !Program.AreDllsLockedDialog(this, selection)))
|
||||
return;
|
||||
|
@ -1097,12 +1060,12 @@ internal sealed partial class SelectForm : CustomForm
|
|||
foreach (TreeNode node in TreeNodes)
|
||||
if (node.Parent is { } parent && node.Tag is Platform platform)
|
||||
{
|
||||
if (node.Text == "Unknown" ? node.Checked : !node.Checked)
|
||||
if ((node.Text == "Unknown" ? node.Checked : !node.Checked)
|
||||
&& !choices.Any(c => c.platform == platform && c.gameId == parent.Name && c.dlcId == node.Name))
|
||||
choices.Add((platform, node.Parent.Name, node.Name));
|
||||
else
|
||||
_ = choices.RemoveAll(n => n.platform == platform && n.gameId == parent.Name && n.dlcId == node.Name);
|
||||
}
|
||||
choices = choices.Distinct().ToList();
|
||||
ProgramData.WriteDlcChoices(choices);
|
||||
loadButton.Enabled = CanLoadDlc();
|
||||
saveButton.Enabled = CanSaveDlc();
|
||||
|
@ -1206,7 +1169,7 @@ internal sealed partial class SelectForm : CustomForm
|
|||
saveKoaloaderButton.Enabled = CanSaveKoaloader();
|
||||
resetKoaloaderButton.Enabled = CanResetKoaloader();
|
||||
koaloaderAllCheckBox.CheckedChanged -= OnKoaloaderAllCheckBoxChanged;
|
||||
koaloaderAllCheckBox.Checked = Selection.AllSafe.TrueForAll(selection => selection.Koaloader);
|
||||
koaloaderAllCheckBox.Checked = Selection.AllSafe.All(selection => selection.Koaloader);
|
||||
koaloaderAllCheckBox.CheckedChanged += OnKoaloaderAllCheckBoxChanged;
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ internal sealed partial class UpdateForm : CustomForm
|
|||
throw new TaskCanceledException();
|
||||
using HttpResponseMessage response = await HttpClientManager.HttpClient.GetAsync(latestRelease.Asset.BrowserDownloadUrl,
|
||||
HttpCompletionOption.ResponseHeadersRead, cancellation.Token);
|
||||
response.EnsureSuccessStatusCode();
|
||||
_ = response.EnsureSuccessStatusCode();
|
||||
if (cancellation is null || Program.Canceled)
|
||||
throw new TaskCanceledException();
|
||||
await using Stream download = await response.Content.ReadAsStreamAsync(cancellation.Token);
|
||||
|
@ -196,18 +196,18 @@ internal sealed partial class UpdateForm : CustomForm
|
|||
string properExecutable = Path.GetFileName(ExecutablePath);
|
||||
string properExecutablePath = Path.Combine(currentDirectory!, properExecutable!);
|
||||
StringBuilder commands = new();
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"\nTASKKILL /F /T /PID {Program.CurrentProcessId}");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $":LOOP");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"TASKLIST | FIND \" {Program.CurrentProcessId}\" ");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"IF NOT ERRORLEVEL 1 (");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $" TIMEOUT /T 1");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $" GOTO LOOP");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $")");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"DEL /F /Q \"{currentPath}\"");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"DEL /F /Q \"{properExecutablePath}\"");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"MOVE /Y \"{ExecutablePath}\" \"{properExecutablePath}\"");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"START \"\" /D \"{currentDirectory}\" \"{properExecutable}\"");
|
||||
commands.AppendLine(CultureInfo.InvariantCulture, $"EXIT");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"\nTASKKILL /F /T /PID {Program.CurrentProcessId}");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $":LOOP");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"TASKLIST | FIND \" {Program.CurrentProcessId}\" ");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"IF NOT ERRORLEVEL 1 (");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $" TIMEOUT /T 1");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $" GOTO LOOP");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $")");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"DEL /F /Q \"{currentPath}\"");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"DEL /F /Q \"{properExecutablePath}\"");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"MOVE /Y \"{ExecutablePath}\" \"{properExecutablePath}\"");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"START \"\" /D \"{currentDirectory}\" \"{properExecutable}\"");
|
||||
_ = commands.AppendLine(CultureInfo.InvariantCulture, $"EXIT");
|
||||
UpdaterPath.WriteFile(commands.ToString(), true, this);
|
||||
Process process = new();
|
||||
ProcessStartInfo startInfo = new()
|
||||
|
@ -216,7 +216,7 @@ internal sealed partial class UpdateForm : CustomForm
|
|||
CreateNoWindow = true
|
||||
};
|
||||
process.StartInfo = startInfo;
|
||||
process.Start();
|
||||
_ = process.Start();
|
||||
return;
|
||||
}
|
||||
if (!retry)
|
||||
|
|
|
@ -6,7 +6,6 @@ using CreamInstaller.Platforms.Epic.Heroic;
|
|||
using CreamInstaller.Utility;
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Epic;
|
||||
|
||||
|
@ -26,13 +25,10 @@ internal static class EpicLibrary
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
|
||||
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||
|
||||
internal static async Task<HashSet<Manifest>> GetGames()
|
||||
internal static async Task<List<Manifest>> GetGames()
|
||||
=> await Task.Run(async () =>
|
||||
{
|
||||
HashSet<Manifest> games = new();
|
||||
List<Manifest> games = new();
|
||||
string manifests = EpicManifestsPath;
|
||||
if (manifests.DirectoryExists())
|
||||
foreach (string item in manifests.EnumerateDirectory("*.item"))
|
||||
|
@ -45,7 +41,7 @@ internal static class EpicLibrary
|
|||
Manifest manifest = JsonConvert.DeserializeObject<Manifest>(json);
|
||||
if (manifest is not null && !games.Any(g
|
||||
=> g.CatalogNamespace == manifest.CatalogNamespace && g.InstallLocation == manifest.InstallLocation))
|
||||
_ = games.Add(manifest);
|
||||
games.Add(manifest);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -14,6 +14,4 @@ public class HeroicAppData
|
|||
[JsonProperty("namespace")] public string Namespace { get; set; }
|
||||
|
||||
[JsonProperty("title")] public string Title { get; set; }
|
||||
|
||||
[JsonProperty("runner")] public string Runner { get; set; }
|
||||
}
|
|
@ -12,7 +12,7 @@ internal static class HeroicLibrary
|
|||
internal static readonly string HeroicLibraryPath
|
||||
= Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\heroic\store_cache\legendary_library.json";
|
||||
|
||||
internal static async Task GetGames(HashSet<Manifest> games)
|
||||
internal static async Task GetGames(List<Manifest> games)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
string libraryPath = HeroicLibraryPath;
|
||||
|
@ -28,14 +28,14 @@ internal static class HeroicLibrary
|
|||
try
|
||||
{
|
||||
HeroicAppData appData = token.ToObject<HeroicAppData>();
|
||||
if (appData is null || appData.Runner != "legendary" || string.IsNullOrWhiteSpace(appData.Install.InstallPath))
|
||||
if (appData is null || string.IsNullOrWhiteSpace(appData.Install.InstallPath))
|
||||
continue;
|
||||
Manifest manifest = new()
|
||||
{
|
||||
DisplayName = appData.Title, CatalogNamespace = appData.Namespace, InstallLocation = appData.Install.InstallPath
|
||||
};
|
||||
if (!games.Any(g => g.CatalogNamespace == manifest.CatalogNamespace && g.InstallLocation == manifest.InstallLocation))
|
||||
_ = games.Add(manifest);
|
||||
games.Add(manifest);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
@ -31,9 +29,6 @@ internal static class ParadoxLauncher
|
|||
}
|
||||
}
|
||||
|
||||
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(Selection paradoxLauncher = null)
|
||||
{
|
||||
paradoxLauncher ??= Selection.FromPlatformId(Platform.Paradox, "PL");
|
||||
|
|
|
@ -59,7 +59,7 @@ internal static class SteamCMD
|
|||
{
|
||||
if (appId != null)
|
||||
{
|
||||
AttemptCount.TryGetValue(appId, out int count);
|
||||
_ = AttemptCount.TryGetValue(appId, out int count);
|
||||
AttemptCount[appId] = ++count;
|
||||
}
|
||||
if (Program.Canceled)
|
||||
|
@ -113,7 +113,6 @@ internal static class SteamCMD
|
|||
_ = Interlocked.Decrement(ref Locks[i]);
|
||||
return appInfo.ToString();
|
||||
}
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
Thread.Sleep(200);
|
||||
goto wait_for_lock;
|
||||
|
@ -232,7 +231,7 @@ internal static class SteamCMD
|
|||
#endif
|
||||
continue;
|
||||
}
|
||||
if (appInfo.Value.Children().ToList().Count == 0)
|
||||
if (!appInfo.Value.Children().Any())
|
||||
return appInfo;
|
||||
VToken type = appInfo.Value.GetChild("common")?.GetChild("type");
|
||||
if (type is not null && type.ToString() != "Game")
|
||||
|
@ -242,7 +241,7 @@ internal static class SteamCMD
|
|||
return appInfo;
|
||||
if (type is not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId))
|
||||
return appInfo;
|
||||
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||
HashSet<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
||||
dlcAppUpdateFile.DeleteFile();
|
||||
appUpdateFile.DeleteFile();
|
||||
|
@ -253,10 +252,10 @@ internal static class SteamCMD
|
|||
return null;
|
||||
}
|
||||
|
||||
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo)
|
||||
internal static async Task<HashSet<string>> ParseDlcAppIds(VProperty appInfo)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
List<string> dlcIds = new();
|
||||
HashSet<string> dlcIds = new();
|
||||
if (Program.Canceled || appInfo is null)
|
||||
return dlcIds;
|
||||
VToken extended = appInfo.Value.GetChild("extended");
|
||||
|
@ -265,8 +264,8 @@ internal static class SteamCMD
|
|||
{
|
||||
VProperty property = (VProperty)vToken;
|
||||
foreach (string id in property.Value.ToString().Split(","))
|
||||
if (int.TryParse(id, out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
|
||||
dlcIds.Add("" + appId);
|
||||
if (int.TryParse(id, out int appId) && appId > 0)
|
||||
_ = dlcIds.Add("" + appId);
|
||||
}
|
||||
VToken depots = appInfo.Value.GetChild("depots");
|
||||
if (depots is null)
|
||||
|
@ -274,8 +273,8 @@ internal static class SteamCMD
|
|||
foreach (VToken vToken in depots.Where(p => p is VProperty property && int.TryParse(property.Key, out int _)))
|
||||
{
|
||||
VProperty property = (VProperty)vToken;
|
||||
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0 && !dlcIds.Contains("" + appId))
|
||||
dlcIds.Add("" + appId);
|
||||
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0)
|
||||
_ = dlcIds.Add("" + appId);
|
||||
}
|
||||
return dlcIds;
|
||||
});
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Threading.Tasks;
|
|||
using CreamInstaller.Utility;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Steam;
|
||||
|
||||
|
@ -22,13 +21,10 @@ internal static class SteamLibrary
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
|
||||
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||
|
||||
internal static async Task<HashSet<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
|
||||
internal static async Task<List<(string appId, string name, string branch, int buildId, string gameDirectory)>> GetGames()
|
||||
=> await Task.Run(async () =>
|
||||
{
|
||||
HashSet<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
||||
List<(string appId, string name, string branch, int buildId, string gameDirectory)> games = new();
|
||||
HashSet<string> gameLibraryDirectories = await GetLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
|
@ -37,7 +33,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;
|
||||
});
|
||||
|
|
|
@ -18,13 +18,14 @@ internal static class SteamStore
|
|||
private const int CooldownGame = 600;
|
||||
private const int CooldownDlc = 1200;
|
||||
|
||||
internal static async Task<List<string>> ParseDlcAppIds(AppData appData)
|
||||
internal static async Task<HashSet<string>> ParseDlcAppIds(AppData appData)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
List<string> dlcIds = new();
|
||||
HashSet<string> dlcIds = new();
|
||||
if (appData.DLC is null)
|
||||
return dlcIds;
|
||||
dlcIds.AddRange(from appId in appData.DLC where appId > 0 select appId.ToString(CultureInfo.InvariantCulture));
|
||||
foreach (string dlcId in from appId in appData.DLC where appId > 0 select appId.ToString(CultureInfo.InvariantCulture))
|
||||
_ = dlcIds.Add(dlcId);
|
||||
return dlcIds;
|
||||
});
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using CreamInstaller.Utility;
|
||||
using Microsoft.Win32;
|
||||
using static CreamInstaller.Resources.Resources;
|
||||
|
||||
namespace CreamInstaller.Platforms.Ubisoft;
|
||||
|
||||
|
@ -21,13 +20,10 @@ internal static class UbisoftLibrary
|
|||
}
|
||||
}
|
||||
|
||||
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(string gameDirectory)
|
||||
=> await Task.Run(async () => await gameDirectory.GetExecutableDirectories(true));
|
||||
|
||||
internal static async Task<HashSet<(string gameId, string name, string gameDirectory)>> GetGames()
|
||||
internal static async Task<List<(string gameId, string name, string gameDirectory)>> GetGames()
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
HashSet<(string gameId, string name, string gameDirectory)> games = new();
|
||||
List<(string gameId, string name, string gameDirectory)> games = new();
|
||||
RegistryKey installsKey = InstallsKey;
|
||||
if (installsKey is null)
|
||||
return games;
|
||||
|
@ -36,7 +32,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;
|
||||
});
|
||||
|
|
|
@ -38,7 +38,7 @@ internal static class Koaloader
|
|||
|
||||
private static void WriteProxy(this string path, string proxyName, BinaryType binaryType)
|
||||
{
|
||||
foreach (string resourceIdentifier in EmbeddedResources.FindAll(r => r.StartsWith("Koaloader", StringComparison.Ordinal)))
|
||||
foreach (string resourceIdentifier in EmbeddedResources.Where(r => r.StartsWith("Koaloader", StringComparison.Ordinal)))
|
||||
{
|
||||
resourceIdentifier.GetProxyInfoFromIdentifier(out string _proxyName, out BinaryType _binaryType);
|
||||
if (_proxyName != proxyName || _binaryType != binaryType)
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using CreamInstaller.Utility;
|
||||
|
@ -13,12 +12,12 @@ namespace CreamInstaller.Resources;
|
|||
|
||||
internal static class Resources
|
||||
{
|
||||
private static List<string> embeddedResources;
|
||||
private static HashSet<string> embeddedResources;
|
||||
|
||||
private static readonly Dictionary<ResourceIdentifier, IReadOnlyList<string>> ResourceMD5s = new()
|
||||
private static readonly Dictionary<ResourceIdentifier, HashSet<string>> ResourceMD5s = new()
|
||||
{
|
||||
{
|
||||
ResourceIdentifier.Koaloader, new List<string>
|
||||
ResourceIdentifier.Koaloader, new()
|
||||
{
|
||||
"8A0958687B5ED7C34DAD037856DD1530", // Koaloader v2.0.0
|
||||
"8FECDEB40980F4E687C10E056232D96B", // Koaloader v2.0.0
|
||||
|
@ -355,7 +354,7 @@ internal static class Resources
|
|||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.EpicOnlineServices32, new List<string>
|
||||
ResourceIdentifier.EpicOnlineServices32, new()
|
||||
{
|
||||
"069A57B1834A960193D2AD6B96926D70", // ScreamAPI v3.0.0
|
||||
"E2FB3A4A9583FDC215832E5F935E4440", // ScreamAPI v3.0.1
|
||||
|
@ -363,7 +362,7 @@ internal static class Resources
|
|||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.EpicOnlineServices64, new List<string>
|
||||
ResourceIdentifier.EpicOnlineServices64, new()
|
||||
{
|
||||
"0D62E57139F1A64F807A9934946A9474", // ScreamAPI v3.0.0
|
||||
"3875C7B735EE80C23239CC4749FDCBE6", // ScreamAPI v3.0.1
|
||||
|
@ -371,7 +370,7 @@ internal static class Resources
|
|||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Steamworks32, new List<string>
|
||||
ResourceIdentifier.Steamworks32, new()
|
||||
{
|
||||
"02594110FE56B2945955D46670B9A094", // CreamAPI v4.5.0.0 Hotfix
|
||||
"B2434578957CBE38BDCE0A671C1262FC", // SmokeAPI v1.0.0
|
||||
|
@ -389,7 +388,7 @@ internal static class Resources
|
|||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Steamworks64, new List<string>
|
||||
ResourceIdentifier.Steamworks64, new()
|
||||
{
|
||||
"30091B91923D9583A54A93ED1145554B", // CreamAPI v4.5.0.0 Hotfix
|
||||
"08713035CAD6F52548FF324D0487B88D", // SmokeAPI v1.0.0
|
||||
|
@ -407,26 +406,26 @@ internal static class Resources
|
|||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Uplay32, new List<string>
|
||||
ResourceIdentifier.Uplay32, new()
|
||||
{
|
||||
"1977967B2549A38EC2DB39D4C8ED499B" // Uplay R1 Unlocker v2.0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Uplay64, new List<string>
|
||||
ResourceIdentifier.Uplay64, new()
|
||||
{
|
||||
"333FEDD9DC2B299419B37ED1624FF8DB" // Uplay R1 Unlocker v2.0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Upc32, new List<string>
|
||||
ResourceIdentifier.Upc32, new()
|
||||
{
|
||||
"C14368BC4EE19FDE8DBAC07E31C67AE4", // Uplay R2 Unlocker v3.0.0
|
||||
"DED3A3EA1876E3110D7D87B9A22946B0" // Uplay R2 Unlocker v3.0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
ResourceIdentifier.Upc64, new List<string>
|
||||
ResourceIdentifier.Upc64, new()
|
||||
{
|
||||
"7D9A4C12972BAABCB6C181920CC0F19B", // Uplay R2 Unlocker v3.0.0
|
||||
"D7FDBFE0FC8D7600FEB8EC0A97713184" // Uplay R2 Unlocker v3.0.1
|
||||
|
@ -434,7 +433,7 @@ internal static class Resources
|
|||
}
|
||||
};
|
||||
|
||||
internal static List<string> EmbeddedResources
|
||||
internal static HashSet<string> EmbeddedResources
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -443,7 +442,7 @@ internal static class Resources
|
|||
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
embeddedResources = new();
|
||||
foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources.", StringComparison.Ordinal)))
|
||||
embeddedResources.Add(resourceName[25..]);
|
||||
_ = embeddedResources.Add(resourceName[25..]);
|
||||
return embeddedResources;
|
||||
}
|
||||
}
|
||||
|
@ -483,21 +482,21 @@ internal static class Resources
|
|||
|
||||
internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) => NativeImports.GetBinaryType(path, out binaryType);
|
||||
|
||||
internal static async Task<HashSet<(string directory, BinaryType binaryType)>> GetExecutableDirectories(this string rootDirectory,
|
||||
bool filterCommon = false, Func<string, bool> validFunc = null)
|
||||
internal static async Task<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false,
|
||||
Func<string, bool> validFunc = null)
|
||||
=> await Task.Run(async ()
|
||||
=> (await rootDirectory.GetExecutables(filterCommon, validFunc)
|
||||
?? (filterCommon || validFunc is not null ? await rootDirectory.GetExecutables() : null))?.Select(e =>
|
||||
{
|
||||
e.path = Path.GetDirectoryName(e.path);
|
||||
return e;
|
||||
}).DistinctBy(e => e.path).ToHashSet());
|
||||
}).DistinctBy(e => e.path).ToList());
|
||||
|
||||
internal static async Task<HashSet<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false,
|
||||
internal static async Task<List<(string path, BinaryType binaryType)>> GetExecutables(this string rootDirectory, bool filterCommon = false,
|
||||
Func<string, bool> validFunc = null)
|
||||
=> await Task.Run(() =>
|
||||
{
|
||||
HashSet<(string path, BinaryType binaryType)> executables = new();
|
||||
List<(string path, BinaryType binaryType)> executables = new();
|
||||
if (Program.Canceled || !rootDirectory.DirectoryExists())
|
||||
return null;
|
||||
foreach (string path in rootDirectory.EnumerateDirectory("*.exe", true))
|
||||
|
@ -507,8 +506,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));
|
||||
Thread.Sleep(1);
|
||||
executables.Add((path, binaryType));
|
||||
}
|
||||
foreach (string path in rootDirectory.EnumerateDirectory("*.exe", true))
|
||||
{
|
||||
|
@ -517,8 +515,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.BIT32)
|
||||
_ = executables.Add((path, binaryType));
|
||||
Thread.Sleep(1);
|
||||
executables.Add((path, binaryType));
|
||||
}
|
||||
return executables.Count > 0 ? executables : null;
|
||||
});
|
||||
|
|
|
@ -25,12 +25,14 @@ internal static class ScreamAPI
|
|||
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
|
||||
{
|
||||
directory.GetScreamApiComponents(out _, out _, out _, out _, out string config, out _);
|
||||
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();
|
||||
HashSet<SelectionDLC> overrideCatalogItems = selection.DLC.Where(dlc => dlc.Type is DLCType.EpicCatalogItem && !dlc.Enabled).ToHashSet();
|
||||
HashSet<SelectionDLC> overrideEntitlements = selection.DLC.Where(dlc => dlc.Type is DLCType.EpicEntitlement && !dlc.Enabled).ToHashSet();
|
||||
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));
|
||||
foreach (SelectionDLC extraDlc in extraSelection.DLC.Where(dlc => dlc.Type is DLCType.EpicCatalogItem && !dlc.Enabled))
|
||||
_ = overrideCatalogItems.Add(extraDlc);
|
||||
foreach (SelectionDLC extraDlc in extraSelection.DLC.Where(dlc => dlc.Type is DLCType.EpicEntitlement && !dlc.Enabled))
|
||||
_ = overrideEntitlements.Add(extraDlc);
|
||||
}
|
||||
if (overrideCatalogItems.Count > 0 || overrideEntitlements.Count > 0)
|
||||
{
|
||||
|
|
|
@ -28,12 +28,13 @@ internal static class SmokeAPI
|
|||
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
|
||||
{
|
||||
directory.GetSmokeApiComponents(out _, out _, out _, out _, out string old_config, out string config, out _, out _, out _);
|
||||
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();
|
||||
HashSet<SelectionDLC> overrideDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
|
||||
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
|
||||
_ = overrideDlc.Add(extraDlc);
|
||||
HashSet<SelectionDLC> injectDlc = new();
|
||||
if (selection.DLC.Count() > 64)
|
||||
injectDlc.AddRange(selection.DLC.Where(dlc => dlc.Enabled && dlc.Type is DLCType.SteamHidden));
|
||||
foreach (SelectionDLC hiddenDlc in selection.DLC.Where(dlc => dlc.Enabled && dlc.Type is DLCType.SteamHidden))
|
||||
_ = injectDlc.Add(hiddenDlc);
|
||||
List<KeyValuePair<string, (string name, SortedList<string, SelectionDLC> injectDlc)>> extraApps = new();
|
||||
foreach (Selection extraSelection in selection.ExtraSelections.Where(extraSelection => extraSelection.DLC.Count() > 64))
|
||||
{
|
||||
|
|
|
@ -25,9 +25,9 @@ internal static class UplayR1
|
|||
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
|
||||
{
|
||||
directory.GetUplayR1Components(out _, out _, out _, out _, out string config, out _);
|
||||
List<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToList();
|
||||
foreach (Selection extraSelection in selection.ExtraSelections)
|
||||
blacklistDlc.AddRange(extraSelection.DLC.Where(dlc => !dlc.Enabled));
|
||||
HashSet<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
|
||||
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
|
||||
_ = blacklistDlc.Add(extraDlc);
|
||||
if (blacklistDlc.Count > 0)
|
||||
{
|
||||
/*if (installForm is not null)
|
||||
|
@ -100,11 +100,10 @@ internal static class UplayR1
|
|||
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, Selection selection, InstallForm installForm = null, bool generateConfig = true)
|
||||
|
|
|
@ -27,9 +27,9 @@ internal static class UplayR2
|
|||
internal static void CheckConfig(string directory, Selection selection, InstallForm installForm = null)
|
||||
{
|
||||
directory.GetUplayR2Components(out _, out _, out _, out _, out _, out _, out string config, out _);
|
||||
List<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToList();
|
||||
foreach (Selection extraSelection in selection.ExtraSelections)
|
||||
blacklistDlc.AddRange(extraSelection.DLC.Where(dlc => !dlc.Enabled));
|
||||
HashSet<SelectionDLC> blacklistDlc = selection.DLC.Where(dlc => !dlc.Enabled).ToHashSet();
|
||||
foreach (SelectionDLC extraDlc in selection.ExtraSelections.SelectMany(extraSelection => extraSelection.DLC.Where(dlc => !dlc.Enabled)))
|
||||
_ = blacklistDlc.Add(extraDlc);
|
||||
if (blacklistDlc.Count > 0)
|
||||
{
|
||||
/*if (installForm is not null)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CreamInstaller.Resources;
|
||||
using CreamInstaller.Utility;
|
||||
|
@ -12,31 +14,42 @@ public enum Platform
|
|||
Epic, Ubisoft
|
||||
}
|
||||
|
||||
internal sealed class Selection
|
||||
internal sealed class Selection : IEquatable<Selection>
|
||||
{
|
||||
internal const string DefaultKoaloaderProxy = "version";
|
||||
|
||||
internal static readonly HashSet<Selection> All = new();
|
||||
internal readonly HashSet<Selection> ExtraSelections = new();
|
||||
internal static readonly ConcurrentDictionary<Selection, byte> All = new();
|
||||
|
||||
internal readonly HashSet<string> DllDirectories;
|
||||
internal readonly List<(string directory, BinaryType binaryType)> ExecutableDirectories;
|
||||
internal readonly HashSet<Selection> ExtraSelections = new();
|
||||
internal readonly string Id;
|
||||
internal readonly string Name;
|
||||
internal readonly Platform Platform;
|
||||
internal readonly string RootDirectory;
|
||||
|
||||
internal HashSet<string> DllDirectories;
|
||||
internal bool Enabled;
|
||||
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 Product;
|
||||
internal string Publisher;
|
||||
internal string RootDirectory;
|
||||
internal string SubIcon;
|
||||
internal string Website;
|
||||
|
||||
internal Selection() => All.Add(this);
|
||||
private Selection(Platform platform, string id, string name, string rootDirectory, HashSet<string> dllDirectories,
|
||||
List<(string directory, BinaryType binaryType)> executableDirectories)
|
||||
{
|
||||
Platform = platform;
|
||||
Id = id;
|
||||
Name = name;
|
||||
RootDirectory = rootDirectory;
|
||||
DllDirectories = dllDirectories;
|
||||
ExecutableDirectories = executableDirectories;
|
||||
_ = All.TryAdd(this, default);
|
||||
}
|
||||
|
||||
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.AllSafe.Where(dlc => dlc.Selection == this);
|
||||
internal IEnumerable<SelectionDLC> DLC => SelectionDLC.AllSafe.Where(dlc => dlc.Selection.Equals(this));
|
||||
|
||||
internal bool AreDllsLocked
|
||||
{
|
||||
|
@ -79,13 +92,20 @@ internal sealed class Selection
|
|||
}
|
||||
}
|
||||
|
||||
internal static List<Selection> AllSafe => All.ToList();
|
||||
internal static HashSet<Selection> AllSafe => All.Keys.ToHashSet();
|
||||
|
||||
internal static List<Selection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
|
||||
internal static HashSet<Selection> AllEnabled => All.Keys.Where(s => s.Enabled).ToHashSet();
|
||||
|
||||
public bool Equals(Selection other)
|
||||
=> other is not null && (ReferenceEquals(this, other) || Id == other.Id && Platform == other.Platform && RootDirectory == other.RootDirectory);
|
||||
|
||||
internal static Selection GetOrCreate(Platform platform, string id, string name, string rootDirectory, HashSet<string> dllDirectories,
|
||||
List<(string directory, BinaryType binaryType)> executableDirectories)
|
||||
=> FromPlatformId(platform, id) ?? new Selection(platform, id, name, rootDirectory, dllDirectories, executableDirectories);
|
||||
|
||||
private void Remove()
|
||||
{
|
||||
_ = All.Remove(this);
|
||||
_ = All.TryRemove(this, out _);
|
||||
foreach (SelectionDLC dlc in DLC)
|
||||
dlc.Selection = null;
|
||||
}
|
||||
|
@ -113,7 +133,14 @@ internal sealed class Selection
|
|||
}
|
||||
|
||||
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
||||
=> AllSafe.ForEach(selection => selection.Validate(programsToScan));
|
||||
{
|
||||
foreach (Selection selection in AllSafe)
|
||||
selection.Validate(programsToScan);
|
||||
}
|
||||
|
||||
internal static Selection FromPlatformId(Platform platform, string gameId) => AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
|
||||
internal static Selection FromPlatformId(Platform platform, string gameId) => AllSafe.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 int GetHashCode() => HashCode.Combine(Id, (int)Platform, RootDirectory);
|
||||
}
|
|
@ -1,26 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
public enum DLCType
|
||||
{
|
||||
Steam, SteamHidden, EpicCatalogItem,
|
||||
None = 0, Steam, SteamHidden, EpicCatalogItem,
|
||||
EpicEntitlement
|
||||
}
|
||||
|
||||
internal sealed class SelectionDLC
|
||||
internal sealed class SelectionDLC : IEquatable<SelectionDLC>
|
||||
{
|
||||
private static readonly HashSet<SelectionDLC> All = new();
|
||||
private static readonly ConcurrentDictionary<SelectionDLC, byte> All = new();
|
||||
|
||||
internal readonly string Id;
|
||||
internal readonly string Name;
|
||||
internal readonly DLCType Type;
|
||||
|
||||
internal bool Enabled;
|
||||
internal string Icon;
|
||||
internal string Id;
|
||||
internal string Name;
|
||||
internal string Product;
|
||||
internal string Publisher;
|
||||
private Selection selection;
|
||||
internal DLCType Type;
|
||||
|
||||
private SelectionDLC(DLCType type, string id, string name)
|
||||
{
|
||||
Type = type;
|
||||
Id = id;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal Selection Selection
|
||||
{
|
||||
|
@ -28,11 +38,19 @@ internal sealed class SelectionDLC
|
|||
set
|
||||
{
|
||||
selection = value;
|
||||
_ = value is null ? All.Remove(this) : All.Add(this);
|
||||
_ = value is null ? All.TryRemove(this, out _) : All.TryAdd(this, default);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<SelectionDLC> AllSafe => All.ToList();
|
||||
internal static HashSet<SelectionDLC> AllSafe => All.Keys.ToHashSet();
|
||||
|
||||
internal static SelectionDLC FromPlatformId(Platform platform, string dlcId) => AllSafe.Find(dlc => dlc.Selection.Platform == platform && dlc.Id == dlcId);
|
||||
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 FromTypeId(DLCType Type, string dlcId) => AllSafe.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 int GetHashCode() => HashCode.Combine(Id, (int)Type);
|
||||
}
|
Loading…
Reference in a new issue