proper game gathering, depot dlcs, appinfo caching

This commit is contained in:
pointfeev 2021-11-06 04:55:37 -04:00
parent b11e5e9fcb
commit 351847727b
No known key found for this signature in database
GPG key ID: AA14DC36C4D7D13C
6 changed files with 195 additions and 178 deletions

View file

@ -52,7 +52,7 @@ namespace CreamInstaller
int cur = 0;
foreach (string directory in selection.SteamApiDllDirectories)
{
UpdateUser("Installing CreamAPI for " + selection.DisplayName + $" in directory \"{directory}\" . . . ", LogColor.Operation);
UpdateUser("Installing CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", LogColor.Operation);
if (!Program.IsProgramRunningDialog(this, selection)) throw new OperationCanceledException();
string api = directory + @"\steam_api.dll";
string api_o = directory + @"\steam_api_o.dll";
@ -89,7 +89,7 @@ namespace CreamInstaller
writer.WriteLine($"appid = {selection.SteamAppId}");
writer.WriteLine();
writer.WriteLine("[dlc]");
UpdateUser($"Added game to cream_api.ini with appid {selection.SteamAppId} ({selection.DisplayName})", LogColor.Resource);
UpdateUser($"Added game to cream_api.ini with appid {selection.SteamAppId} ({selection.Name})", LogColor.Resource);
foreach (Tuple<int, string> dlcApp in selection.SelectedSteamDlc)
{
writer.WriteLine($"{dlcApp.Item1} = {dlcApp.Item2}");
@ -129,12 +129,12 @@ namespace CreamInstaller
try
{
await OperateFor(selection);
UpdateUser($"Operation succeeded for {selection.DisplayName}.", LogColor.Success);
UpdateUser($"Operation succeeded for {selection.Name}.", LogColor.Success);
selection.Enabled = false;
}
catch (Exception exception)
{
UpdateUser($"Operation failed for {selection.DisplayName}: " + exception.ToString(), LogColor.Error);
UpdateUser($"Operation failed for {selection.Name}: " + exception.ToString(), LogColor.Error);
}
++CompleteOperationsCount;
}
@ -144,7 +144,7 @@ namespace CreamInstaller
{
if (FailedSelections.Count == 1)
{
throw new CustomMessageException($"Operation failed for {FailedSelections.First().DisplayName}.");
throw new CustomMessageException($"Operation failed for {FailedSelections.First().Name}.");
}
else
{

View file

@ -39,7 +39,7 @@ namespace CreamInstaller
if (selection.AreSteamApiDllsLocked)
{
if (new DialogForm(form).Show(ApplicationName, SystemIcons.Error,
$"ERROR: {selection.DisplayName} is currently running!" +
$"ERROR: {selection.Name} is currently running!" +
"\n\nPlease close the program/game to continue . . . ",
"Retry", "Cancel") == DialogResult.OK)
{

View file

@ -1,4 +1,5 @@
using System;
using Gameloop.Vdf.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
@ -8,13 +9,13 @@ namespace CreamInstaller
{
public bool Enabled = true;
public string Identifier;
public string DisplayName;
public string Name;
public string RootDirectory;
public int SteamAppId;
public List<string> SteamApiDllDirectories;
public Dictionary<string, string> AppInfo = new();
public VProperty AppInfo = null;
public List<Tuple<int, string>> AllSteamDlc = new();
public List<Tuple<int, string>> SelectedSteamDlc = new();
public List<Tuple<int, string, List<Tuple<int, string>>>> ExtraSteamAppIdDlc = new();
@ -47,9 +48,10 @@ namespace CreamInstaller
}
}
else SelectedSteamDlc.Remove(dlcApp);
return;
break;
}
}
if (!SelectedSteamDlc.Any()) this.Enabled = false;
}
public ProgramSelection() => All.Add(this);
@ -60,8 +62,6 @@ namespace CreamInstaller
public static List<ProgramSelection> AllSafeEnabled => AllSafe.FindAll(s => s.Enabled);
public static ProgramSelection FromIdentifier(string identifier) => AllSafe.Find(s => s.Identifier == identifier);
public static ProgramSelection FromDisplayName(string displayName) => AllSafe.Find(s => s.DisplayName == displayName);
public static ProgramSelection FromName(string displayName) => AllSafe.Find(s => s.Name == displayName);
}
}

