fix concurrency error, add better exception handling, create folders
This commit is contained in:
parent
d84809ec2c
commit
cdb9d6a658
20 changed files with 113 additions and 57 deletions
|
@ -24,6 +24,7 @@
|
|||
<Authors>pointfeev</Authors>
|
||||
<PackageId>pointfeev.creaminstaller</PackageId>
|
||||
<StartupObject>CreamInstaller.Program</StartupObject>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
|
@ -38,11 +39,11 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="steam_api64.dll" />
|
||||
<EmbeddedResource Include="Resources\steam_api64.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="steam_api.dll" />
|
||||
<EmbeddedResource Include="Resources\steam_api.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -51,8 +52,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="MainForm.cs" />
|
||||
<Compile Update="SelectForm.cs" />
|
||||
<Compile Update="Forms\MainForm.cs" />
|
||||
<Compile Update="Forms\SelectForm.cs" />
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
public class CustomMessageException : Exception
|
||||
{
|
||||
private string message;
|
||||
public override string Message => message ?? "CustomMessageException";
|
||||
|
||||
public override string ToString() => Message;
|
||||
|
||||
public CustomMessageException(string message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
55
CreamInstaller/ExceptionHandler.cs
Normal file
55
CreamInstaller/ExceptionHandler.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
public static class ExceptionHandler
|
||||
{
|
||||
public static bool OutputException(Exception e)
|
||||
{
|
||||
while (!(e.InnerException is null)) e = e.InnerException;
|
||||
string output = "";
|
||||
string[] stackTrace = e.StackTrace?.Split('\n');
|
||||
if (!(stackTrace is null) && stackTrace.Length > 0)
|
||||
{
|
||||
output += "STACK TRACE\n";
|
||||
for (int i = 0; i < Math.Min(stackTrace.Length, 3); i++)
|
||||
{
|
||||
string line = stackTrace[i];
|
||||
if (!(line is null))
|
||||
{
|
||||
output += "\n " + line.Substring(line.IndexOf("at"));
|
||||
}
|
||||
}
|
||||
}
|
||||
string[] messageLines = e.Message?.Split('\n');
|
||||
if (!(messageLines is null) && messageLines.Length > 0)
|
||||
{
|
||||
if (output.Length > 0) output += "\n\n";
|
||||
output += "MESSAGE\n";
|
||||
for (int i = 0; i < messageLines.Length; i++)
|
||||
{
|
||||
string line = messageLines[i];
|
||||
if (!(line is null))
|
||||
{
|
||||
output += "\n " + messageLines[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return MessageBox.Show(output, caption: "CreamInstaller encountered an exception", buttons: MessageBoxButtons.RetryCancel, icon: MessageBoxIcon.Error) == DialogResult.Retry;
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomMessageException : Exception
|
||||
{
|
||||
private string message;
|
||||
public override string Message => message ?? "CustomMessageException";
|
||||
|
||||
public override string ToString() => Message;
|
||||
|
||||
public CustomMessageException(string message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Gameloop.Vdf.Linq;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
|
@ -75,7 +76,7 @@ namespace CreamInstaller
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool GetGamesFromLibraryDirectory(string libraryDirectory, out List<Tuple<int, string, int, string>> games)
|
||||
private bool GetGamesFromLibraryDirectory(string libraryDirectory, out List<Tuple<int, string, string, int, string>> games)
|
||||
{
|
||||
games = new();
|
||||
if (Program.Canceled) return false;
|
||||
|
@ -91,14 +92,16 @@ namespace CreamInstaller
|
|||
string installdir = property.Value.installdir.ToString();
|
||||
string name = property.Value.name.ToString();
|
||||
string _buildid = property.Value.buildid.ToString();
|
||||
if (string.IsNullOrWhiteSpace(_appid)
|
||||
if (string.IsNullOrWhiteSpace(_appid)
|
||||
|| string.IsNullOrWhiteSpace(installdir)
|
||||
|| string.IsNullOrWhiteSpace(name)
|
||||
|| string.IsNullOrWhiteSpace(_buildid)) continue;
|
||||
string gameDirectory = libraryDirectory + @"\common\" + installdir;
|
||||
string branch = property.Value.UserConfig?.betakey?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(branch)) branch = "public";
|
||||
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));
|
||||
games.Add(new(appid, name, branch, buildid, gameDirectory));
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
@ -109,46 +112,39 @@ namespace CreamInstaller
|
|||
|
||||
private readonly List<TreeNode> treeNodes = new();
|
||||
|
||||
internal readonly Dictionary<int, Dictionary<int, string>> DLC = new();
|
||||
|
||||
internal List<Task> RunningTasks = null;
|
||||
internal List<Task> RunningTasks = new();
|
||||
|
||||
private void GetCreamApiApplicablePrograms(IProgress<int> progress)
|
||||
{
|
||||
int cur = 0;
|
||||
if (Program.Canceled) return;
|
||||
List<Tuple<int, string, int, string>> applicablePrograms = new();
|
||||
List<Tuple<int, string, string, int, string>> applicablePrograms = new();
|
||||
string launcherRootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Programs\\Paradox Interactive";
|
||||
if (Directory.Exists(launcherRootDirectory)) applicablePrograms.Add(new(0, "Paradox Launcher", 0, launcherRootDirectory));
|
||||
if (Directory.Exists(launcherRootDirectory)) applicablePrograms.Add(new(0, "Paradox Launcher", "", 0, launcherRootDirectory));
|
||||
foreach (string libraryDirectory in GameLibraryDirectories)
|
||||
if (GetGamesFromLibraryDirectory(libraryDirectory, out List<Tuple<int, string, int, string>> games))
|
||||
foreach (Tuple<int, string, int, string> game in games)
|
||||
if (GetGamesFromLibraryDirectory(libraryDirectory, out List<Tuple<int, string, string, int, string>> games))
|
||||
foreach (Tuple<int, string, string, int, string> game in games)
|
||||
applicablePrograms.Add(game);
|
||||
RunningTasks = new();
|
||||
foreach (Tuple<int, string, int, string> program in applicablePrograms)
|
||||
RunningTasks.Clear();
|
||||
foreach (Tuple<int, string, string, int, string> program in applicablePrograms)
|
||||
{
|
||||
int appId = program.Item1;
|
||||
string name = program.Item2;
|
||||
int buildId = program.Item3;
|
||||
string directory = program.Item4;
|
||||
string branch = program.Item3;
|
||||
int buildId = program.Item4;
|
||||
string directory = program.Item5;
|
||||
if (Program.Canceled) return;
|
||||
// easy anti cheat detects DLL changes, so skip those games
|
||||
if (Directory.Exists(directory + @"\EasyAntiCheat")) continue;
|
||||
// battleye in DayZ detects DLL changes, but not in Arma3?
|
||||
//if (Directory.Exists(directory + @"\BattlEye")) continue;
|
||||
if (name == "DayZ") continue;
|
||||
if (name != "Arma 3" && Directory.Exists(directory + @"\BattlEye")) continue;
|
||||
Task task = new(() =>
|
||||
{
|
||||
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;
|
||||
Dictionary<int, string> dlc = null;
|
||||
if (!DLC.TryGetValue(appId, out dlc))
|
||||
{
|
||||
dlc = new();
|
||||
DLC.Add(appId, dlc);
|
||||
}
|
||||
if (Program.Canceled || (name != "Paradox Launcher" && !SteamCMD.GetAppInfo(appId, out appInfo, branch, buildId))) return;
|
||||
if (Program.Canceled) return;
|
||||
ConcurrentDictionary<int, string> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<int> dlcIds = new();
|
||||
if (!(appInfo is null))
|
||||
|
@ -175,9 +171,9 @@ namespace CreamInstaller
|
|||
if (Program.Canceled) return;
|
||||
string dlcName = null;
|
||||
VProperty dlcAppInfo = null;
|
||||
if (SteamCMD.GetAppInfo(id, 0, out dlcAppInfo)) dlcName = dlcAppInfo?.Value?["common"]?["name"]?.ToString();
|
||||
if (SteamCMD.GetAppInfo(id, out dlcAppInfo)) dlcName = dlcAppInfo?.Value?["common"]?["name"]?.ToString();
|
||||
if (Program.Canceled) return;
|
||||
if (string.IsNullOrWhiteSpace(dlcName)) dlcName = $"Unnamed DLC ({id})";
|
||||
if (string.IsNullOrWhiteSpace(dlcName)) dlcName = $"Unknown DLC ({id})";
|
||||
dlc[id] = dlcName;
|
||||
});
|
||||
dlcTasks.Add(task);
|
|
@ -29,7 +29,15 @@ namespace CreamInstaller
|
|||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.ApplicationExit += new EventHandler(OnApplicationExit);
|
||||
Application.Run(new MainForm());
|
||||
retry:
|
||||
try
|
||||
{
|
||||
Application.Run(new MainForm());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ExceptionHandler.OutputException(e)) goto retry;
|
||||
}
|
||||
}
|
||||
mutex.Close();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace CreamInstaller
|
|||
{
|
||||
public static void WriteResourceToFile(string resourceName, string filePath)
|
||||
{
|
||||
using Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("CreamInstaller." + resourceName);
|
||||
using Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(@"CreamInstaller.Resources." + resourceName);
|
||||
using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
|
||||
resource.CopyTo(file);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
@ -15,7 +16,9 @@ namespace 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 AppInfoCachePath = DirectoryPath + @"\appinfocache";
|
||||
public static string AppCachePath = DirectoryPath + @"\appcache";
|
||||
public static string AppCacheAppInfoPath = AppCachePath + @"\appinfo.vdf";
|
||||
public static string AppInfoPath = DirectoryPath + @"\appinfo";
|
||||
|
||||
public static bool Run(string command, out string output)
|
||||
{
|
||||
|
@ -52,16 +55,18 @@ namespace CreamInstaller
|
|||
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
||||
File.Delete(ArchivePath);
|
||||
}
|
||||
if (File.Exists(AppCacheAppInfoPath)) File.Delete(AppCacheAppInfoPath);
|
||||
if (!File.Exists(DllPath)) Run($@"+quit", out _);
|
||||
}
|
||||
|
||||
public static bool GetAppInfo(int appId, int buildId, out VProperty appInfo)
|
||||
public static bool GetAppInfo(int appId, out VProperty appInfo, string branch = "public", int buildId = 0)
|
||||
{
|
||||
appInfo = null;
|
||||
if (Program.Canceled) return false;
|
||||
string output;
|
||||
string appUpdatePath = $@"{AppInfoCachePath}\{appId}";
|
||||
string appUpdatePath = $@"{AppInfoPath}\{appId}";
|
||||
string appUpdateFile = $@"{appUpdatePath}\appinfo.txt";
|
||||
restart:
|
||||
if (Directory.Exists(appUpdatePath) && File.Exists(appUpdateFile)) output = File.ReadAllText(appUpdateFile);
|
||||
else
|
||||
{
|
||||
|
@ -76,18 +81,26 @@ namespace CreamInstaller
|
|||
}
|
||||
}
|
||||
if (Program.Canceled || output is null) return false;
|
||||
try { appInfo = VdfConvert.Deserialize(output); } catch { }
|
||||
try { appInfo = VdfConvert.Deserialize(output); }
|
||||
catch
|
||||
{
|
||||
if (File.Exists(appUpdateFile))
|
||||
{
|
||||
File.Delete(appUpdateFile);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
if (!(appInfo is null) && appInfo.Value is VValue) goto restart;
|
||||
if (appInfo is null || (!(appInfo.Value is VValue) && appInfo.Value.Children().ToList().Count == 0)) return true;
|
||||
VToken type = appInfo.Value is VValue ? null : appInfo.Value?["common"]?["type"];
|
||||
if (type is null || type.ToString() == "Game")
|
||||
{
|
||||
string buildid = appInfo.Value is VValue ? null : appInfo.Value["depots"]?["public"]?["buildid"]?.ToString();
|
||||
string buildid = appInfo.Value is VValue ? null : appInfo.Value["depots"]?["branches"]?[branch]?["buildid"]?.ToString();
|
||||
if (buildid is null && !(type is null)) return true;
|
||||
if (type is null || int.Parse(buildid) < buildId)
|
||||
{
|
||||
File.Delete(appUpdateFile);
|
||||
bool success = GetAppInfo(appId, buildId, out appInfo);
|
||||
return success;
|
||||
if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue