v3.3.0.0
- Added multiple Thread.Sleep statements to hopefully reduce CPU overload program crashes - Added a pre-scan program/game selection dialog
This commit is contained in:
parent
994d01a419
commit
49a2496d74
14 changed files with 392 additions and 41 deletions
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
@ -14,10 +15,16 @@ internal class CustomTreeView : TreeView
|
|||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
private class TreeNodeSorter : IComparer
|
||||
{
|
||||
public int Compare(object a, object b) => AppIdComparer.Comparer.Compare((a as TreeNode).Name, (b as TreeNode).Name);
|
||||
}
|
||||
|
||||
internal CustomTreeView() : base()
|
||||
{
|
||||
DrawMode = TreeViewDrawMode.OwnerDrawAll;
|
||||
DrawNode += new DrawTreeNodeEventHandler(DrawTreeNode);
|
||||
TreeViewNodeSorter = new TreeNodeSorter();
|
||||
}
|
||||
|
||||
private void DrawTreeNode(object sender, DrawTreeNodeEventArgs e)
|
||||
|
@ -35,7 +42,7 @@ internal class CustomTreeView : TreeView
|
|||
|
||||
string subText = node.Name;
|
||||
if (string.IsNullOrWhiteSpace(subText) || subText == "ParadoxLauncher"
|
||||
|| ProgramSelection.FromId(subText) is null && ProgramSelection.GetDlcFromId(subText) is null)
|
||||
|| node.Tag is null && ProgramSelection.FromId(subText) is null && ProgramSelection.GetDlcFromId(subText) is null)
|
||||
return;
|
||||
|
||||
Size subSize = TextRenderer.MeasureText(graphics, subText, subFont);
|
||||
|
@ -46,4 +53,4 @@ internal class CustomTreeView : TreeView
|
|||
Point subLocation = new(location.X - 1, location.Y + 1);
|
||||
TextRenderer.DrawText(graphics, subText, subFont, subLocation, Color.Gray);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<Version>3.2.3.1</Version>
|
||||
<Version>3.3.0.0</Version>
|
||||
<PackageIcon>Resources\ini.ico</PackageIcon>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||
|
@ -42,6 +42,9 @@
|
|||
<PackageReference Include="Onova" Version="2.6.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Forms\SelectDialogForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\MainForm.cs" />
|
||||
<Compile Update="Forms\SelectForm.cs" />
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
|
@ -51,6 +54,9 @@
|
|||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Forms\SelectDialogForm.resx">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
@ -31,6 +32,7 @@ internal static class EpicLibrary
|
|||
foreach (string file in files)
|
||||
{
|
||||
if (Program.Canceled) return games;
|
||||
Thread.Sleep(0);
|
||||
string json = File.ReadAllText(file);
|
||||
try
|
||||
{
|
||||
|
@ -58,6 +60,7 @@ internal static class EpicLibrary
|
|||
foreach (string _directory in directories)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
Thread.Sleep(0);
|
||||
try
|
||||
{
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
|
|
|
@ -30,7 +30,7 @@ internal partial class DialogForm : CustomForm
|
|||
return ShowDialog();
|
||||
}
|
||||
|
||||
internal void OnResize(object s, EventArgs e) =>
|
||||
private void OnResize(object s, EventArgs e) =>
|
||||
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
||||
? Program.ApplicationNameShort
|
||||
: Program.ApplicationName;
|
||||
|
|
159
CreamInstaller/Forms/SelectDialogForm.Designer.cs
generated
Normal file
159
CreamInstaller/Forms/SelectDialogForm.Designer.cs
generated
Normal file
|
@ -0,0 +1,159 @@
|
|||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
partial class SelectDialogForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.acceptButton = new System.Windows.Forms.Button();
|
||||
this.groupBox = new System.Windows.Forms.GroupBox();
|
||||
this.selectionTreeView = new Components.CustomTreeView();
|
||||
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.allCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.groupBox.SuspendLayout();
|
||||
this.flowLayoutPanel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// acceptButton
|
||||
//
|
||||
this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.acceptButton.AutoSize = true;
|
||||
this.acceptButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.acceptButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.acceptButton.Location = new System.Drawing.Point(360, 243);
|
||||
this.acceptButton.Name = "acceptButton";
|
||||
this.acceptButton.Padding = new System.Windows.Forms.Padding(12, 0, 12, 0);
|
||||
this.acceptButton.Size = new System.Drawing.Size(61, 24);
|
||||
this.acceptButton.TabIndex = 0;
|
||||
this.acceptButton.Text = "OK";
|
||||
this.acceptButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// groupBox
|
||||
//
|
||||
this.groupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.groupBox.Controls.Add(this.selectionTreeView);
|
||||
this.groupBox.Controls.Add(this.flowLayoutPanel2);
|
||||
this.groupBox.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox.MinimumSize = new System.Drawing.Size(240, 40);
|
||||
this.groupBox.Name = "groupBox";
|
||||
this.groupBox.Size = new System.Drawing.Size(409, 225);
|
||||
this.groupBox.TabIndex = 3;
|
||||
this.groupBox.TabStop = false;
|
||||
this.groupBox.Text = "Choices";
|
||||
//
|
||||
// selectionTreeView
|
||||
//
|
||||
this.selectionTreeView.BackColor = System.Drawing.SystemColors.Control;
|
||||
this.selectionTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.selectionTreeView.CheckBoxes = true;
|
||||
this.selectionTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.selectionTreeView.DrawMode = System.Windows.Forms.TreeViewDrawMode.OwnerDrawAll;
|
||||
this.selectionTreeView.Location = new System.Drawing.Point(3, 19);
|
||||
this.selectionTreeView.Name = "selectionTreeView";
|
||||
this.selectionTreeView.ShowLines = false;
|
||||
this.selectionTreeView.ShowPlusMinus = false;
|
||||
this.selectionTreeView.ShowRootLines = false;
|
||||
this.selectionTreeView.Size = new System.Drawing.Size(403, 203);
|
||||
this.selectionTreeView.Sorted = true;
|
||||
this.selectionTreeView.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanel2
|
||||
//
|
||||
this.flowLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.flowLayoutPanel2.AutoSize = true;
|
||||
this.flowLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.flowLayoutPanel2.Controls.Add(this.allCheckBox);
|
||||
this.flowLayoutPanel2.Location = new System.Drawing.Point(366, -1);
|
||||
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
|
||||
this.flowLayoutPanel2.Size = new System.Drawing.Size(37, 19);
|
||||
this.flowLayoutPanel2.TabIndex = 1007;
|
||||
//
|
||||
// allCheckBox
|
||||
//
|
||||
this.allCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.allCheckBox.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.allCheckBox.Location = new System.Drawing.Point(3, 0);
|
||||
this.allCheckBox.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
|
||||
this.allCheckBox.Name = "allCheckBox";
|
||||
this.allCheckBox.Size = new System.Drawing.Size(34, 19);
|
||||
this.allCheckBox.TabIndex = 1;
|
||||
this.allCheckBox.Text = "All";
|
||||
this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged);
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.AutoSize = true;
|
||||
this.cancelButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.cancelButton.Location = new System.Drawing.Point(12, 243);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Padding = new System.Windows.Forms.Padding(12, 0, 12, 0);
|
||||
this.cancelButton.Size = new System.Drawing.Size(81, 24);
|
||||
this.cancelButton.TabIndex = 4;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SelectDialogForm
|
||||
//
|
||||
this.AcceptButton = this.acceptButton;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(433, 279);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.acceptButton);
|
||||
this.Controls.Add(this.groupBox);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "SelectDialogForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "SelectDialogForm";
|
||||
this.TopMost = true;
|
||||
this.groupBox.ResumeLayout(false);
|
||||
this.groupBox.PerformLayout();
|
||||
this.flowLayoutPanel2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Button acceptButton;
|
||||
private System.Windows.Forms.GroupBox groupBox;
|
||||
private Components.CustomTreeView selectionTreeView;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
|
||||
private System.Windows.Forms.CheckBox allCheckBox;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
}
|
||||
}
|
80
CreamInstaller/Forms/SelectDialogForm.cs
Normal file
80
CreamInstaller/Forms/SelectDialogForm.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using CreamInstaller.Components;
|
||||
|
||||
namespace CreamInstaller;
|
||||
|
||||
internal partial class SelectDialogForm : CustomForm
|
||||
{
|
||||
internal SelectDialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
||||
|
||||
private readonly List<(string platform, string id, string name)> selected = new();
|
||||
internal List<(string platform, string id, string name)> QueryUser(string groupBoxText, List<(string platform, string id, string name, bool alreadySelected)> choices)
|
||||
{
|
||||
groupBox.Text = groupBoxText;
|
||||
allCheckBox.Enabled = false;
|
||||
acceptButton.Enabled = false;
|
||||
selectionTreeView.AfterCheck += OnTreeNodeChecked;
|
||||
foreach ((string platform, string id, string name, bool alreadySelected) in choices)
|
||||
{
|
||||
TreeNode node = new();
|
||||
node.Tag = platform;
|
||||
node.Name = id;
|
||||
node.Text = name;
|
||||
node.Checked = alreadySelected;
|
||||
OnTreeNodeChecked(node);
|
||||
selectionTreeView.Nodes.Add(node);
|
||||
}
|
||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||
allCheckBox.Checked = selectionTreeView.Nodes.Cast<TreeNode>().All(n => n.Checked);
|
||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||
allCheckBox.Enabled = true;
|
||||
acceptButton.Enabled = selected.Any();
|
||||
OnResize(null, null);
|
||||
Resize += OnResize;
|
||||
return ShowDialog() == DialogResult.OK ? selected : null;
|
||||
}
|
||||
|
||||
private void OnTreeNodeChecked(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
OnTreeNodeChecked(e.Node);
|
||||
acceptButton.Enabled = selected.Any();
|
||||
}
|
||||
|
||||
private void OnTreeNodeChecked(TreeNode node)
|
||||
{
|
||||
string id = node.Name;
|
||||
if (node.Checked)
|
||||
selected.Add((node.Tag as string, id, node.Text));
|
||||
else
|
||||
selected.RemoveAll(s => s.id == id);
|
||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||
allCheckBox.Checked = selectionTreeView.Nodes.Cast<TreeNode>().All(n => n.Checked);
|
||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||
}
|
||||
|
||||
private void OnResize(object s, EventArgs e) =>
|
||||
Text = TextRenderer.MeasureText(Program.ApplicationName, Font).Width > Size.Width - 100
|
||||
? Program.ApplicationNameShort
|
||||
: Program.ApplicationName;
|
||||
|
||||
private void OnAllCheckBoxChanged(object sender, EventArgs e)
|
||||
{
|
||||
bool shouldCheck = false;
|
||||
foreach (TreeNode node in selectionTreeView.Nodes)
|
||||
if (!node.Checked)
|
||||
shouldCheck = true;
|
||||
foreach (TreeNode node in selectionTreeView.Nodes)
|
||||
{
|
||||
node.Checked = shouldCheck;
|
||||
OnTreeNodeChecked(node);
|
||||
}
|
||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||
allCheckBox.Checked = shouldCheck;
|
||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||
}
|
||||
}
|
60
CreamInstaller/Forms/SelectDialogForm.resx
Normal file
60
CreamInstaller/Forms/SelectDialogForm.resx
Normal file
|
@ -0,0 +1,60 @@
|
|||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -82,6 +81,7 @@ internal partial class SelectForm : CustomForm
|
|||
|
||||
private async Task GetApplicablePrograms(IProgress<int> progress)
|
||||
{
|
||||
if (ProgramsToScan is null || !ProgramsToScan.Any()) return;
|
||||
int TotalGameCount = 0;
|
||||
int CompleteGameCount = 0;
|
||||
void AddToRemainingGames(string gameName)
|
||||
|
@ -99,7 +99,7 @@ internal partial class SelectForm : CustomForm
|
|||
RemainingGames.Clear(); // for display purposes only, otherwise ignorable
|
||||
RemainingDLCs.Clear(); // for display purposes only, otherwise ignorable
|
||||
List<Task> appTasks = new();
|
||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||
if (Directory.Exists(ParadoxLauncher.InstallPath) && ProgramsToScan.Any(c => c.platform == "Paradox" && c.id == "ParadoxLauncher"))
|
||||
{
|
||||
ProgramSelection selection = ProgramSelection.FromId("ParadoxLauncher");
|
||||
selection ??= new();
|
||||
|
@ -119,7 +119,7 @@ internal partial class SelectForm : CustomForm
|
|||
programNode.Remove();
|
||||
selectionTreeView.Nodes.Add(programNode);
|
||||
}
|
||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||
if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan.Any(c => c.platform == "Steam"))
|
||||
{
|
||||
List<Tuple<string, string, string, int, string>> steamGames = await SteamLibrary.GetGames();
|
||||
foreach (Tuple<string, string, string, int, string> program in steamGames)
|
||||
|
@ -129,10 +129,9 @@ internal partial class SelectForm : CustomForm
|
|||
string branch = program.Item3;
|
||||
int buildId = program.Item4;
|
||||
string directory = program.Item5;
|
||||
Thread.Sleep(0);
|
||||
ProgramSelection selection = ProgramSelection.FromId(appId);
|
||||
if (Program.Canceled) return;
|
||||
if (Program.IsGameBlocked(name, directory)) continue;
|
||||
Thread.Sleep(0);
|
||||
if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.id == appId)) continue;
|
||||
AddToRemainingGames(name);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
|
@ -162,6 +161,7 @@ internal partial class SelectForm : CustomForm
|
|||
foreach (string dlcAppId in dlcIds)
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
Thread.Sleep(0);
|
||||
AddToRemainingDLCs(dlcAppId);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ internal partial class SelectForm : CustomForm
|
|||
await task;
|
||||
}
|
||||
|
||||
selection ??= new();
|
||||
ProgramSelection selection = ProgramSelection.FromId(appId) ?? new();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraDlc.Any();
|
||||
selection.Usable = true;
|
||||
selection.Id = appId;
|
||||
|
@ -255,7 +255,7 @@ internal partial class SelectForm : CustomForm
|
|||
appTasks.Add(task);
|
||||
}
|
||||
}
|
||||
if (Directory.Exists(EpicLibrary.EpicAppDataPath))
|
||||
if (Directory.Exists(EpicLibrary.EpicAppDataPath) && ProgramsToScan.Any(c => c.platform == "Epic"))
|
||||
{
|
||||
List<Manifest> epicGames = await EpicLibrary.GetGames();
|
||||
foreach (Manifest manifest in epicGames)
|
||||
|
@ -263,10 +263,9 @@ internal partial class SelectForm : CustomForm
|
|||
string @namespace = manifest.CatalogNamespace;
|
||||
string name = manifest.DisplayName;
|
||||
string directory = manifest.InstallLocation;
|
||||
Thread.Sleep(0);
|
||||
ProgramSelection selection = ProgramSelection.FromId(@namespace);
|
||||
if (Program.Canceled) return;
|
||||
if (Program.IsGameBlocked(name, directory)) continue;
|
||||
Thread.Sleep(0);
|
||||
if (Program.IsGameBlocked(name, directory) || !ProgramsToScan.Any(c => c.id == @namespace)) continue;
|
||||
AddToRemainingGames(name);
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
|
@ -292,6 +291,7 @@ internal partial class SelectForm : CustomForm
|
|||
Task task = Task.Run(() =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
Thread.Sleep(0);
|
||||
entitlements[id] = (name, product, icon, developer);
|
||||
RemoveFromRemainingDLCs(id);
|
||||
});
|
||||
|
@ -311,7 +311,7 @@ internal partial class SelectForm : CustomForm
|
|||
await task;
|
||||
}
|
||||
|
||||
selection ??= new();
|
||||
ProgramSelection selection = ProgramSelection.FromId(@namespace) ?? new();
|
||||
selection.Enabled = allCheckBox.Checked || selection.SelectedDlc.Any() || selection.ExtraDlc.Any();
|
||||
selection.Usable = true;
|
||||
selection.Id = @namespace;
|
||||
|
@ -356,7 +356,7 @@ internal partial class SelectForm : CustomForm
|
|||
programNode.Nodes.Add(entitlementsNode);*/
|
||||
foreach (KeyValuePair<string, (string name, string product, string icon, string developer)> pair in entitlements)
|
||||
{
|
||||
if (Program.Canceled || programNode is null/* || entitlementsNode is null*/) return;
|
||||
if (programNode is null/* || entitlementsNode is null*/) return;
|
||||
Thread.Sleep(0);
|
||||
string dlcId = pair.Key;
|
||||
(DlcType type, string name, string icon) dlcApp = (DlcType.Entitlement, pair.Value.name, pair.Value.icon);
|
||||
|
@ -384,7 +384,8 @@ internal partial class SelectForm : CustomForm
|
|||
}
|
||||
}
|
||||
|
||||
private async void OnLoad()
|
||||
private List<(string platform, string id, string name)> ProgramsToScan;
|
||||
private async void OnLoad(bool selectGamesToScan = false)
|
||||
{
|
||||
Program.Canceled = false;
|
||||
blockedGamesCheckBox.Enabled = false;
|
||||
|
@ -396,8 +397,33 @@ internal partial class SelectForm : CustomForm
|
|||
installButton.Enabled = false;
|
||||
uninstallButton.Enabled = installButton.Enabled;
|
||||
selectionTreeView.Enabled = false;
|
||||
progressLabel.Text = "Waiting for user to select which programs/games to scan . . .";
|
||||
ShowProgressBar();
|
||||
|
||||
if (ProgramsToScan is null || !ProgramsToScan.Any() || selectGamesToScan)
|
||||
{
|
||||
List<(string platform, string id, string name, bool alreadySelected)> gameChoices = new();
|
||||
if (Directory.Exists(ParadoxLauncher.InstallPath))
|
||||
gameChoices.Add(("Paradox", "ParadoxLauncher", "Paradox Launcher", ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == "ParadoxLauncher")));
|
||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||
foreach (Tuple<string, string, string, int, string> program in await SteamLibrary.GetGames())
|
||||
if (!Program.IsGameBlocked(program.Item1, program.Item5))
|
||||
gameChoices.Add(("Steam", program.Item1, program.Item2, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == program.Item1)));
|
||||
if (Directory.Exists(EpicLibrary.EpicAppDataPath))
|
||||
foreach (Manifest manifest in await EpicLibrary.GetGames())
|
||||
if (!Program.IsGameBlocked(manifest.DisplayName, manifest.InstallLocation))
|
||||
gameChoices.Add(("Epic", manifest.CatalogNamespace, manifest.DisplayName, ProgramsToScan is not null && ProgramsToScan.Any(p => p.id == manifest.CatalogNamespace)));
|
||||
if (gameChoices.Any())
|
||||
{
|
||||
using SelectDialogForm form = new(this);
|
||||
List<(string platform, string id, string name)> choices = form.QueryUser("Choose which programs/games to scan:", gameChoices);
|
||||
if (choices is not null) ProgramsToScan = choices;
|
||||
noneFoundLabel.Text = "None of the chosen programs/games were CreamAPI-applicable or ScreamAPI-applicable!\n\nPress the \"Rescan Programs / Games\" button to re-choose.";
|
||||
}
|
||||
else
|
||||
noneFoundLabel.Text = "No CreamAPI-applicable or ScreamAPI-applicable programs/games were found on your computer!";
|
||||
}
|
||||
|
||||
bool setup = true;
|
||||
int maxProgress = 0;
|
||||
int curProgress = 0;
|
||||
|
@ -406,6 +432,7 @@ internal partial class SelectForm : CustomForm
|
|||
progress.ProgressChanged += (sender, _progress) =>
|
||||
{
|
||||
if (Program.Canceled) return;
|
||||
Thread.Sleep(0);
|
||||
if (_progress < 0 || _progress > maxProgress) maxProgress = -_progress;
|
||||
else curProgress = _progress;
|
||||
int p = Math.Max(Math.Min((int)((float)(curProgress / (float)maxProgress) * 100), 100), 0);
|
||||
|
@ -415,14 +442,14 @@ internal partial class SelectForm : CustomForm
|
|||
};
|
||||
|
||||
await ProgramData.Setup();
|
||||
if (Directory.Exists(SteamLibrary.InstallPath))
|
||||
if (Directory.Exists(SteamLibrary.InstallPath) && ProgramsToScan is not null && ProgramsToScan.Any(c => c.platform == "Steam"))
|
||||
{
|
||||
progressLabel.Text = $"Setting up SteamCMD . . . ";
|
||||
await SteamCMD.Setup(iProgress);
|
||||
}
|
||||
setup = false;
|
||||
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
||||
ProgramSelection.ValidateAll();
|
||||
ProgramSelection.ValidateAll(ProgramsToScan);
|
||||
TreeNodes.ForEach(node => node.Remove());
|
||||
await GetApplicablePrograms(iProgress);
|
||||
await SteamCMD.Cleanup();
|
||||
|
@ -502,11 +529,6 @@ internal partial class SelectForm : CustomForm
|
|||
return treeNodes;
|
||||
}
|
||||
|
||||
private class TreeNodeSorter : IComparer
|
||||
{
|
||||
public int Compare(object a, object b) => AppIdComparer.Comparer.Compare((a as TreeNode).Name, (b as TreeNode).Name);
|
||||
}
|
||||
|
||||
private void ShowProgressBar()
|
||||
{
|
||||
progressBar.Value = 0;
|
||||
|
@ -543,7 +565,6 @@ internal partial class SelectForm : CustomForm
|
|||
try
|
||||
{
|
||||
HideProgressBar();
|
||||
selectionTreeView.TreeViewNodeSorter = new TreeNodeSorter();
|
||||
selectionTreeView.AfterCheck += OnTreeViewNodeCheckedChanged;
|
||||
selectionTreeView.NodeMouseClick += (sender, e) =>
|
||||
{
|
||||
|
@ -649,7 +670,7 @@ internal partial class SelectForm : CustomForm
|
|||
}
|
||||
contextMenuStrip.Show(selectionTreeView, e.Location);
|
||||
};
|
||||
OnLoad();
|
||||
OnLoad(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -682,7 +703,7 @@ internal partial class SelectForm : CustomForm
|
|||
|
||||
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
|
||||
|
||||
private void OnScan(object sender, EventArgs e) => OnLoad();
|
||||
private void OnScan(object sender, EventArgs e) => OnLoad(true);
|
||||
|
||||
private void OnCancel(object sender, EventArgs e)
|
||||
{
|
||||
|
@ -711,7 +732,7 @@ internal partial class SelectForm : CustomForm
|
|||
private void OnBlockProtectedGamesCheckBoxChanged(object sender, EventArgs e)
|
||||
{
|
||||
Program.BlockProtectedGames = blockedGamesCheckBox.Checked;
|
||||
OnLoad();
|
||||
OnLoad(true);
|
||||
}
|
||||
|
||||
private readonly string helpButtonListPrefix = "\n • ";
|
||||
|
|
|
@ -57,7 +57,4 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="nodeContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -26,11 +26,11 @@ internal static class Program
|
|||
internal static readonly string[] ProtectedGameDirectories = { @"\EasyAntiCheat", @"\BattlEye" }; // DLL detections
|
||||
internal static readonly string[] ProtectedGameDirectoryExceptions = { "Arma 3" }; // Arma 3's BattlEye doesn't detect DLL changes?
|
||||
|
||||
internal static bool IsGameBlocked(string name, string directory)
|
||||
internal static bool IsGameBlocked(string name, string directory = null)
|
||||
{
|
||||
if (!BlockProtectedGames) return false;
|
||||
if (ProtectedGameNames.Contains(name)) return true;
|
||||
if (!ProtectedGameDirectoryExceptions.Contains(name))
|
||||
if (directory is not null && !ProtectedGameDirectoryExceptions.Contains(name))
|
||||
foreach (string path in ProtectedGameDirectories)
|
||||
if (Directory.Exists(directory + path)) return true;
|
||||
return false;
|
||||
|
|
|
@ -101,8 +101,20 @@ internal class ProgramSelection
|
|||
if (!DllDirectories.Any()) All.Remove(this);
|
||||
}
|
||||
|
||||
internal void Validate(List<(string platform, string id, string name)> programsToScan)
|
||||
{
|
||||
if (programsToScan is null || !programsToScan.Any(p => p.id == Id))
|
||||
{
|
||||
All.Remove(this);
|
||||
return;
|
||||
}
|
||||
Validate();
|
||||
}
|
||||
|
||||
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
|
||||
|
||||
internal static void ValidateAll(List<(string platform, string id, string name)> programsToScan) => AllSafe.ForEach(selection => selection.Validate(programsToScan));
|
||||
|
||||
internal static List<ProgramSelection> All = new();
|
||||
|
||||
internal static List<ProgramSelection> AllSafe => All.ToList();
|
||||
|
|
|
@ -36,9 +36,11 @@ internal static class SteamCMD
|
|||
{
|
||||
wait_for_lock:
|
||||
if (Program.Canceled) return "";
|
||||
Thread.Sleep(0);
|
||||
for (int i = 0; i < locks.Length; i++)
|
||||
{
|
||||
if (Program.Canceled) return "";
|
||||
Thread.Sleep(0);
|
||||
if (Interlocked.CompareExchange(ref locks[i], 1, 0) == 0)
|
||||
{
|
||||
if (appId is not null)
|
||||
|
@ -107,7 +109,7 @@ internal static class SteamCMD
|
|||
Interlocked.Decrement(ref locks[i]);
|
||||
return appInfo;
|
||||
}
|
||||
Thread.Sleep(0);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
Thread.Sleep(200);
|
||||
goto wait_for_lock;
|
||||
|
@ -121,11 +123,10 @@ internal static class SteamCMD
|
|||
await Cleanup();
|
||||
if (!File.Exists(FilePath))
|
||||
{
|
||||
using (HttpClient httpClient = new())
|
||||
{
|
||||
byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
|
||||
file.Write(ArchivePath);
|
||||
}
|
||||
HttpClient httpClient = HttpClientManager.HttpClient;
|
||||
if (httpClient is null) return;
|
||||
byte[] file = await httpClient.GetByteArrayAsync(new Uri("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip"));
|
||||
file.Write(ArchivePath);
|
||||
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
||||
File.Delete(ArchivePath);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
@ -30,6 +31,8 @@ internal static class SteamLibrary
|
|||
List<string> gameLibraryDirectories = await GetLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
if (Program.Canceled) return games;
|
||||
Thread.Sleep(0);
|
||||
List<Tuple<string, string, string, int, string>> directoryGames = await GetGamesFromLibraryDirectory(libraryDirectory);
|
||||
if (directoryGames is not null)
|
||||
foreach (Tuple<string, string, string, int, string> game in directoryGames)
|
||||
|
@ -54,6 +57,7 @@ internal static class SteamLibrary
|
|||
foreach (string _directory in directories)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
Thread.Sleep(0);
|
||||
try
|
||||
{
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
|
@ -72,6 +76,7 @@ internal static class SteamLibrary
|
|||
foreach (string file in files)
|
||||
{
|
||||
if (Program.Canceled) return null;
|
||||
Thread.Sleep(0);
|
||||
if (ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
|
||||
{
|
||||
string appId = result.Value.GetChild("appid")?.ToString();
|
||||
|
|
|
@ -14,7 +14,7 @@ internal static class HttpClientManager
|
|||
internal static void Setup()
|
||||
{
|
||||
HttpClient = new();
|
||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"{Environment.MachineName}CI{Application.ProductVersion.Replace(".", "")}{Environment.UserName}");
|
||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", $"CI{Application.ProductVersion.Replace(".", "")}");
|
||||
}
|
||||
|
||||
internal static async Task<string> EnsureGet(string url)
|
||||
|
|
Loading…
Reference in a new issue