View file

@ -108,11 +108,11 @@ namespace CreamInstaller
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.BackColor = System.Drawing.SystemColors.Control;
this.treeView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
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;
//

View file

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -32,63 +31,70 @@ namespace CreamInstaller
if (steamInstallPath == null) steamInstallPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Valve\\Steam", "InstallPath", null) as string;
if (steamInstallPath != null)
{
string mainLibraryFolder = steamInstallPath + "\\steamapps\\common";
gameDirectories.Add(mainLibraryFolder);
string libraryFolders = steamInstallPath + "\\steamapps\\libraryfolders.vdf";
VProperty property = VdfConvert.Deserialize(File.ReadAllText(libraryFolders));
foreach (VProperty _property in property.Value)
if (int.TryParse(_property.Key, out _) && Directory.Exists(_property.Value.ToString()))
gameDirectories.Add(_property.Value.ToString());
string libraryFolder = steamInstallPath + @"\steamapps";
gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
dynamic property = VdfConvert.Deserialize(File.ReadAllText(libraryFolders));
foreach (dynamic _property in property.Value)
{
if (int.TryParse(_property.Key, out int _))
{
string path = _property.Value.path.ToString() + @"\steamapps";
if (string.IsNullOrWhiteSpace(path)) continue;
if (!gameDirectories.Contains(path)) gameDirectories.Add(path);
}
}
}
return gameDirectories;
}
}
private bool GetSteamApiDllDirectoriesFromGameDirectory(string gameDirectory, out List<string> steamApiDllDirectories)
private bool GetDllDirectoriesFromGameDirectory(string gameDirectory, out List<string> dllDirectories)
{
steamApiDllDirectories = new();
dllDirectories = new();
if (Program.Canceled) return false;
string api = gameDirectory + @"\steam_api.dll";
string api64 = gameDirectory + @"\steam_api64.dll";
if (File.Exists(api) || File.Exists(api64)) steamApiDllDirectories.Add(gameDirectory);
if (File.Exists(api) || File.Exists(api64)) dllDirectories.Add(gameDirectory);
foreach (string _directory in Directory.GetDirectories(gameDirectory))
{
if (Program.Canceled) return false;
try
{
if (GetSteamApiDllDirectoriesFromGameDirectory(_directory, out List<string> _steamApiDllDirectories))
steamApiDllDirectories.AddRange(_steamApiDllDirectories);
if (GetDllDirectoriesFromGameDirectory(_directory, out List<string> _dllDirectories))
dllDirectories.AddRange(_dllDirectories);
}
catch { }
}
if (!steamApiDllDirectories.Any()) return false;
if (!dllDirectories.Any()) return false;
return true;
}
private bool GetSteamAppIdFromGameDirectory(string gameDirectory, out int appId)
private bool GetGamesFromLibraryDirectory(string libraryDirectory, out List<Tuple<int, string, int, string>> games)
{
appId = 0;
games = new();
if (Program.Canceled) return false;
string file = gameDirectory + "\\steam_appid.txt";
if (File.Exists(file) && int.TryParse(File.ReadAllText(file), out appId)) return true;
foreach (string _directory in Directory.GetDirectories(gameDirectory))
foreach (string directory in Directory.GetFiles(libraryDirectory))
{
if (Program.Canceled) return false;
if (GetSteamAppIdFromGameDirectory(_directory, out appId)) return true;
if (Path.GetExtension(directory) == ".acf")
{
dynamic property = VdfConvert.Deserialize(File.ReadAllText(directory));
string _appid = property.Value.appid.ToString();
string installdir = property.Value.installdir.ToString();
string name = property.Value.name.ToString();
string _buildid = property.Value.buildid.ToString();
if (string.IsNullOrWhiteSpace(_appid)
|| string.IsNullOrWhiteSpace(installdir)
|| string.IsNullOrWhiteSpace(name)
|| string.IsNullOrWhiteSpace(_buildid)) continue;
string gameDirectory = libraryDirectory + @"\common\" + installdir;
if (!int.TryParse(_appid, out int appid)) continue;
if (!int.TryParse(_buildid, out int buildid)) continue;
games.Add(new(appid, name, buildid, gameDirectory));
}
}
return false;
}
private bool GetGameDirectoriesFromLibraryDirectory(string libraryDirectory, out List<string> gameDirectories)
{
gameDirectories = new();
if (Program.Canceled) return false;
foreach (string _directory in Directory.GetDirectories(libraryDirectory))
{
if (Program.Canceled) return false;
if (Directory.Exists(_directory)) gameDirectories.Add(_directory);
}
if (!gameDirectories.Any()) return false;
if (!games.Any()) return false;
return true;
}
@ -102,120 +108,121 @@ namespace CreamInstaller
{
int cur = 0;
if (Program.Canceled) return;
List<Tuple<string, string>> applicablePrograms = new();
List<Tuple<int, string, int, string>> applicablePrograms = new();
string launcherRootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Programs\\Paradox Interactive";
if (Directory.Exists(launcherRootDirectory)) applicablePrograms.Add(new Tuple<string, string>("Paradox Launcher", launcherRootDirectory));
if (Directory.Exists(launcherRootDirectory)) applicablePrograms.Add(new(0, "Paradox Launcher", 0, launcherRootDirectory));
foreach (string libraryDirectory in GameLibraryDirectories)
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));
if (GetGamesFromLibraryDirectory(libraryDirectory, out List<Tuple<int, string, int, string>> games))
foreach (Tuple<int, string, int, string> game in games)
applicablePrograms.Add(game);
RunningTasks = new();
foreach (Tuple<string, string> program in applicablePrograms)
foreach (Tuple<int, string, int, string> program in applicablePrograms)
{
string identifier = program.Item1;
string rootDirectory = program.Item2;
int appId = program.Item1;
string name = program.Item2;
int buildId = program.Item3;
string directory = program.Item4;
if (Program.Canceled) return;
if (Directory.Exists(directory + @"\EasyAntiCheat")) continue;
Task task = new(() =>
{
try
if (Program.Canceled || !GetDllDirectoriesFromGameDirectory(directory, out List<string> dllDirectories)) return;
VProperty appInfo = null;
if (Program.Canceled || (name != "Paradox Launcher" && !SteamCMD.GetAppInfo(appId, buildId, out appInfo))) return;
List<Tuple<int, string>> dlc = null;
if (!DLC.TryGetValue(appId, out dlc))
{
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(appId, dlc);
}
if (Program.Canceled) return;
List<Task> dlcTasks = new();
List<int> dlcIds = new();
if (!(appInfo is null))
{
try
{
dlc = new();
DLC.Add(steamAppId, dlc);
if (!(appInfo.Value["extended"] is null))
foreach (VProperty property in appInfo.Value["extended"])
if (property.Key.ToString() == "listofdlc")
foreach (string id in property.Value.ToString().Split(","))
if (!dlcIds.Contains(int.Parse(id)))
dlcIds.Add(int.Parse(id));
}
if (Program.Canceled) return;
List<Task> dlcTasks = new();
if (!(appInfo is null) && appInfo.TryGetValue("listofdlc", out list))
catch { }
try
{
if (!(appInfo.Value["depots"] is null))
foreach (VProperty _property in appInfo.Value["depots"])
if (int.TryParse(_property.Key.ToString(), out int _))
if (int.TryParse(_property.Value?["dlcappid"]?.ToString(), out int appid) && !dlcIds.Contains(appid))
dlcIds.Add(appid);
}
catch { }
}
if (!(dlcIds is null) && dlcIds.Count > 0)
{
foreach (int id in dlcIds)
{
if (Program.Canceled) return;
string[] nums = Regex.Replace(list, "[^0-9,]+", "").Split(",");
List<int> ids = new();
foreach (string s in nums)
{
if (Program.Canceled) return;
ids.Add(int.Parse(s));
}
Task task = new(() =>
{
try
{
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)) dlcName = "Unknown DLC";
dlc.Add(new Tuple<int, string>(id, dlcName));
}
}
catch { }
if (Program.Canceled) return;
string dlcName = null;
VProperty dlcAppInfo = null;
if (SteamCMD.GetAppInfo(id, 0, out dlcAppInfo)) try { dlcName = dlcAppInfo?.Value?["common"]?["name"]?.ToString(); } catch { }
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(dlcName)) dlcName = $"Unnamed DLC ({id})";
dlc.Add(new Tuple<int, string>(id, dlcName));
});
dlcTasks.Add(task);
RunningTasks.Add(task);
task.Start();
progress.Report(-RunningTasks.Count);
}
else if (identifier != "Paradox Launcher") return;
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(identifier)) return;
string displayName = identifier;
if (!(appInfo is null)) appInfo.TryGetValue("name", out displayName);
if (string.IsNullOrWhiteSpace(displayName)) displayName = "Unknown Game";
if (Program.Canceled) return;
ProgramSelection selection = ProgramSelection.FromIdentifier(identifier) ?? new();
selection.Identifier = identifier;
selection.DisplayName = displayName;
selection.RootDirectory = rootDirectory;
selection.SteamAppId = steamAppId;
selection.SteamApiDllDirectories = steamApiDllDirectories;
selection.AppInfo = appInfo;
foreach (Task task in dlcTasks.ToList())
{
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);
selection.AllSteamDlc.Add(dlcApp);
selection.SelectedSteamDlc.Add(dlcApp);
}
});
}
catch { }
else if (name != "Paradox Launcher") return;
if (Program.Canceled) return;
if (string.IsNullOrWhiteSpace(name)) return;
if (Program.Canceled) return;
ProgramSelection selection = ProgramSelection.FromName(name) ?? new();
selection.Name = name;
selection.RootDirectory = directory;
selection.SteamAppId = appId;
selection.SteamApiDllDirectories = dllDirectories;
selection.AppInfo = appInfo;
foreach (Task task in dlcTasks.ToList())
{
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 == name) ?? new();
programNode.Text = name;
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);
selection.AllSteamDlc.Add(dlcApp);
selection.SelectedSteamDlc.Add(dlcApp);
}
});
});
RunningTasks.Add(task);
task.Start();
@ -282,7 +289,7 @@ namespace CreamInstaller
ProgramSelection.All.RemoveAll(selection => !Directory.Exists(selection.RootDirectory) || !selection.SteamApiDllDirectories.Any());
foreach (TreeNode treeNode in treeNodes)
{
if (treeNode.Parent is null && ProgramSelection.FromDisplayName(treeNode.Text) is null)
if (treeNode.Parent is null && ProgramSelection.FromName(treeNode.Text) is null)
{
treeNode.Remove();
}
@ -297,7 +304,6 @@ namespace CreamInstaller
{
allCheckBox.Enabled = true;
treeView1.CheckBoxes = true;
treeView1.ExpandAll();
treeNodes.ForEach(node => node.Checked = true);
if (ProgramSelection.AllSafeEnabled.Any())
{
@ -315,10 +321,10 @@ namespace CreamInstaller
private void OnTreeViewNodeCheckedChanged(object sender, TreeViewEventArgs e)
{
ProgramSelection selection = ProgramSelection.FromDisplayName(e.Node.Text);
ProgramSelection selection = ProgramSelection.FromName(e.Node.Text);
if (selection is null)
{
selection = ProgramSelection.FromDisplayName(e.Node.Parent.Text);
selection = ProgramSelection.FromName(e.Node.Parent.Text);
treeView1.AfterCheck -= OnTreeViewNodeCheckedChanged;
e.Node.Parent.Checked = e.Node.Parent.Nodes.Cast<TreeNode>().ToList().Any(treeNode => treeNode.Checked);
treeView1.AfterCheck += OnTreeViewNodeCheckedChanged;
@ -339,30 +345,29 @@ namespace CreamInstaller
private void OnLoad(object sender, EventArgs e)
{
treeView1.BeforeCollapse += (sender, e) => e.Cancel = true;
treeView1.AfterCheck += OnTreeViewNodeCheckedChanged;
OnLoad();
}
private static bool ParadoxLauncherDlcDialog(Form form)
{
ProgramSelection paradoxLauncher = ProgramSelection.FromIdentifier("Paradox Launcher");
ProgramSelection paradoxLauncher = ProgramSelection.FromName("Paradox Launcher");
if (!(paradoxLauncher is null) && paradoxLauncher.Enabled)
{
paradoxLauncher.ExtraSteamAppIdDlc = new();
foreach (ProgramSelection selection in ProgramSelection.AllSafeEnabled)
{
if (selection.Identifier == paradoxLauncher.Identifier) continue;
if (!selection.AppInfo.TryGetValue("publisher", out string publisher) || publisher != "Paradox Interactive") continue;
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.DisplayName, selection.SelectedSteamDlc));
if (selection.Name == paradoxLauncher.Name) continue;
if (selection.AppInfo.Value["extended"]["publisher"].ToString() != "Paradox Interactive") continue;
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.Name, selection.SelectedSteamDlc));
}
if (!paradoxLauncher.ExtraSteamAppIdDlc.Any())
{
foreach (ProgramSelection selection in ProgramSelection.AllSafe)
{
if (selection.Identifier == paradoxLauncher.Identifier) continue;
if (!selection.AppInfo.TryGetValue("publisher", out string publisher) || publisher != "Paradox Interactive") continue;
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.DisplayName, selection.AllSteamDlc));
if (selection.Name == paradoxLauncher.Name) continue;
if (selection.AppInfo.Value["extended"]["publisher"].ToString() != "Paradox Interactive") continue;
paradoxLauncher.ExtraSteamAppIdDlc.Add(new(selection.SteamAppId, selection.Name, selection.AllSteamDlc));
}
}
if (!paradoxLauncher.ExtraSteamAppIdDlc.Any())

View file

@ -1,4 +1,5 @@
using System;
using Gameloop.Vdf;
using Gameloop.Vdf.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -53,37 +54,48 @@ namespace CreamInstaller
if (!File.Exists(DllPath)) Run($@"+quit", out _);
}
public static bool GetAppInfo(int steamAppId, out Dictionary<string, string> appInfo)
private static Dictionary<int, int> retries = new();
public static bool GetAppInfo(int appId, int buildId, out VProperty appInfo)
{
appInfo = new();
appInfo = null;
if (Program.Canceled) return false;
string output;
string appUpdatePath = $@"{AppInfoCachePath}\{steamAppId}";
string appUpdatePath = $@"{AppInfoCachePath}\{appId}";
string appUpdateFile = $@"{appUpdatePath}\appinfo.txt";
// need a fast way to make sure the cached info is up-to-date and correct
//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 _);
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 (Directory.Exists(appUpdatePath) && File.Exists(appUpdateFile)) output = File.ReadAllText(appUpdateFile);
else
{
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("\"");
int fourth = 1 + third + s.Substring(third + 1).IndexOf("\"");
if (first > -1 && second > 0 && third > 0 && fourth > 0)
Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +force_install_dir {appUpdatePath} +app_update 4 +quit", out _);
Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +quit", out output);
int openBracket = output.IndexOf("{");
int closeBracket = output.LastIndexOf("}");
output = $"\"{appId}\"\n" + output.Substring(openBracket, 1 + closeBracket - openBracket);
File.WriteAllText(appUpdateFile, output);
}
if (Program.Canceled || output is null) return false;
appInfo = VdfConvert.Deserialize(output);
try
{
VToken type = appInfo?.Value?["common"]?["type"];
if (type is null || type.ToString() == "Game")
{
string a = s.Substring(first + 1, Math.Max(second - first - 1, 0));
string b = s.Substring(third + 1, Math.Max(fourth - third - 1, 0));
if (string.IsNullOrWhiteSpace(a) || string.IsNullOrWhiteSpace(b)) continue;
if (!appInfo.TryGetValue(a, out _)) appInfo.Add(a, b);
string buildid = appInfo.Value["depots"]?["public"]?["buildid"]?.ToString();
buildid = buildid ?? appInfo.Value["depots"]?["branches"]?["public"]?["buildid"]?.ToString();
if (type is null || int.Parse(buildid) < buildId
|| appInfo.Value["extended"] is null
|| appInfo.Value["depots"] is null)
{
if (retries.TryGetValue(appId, out int count)) retries[appId] = ++count;
else retries.Add(appId, 1);
if (count > 3) return false;
File.Delete(appUpdateFile);
bool success = GetAppInfo(appId, buildId, out appInfo);
return success;
}
}
}
catch { }
return true;
}