v2.2.2.0
- Massive refactoring and asynchronous fixes - Disabled file operations from displaying in the install info label, and they now only display in the log - Disabled selection validation, as previous issues warranting it have since been fixed
This commit is contained in:
parent
70f009abb5
commit
5024cd2194
12 changed files with 414 additions and 580 deletions
219
.editorconfig
Normal file
219
.editorconfig
Normal file
|
@ -0,0 +1,219 @@
|
|||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = true
|
||||
dotnet_sort_system_directives_first = true
|
||||
file_header_template = unset
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
|
||||
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:suggestion
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_collection_initializer = true
|
||||
dotnet_style_explicit_tuple_names = true
|
||||
dotnet_style_namespace_match_folder = true
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_object_initializer = true
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
dotnet_style_prefer_auto_properties = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||
dotnet_style_prefer_inferred_tuple_names = true
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
|
||||
# Field preferences
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
|
||||
# Suppression preferences
|
||||
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||
|
||||
# New line preferences
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = false:suggestion
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:suggestion
|
||||
csharp_style_var_for_built_in_types = false:suggestion
|
||||
csharp_style_var_when_type_is_apparent = false:suggestion
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_accessors = true:suggestion
|
||||
csharp_style_expression_bodied_constructors = true:suggestion
|
||||
csharp_style_expression_bodied_indexers = true:suggestion
|
||||
csharp_style_expression_bodied_lambdas = true:suggestion
|
||||
csharp_style_expression_bodied_local_functions = true:suggestion
|
||||
csharp_style_expression_bodied_methods = true:suggestion
|
||||
csharp_style_expression_bodied_operators = true:suggestion
|
||||
csharp_style_expression_bodied_properties = true:suggestion
|
||||
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = false:suggestion
|
||||
csharp_prefer_simple_using_statement = true
|
||||
csharp_style_namespace_declarations = file_scoped:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_deconstructed_variable_declaration = true
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_pattern_local_over_anonymous_function = true
|
||||
csharp_style_prefer_index_operator = true
|
||||
csharp_style_prefer_null_check_over_type_check = true
|
||||
csharp_style_prefer_range_operator = true
|
||||
csharp_style_throw_expression = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = unused_local_variable:suggestion
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace:suggestion
|
||||
|
||||
# New line preferences
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:suggestion
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:suggestion
|
||||
|
||||
#### C# Formatting Rules ####
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
|
@ -53,14 +53,8 @@ namespace CreamInstaller
|
|||
private readonly string message;
|
||||
public override string Message => message ?? "CustomMessageException";
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Message;
|
||||
}
|
||||
public override string ToString() => Message;
|
||||
|
||||
internal CustomMessageException(string message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
internal CustomMessageException(string message) => this.message = message;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
using Gameloop.Vdf.Linq;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
internal class ProgramSelection
|
||||
|
@ -81,10 +82,7 @@ namespace CreamInstaller
|
|||
Enabled = SelectedSteamDlc.Any();
|
||||
}
|
||||
|
||||
internal ProgramSelection()
|
||||
{
|
||||
All.Add(this);
|
||||
}
|
||||
internal ProgramSelection() => All.Add(this);
|
||||
|
||||
internal void Validate()
|
||||
{
|
||||
|
@ -95,10 +93,7 @@ namespace CreamInstaller
|
|||
}
|
||||
}
|
||||
|
||||
internal static void ValidateAll()
|
||||
{
|
||||
All.ForEach(selection => selection.Validate());
|
||||
}
|
||||
internal static void ValidateAll() => All.ForEach(selection => selection.Validate());
|
||||
|
||||
internal static List<ProgramSelection> All => Program.ProgramSelections;
|
||||
|
||||
|
@ -106,10 +101,7 @@ namespace CreamInstaller
|
|||
|
||||
internal static List<ProgramSelection> AllSafeEnabled => AllSafe.FindAll(s => s.Enabled);
|
||||
|
||||
internal static ProgramSelection FromAppId(int appId)
|
||||
{
|
||||
return AllSafe.Find(s => s.SteamAppId == appId);
|
||||
}
|
||||
internal static ProgramSelection FromAppId(int appId) => AllSafe.Find(s => s.SteamAppId == appId);
|
||||
|
||||
internal static KeyValuePair<int, string>? GetDlcFromAppId(int appId)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
@ -11,6 +9,9 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
internal static class SteamCMD
|
||||
|
@ -26,12 +27,9 @@ namespace CreamInstaller
|
|||
internal static readonly Version MinimumAppInfoVersion = Version.Parse("2.0.3.2");
|
||||
internal static readonly string AppInfoVersionPath = AppInfoPath + @"\version.txt";
|
||||
|
||||
internal static string Run(string command)
|
||||
internal static async Task<string> Run(string command) => await Task.Run(() =>
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (Program.Canceled) return "";
|
||||
List<string> logs = new();
|
||||
ProcessStartInfo processStartInfo = new()
|
||||
{
|
||||
|
@ -55,7 +53,7 @@ namespace CreamInstaller
|
|||
process.WaitForExit();
|
||||
}
|
||||
return string.Join("\r\n", logs);
|
||||
}
|
||||
});
|
||||
|
||||
internal static async Task Setup()
|
||||
{
|
||||
|
@ -67,56 +65,34 @@ namespace CreamInstaller
|
|||
byte[] file = await httpClient.GetByteArrayAsync("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip");
|
||||
file.Write(ArchivePath);
|
||||
}
|
||||
|
||||
ZipFile.ExtractToDirectory(ArchivePath, DirectoryPath);
|
||||
File.Delete(ArchivePath);
|
||||
}
|
||||
if (File.Exists(AppCacheAppInfoPath))
|
||||
{
|
||||
File.Delete(AppCacheAppInfoPath);
|
||||
}
|
||||
|
||||
if (File.Exists(AppCacheAppInfoPath)) File.Delete(AppCacheAppInfoPath);
|
||||
if (!File.Exists(AppInfoVersionPath) || !Version.TryParse(File.ReadAllText(AppInfoVersionPath, Encoding.UTF8), out Version version) || version < MinimumAppInfoVersion)
|
||||
{
|
||||
if (Directory.Exists(AppInfoPath))
|
||||
{
|
||||
Directory.Delete(AppInfoPath, true);
|
||||
}
|
||||
|
||||
if (Directory.Exists(AppInfoPath)) Directory.Delete(AppInfoPath, true);
|
||||
Directory.CreateDirectory(AppInfoPath);
|
||||
File.WriteAllText(AppInfoVersionPath, Application.ProductVersion, Encoding.UTF8);
|
||||
}
|
||||
if (!File.Exists(DllPath))
|
||||
{
|
||||
Run($@"+quit");
|
||||
}
|
||||
if (!File.Exists(DllPath)) await Run($@"+quit");
|
||||
}
|
||||
|
||||
internal static bool GetAppInfo(int appId, out VProperty appInfo, string branch = "public", int buildId = 0)
|
||||
internal static async Task<VProperty> GetAppInfo(int appId, string branch = "public", int buildId = 0)
|
||||
{
|
||||
appInfo = null;
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VProperty appInfo = null;
|
||||
if (Program.Canceled) return null;
|
||||
string output;
|
||||
string appUpdatePath = $@"{AppInfoPath}\{appId}";
|
||||
string appUpdateFile = $@"{appUpdatePath}\appinfo.txt";
|
||||
restart:
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return null;
|
||||
if (Directory.Exists(appUpdatePath) && File.Exists(appUpdateFile))
|
||||
{
|
||||
output = File.ReadAllText(appUpdateFile, Encoding.UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +force_install_dir {appUpdatePath} +app_update 4 +quit");
|
||||
output = Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +quit");
|
||||
await Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +force_install_dir {appUpdatePath} +app_update 4 +quit");
|
||||
output = await Run($@"+@ShutdownOnFailedCommand 0 +login anonymous +app_info_print {appId} +quit");
|
||||
int openBracket = output.IndexOf("{");
|
||||
int closeBracket = output.LastIndexOf("}");
|
||||
if (openBracket != -1 && closeBracket != -1)
|
||||
|
@ -125,11 +101,7 @@ namespace CreamInstaller
|
|||
File.WriteAllText(appUpdateFile, output, Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
if (Program.Canceled || output is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Program.Canceled || output is null) return null;
|
||||
try { appInfo = VdfConvert.Deserialize(output); }
|
||||
catch
|
||||
{
|
||||
|
@ -139,85 +111,46 @@ namespace CreamInstaller
|
|||
goto restart;
|
||||
}
|
||||
}
|
||||
if (appInfo.Value is VValue)
|
||||
{
|
||||
goto restart;
|
||||
}
|
||||
|
||||
if (appInfo.Value is VValue) goto restart;
|
||||
if (appInfo is null || (appInfo.Value is not VValue && appInfo.Value.Children().ToList().Count == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return appInfo;
|
||||
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"]?["branches"]?[branch]?["buildid"]?.ToString();
|
||||
if (buildid is null && type is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (buildid is null && type is not null) return appInfo;
|
||||
if (type is null || int.Parse(buildid) < buildId)
|
||||
{
|
||||
foreach (int id in ParseDlcAppIds(appInfo))
|
||||
List<int> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||
foreach (int id in dlcAppIds)
|
||||
{
|
||||
string dlcAppUpdatePath = $@"{AppInfoPath}\{id}";
|
||||
if (Directory.Exists(dlcAppUpdatePath))
|
||||
{
|
||||
Directory.Delete(dlcAppUpdatePath, true);
|
||||
}
|
||||
}
|
||||
if (Directory.Exists(appUpdatePath))
|
||||
{
|
||||
Directory.Delete(appUpdatePath, true);
|
||||
if (Directory.Exists(dlcAppUpdatePath)) Directory.Delete(dlcAppUpdatePath, true);
|
||||
}
|
||||
if (Directory.Exists(appUpdatePath)) Directory.Delete(appUpdatePath, true);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
internal static List<int> ParseDlcAppIds(VProperty appInfo)
|
||||
internal static async Task<List<int>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
||||
{
|
||||
List<int> dlcIds = new();
|
||||
if (appInfo is not VProperty)
|
||||
{
|
||||
return dlcIds;
|
||||
}
|
||||
|
||||
if (appInfo is not VProperty) return dlcIds;
|
||||
if (appInfo.Value["extended"] is not 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 (appInfo.Value["depots"] is not 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dlcIds;
|
||||
}
|
||||
});
|
||||
|
||||
internal static async Task Kill()
|
||||
{
|
||||
|
@ -227,10 +160,7 @@ namespace CreamInstaller
|
|||
process.Kill();
|
||||
tasks.Add(Task.Run(() => process.WaitForExit()));
|
||||
}
|
||||
foreach (Task task in tasks)
|
||||
{
|
||||
await task;
|
||||
}
|
||||
foreach (Task task in tasks) await task;
|
||||
}
|
||||
|
||||
internal static void Dispose()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<Version>2.2.1.1</Version>
|
||||
<Version>2.2.2.0</Version>
|
||||
<PackageIcon>Resources\ini.ico</PackageIcon>
|
||||
<PackageIconUrl />
|
||||
<Description>Automatically generates and installs CreamAPI files for Steam games on the user's computer. It can also generate and install CreamAPI for the Paradox Launcher should the user select a Paradox Interactive game.</Description>
|
||||
|
|
|
@ -4,15 +4,9 @@ namespace CreamInstaller
|
|||
{
|
||||
internal class CustomForm : Form
|
||||
{
|
||||
internal CustomForm() : base()
|
||||
{
|
||||
Icon = Properties.Resources.Icon;
|
||||
}
|
||||
internal CustomForm() : base() => Icon = Properties.Resources.Icon;
|
||||
|
||||
internal CustomForm(IWin32Window owner) : this()
|
||||
{
|
||||
Owner = owner as Form;
|
||||
}
|
||||
internal CustomForm(IWin32Window owner) : this() => Owner = owner as Form;
|
||||
|
||||
protected override CreateParams CreateParams // Double buffering for all controls
|
||||
{
|
||||
|
|
|
@ -5,10 +5,7 @@ namespace CreamInstaller
|
|||
{
|
||||
internal partial class DialogForm : CustomForm
|
||||
{
|
||||
internal DialogForm(IWin32Window owner) : base(owner)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
|
||||
|
||||
internal DialogResult Show(string formName, Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null)
|
||||
{
|
||||
|
@ -21,10 +18,7 @@ namespace CreamInstaller
|
|||
cancelButton.Enabled = false;
|
||||
cancelButton.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cancelButton.Text = cancelButtonText;
|
||||
}
|
||||
else cancelButton.Text = cancelButtonText;
|
||||
return ShowDialog();
|
||||
}
|
||||
}
|
||||
|
|
1
CreamInstaller/Forms/InstallForm.Designer.cs
generated
1
CreamInstaller/Forms/InstallForm.Designer.cs
generated
|
@ -51,6 +51,7 @@ namespace CreamInstaller
|
|||
//
|
||||
this.userInfoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.userInfoLabel.AutoEllipsis = true;
|
||||
this.userInfoLabel.FlatStyle = System.Windows.Forms.FlatStyle.System;
|
||||
this.userInfoLabel.Location = new System.Drawing.Point(12, 9);
|
||||
this.userInfoLabel.Name = "userInfoLabel";
|
||||
|
|
|
@ -30,23 +30,17 @@ namespace CreamInstaller
|
|||
internal void UpdateProgress(int progress)
|
||||
{
|
||||
int value = (int)((float)(CompleteOperationsCount / (float)OperationsCount) * 100) + (progress / OperationsCount);
|
||||
if (value < userProgressBar.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (value < userProgressBar.Value) return;
|
||||
userProgressBar.Value = value;
|
||||
}
|
||||
|
||||
internal async Task UpdateUser(string text, Color color, bool log = true)
|
||||
internal async Task UpdateUser(string text, Color color, bool info = true, bool log = true)
|
||||
{
|
||||
userInfoLabel.Text = text;
|
||||
if (info) userInfoLabel.Text = text;
|
||||
if (log && !logTextBox.IsDisposed)
|
||||
{
|
||||
if (logTextBox.Text.Length > 0)
|
||||
{
|
||||
logTextBox.AppendText(Environment.NewLine, color);
|
||||
}
|
||||
logTextBox.AppendText(userInfoLabel.Text, color);
|
||||
if (logTextBox.Text.Length > 0) logTextBox.AppendText(Environment.NewLine, color);
|
||||
logTextBox.AppendText(text, color);
|
||||
}
|
||||
await Task.Run(() => Thread.Sleep(1)); // to keep the text box control from glitching
|
||||
}
|
||||
|
@ -59,11 +53,11 @@ namespace CreamInstaller
|
|||
writer.WriteLine($"appid = {steamAppId}");
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("[dlc]");
|
||||
await UpdateUser($"Added game to cream_api.ini with appid {steamAppId} ({name})", InstallationLog.Resource);
|
||||
await UpdateUser($"Added game to cream_api.ini with appid {steamAppId} ({name})", InstallationLog.Resource, info: false);
|
||||
foreach (KeyValuePair<int, string> dlcApp in steamDlcApps)
|
||||
{
|
||||
writer.WriteLine($"{dlcApp.Key} = {dlcApp.Value}");
|
||||
await UpdateUser($"Added DLC to cream_api.ini with appid {dlcApp.Key} ({dlcApp.Value})", InstallationLog.Resource);
|
||||
await UpdateUser($"Added DLC to cream_api.ini with appid {dlcApp.Key} ({dlcApp.Value})", InstallationLog.Resource, info: false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,25 +85,25 @@ namespace CreamInstaller
|
|||
if (File.Exists(api))
|
||||
{
|
||||
File.Delete(api);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(api)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
File.Move(api_o, api);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api_o)} -> {Path.GetFileName(api)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api_o)} -> {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
if (File.Exists(api64))
|
||||
{
|
||||
File.Delete(api64);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(api64)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
File.Move(api64_o, api64);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(cApi))
|
||||
{
|
||||
File.Delete(cApi);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(cApi)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Deleted file: {Path.GetFileName(cApi)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -117,22 +111,22 @@ namespace CreamInstaller
|
|||
if (File.Exists(api) && !File.Exists(api_o))
|
||||
{
|
||||
File.Move(api, api_o);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api)} -> {Path.GetFileName(api_o)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api)} -> {Path.GetFileName(api_o)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(api_o))
|
||||
{
|
||||
Properties.Resources.API.Write(api);
|
||||
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(api64) && !File.Exists(api64_o))
|
||||
{
|
||||
File.Move(api64, api64_o);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Renamed file: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
if (File.Exists(api64_o))
|
||||
{
|
||||
Properties.Resources.API64.Write(api64);
|
||||
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api64)}", InstallationLog.Resource);
|
||||
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
|
||||
}
|
||||
await UpdateUser("Generating CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
|
||||
File.Create(cApi).Close();
|
||||
|
@ -161,10 +155,7 @@ namespace CreamInstaller
|
|||
CompleteOperationsCount = 0;
|
||||
foreach (ProgramSelection selection in programSelections)
|
||||
{
|
||||
if (!Program.IsProgramRunningDialog(this, selection))
|
||||
{
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) throw new OperationCanceledException();
|
||||
try
|
||||
{
|
||||
await OperateFor(selection);
|
||||
|
@ -180,16 +171,8 @@ namespace CreamInstaller
|
|||
await Program.Cleanup();
|
||||
List<ProgramSelection> FailedSelections = ProgramSelection.AllSafeEnabled;
|
||||
if (FailedSelections.Any())
|
||||
{
|
||||
if (FailedSelections.Count == 1)
|
||||
{
|
||||
throw new CustomMessageException($"Operation failed for {FailedSelections.First().Name}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new CustomMessageException($"Operation failed for {FailedSelections.Count} programs.");
|
||||
}
|
||||
}
|
||||
if (FailedSelections.Count == 1) throw new CustomMessageException($"Operation failed for {FailedSelections.First().Name}.");
|
||||
else throw new CustomMessageException($"Operation failed for {FailedSelections.Count} programs.");
|
||||
}
|
||||
|
||||
private readonly int ProgramCount = ProgramSelection.AllSafeEnabled.Count;
|
||||
|
@ -228,10 +211,7 @@ namespace CreamInstaller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ExceptionHandler.OutputException(e))
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
if (ExceptionHandler.OutputException(e)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
@ -248,10 +228,7 @@ namespace CreamInstaller
|
|||
Start();
|
||||
}
|
||||
|
||||
private void OnCancel(object sender, EventArgs e)
|
||||
{
|
||||
Program.Cleanup().Wait();
|
||||
}
|
||||
private void OnCancel(object sender, EventArgs e) => Program.Cleanup().Wait();
|
||||
|
||||
private void OnReselect(object sender, EventArgs e)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
using HtmlAgilityPack;
|
||||
using Onova;
|
||||
using Onova.Models;
|
||||
using Onova.Services;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
@ -13,6 +9,12 @@ using System.Threading.Tasks;
|
|||
using System.Web;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using HtmlAgilityPack;
|
||||
|
||||
using Onova;
|
||||
using Onova.Models;
|
||||
using Onova.Services;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
internal partial class MainForm : CustomForm
|
||||
|
@ -33,7 +35,6 @@ namespace CreamInstaller
|
|||
cancellationTokenSource.Dispose();
|
||||
cancellationTokenSource = null;
|
||||
}
|
||||
|
||||
Hide();
|
||||
new SelectForm(this).ShowDialog();
|
||||
Close();
|
||||
|
@ -93,7 +94,6 @@ namespace CreamInstaller
|
|||
changelogTreeView.Visible = true;
|
||||
Version currentVersion = new(Application.ProductVersion);
|
||||
foreach (Version version in versions)
|
||||
{
|
||||
if (version > currentVersion && !changelogTreeView.Nodes.ContainsKey(version.ToString()))
|
||||
{
|
||||
TreeNode root = new($"v{version}");
|
||||
|
@ -128,7 +128,6 @@ namespace CreamInstaller
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +138,6 @@ namespace CreamInstaller
|
|||
{
|
||||
string FileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
||||
if (FileName != "CreamInstaller.exe")
|
||||
{
|
||||
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Warning,
|
||||
"WARNING: CreamInstaller.exe was renamed!" +
|
||||
"\n\nThis will cause unwanted behavior when updating the program!",
|
||||
|
@ -148,24 +146,16 @@ namespace CreamInstaller
|
|||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
OnLoad();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ExceptionHandler.OutputException(e))
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (ExceptionHandler.OutputException(e)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIgnore(object sender, EventArgs e)
|
||||
{
|
||||
StartProgram();
|
||||
}
|
||||
private void OnIgnore(object sender, EventArgs e) => StartProgram();
|
||||
|
||||
private async void OnUpdate(object sender, EventArgs e)
|
||||
{
|
||||
|
@ -200,10 +190,7 @@ namespace CreamInstaller
|
|||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
OnLoad();
|
||||
}
|
||||
else OnLoad();
|
||||
}
|
||||
|
||||
private void OnUpdateCancel(object sender, EventArgs e)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -13,6 +10,11 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Gameloop.Vdf;
|
||||
using Gameloop.Vdf.Linq;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CreamInstaller
|
||||
{
|
||||
internal partial class SelectForm : CustomForm
|
||||
|
@ -24,118 +26,74 @@ namespace CreamInstaller
|
|||
Program.SelectForm = this;
|
||||
}
|
||||
|
||||
private static List<string> GameLibraryDirectories
|
||||
private static async Task<List<string>> GameLibraryDirectories() => await Task.Run(() =>
|
||||
{
|
||||
get
|
||||
List<string> gameDirectories = new();
|
||||
if (Program.Canceled) return gameDirectories;
|
||||
string steamInstallPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Valve\\Steam", "InstallPath", null) as string;
|
||||
steamInstallPath ??= Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Valve\\Steam", "InstallPath", null) as string;
|
||||
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
|
||||
{
|
||||
List<string> gameDirectories = new();
|
||||
if (Program.Canceled)
|
||||
string libraryFolder = steamInstallPath + @"\steamapps";
|
||||
if (Directory.Exists(libraryFolder))
|
||||
{
|
||||
return gameDirectories;
|
||||
}
|
||||
|
||||
string steamInstallPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Valve\\Steam", "InstallPath", null) as string;
|
||||
if (steamInstallPath == null)
|
||||
{
|
||||
steamInstallPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Valve\\Steam", "InstallPath", null) as string;
|
||||
}
|
||||
|
||||
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
|
||||
{
|
||||
string libraryFolder = steamInstallPath + @"\steamapps";
|
||||
if (Directory.Exists(libraryFolder))
|
||||
gameDirectories.Add(libraryFolder);
|
||||
try
|
||||
{
|
||||
gameDirectories.Add(libraryFolder);
|
||||
try
|
||||
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
||||
if (File.Exists(libraryFolders))
|
||||
{
|
||||
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
|
||||
if (File.Exists(libraryFolders))
|
||||
{
|
||||
dynamic property = VdfConvert.Deserialize(File.ReadAllText(libraryFolders, Encoding.UTF8));
|
||||
foreach (dynamic _property in property.Value)
|
||||
dynamic property = VdfConvert.Deserialize(File.ReadAllText(libraryFolders, Encoding.UTF8)).Value;
|
||||
foreach (dynamic _property in property)
|
||||
if (int.TryParse(_property.Key, out int _))
|
||||
{
|
||||
if (int.TryParse(_property.Key, out int _))
|
||||
{
|
||||
string path = _property.Value.path.ToString() + @"\steamapps";
|
||||
if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!gameDirectories.Contains(path))
|
||||
{
|
||||
gameDirectories.Add(path);
|
||||
}
|
||||
}
|
||||
string path = _property.Value.path.ToString() + @"\steamapps";
|
||||
if (string.IsNullOrWhiteSpace(path) || !Directory.Exists(path)) continue;
|
||||
if (!gameDirectories.Contains(path)) gameDirectories.Add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return gameDirectories;
|
||||
}
|
||||
}
|
||||
return gameDirectories;
|
||||
});
|
||||
|
||||
private static bool GetDllDirectoriesFromGameDirectory(string gameDirectory, out List<string> dllDirectories)
|
||||
private static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
|
||||
{
|
||||
dllDirectories = new();
|
||||
if (Program.Canceled || !Directory.Exists(gameDirectory))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<string> dllDirectories = new();
|
||||
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
|
||||
string api = gameDirectory + @"\steam_api.dll";
|
||||
string api64 = gameDirectory + @"\steam_api64.dll";
|
||||
if (File.Exists(api) || File.Exists(api64))
|
||||
if (File.Exists(api) || File.Exists(api64)) dllDirectories.Add(gameDirectory);
|
||||
string[] directories = Directory.GetDirectories(gameDirectory);
|
||||
foreach (string _directory in directories)
|
||||
{
|
||||
dllDirectories.Add(gameDirectory);
|
||||
}
|
||||
|
||||
foreach (string _directory in Directory.GetDirectories(gameDirectory))
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return null;
|
||||
try
|
||||
{
|
||||
if (GetDllDirectoriesFromGameDirectory(_directory, out List<string> _dllDirectories))
|
||||
{
|
||||
dllDirectories.AddRange(_dllDirectories);
|
||||
}
|
||||
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
|
||||
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
if (!dllDirectories.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!dllDirectories.Any()) return null;
|
||||
return dllDirectories;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool GetGamesFromLibraryDirectory(string libraryDirectory, out List<Tuple<int, string, string, int, string>> games)
|
||||
private static async Task<List<Tuple<int, string, string, int, string>>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
|
||||
{
|
||||
games = new();
|
||||
if (Program.Canceled || !Directory.Exists(libraryDirectory))
|
||||
List<Tuple<int, string, string, int, string>> games = new();
|
||||
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return null;
|
||||
string[] files = Directory.GetFiles(libraryDirectory);
|
||||
foreach (string file in files)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (string directory in Directory.GetFiles(libraryDirectory))
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Path.GetExtension(directory) == ".acf")
|
||||
if (Program.Canceled) return null;
|
||||
if (Path.GetExtension(file) == ".acf")
|
||||
{
|
||||
try
|
||||
{
|
||||
dynamic property = VdfConvert.Deserialize(File.ReadAllText(directory, Encoding.UTF8));
|
||||
dynamic property = VdfConvert.Deserialize(File.ReadAllText(file, Encoding.UTF8));
|
||||
string _appid = property.Value.appid.ToString();
|
||||
string installdir = property.Value.installdir.ToString();
|
||||
string name = property.Value.name.ToString();
|
||||
|
@ -144,39 +102,20 @@ namespace CreamInstaller
|
|||
|| string.IsNullOrWhiteSpace(installdir)
|
||||
|| string.IsNullOrWhiteSpace(name)
|
||||
|| string.IsNullOrWhiteSpace(_buildid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string branch = property.Value.UserConfig?.betakey?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(branch))
|
||||
{
|
||||
branch = "public";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!int.TryParse(_appid, out int appid)) continue;
|
||||
if (!int.TryParse(_buildid, out int buildid)) continue;
|
||||
games.Add(new(appid, name, branch, buildid, gameDirectory));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
if (!games.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
if (!games.Any()) return null;
|
||||
return games;
|
||||
});
|
||||
|
||||
internal List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
|
||||
private List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
|
||||
|
@ -194,30 +133,21 @@ namespace CreamInstaller
|
|||
|
||||
private async Task GetCreamApiApplicablePrograms(IProgress<int> progress)
|
||||
{
|
||||
int cur = 0;
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
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));
|
||||
}
|
||||
|
||||
foreach (string libraryDirectory in GameLibraryDirectories)
|
||||
List<string> gameLibraryDirectories = await GameLibraryDirectories();
|
||||
foreach (string libraryDirectory in gameLibraryDirectories)
|
||||
{
|
||||
if (GetGamesFromLibraryDirectory(libraryDirectory, out List<Tuple<int, string, string, int, string>> games))
|
||||
{
|
||||
List<Tuple<int, string, string, int, string>> games = await GetGamesFromLibraryDirectory(libraryDirectory);
|
||||
if (games is not null)
|
||||
foreach (Tuple<int, string, string, int, string> game in games)
|
||||
{
|
||||
applicablePrograms.Add(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cur = 0;
|
||||
RunningTasks.Clear();
|
||||
foreach (Tuple<int, string, string, int, string> program in applicablePrograms)
|
||||
{
|
||||
|
@ -227,23 +157,14 @@ namespace CreamInstaller
|
|||
int buildId = program.Item4;
|
||||
string directory = program.Item5;
|
||||
ProgramSelection selection = ProgramSelection.FromAppId(appId);
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
if (Program.BlockProtectedGames)
|
||||
{
|
||||
bool blockedGame = Program.ProtectedGameNames.Contains(name);
|
||||
if (!Program.ProtectedGameDirectoryExceptions.Contains(name))
|
||||
{
|
||||
foreach (string path in Program.ProtectedGameDirectories)
|
||||
{
|
||||
if (Directory.Exists(directory + path))
|
||||
{
|
||||
blockedGame = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (blockedGame)
|
||||
{
|
||||
if (selection is not null)
|
||||
|
@ -254,59 +175,32 @@ namespace CreamInstaller
|
|||
continue;
|
||||
}
|
||||
}
|
||||
Task task = Task.Run(async () =>
|
||||
RunningTasks.Add(Task.Run(async () =>
|
||||
{
|
||||
if (Program.Canceled || !GetDllDirectoriesFromGameDirectory(directory, out List<string> dllDirectories))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
List<string> dllDirectories = await GetDllDirectoriesFromGameDirectory(directory);
|
||||
if (dllDirectories is null) return;
|
||||
VProperty appInfo = null;
|
||||
if (Program.Canceled || (appId > 0 && !SteamCMD.GetAppInfo(appId, out appInfo, branch, buildId)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (appId > 0) appInfo = await SteamCMD.GetAppInfo(appId, branch, buildId);
|
||||
if (appId > 0 && appInfo is null) return;
|
||||
if (Program.Canceled) return;
|
||||
ConcurrentDictionary<int, string> dlc = new();
|
||||
List<Task> dlcTasks = new();
|
||||
List<int> dlcIds = SteamCMD.ParseDlcAppIds(appInfo);
|
||||
List<int> dlcIds = await SteamCMD.ParseDlcAppIds(appInfo);
|
||||
if (dlcIds.Count > 0)
|
||||
{
|
||||
foreach (int id in dlcIds)
|
||||
{
|
||||
if (Program.Canceled)
|
||||
if (Program.Canceled) return;
|
||||
Task task = Task.Run(async () =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Task task = Task.Run(() =>
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
string dlcName = null;
|
||||
if (SteamCMD.GetAppInfo(id, out VProperty dlcAppInfo))
|
||||
{
|
||||
VProperty dlcAppInfo = await SteamCMD.GetAppInfo(id);
|
||||
if (dlcAppInfo is not null)
|
||||
dlcName = dlcAppInfo?.Value?["common"]?["name"]?.ToString();
|
||||
}
|
||||
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(dlcName))
|
||||
{
|
||||
return; //dlcName = "Unknown DLC";
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
if (string.IsNullOrWhiteSpace(dlcName)) return; //dlcName = "Unknown DLC";
|
||||
dlc[id] = /*$"[{id}] " +*/ dlcName;
|
||||
progress.Report(++cur);
|
||||
});
|
||||
|
@ -315,20 +209,9 @@ namespace CreamInstaller
|
|||
}
|
||||
progress.Report(-RunningTasks.Count);
|
||||
}
|
||||
else if (appId > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (appId > 0) return;
|
||||
if (Program.Canceled) return;
|
||||
if (string.IsNullOrWhiteSpace(name)) return;
|
||||
|
||||
selection ??= new();
|
||||
selection.Usable = true;
|
||||
|
@ -337,31 +220,17 @@ namespace CreamInstaller
|
|||
selection.SteamAppId = appId;
|
||||
selection.SteamApiDllDirectories = dllDirectories;
|
||||
selection.AppInfo = appInfo;
|
||||
if (allCheckBox.Checked)
|
||||
{
|
||||
selection.Enabled = true;
|
||||
}
|
||||
if (allCheckBox.Checked) selection.Enabled = true;
|
||||
|
||||
foreach (Task task in dlcTasks.ToList())
|
||||
foreach (Task task in dlcTasks)
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
selectionTreeView.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled) return;
|
||||
TreeNode programNode = TreeNodes.Find(s => s.Name == "" + appId) ?? new();
|
||||
programNode.Name = "" + appId;
|
||||
programNode.Text = /*(appId > 0 ? $"[{appId}] " : "") +*/ name;
|
||||
|
@ -374,19 +243,11 @@ namespace CreamInstaller
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (KeyValuePair<int, string> dlcApp in dlc.ToList())
|
||||
foreach (KeyValuePair<int, string> dlcApp in dlc)
|
||||
{
|
||||
if (Program.Canceled || programNode is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.Canceled || programNode is null) return;
|
||||
selection.AllSteamDlc[dlcApp.Key] = dlcApp.Value;
|
||||
if (allCheckBox.Checked)
|
||||
{
|
||||
selection.SelectedSteamDlc[dlcApp.Key] = dlcApp.Value;
|
||||
}
|
||||
|
||||
if (allCheckBox.Checked) selection.SelectedSteamDlc[dlcApp.Key] = dlcApp.Value;
|
||||
TreeNode dlcNode = TreeNodes.Find(s => s.Name == "" + dlcApp.Key) ?? new();
|
||||
dlcNode.Name = "" + dlcApp.Key;
|
||||
dlcNode.Text = dlcApp.Value;
|
||||
|
@ -397,17 +258,13 @@ namespace CreamInstaller
|
|||
}
|
||||
});
|
||||
progress.Report(++cur);
|
||||
});
|
||||
RunningTasks.Add(task);
|
||||
}));
|
||||
}
|
||||
progress.Report(-RunningTasks.Count);
|
||||
progress.Report(cur);
|
||||
foreach (Task task in RunningTasks.ToList())
|
||||
{
|
||||
if (Program.Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Program.Canceled) return;
|
||||
await task;
|
||||
}
|
||||
progress.Report(RunningTasks.Count);
|
||||
|
@ -428,7 +285,6 @@ namespace CreamInstaller
|
|||
installButton.Enabled = false;
|
||||
uninstallButton.Enabled = installButton.Enabled;
|
||||
selectionTreeView.Enabled = false;
|
||||
|
||||
progressLabel.Visible = true;
|
||||
progressBar1.Visible = true;
|
||||
progressBar1.Value = 0;
|
||||
|
@ -441,44 +297,20 @@ namespace CreamInstaller
|
|||
IProgress<int> iProgress = progress;
|
||||
progress.ProgressChanged += (sender, _progress) =>
|
||||
{
|
||||
if (_progress < 0)
|
||||
{
|
||||
maxProgress = -_progress;
|
||||
}
|
||||
else
|
||||
{
|
||||
curProgress = _progress;
|
||||
}
|
||||
|
||||
if (_progress < 0) maxProgress = -_progress;
|
||||
else curProgress = _progress;
|
||||
int p = Math.Max(Math.Min((int)((float)(curProgress / (float)maxProgress) * 100), 100), 0);
|
||||
if (validating)
|
||||
{
|
||||
progressLabel.Text = $"Validating . . . {p}% ({curProgress}/{maxProgress})";
|
||||
}
|
||||
else if (setup)
|
||||
{
|
||||
progressLabel.Text = $"Setting up SteamCMD . . . {p}% ({curProgress}/{maxProgress})";
|
||||
}
|
||||
else
|
||||
{
|
||||
progressLabel.Text = $"Gathering and caching your applicable games and their DLCs . . . {p}% ({curProgress}/{maxProgress})";
|
||||
}
|
||||
|
||||
if (validating) progressLabel.Text = $"Validating . . . {p}% ({curProgress}/{maxProgress})";
|
||||
else if (setup) progressLabel.Text = $"Setting up SteamCMD . . . {p}% ({curProgress}/{maxProgress})";
|
||||
else progressLabel.Text = $"Gathering and caching your applicable games and their DLCs . . . {p}% ({curProgress}/{maxProgress})";
|
||||
progressBar1.Value = p;
|
||||
};
|
||||
|
||||
iProgress.Report(-1660); // not exact, number varies
|
||||
int cur = 0;
|
||||
iProgress.Report(cur);
|
||||
if (!validating)
|
||||
{
|
||||
progressLabel.Text = "Setting up SteamCMD . . . ";
|
||||
}
|
||||
|
||||
if (!Directory.Exists(SteamCMD.DirectoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(SteamCMD.DirectoryPath);
|
||||
}
|
||||
if (!validating) progressLabel.Text = "Setting up SteamCMD . . . ";
|
||||
if (!Directory.Exists(SteamCMD.DirectoryPath)) Directory.CreateDirectory(SteamCMD.DirectoryPath);
|
||||
|
||||
FileSystemWatcher watcher = new(SteamCMD.DirectoryPath);
|
||||
watcher.Changed += (sender, e) => iProgress.Report(++cur);
|
||||
|
@ -489,60 +321,42 @@ namespace CreamInstaller
|
|||
watcher.Dispose();
|
||||
|
||||
setup = false;
|
||||
if (!validating)
|
||||
{
|
||||
progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
||||
}
|
||||
if (!validating) progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . ";
|
||||
|
||||
await GetCreamApiApplicablePrograms(iProgress);
|
||||
ProgramSelection.ValidateAll();
|
||||
TreeNodes.ForEach(node =>
|
||||
{
|
||||
if (node.Parent is null && ProgramSelection.FromAppId(int.Parse(node.Name)) is null)
|
||||
{
|
||||
node.Remove();
|
||||
}
|
||||
if (node.Parent is null && ProgramSelection.FromAppId(int.Parse(node.Name)) is null) node.Remove();
|
||||
});
|
||||
|
||||
progressBar1.Value = 100;
|
||||
groupBox1.Size = new(groupBox1.Size.Width, groupBox1.Size.Height + 44);
|
||||
progressLabel.Visible = false;
|
||||
progressBar1.Visible = false;
|
||||
|
||||
selectionTreeView.Enabled = ProgramSelection.All.Any();
|
||||
allCheckBox.Enabled = selectionTreeView.Enabled;
|
||||
noneFoundLabel.Visible = !selectionTreeView.Enabled;
|
||||
|
||||
installButton.Enabled = ProgramSelection.AllSafeEnabled.Any();
|
||||
uninstallButton.Enabled = installButton.Enabled;
|
||||
cancelButton.Enabled = false;
|
||||
scanButton.Enabled = true;
|
||||
|
||||
blockedGamesCheckBox.Enabled = true;
|
||||
blockProtectedHelpButton.Enabled = true;
|
||||
|
||||
progressLabel.Text = "Validating . . . ";
|
||||
if (!validating && !Program.Canceled)
|
||||
{
|
||||
OnLoad(true);
|
||||
}
|
||||
//if (!validating && !Program.Canceled) OnLoad(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ExceptionHandler.OutputException(e))
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
if (ExceptionHandler.OutputException(e)) goto retry;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTreeViewNodeCheckedChanged(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
if (e.Action == TreeViewAction.Unknown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (e.Action == TreeViewAction.Unknown) return;
|
||||
TreeNode node = e.Node;
|
||||
if (node is not null)
|
||||
{
|
||||
|
@ -563,10 +377,7 @@ namespace CreamInstaller
|
|||
selection.ToggleAllDlc(node.Checked);
|
||||
node.Nodes.Cast<TreeNode>().ToList().ForEach(treeNode => treeNode.Checked = node.Checked);
|
||||
}
|
||||
else
|
||||
{
|
||||
selection.Enabled = node.Checked;
|
||||
}
|
||||
else selection.Enabled = node.Checked;
|
||||
allCheckBox.CheckedChanged -= OnAllCheckBoxChanged;
|
||||
allCheckBox.Checked = TreeNodes.TrueForAll(treeNode => treeNode.Checked);
|
||||
allCheckBox.CheckedChanged += OnAllCheckBoxChanged;
|
||||
|
@ -593,18 +404,13 @@ namespace CreamInstaller
|
|||
selectionTreeView.NodeMouseClick += (sender, e) =>
|
||||
{
|
||||
TreeNode node = e.Node;
|
||||
if (e.Button == MouseButtons.Right && node.Bounds.Contains(e.Location))
|
||||
{
|
||||
string appId = node.Name;
|
||||
if (appId != "0")
|
||||
string appId = node.Name;
|
||||
if (e.Button == MouseButtons.Right && node.Bounds.Contains(e.Location) && appId != "0")
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "https://steamdb.info/app/" + appId,
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
}
|
||||
FileName = "https://steamdb.info/app/" + appId,
|
||||
UseShellExecute = true
|
||||
});
|
||||
};
|
||||
OnLoad();
|
||||
}
|
||||
|
@ -617,31 +423,17 @@ namespace CreamInstaller
|
|||
paradoxLauncher.ExtraSteamAppIdDlc.Clear();
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllSafeEnabled)
|
||||
{
|
||||
if (selection.Name == paradoxLauncher.Name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (selection.AppInfo.Value["extended"]["publisher"].ToString() != "Paradox Interactive")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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.Name == paradoxLauncher.Name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (selection.AppInfo.Value["extended"]["publisher"].ToString() != "Paradox Interactive")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -657,9 +449,7 @@ namespace CreamInstaller
|
|||
$"WARNING: There are no installed games with DLC that can be added to the Paradox Launcher!" +
|
||||
"\n\nInstalling CreamAPI for the Paradox Launcher is pointless, since no DLC will be added to the configuration!",
|
||||
"Ignore", "Cancel") == DialogResult.OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -671,16 +461,8 @@ namespace CreamInstaller
|
|||
if (ProgramSelection.All.Any())
|
||||
{
|
||||
foreach (ProgramSelection selection in ProgramSelection.AllSafeEnabled)
|
||||
{
|
||||
if (!Program.IsProgramRunningDialog(this, selection))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ParadoxLauncherDlcDialog(this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!Program.IsProgramRunningDialog(this, selection)) return;
|
||||
if (ParadoxLauncherDlcDialog(this)) return;
|
||||
Hide();
|
||||
InstallForm installForm = new(this, uninstall);
|
||||
installForm.ShowDialog();
|
||||
|
@ -690,27 +472,13 @@ namespace CreamInstaller
|
|||
Show();
|
||||
OnLoad();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstall(object sender, EventArgs e)
|
||||
{
|
||||
OnAccept(false);
|
||||
}
|
||||
|
||||
private void OnUninstall(object sender, EventArgs e)
|
||||
{
|
||||
OnAccept(true);
|
||||
}
|
||||
|
||||
private void OnScan(object sender, EventArgs e)
|
||||
{
|
||||
OnLoad();
|
||||
}
|
||||
private void OnInstall(object sender, EventArgs e) => OnAccept(false);
|
||||
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
|
||||
private void OnScan(object sender, EventArgs e) => OnLoad();
|
||||
|
||||
private void OnCancel(object sender, EventArgs e)
|
||||
{
|
||||
|
@ -728,10 +496,7 @@ namespace CreamInstaller
|
|||
{
|
||||
if (node.Parent is null)
|
||||
{
|
||||
if (!node.Checked)
|
||||
{
|
||||
shouldCheck = true;
|
||||
}
|
||||
if (!node.Checked) shouldCheck = true;
|
||||
if (node.Checked != shouldCheck)
|
||||
{
|
||||
node.Checked = shouldCheck;
|
||||
|
@ -753,19 +518,13 @@ namespace CreamInstaller
|
|||
{
|
||||
string blockedGames = "";
|
||||
foreach (string name in Program.ProtectedGameNames)
|
||||
{
|
||||
blockedGames += helpButtonListPrefix + name;
|
||||
}
|
||||
string blockedDirectories = "";
|
||||
foreach (string path in Program.ProtectedGameDirectories)
|
||||
{
|
||||
blockedDirectories += helpButtonListPrefix + path;
|
||||
}
|
||||
string blockedDirectoryExceptions = "";
|
||||
foreach (string name in Program.ProtectedGameDirectoryExceptions)
|
||||
{
|
||||
blockedDirectoryExceptions += helpButtonListPrefix + name;
|
||||
}
|
||||
new DialogForm(this).Show(blockedGamesCheckBox.Text, SystemIcons.Information,
|
||||
"Blocks the program from caching and displaying games protected by DLL checks," +
|
||||
"\nanti-cheats, or that are confirmed not to be working with CreamAPI." +
|
||||
|
|
|
@ -41,11 +41,7 @@ namespace CreamInstaller
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ExceptionHandler.OutputException(e))
|
||||
{
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (ExceptionHandler.OutputException(e)) goto retry;
|
||||
Application.Exit();
|
||||
return;
|
||||
}
|
||||
|
@ -61,14 +57,9 @@ namespace CreamInstaller
|
|||
$"ERROR: {selection.Name} is currently running!" +
|
||||
"\n\nPlease close the program/game to continue . . . ",
|
||||
"Retry", "Cancel") == DialogResult.OK)
|
||||
{
|
||||
return IsProgramRunningDialog(form, selection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -86,17 +77,13 @@ namespace CreamInstaller
|
|||
internal static List<ProgramSelection> ProgramSelections = new();
|
||||
|
||||
internal static bool Canceled = false;
|
||||
|
||||
internal static async Task Cleanup(bool cancel = true)
|
||||
{
|
||||
Canceled = cancel;
|
||||
await SteamCMD.Kill();
|
||||
}
|
||||
|
||||
private static void OnApplicationExit(object s, EventArgs e)
|
||||
{
|
||||
Cleanup().Wait();
|
||||
}
|
||||
private static void OnApplicationExit(object s, EventArgs e) => Cleanup().Wait();
|
||||
|
||||
internal static void InheritLocation(this Form form, Form fromForm)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue