appinfo gathering, caching, and basic display

This commit is contained in:
pointfeev 2021-11-05 01:42:25 -04:00
parent f5ba69f380
commit 3e50f5fa70
No known key found for this signature in database
GPG key ID: AA14DC36C4D7D13C
6 changed files with 294 additions and 233 deletions

View file

@ -1,69 +1,67 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework> <TargetFramework>net5.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>ini.ico</ApplicationIcon> <ApplicationIcon>ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract> <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>2.0.0.0</Version> <Version>2.0.0.0</Version>
<PackageIcon>ini.ico</PackageIcon> <PackageIcon>ini.ico</PackageIcon>
<PackageIconUrl /> <PackageIconUrl />
<Description>Automatically downloads and installs CreamAPI files for programs/games.</Description> <Description>Automatically downloads and installs CreamAPI files for programs/games.</Description>
<PackageLicenseFile>LICENSE</PackageLicenseFile> <PackageLicenseFile>LICENSE</PackageLicenseFile>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright> <Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/pointfeev/CreamInstaller</PackageProjectUrl> <PackageProjectUrl>https://github.com/pointfeev/CreamInstaller</PackageProjectUrl>
<RepositoryUrl>https://github.com/pointfeev/CreamInstaller</RepositoryUrl> <RepositoryUrl>https://github.com/pointfeev/CreamInstaller</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<PackageReleaseNotes>Automatically downloads and installs CreamAPI files for programs/games.</PackageReleaseNotes> <PackageReleaseNotes>Automatically downloads and installs CreamAPI files for programs/games.</PackageReleaseNotes>
<PackageTags>steam, dlc</PackageTags> <PackageTags>steam, dlc</PackageTags>
<AssemblyName>CreamInstaller</AssemblyName> <AssemblyName>CreamInstaller</AssemblyName>
<Company>CreamInstaller</Company> <Company>CreamInstaller</Company>
<Product>CreamAPI Downloader &amp; Installer</Product> <Product>CreamAPI Downloader &amp; Installer</Product>
<Authors>pointfeev</Authors> <Authors>pointfeev</Authors>
<PackageId>pointfeev.creaminstaller</PackageId> <PackageId>pointfeev.creaminstaller</PackageId>
<StartupObject>CreamInstaller.Program</StartupObject> <StartupObject>CreamInstaller.Program</StartupObject>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Gameloop.Vdf" Version="0.6.1" /> <PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
<PackageReference Include="koskit.SteamCmdFluentApi" Version="1.0.4" /> <PackageReference Include="Onova" Version="2.6.2" />
<PackageReference Include="Onova" Version="2.6.2" /> </ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="MainForm.cs" /> <Compile Update="MainForm.cs" />
<Compile Update="SelectForm.cs" /> <Compile Update="SelectForm.cs" />
<Compile Update="Properties\Resources.Designer.cs"> <Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon> <DependentUpon>Resources.resx</DependentUpon>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx"> <EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="ini.ico">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="ini.ico">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
</Project> </Project>

View file

