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

View file

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

View file

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

View file

@ -1,5 +1,4 @@

using System;
using System.Windows.Forms;
namespace CreamInstaller
@ -37,9 +36,9 @@ namespace CreamInstaller
this.cancelButton = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.allCheckBox = new System.Windows.Forms.CheckBox();
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.label2 = new System.Windows.Forms.Label();
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)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox1.Controls.Add(this.allCheckBox);
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.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(460, 236);
@ -91,6 +90,32 @@ namespace CreamInstaller
this.groupBox1.TabStop = false;
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
//
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.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
//
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.Label label1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox allCheckBox;
private Label noneFoundLabel;
private Button scanButton;
private TreeView treeView1;
private Label noneFoundLabel;
}
}

View file

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

View file

@ -1,5 +1,4 @@
using SteamCmdFluentApi;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -11,43 +10,68 @@ namespace CreamInstaller
public static class SteamCMD
{
public static string DirectoryPath = Path.GetTempPath() + "CreamInstaller";
public static string FilePath = DirectoryPath + "\\steamcmd.exe";
public static string ArchivePath = DirectoryPath + "\\steamcmd.zip";
public static string DllPath = DirectoryPath + "\\steamclient.dll";
public static string FilePath = DirectoryPath + @"\steamcmd.exe";
public static string ArchivePath = DirectoryPath + @"\steamcmd.zip";
public static string DllPath = DirectoryPath + @"\steamclient.dll";
public static string AppUpdatePath = DirectoryPath + @"\appupdate";
private static SteamCmd current = null;
public static SteamCmd Current
public static bool Run(string command, out string output)
{
get
bool success = true;
List<string> logs = new();
ProcessStartInfo processStartInfo = new()
{
if (current is null) current = SteamCmd.WithExecutable(FilePath);
return current;
FileName = FilePath,
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()
{
Kill();
if (!Directory.Exists(DirectoryPath)) Directory.CreateDirectory(DirectoryPath);
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);
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)
{
appInfo = new();
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
bool success = Current.TryToExecuteCommand($@"+login anonymous +app_info_update 1 +app_info_request {steamAppId} +app_info_print {steamAppId} +quit", out string output);
if (!success) return false;
string output = null;
string appUpdatePath = $@"{AppUpdatePath}\{steamAppId}";
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))
{
if (Program.Canceled) return false;
int first = s.IndexOf("\"");
int second = 1 + first + s.Substring(first + 1).IndexOf("\"");
int third = 1 + second + s.Substring(second + 1).IndexOf("\"");
@ -65,7 +89,7 @@ namespace CreamInstaller
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()