@ -147,18 +147,13 @@ namespace CreamInstaller
private void Operate() private void Operate()
{ {
OperationsCount = Program.ProgramSelections.FindAll(selection => selection.Enabled).Count; OperationsCount = Program.ProgramSelections.ToList().FindAll(selection => selection.Enabled).Count;
CompleteOperationsCount = 0; CompleteOperationsCount = 0;
foreach (ProgramSelection selection in Program.ProgramSelections.ToList()) foreach (ProgramSelection selection in Program.ProgramSelections.ToList())
{ {
if (!selection.Enabled) { continue; } if (!selection.Enabled) continue;
if (!Program.IsProgramRunningDialog(this, selection)) throw new OperationCanceledException();
if (!Program.IsProgramRunningDialog(this, selection))
{
throw new OperationCanceledException();
}
try try
{ {
OperateFor(selection); OperateFor(selection);
@ -169,13 +164,10 @@ namespace CreamInstaller
{ {
UpdateUser($"Operation failed for {selection.DisplayName}: " + exception.ToString(), LogColor.Error); UpdateUser($"Operation failed for {selection.DisplayName}: " + exception.ToString(), LogColor.Error);
} }
++CompleteOperationsCount; ++CompleteOperationsCount;
} }
Program.Cleanup(); Program.Cleanup();
List<ProgramSelection> FailedSelections = Program.ProgramSelections.ToList().FindAll(selection => selection.Enabled);
List<ProgramSelection> FailedSelections = Program.ProgramSelections.FindAll(selection => selection.Enabled);
if (FailedSelections.Any()) if (FailedSelections.Any())
{ {
if (FailedSelections.Count == 1) if (FailedSelections.Count == 1)
@ -189,7 +181,7 @@ namespace CreamInstaller
} }
} }
private readonly int ProgramCount = Program.ProgramSelections.FindAll(selection => selection.Enabled).Count; private readonly int ProgramCount = Program.ProgramSelections.ToList().FindAll(selection => selection.Enabled).Count;
private void Start() private void Start()
{ {

View file

@ -6,7 +6,7 @@ namespace CreamInstaller
{ {
public bool Enabled = true; public bool Enabled = true;
public string Name; public string Identifier;
public string DisplayName; public string DisplayName;
public string RootDirectory; public string RootDirectory;
public int SteamAppId; public int SteamAppId;
@ -19,23 +19,14 @@ namespace CreamInstaller
foreach (string directory in SteamApiDllDirectories) foreach (string directory in SteamApiDllDirectories)
{ {
string file = directory + "\\steam_api64.dll"; string file = directory + "\\steam_api64.dll";
if (file.IsFilePathLocked()) if (file.IsFilePathLocked()) return true;
{
return true;
}
} }
return false; return false;
} }
} }
public ProgramSelection() public ProgramSelection() => Program.ProgramSelections.Add(this);
{
Program.ProgramSelections.Add(this);
}
public void Toggle(bool Enabled) public void Toggle(bool Enabled) => this.Enabled = Enabled;
{
this.Enabled = Enabled;
}
} }
} }

View file

@ -1,5 +1,4 @@
 
using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace CreamInstaller namespace CreamInstaller
@ -37,9 +36,9 @@ namespace CreamInstaller
this.cancelButton = new System.Windows.Forms.Button(); this.cancelButton = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox(); this.groupBox1 = new System.Windows.Forms.GroupBox();
this.allCheckBox = new System.Windows.Forms.CheckBox();
this.noneFoundLabel = new System.Windows.Forms.Label(); this.noneFoundLabel = new System.Windows.Forms.Label();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.treeView1 = new System.Windows.Forms.TreeView();
this.allCheckBox = new System.Windows.Forms.CheckBox();
this.progressBar1 = new System.Windows.Forms.ProgressBar(); this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.label2 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label();
this.scanButton = new System.Windows.Forms.Button(); this.scanButton = new System.Windows.Forms.Button();
@ -81,9 +80,9 @@ namespace CreamInstaller
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.groupBox1.Controls.Add(this.allCheckBox);
this.groupBox1.Controls.Add(this.noneFoundLabel); this.groupBox1.Controls.Add(this.noneFoundLabel);
this.groupBox1.Controls.Add(this.flowLayoutPanel1); this.groupBox1.Controls.Add(this.treeView1);
this.groupBox1.Controls.Add(this.allCheckBox);
this.groupBox1.Location = new System.Drawing.Point(12, 12); this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1"; this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(460, 236); this.groupBox1.Size = new System.Drawing.Size(460, 236);
@ -91,6 +90,32 @@ namespace CreamInstaller
this.groupBox1.TabStop = false; this.groupBox1.TabStop = false;
this.groupBox1.Text = "Programs / Games"; this.groupBox1.Text = "Programs / Games";
// //
// noneFoundLabel
//
this.noneFoundLabel.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.noneFoundLabel.Location = new System.Drawing.Point(6, 22);
this.noneFoundLabel.Name = "noneFoundLabel";
this.noneFoundLabel.Size = new System.Drawing.Size(448, 208);
this.noneFoundLabel.TabIndex = 1002;
this.noneFoundLabel.Text = "No CreamAPI-applicable programs were found on your computer!";
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.noneFoundLabel.Visible = false;
//
// treeView1
//
this.treeView1.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.treeView1.CheckBoxes = true;
this.treeView1.Location = new System.Drawing.Point(6, 22);
this.treeView1.Name = "treeView1";
this.treeView1.ShowPlusMinus = false;
this.treeView1.ShowRootLines = false;
this.treeView1.Size = new System.Drawing.Size(448, 208);
this.treeView1.TabIndex = 1001;
//
// allCheckBox // allCheckBox
// //
this.allCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.allCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@ -106,27 +131,6 @@ namespace CreamInstaller
this.allCheckBox.UseVisualStyleBackColor = true; this.allCheckBox.UseVisualStyleBackColor = true;
this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged); this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged);
// //
// noneFoundLabel
//
this.noneFoundLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.noneFoundLabel.Enabled = false;
this.noneFoundLabel.Location = new System.Drawing.Point(3, 19);
this.noneFoundLabel.Name = "noneFoundLabel";
this.noneFoundLabel.Size = new System.Drawing.Size(454, 214);
this.noneFoundLabel.TabIndex = 0;
this.noneFoundLabel.Text = "No CreamAPI-applicable programs or games were found on your computer!";
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.noneFoundLabel.Visible = false;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowLayoutPanel1.Location = new System.Drawing.Point(3, 19);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(454, 214);
this.flowLayoutPanel1.TabIndex = 1000;
//
// progressBar1 // progressBar1
// //
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
@ -193,12 +197,12 @@ namespace CreamInstaller
private System.Windows.Forms.Button cancelButton; private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label1;
private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ProgressBar progressBar1; private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox allCheckBox; private System.Windows.Forms.CheckBox allCheckBox;
private Label noneFoundLabel;
private Button scanButton; private Button scanButton;
private TreeView treeView1;
private Label noneFoundLabel;
} }
} }

View file

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
@ -48,7 +47,7 @@ namespace CreamInstaller
{ {
steamApiDllDirectories = new(); steamApiDllDirectories = new();
if (Program.Canceled) return false; if (Program.Canceled) return false;
string api = "";//gameDirectory + "\\steam_api.dll"; string api = gameDirectory + "\\steam_api.dll";
string api64 = gameDirectory + "\\steam_api64.dll"; string api64 = gameDirectory + "\\steam_api64.dll";
if (File.Exists(api) || File.Exists(api64)) steamApiDllDirectories.Add(gameDirectory); if (File.Exists(api) || File.Exists(api64)) steamApiDllDirectories.Add(gameDirectory);
foreach (string _directory in Directory.GetDirectories(gameDirectory)) foreach (string _directory in Directory.GetDirectories(gameDirectory))
@ -92,15 +91,15 @@ namespace CreamInstaller
return true; return true;
} }
private readonly List<CheckBox> checkBoxes = new(); private readonly List<TreeNode> treeNodes = new();
private readonly Dictionary<int, string> dlc = new(); internal readonly Dictionary<int, List<Tuple<int, string>>> DLC = new();
[DllImport("kernel32")] internal List<Task> RunningTasks = null;
private static extern bool AllocConsole();
private void GetCreamApiApplicablePrograms(IProgress<int> progress) private void GetCreamApiApplicablePrograms(IProgress<int> progress)
{ {
int cur = 0;
if (Program.Canceled) return; if (Program.Canceled) return;
List<Tuple<string, string>> applicablePrograms = new(); List<Tuple<string, string>> applicablePrograms = new();
string launcherRootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Programs\\Paradox Interactive"; string launcherRootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Programs\\Paradox Interactive";
@ -109,85 +108,122 @@ namespace CreamInstaller
if (GetGameDirectoriesFromLibraryDirectory(libraryDirectory, out List<string> gameDirectories)) if (GetGameDirectoriesFromLibraryDirectory(libraryDirectory, out List<string> gameDirectories))
foreach (string gameDirectory in gameDirectories) foreach (string gameDirectory in gameDirectories)
applicablePrograms.Add(new Tuple<string, string>(Path.GetFileName(gameDirectory) ?? "unknown_" + applicablePrograms.Count, gameDirectory)); applicablePrograms.Add(new Tuple<string, string>(Path.GetFileName(gameDirectory) ?? "unknown_" + applicablePrograms.Count, gameDirectory));
List<Task> tasks = new(); RunningTasks = new();
foreach (Tuple<string, string> program in applicablePrograms) foreach (Tuple<string, string> program in applicablePrograms)
{ {
string name = program.Item1; string identifier = program.Item1;
string rootDirectory = program.Item2; string rootDirectory = program.Item2;
if (Program.Canceled) return; if (Program.Canceled) return;
Task task = new Task(() => Task task = new(() =>
{ {
int steamAppId = 0; try
if (Program.Canceled || Program.ProgramSelections.Any(s => s.Name == name)
|| (name != "Paradox Launcher" && !GetSteamAppIdFromGameDirectory(rootDirectory, out steamAppId))
|| !GetSteamApiDllDirectoriesFromGameDirectory(rootDirectory, out List<string> steamApiDllDirectories))
return;
Dictionary<string, string> appInfo = null;
if (Program.Canceled || (name != "Paradox Launcher" && !SteamCMD.GetAppInfo(steamAppId, out appInfo))) return;
string list = null;
if (!(appInfo is null) && appInfo.TryGetValue("listofdlc", out list))
{ {
int steamAppId = 0;
if (Program.Canceled
|| (identifier != "Paradox Launcher" && !GetSteamAppIdFromGameDirectory(rootDirectory, out steamAppId))
|| !GetSteamApiDllDirectoriesFromGameDirectory(rootDirectory, out List<string> steamApiDllDirectories))
return;
Dictionary<string, string> appInfo = null;
if (Program.Canceled || (identifier != "Paradox Launcher" && !SteamCMD.GetAppInfo(steamAppId, out appInfo))) return;
string list = null;
List<Tuple<int, string>> dlc = null;
if (!DLC.TryGetValue(steamAppId, out dlc))
{
dlc = new();
DLC.Add(steamAppId, dlc);
}
if (Program.Canceled) return; if (Program.Canceled) return;
string[] nums = list.Split(","); List<Task> dlcTasks = new();
List<int> ids = new(); if (!(appInfo is null) && appInfo.TryGetValue("listofdlc", out list))
foreach (string s in nums) ids.Add(int.Parse(s));
foreach (int id in ids)
{ {
if (Program.Canceled) return; if (Program.Canceled) return;
string dlcName = null; Task task = new(() =>
Dictionary<string, string> dlcAppInfo = null; {
//if (SteamCMD.GetAppInfo(id, out dlcAppInfo)) dlcAppInfo.TryGetValue("name", out dlcName); try
dlc.Add(id, dlcName); {
Console.WriteLine(id + " = " + dlcName); string[] nums = list.Split(",");
List<int> ids = new();
foreach (string s in nums)
{
if (Program.Canceled) return;
ids.Add(int.Parse(s));
}
foreach (int id in ids)
{
if (Program.Canceled) return;
string dlcName = null;
Dictionary<string, string> dlcAppInfo = null;
if (SteamCMD.GetAppInfo(id, out dlcAppInfo)) dlcAppInfo.TryGetValue("name", out dlcName);
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(dlcName)) continue;
dlc.Add(new Tuple<int, string>(id, dlcName));
}
}
catch { }
});
dlcTasks.Add(task);
RunningTasks.Add(task);
task.Start();
progress.Report(-RunningTasks.Count);
} }
} else if (identifier != "Paradox Launcher") return;
else if (name != "Paradox Launcher") return; if (Program.Canceled) return;
ProgramSelection selection = new(); string displayName = identifier;
selection.Name = name; if (!(appInfo is null)) appInfo.TryGetValue("name", out displayName);
string displayName = name; if (string.IsNullOrWhiteSpace(displayName)) return;
if (!(appInfo is null)) appInfo.TryGetValue("name", out displayName); if (Program.Canceled) return;
selection.DisplayName = displayName;
selection.RootDirectory = rootDirectory;
selection.SteamAppId = steamAppId;
selection.SteamApiDllDirectories = steamApiDllDirectories;
flowLayoutPanel1.Invoke((MethodInvoker)delegate ProgramSelection selection = Program.ProgramSelections.Find(s => s.Identifier == identifier) ?? new();
{ selection.Identifier = identifier;
CheckBox checkBox = new(); selection.DisplayName = displayName;
checkBoxes.Add(checkBox); selection.RootDirectory = rootDirectory;
checkBox.AutoSize = true; selection.SteamAppId = steamAppId;
checkBox.Parent = flowLayoutPanel1; selection.SteamApiDllDirectories = steamApiDllDirectories;
checkBox.Text = selection.DisplayName;
checkBox.Checked = true;
checkBox.Enabled = false;
checkBox.TabStop = true;
checkBox.TabIndex = 1 + checkBoxes.Count;
checkBox.CheckedChanged += (sender, e) => foreach (Task task in dlcTasks.ToList())
{ {
selection.Toggle(checkBox.Checked); if (Program.Canceled) return;
acceptButton.Enabled = Program.ProgramSelections.Any(selection => selection.Enabled); progress.Report(cur++);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged; task.Wait();
allCheckBox.Checked = checkBoxes.TrueForAll(checkBox => checkBox.Checked); }
allCheckBox.CheckedChanged += OnAllCheckBoxChanged; if (Program.Canceled) return;
}; treeView1.Invoke((MethodInvoker)delegate
}); {
if (Program.Canceled) return;
TreeNode programNode = treeNodes.Find(s => s.Text == displayName) ?? new();
programNode.Text = displayName;
programNode.Remove();
treeView1.Nodes.Add(programNode);
treeNodes.Remove(programNode);
treeNodes.Add(programNode);
foreach (Tuple<int, string> dlcApp in dlc.ToList())
{
if (Program.Canceled || programNode is null) return;
TreeNode dlcNode = treeNodes.Find(s => s.Text == dlcApp.Item2) ?? new();
dlcNode.Text = dlcApp.Item2;
dlcNode.Remove();
programNode.Nodes.Add(dlcNode);
treeNodes.Remove(dlcNode);
treeNodes.Add(dlcNode);
}
});
}
catch { }
}); });
tasks.Add(task); RunningTasks.Add(task);
task.Start(); task.Start();
} }
int max = tasks.Count; progress.Report(-RunningTasks.Count);
progress.Report(max);
int cur = 0;
progress.Report(cur); progress.Report(cur);
foreach (Task task in tasks) foreach (Task task in RunningTasks.ToList())
{ {
if (Program.Canceled) return;
progress.Report(cur++); progress.Report(cur++);
task.Wait(); task.Wait();
} }
progress.Report(max); progress.Report(RunningTasks.Count);
} }
private async void OnLoad() private async void OnLoad()
@ -198,57 +234,52 @@ namespace CreamInstaller
noneFoundLabel.Visible = false; noneFoundLabel.Visible = false;
allCheckBox.Enabled = false; allCheckBox.Enabled = false;
acceptButton.Enabled = false; acceptButton.Enabled = false;
checkBoxes.ForEach(checkBox => checkBox.Enabled = false); treeView1.CheckBoxes = false;
label2.Visible = true; label2.Visible = true;
progressBar1.Visible = true; progressBar1.Visible = true;
progressBar1.Value = 0; progressBar1.Value = 0;
groupBox1.Size = new Size(groupBox1.Size.Width, groupBox1.Size.Height - 44); groupBox1.Size = new Size(groupBox1.Size.Width, groupBox1.Size.Height - 44);
AllocConsole();
bool setup = true; bool setup = true;
int maxProgress = 0; int maxProgress = 0;
int curProgress = 0;
Progress<int> progress = new(); Progress<int> progress = new();
IProgress<int> iProgress = progress; IProgress<int> iProgress = progress;
progress.ProgressChanged += (sender, _progress) => progress.ProgressChanged += (sender, _progress) =>
{ {
if (maxProgress == 0) maxProgress = _progress; if (_progress < 0) maxProgress = -_progress;
else else curProgress = _progress;
{ int p = Math.Max(Math.Min((int)((float)(curProgress / (float)maxProgress) * 100), 100), 0);
int p = Math.Max(Math.Min((int)((float)(_progress / (float)maxProgress) * 100), 100), 0); if (setup) label2.Text = "Setting up SteamCMD . . . " + p + "%";
if (setup) label2.Text = "Setting up SteamCMD . . . " + p + "% (" + _progress + "/" + maxProgress + ")"; else label2.Text = "Gathering your CreamAPI-applicable games and their DLCs . . . " + p + "%";
else label2.Text = "Scanning for CreamAPI-applicable programs on your computer . . . " + p + "% (" + _progress + "/" + maxProgress + ")"; progressBar1.Value = p;
progressBar1.Value = p;
}
}; };
int max = 1660; // not exact, number varies iProgress.Report(-1660); // not exact, number varies
iProgress.Report(max);
int cur = 0; int cur = 0;
iProgress.Report(cur); iProgress.Report(cur);
label2.Text = "Setting up SteamCMD . . . "; label2.Text = "Setting up SteamCMD . . . ";
FileSystemWatcher watcher = new FileSystemWatcher(SteamCMD.DirectoryPath); if (!Directory.Exists(SteamCMD.DirectoryPath)) Directory.CreateDirectory(SteamCMD.DirectoryPath);
FileSystemWatcher watcher = new(SteamCMD.DirectoryPath);
watcher.Changed += (sender, e) => iProgress.Report(++cur); watcher.Changed += (sender, e) => iProgress.Report(++cur);
watcher.Filter = "*"; watcher.Filter = "*";
watcher.IncludeSubdirectories = true; watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true; watcher.EnableRaisingEvents = true;
await Task.Run(() => SteamCMD.Setup()); await Task.Run(() => SteamCMD.Setup());
watcher.Dispose(); watcher.Dispose();
Clipboard.SetText(cur.ToString());
maxProgress = 0;
setup = false; setup = false;
label2.Text = "Scanning for CreamAPI-applicable programs on your computer . . . "; label2.Text = "Gathering your CreamAPI-applicable games and their DLCs . . . ";
await Task.Run(() => GetCreamApiApplicablePrograms(iProgress)); await Task.Run(() => GetCreamApiApplicablePrograms(iProgress));
Program.ProgramSelections.ForEach(selection => selection.SteamApiDllDirectories.RemoveAll(directory => !Directory.Exists(directory))); Program.ProgramSelections.ForEach(selection => selection.SteamApiDllDirectories.RemoveAll(directory => !Directory.Exists(directory)));
Program.ProgramSelections.RemoveAll(selection => !Directory.Exists(selection.RootDirectory) || !selection.SteamApiDllDirectories.Any()); Program.ProgramSelections.RemoveAll(selection => !Directory.Exists(selection.RootDirectory) || !selection.SteamApiDllDirectories.Any());
foreach (CheckBox checkBox in checkBoxes) foreach (TreeNode treeNode in treeNodes)
{ {
if (!Program.ProgramSelections.Any(selection => selection.DisplayName == checkBox.Text)) if (treeNode.Parent is null && !Program.ProgramSelections.Any(selection => selection.DisplayName == treeNode.Text))
{ {
checkBox.Dispose(); treeNode.Remove();
} }
} }
@ -260,7 +291,9 @@ namespace CreamInstaller
if (Program.ProgramSelections.Any()) if (Program.ProgramSelections.Any())
{ {
allCheckBox.Enabled = true; allCheckBox.Enabled = true;
checkBoxes.ForEach(checkBox => checkBox.Enabled = true); treeView1.CheckBoxes = true;
treeView1.ExpandAll();
treeNodes.ForEach(node => node.Checked = true);
if (Program.ProgramSelections.Any(selection => selection.Enabled)) if (Program.ProgramSelections.Any(selection => selection.Enabled))
{ {
acceptButton.Enabled = true; acceptButton.Enabled = true;
@ -275,8 +308,32 @@ namespace CreamInstaller
scanButton.Enabled = true; scanButton.Enabled = true;
} }
private void OnChange(object sender, TreeViewEventArgs e)
{
ProgramSelection selection = Program.ProgramSelections.ToList().Find(selection => selection.DisplayName == e.Node.Text);
if (selection is null)
{
treeView1.AfterCheck -= OnChange;
e.Node.Parent.Checked = e.Node.Parent.Nodes.Cast<TreeNode>().ToList().Any(treeNode => treeNode.Checked);
treeView1.AfterCheck += OnChange;
}
else
{
selection.Toggle(e.Node.Checked);
treeView1.AfterCheck -= OnChange;
e.Node.Nodes.Cast<TreeNode>().ToList().ForEach(treeNode => treeNode.Checked = e.Node.Checked);
treeView1.AfterCheck += OnChange;
acceptButton.Enabled = Program.ProgramSelections.ToList().Any(selection => selection.Enabled);
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
allCheckBox.Checked = treeNodes.TrueForAll(treeNode => treeNode.Checked);
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
}
}
private void OnLoad(object sender, EventArgs e) private void OnLoad(object sender, EventArgs e)
{ {
treeView1.BeforeCollapse += (sender, e) => e.Cancel = true;
treeView1.AfterCheck += OnChange;
OnLoad(); OnLoad();
} }
@ -284,7 +341,7 @@ namespace CreamInstaller
{ {
if (Program.ProgramSelections.Count > 0) if (Program.ProgramSelections.Count > 0)
{ {
foreach (ProgramSelection selection in Program.ProgramSelections) foreach (ProgramSelection selection in Program.ProgramSelections.ToList())
{ {
if (!Program.IsProgramRunningDialog(this, selection)) if (!Program.IsProgramRunningDialog(this, selection))
{ {
@ -297,11 +354,11 @@ namespace CreamInstaller
installForm.ShowDialog(); installForm.ShowDialog();
if (installForm.Reselecting) if (installForm.Reselecting)
{ {
foreach (CheckBox checkBox in checkBoxes) //foreach (TreeNode treeNode in treeNodes)
{ //{
checkBox.Checked = !checkBox.Checked; // treeNode.Checked = !treeNode.Checked;
checkBox.Checked = !checkBox.Checked; // to fire CheckChanged // treeNode.Checked = !treeNode.Checked; // to fire checked event
} //}
int X = installForm.Location.X + installForm.Size.Width / 2 - Size.Width / 2; int X = installForm.Location.X + installForm.Size.Width / 2 - Size.Width / 2;
int Y = installForm.Location.Y + installForm.Size.Height / 2 - Size.Height / 2; int Y = installForm.Location.Y + installForm.Size.Height / 2 - Size.Height / 2;
Location = new Point(X, Y); Location = new Point(X, Y);
@ -327,17 +384,12 @@ namespace CreamInstaller
private void OnAllCheckBoxChanged(object sender, EventArgs e) private void OnAllCheckBoxChanged(object sender, EventArgs e)
{ {
bool shouldCheck = false; bool shouldCheck = false;
foreach (CheckBox checkBox in checkBoxes) foreach (TreeNode treeNode in treeNodes)
{ if (treeNode.Parent is null && !treeNode.Checked)
if (!checkBox.Checked)
{
shouldCheck = true; shouldCheck = true;
} foreach (TreeNode treeNode in treeNodes)
} if (treeNode.Parent is null)
foreach (CheckBox checkBox in checkBoxes) treeNode.Checked = shouldCheck;
{
checkBox.Checked = shouldCheck;
}
allCheckBox.Checked = shouldCheck; allCheckBox.Checked = shouldCheck;
} }
} }

View file

@ -1,5 +1,4 @@
using SteamCmdFluentApi; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -11,43 +10,68 @@ namespace CreamInstaller
public static class SteamCMD public static class SteamCMD
{ {
public static string DirectoryPath = Path.GetTempPath() + "CreamInstaller"; public static string DirectoryPath = Path.GetTempPath() + "CreamInstaller";
public static string FilePath = DirectoryPath + "\\steamcmd.exe"; public static string FilePath = DirectoryPath + @"\steamcmd.exe";
public static string ArchivePath = DirectoryPath + "\\steamcmd.zip"; public static string ArchivePath = DirectoryPath + @"\steamcmd.zip";
public static string DllPath = DirectoryPath + "\\steamclient.dll"; public static string DllPath = DirectoryPath + @"\steamclient.dll";
public static string AppUpdatePath = DirectoryPath + @"\appupdate";
private static SteamCmd current = null; public static bool Run(string command, out string output)
public static SteamCmd Current
{ {
get bool success = true;
List<string> logs = new();
ProcessStartInfo processStartInfo = new()
{ {
if (current is null) current = SteamCmd.WithExecutable(FilePath); FileName = FilePath,
return current; RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true,
UseShellExecute = false,
Arguments = command,
CreateNoWindow = true
};
using (Process process = Process.Start(processStartInfo))
{
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => logs.Add(e.Data);
process.BeginOutputReadLine();
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => logs.Add(e.Data);
process.BeginErrorReadLine();
process.WaitForExit();
} }
output = string.Join("\r\n", logs);
return success;
} }
public static void Setup() public static void Setup()
{ {
Kill(); Kill();
if (!Directory.Exists(DirectoryPath)) Directory.CreateDirectory(DirectoryPath);
if (!File.Exists(FilePath)) if (!File.Exists(FilePath))
{ {
using (WebClient webClient = new WebClient()) webClient.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", ArchivePath); using (WebClient webClient = new()) webClient.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", ArchivePath);
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath); ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
File.Delete(ArchivePath); File.Delete(ArchivePath);
} }
if (!File.Exists(DllPath)) Current.TryToExecuteCommand($@"+login anonymous +app_info_update 1 +quit", out _); if (!File.Exists(DllPath)) Run($@"+quit", out _);
} }
public static bool GetAppInfo(int steamAppId, out Dictionary<string, string> appInfo) public static bool GetAppInfo(int steamAppId, out Dictionary<string, string> appInfo)
{ {
appInfo = new(); appInfo = new();
if (Program.Canceled) return false; if (Program.Canceled) return false;
// need to find a way to request app info, currently it won't work from the command line like below string output = null;
bool success = Current.TryToExecuteCommand($@"+login anonymous +app_info_update 1 +app_info_request {steamAppId} +app_info_print {steamAppId} +quit", out string output); string appUpdatePath = $@"{AppUpdatePath}\{steamAppId}";
if (!success) return false; string appUpdateFile = $@"{appUpdatePath}\appinfo.txt";
if (Directory.Exists(appUpdatePath) && File.Exists(appUpdateFile)) output = File.ReadAllText(appUpdateFile);
else
{
Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {steamAppId} +force_install_dir {appUpdatePath} +app_update 4 +quit", out _);
if (Program.Canceled) return false;
Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {steamAppId} +quit", out output);
File.WriteAllText(appUpdateFile, output);
}
if (Program.Canceled || output is null) return false;
foreach (string s in output.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) foreach (string s in output.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
{ {
if (Program.Canceled) return false;
int first = s.IndexOf("\""); int first = s.IndexOf("\"");
int second = 1 + first + s.Substring(first + 1).IndexOf("\""); int second = 1 + first + s.Substring(first + 1).IndexOf("\"");
int third = 1 + second + s.Substring(second + 1).IndexOf("\""); int third = 1 + second + s.Substring(second + 1).IndexOf("\"");
@ -65,7 +89,7 @@ namespace CreamInstaller
public static void Kill() public static void Kill()
{ {
foreach (Process process in Process.GetProcessesByName("steamcmd")) { process.Kill(); process.WaitForExit(); } foreach (Process process in Process.GetProcessesByName("steamcmd")) process.Kill();
} }
public static void Dispose() public static void Dispose()