From 820e2abf419a7e972e875e3c76a4fac5d9e7b7f5 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Wed, 1 Apr 2020 19:43:49 -0500 Subject: [PATCH 1/4] DictionaryExt.Add many --- Wabbajack.Common/Extensions/DictionaryExt.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Wabbajack.Common/Extensions/DictionaryExt.cs b/Wabbajack.Common/Extensions/DictionaryExt.cs index dceaf8f4..2dcf9d0f 100644 --- a/Wabbajack.Common/Extensions/DictionaryExt.cs +++ b/Wabbajack.Common/Extensions/DictionaryExt.cs @@ -18,5 +18,21 @@ namespace Wabbajack dict[key] = ret; return ret; } + + public static void Add(this IDictionary dict, IEnumerable> vals) + { + foreach (var val in vals) + { + dict.Add(val); + } + } + + public static void Set(this IDictionary dict, IEnumerable> vals) + { + foreach (var val in vals) + { + dict[val.Key] = val.Value; + } + } } } From ec4ec21a7c4143dc7ff9a46765f049e515671532 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 2 Apr 2020 10:35:32 -0500 Subject: [PATCH 2/4] Added nullability errors --- .editorconfig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 9270fbad..06238767 100644 --- a/.editorconfig +++ b/.editorconfig @@ -121,4 +121,67 @@ csharp_preserve_single_line_blocks = true # CS4014: Task not awaited dotnet_diagnostic.CS4014.severity = error # CS1998: Async function does not contain await -dotnet_diagnostic.CS1998.severity = silent \ No newline at end of file +dotnet_diagnostic.CS1998.severity = silent + +############################### +# C# Nullability # +############################### +# CS8602: Dereference of a possibly null reference. +dotnet_diagnostic.CS8602.severity = error + +# CS8600: Converting null literal or possible null value to non-nullable type. +dotnet_diagnostic.CS8600.severity = error + +# CS8619: Nullability of reference types in value doesn't match target type. +dotnet_diagnostic.CS8619.severity = error + +# CS8603: Possible null reference return. +dotnet_diagnostic.CS8603.severity = error + +# CS8625: Cannot convert null literal to non-nullable reference type. +dotnet_diagnostic.CS8625.severity = error + +# CS8653: A default expression introduces a null value for a type parameter. +dotnet_diagnostic.CS8653.severity = silent + +# CS8601: Possible null reference assignment. +dotnet_diagnostic.CS8601.severity = error + +# CS8604: Possible null reference argument. +dotnet_diagnostic.CS8604.severity = error + +# CS8622: Nullability of reference types in type of parameter doesn't match the target delegate. +dotnet_diagnostic.CS8622.severity = error + +# CS8610: Nullability of reference types in type of parameter doesn't match overridden member. +dotnet_diagnostic.CS8610.severity = error + +# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable. +dotnet_diagnostic.CS8618.severity = error + +# CS8629: Nullable value type may be null. +dotnet_diagnostic.CS8629.severity = error + +# CS8620: Argument cannot be used for parameter due to differences in the nullability of reference types. +dotnet_diagnostic.CS8620.severity = error + +# CS8614: Nullability of reference types in type of parameter doesn't match implicitly implemented member. +dotnet_diagnostic.CS8614.severity = error + +# CS8617: Nullability of reference types in type of parameter doesn't match implemented member. +dotnet_diagnostic.CS8617.severity = error + +# CS8611: Nullability of reference types in type of parameter doesn't match partial method declaration. +dotnet_diagnostic.CS8611.severity = error + +# CS8597: Thrown value may be null. +dotnet_diagnostic.CS8597.severity = error + +# CS8609: Nullability of reference types in return type doesn't match overridden member. +dotnet_diagnostic.CS8609.severity = error + +# CS8714: The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. +dotnet_diagnostic.CS8714.severity = error + +# CS8605: Unboxing a possibly null value. +dotnet_diagnostic.CS8605.severity = error \ No newline at end of file From ddc85185f4a052638e2dcda02a6af3256b44c2d6 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Thu, 2 Apr 2020 11:09:05 -0500 Subject: [PATCH 3/4] Removed HashHelper in favor of System.HashCode --- Wabbajack.Common/Error States/GetResponse.cs | 6 +- Wabbajack.Common/Extensions/HashHelper.cs | 133 ------------------- 2 files changed, 4 insertions(+), 135 deletions(-) delete mode 100644 Wabbajack.Common/Extensions/HashHelper.cs diff --git a/Wabbajack.Common/Error States/GetResponse.cs b/Wabbajack.Common/Error States/GetResponse.cs index fc78dacd..1a5183d6 100644 --- a/Wabbajack.Common/Error States/GetResponse.cs +++ b/Wabbajack.Common/Error States/GetResponse.cs @@ -53,8 +53,10 @@ namespace Wabbajack public override int GetHashCode() { - return HashHelper.GetHashCode(Value) - .CombineHashCode(Succeeded.GetHashCode()); + System.HashCode hash = new HashCode(); + hash.Add(Value); + hash.Add(Succeeded); + return hash.ToHashCode(); } public override string ToString() diff --git a/Wabbajack.Common/Extensions/HashHelper.cs b/Wabbajack.Common/Extensions/HashHelper.cs deleted file mode 100644 index 8126e04e..00000000 --- a/Wabbajack.Common/Extensions/HashHelper.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Collections.Generic; - -/* - * Taken from: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode - */ -namespace Wabbajack -{ - public static class HashHelper - { - public static int GetHashCode(T1 arg1, T2 arg2) - { - unchecked - { - return 31 * (arg1 == null ? 0 : arg1.GetHashCode()) - + (arg2 == null ? 0 : arg2.GetHashCode()); - } - } - - public static int GetHashCode(T1 arg1, T2 arg2, T3 arg3) - { - unchecked - { - int hash = (arg1 == null ? 0 : arg1.GetHashCode()); - hash = 31 * hash + (arg2 == null ? 0 : arg2.GetHashCode()); - return 31 * hash + (arg3 == null ? 0 : arg3.GetHashCode()); - } - } - - public static int GetHashCode(T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - unchecked - { - int hash = (arg1 == null ? 0 : arg1.GetHashCode()); - hash = 31 * hash + (arg2 == null ? 0 : arg2.GetHashCode()); - hash = 31 * hash + (arg3 == null ? 0 : arg3.GetHashCode()); - return 31 * hash + (arg4 == null ? 0 : arg4.GetHashCode()); - } - } - - public static int GetHashCode(params T[] list) - { - unchecked - { - int hash = 0; - if (list == null) return hash; - for (int i = 0; i < list.Length; i++) - { - hash = 31 * hash + GetHashCode(list[i]); - } - return hash; - } - } - - public static int GetHashCode(ReadOnlySpan span) - { - unchecked - { - int hash = 0; - if (span == null) return hash; - for (int i = 0; i < span.Length; i++) - { - hash = 31 * hash + GetHashCode(span[i]); - } - return hash; - } - } - - public static int GetHashCode(T t) - { - unchecked - { - return (t == null ? 0 : t.GetHashCode()); - } - } - - public static int GetHashCode(IEnumerable list) - { - unchecked - { - int hash = 0; - foreach (var item in list) - { - hash = 31 * hash + (item == null ? 0 : item.GetHashCode()); - } - return hash; - } - } - - /// - /// Gets a hashcode for a collection for that the order of items - /// does not matter. - /// So {1, 2, 3} and {3, 2, 1} will get same hash code. - /// - public static int GetHashCode_OrderBlind( - IEnumerable list) - { - unchecked - { - int hash = 0; - int count = 0; - foreach (var item in list) - { - hash += (item == null ? 0 : item.GetHashCode()); - count++; - } - return 31 * hash + count.GetHashCode(); - } - } - - /// - /// Alternative way to get a hashcode is to use a fluent - /// interface like this:
- /// return 0.CombineHashCode(field1).CombineHashCode(field2). - /// CombineHashCode(field3); - ///
- public static int CombineHashCode(this int hashCode, T arg) - { - unchecked - { - return CombineHashCode(hashCode, (arg == null ? 0 : arg.GetHashCode())); - } - } - - public static int CombineHashCode(this int hashCode, int rhsHash) - { - unchecked - { - return 31 * hashCode + rhsHash; - } - } - } -} From 21b52fb3615e822b8c1058757990ff00f5fb8d3e Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Fri, 3 Apr 2020 18:23:13 -0500 Subject: [PATCH 4/4] Enabled nullability for Wabbajack.Common --- Wabbajack.Common/AsyncBlockingCollection.cs | 7 +-- Wabbajack.Common/CLI.cs | 6 +- Wabbajack.Common/DynamicIniData.cs | 5 +- Wabbajack.Common/Enumerable.cs | 14 ----- .../Error States/ErrorResponse.cs | 16 ++--- Wabbajack.Common/Error States/GetResponse.cs | 16 ++--- Wabbajack.Common/Extensions/DictionaryExt.cs | 4 ++ Wabbajack.Common/Extensions/EnumExt.cs | 4 +- Wabbajack.Common/Extensions/EnumerableExt.cs | 9 ++- Wabbajack.Common/Extensions/RxExt.cs | 14 +++-- Wabbajack.Common/Extensions/TaskExt.cs | 2 +- Wabbajack.Common/GameMetaData.cs | 40 ++++++------- Wabbajack.Common/Hash.cs | 3 +- Wabbajack.Common/Json.cs | 30 ++++++---- Wabbajack.Common/KnownFolders/KnownFolder.cs | 1 + .../KnownFolders/KnownFolderType.cs | 1 + Wabbajack.Common/KnownFolders/KnownFolders.cs | 1 + Wabbajack.Common/MessagePack.cs | 4 +- ...nager1.cs => ModListAssociationManager.cs} | 2 +- Wabbajack.Common/Paths.cs | 59 ++++++++----------- Wabbajack.Common/ProcessHelper.cs | 6 +- Wabbajack.Common/SplittingStream.cs | 2 +- .../StatusFeed/Errors/FileExtractionError.cs | 4 +- .../StatusFeed/Errors/GenericException.cs | 10 ++-- Wabbajack.Common/StatusFeed/GenericInfo.cs | 4 +- Wabbajack.Common/StatusFileStream.cs | 4 +- ...StatusUpdate.cs => StatusUpdateTracker.cs} | 0 Wabbajack.Common/StoreHandlers/GOGHandler.cs | 18 +++--- .../StoreHandlers/SteamHandler.cs | 50 +++++++--------- .../StoreHandlers/StoreHandler.cs | 8 +-- Wabbajack.Common/Util/AsyncLock.cs | 2 +- Wabbajack.Common/Util/DiskSlabAllocator.cs | 6 +- Wabbajack.Common/Util/Percent.cs | 4 +- Wabbajack.Common/Util/TempFile.cs | 1 - Wabbajack.Common/Utils.cs | 50 ++++++---------- Wabbajack.Common/Wabbajack.Common.csproj | 2 +- Wabbajack.Common/WorkQueue.cs | 4 +- 37 files changed, 189 insertions(+), 224 deletions(-) delete mode 100644 Wabbajack.Common/Enumerable.cs rename Wabbajack.Common/{ModListAssociationManager1.cs => ModListAssociationManager.cs} (96%) rename Wabbajack.Common/{StatusUpdate.cs => StatusUpdateTracker.cs} (100%) diff --git a/Wabbajack.Common/AsyncBlockingCollection.cs b/Wabbajack.Common/AsyncBlockingCollection.cs index 3d7dd04a..15e53625 100644 --- a/Wabbajack.Common/AsyncBlockingCollection.cs +++ b/Wabbajack.Common/AsyncBlockingCollection.cs @@ -9,13 +9,8 @@ namespace Wabbajack.Common { public class AsyncBlockingCollection : IDisposable { - private readonly ConcurrentQueue _collection; + private readonly ConcurrentQueue _collection = new ConcurrentQueue(); private bool isDisposed = false; - - public AsyncBlockingCollection() - { - _collection = new ConcurrentQueue(); - } public void Add(T val) { diff --git a/Wabbajack.Common/CLI.cs b/Wabbajack.Common/CLI.cs index 662d39af..1d72339f 100644 --- a/Wabbajack.Common/CLI.cs +++ b/Wabbajack.Common/CLI.cs @@ -10,10 +10,10 @@ namespace Wabbajack.Common public static bool NoSettings { get; set; } [CLIOptions("apikey", HelpText = "Manually input an Nexus api key")] - public static string ApiKey { get; set; } + public static string? ApiKey { get; set; } [CLIOptions("install", ShortOption = 'i', HelpText = "Install a ModList via CLI")] - public static string InstallPath { get; set; } + public static string? InstallPath { get; set; } [CLIOptions("help", ShortOption = 'h', HelpText = "Display this message")] public static bool Help { get; set; } @@ -94,7 +94,7 @@ namespace Wabbajack.Common // -shortOption, short name of the option. Eg: -o public char ShortOption; // text to be displayed when --help is called - public string HelpText; + public string HelpText = string.Empty; public CLIOptions(string option) { diff --git a/Wabbajack.Common/DynamicIniData.cs b/Wabbajack.Common/DynamicIniData.cs index 9f5a7c64..5aacb271 100644 --- a/Wabbajack.Common/DynamicIniData.cs +++ b/Wabbajack.Common/DynamicIniData.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Text; using System.Text.RegularExpressions; @@ -35,7 +36,7 @@ namespace Wabbajack.Common return true; } - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, [MaybeNullWhen(false)] out object result) { if (indexes.Length > 1) { @@ -114,7 +115,7 @@ namespace Wabbajack.Common return Encoding.UTF8.GetString(acc.ToArray()); } - public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, [MaybeNullWhen(false)] out object result) { if (indexes.Length > 1) { diff --git a/Wabbajack.Common/Enumerable.cs b/Wabbajack.Common/Enumerable.cs deleted file mode 100644 index 3307eb59..00000000 --- a/Wabbajack.Common/Enumerable.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Wabbajack.Common -{ - public static partial class Utils - { - public static IEnumerable Cons(this IEnumerable coll, T next) - { - yield return next; - foreach (var itm in coll) yield return itm; - } - - } -} diff --git a/Wabbajack.Common/Error States/ErrorResponse.cs b/Wabbajack.Common/Error States/ErrorResponse.cs index a5df539c..c0fecf48 100644 --- a/Wabbajack.Common/Error States/ErrorResponse.cs +++ b/Wabbajack.Common/Error States/ErrorResponse.cs @@ -8,7 +8,7 @@ namespace Wabbajack public readonly static ErrorResponse Failure = new ErrorResponse(); public bool Succeeded { get; } - public Exception Exception { get; } + public Exception? Exception { get; } private readonly string _reason; public bool Failed => !Succeeded; @@ -32,15 +32,15 @@ namespace Wabbajack } bool IErrorResponse.Succeeded => Succeeded; - Exception IErrorResponse.Exception => Exception; + Exception? IErrorResponse.Exception => Exception; private ErrorResponse( bool succeeded, - string reason = null, - Exception ex = null) + string? reason = null, + Exception? ex = null) { Succeeded = succeeded; - _reason = reason; + _reason = reason ?? string.Empty; Exception = ex; } @@ -60,7 +60,7 @@ namespace Wabbajack return new ErrorResponse(true, reason); } - public static ErrorResponse Fail(string reason, Exception ex = null) + public static ErrorResponse Fail(string reason, Exception? ex = null) { return new ErrorResponse(false, reason: reason, ex: ex); } @@ -75,7 +75,7 @@ namespace Wabbajack return new ErrorResponse(false); } - public static ErrorResponse Create(bool successful, string reason = null) + public static ErrorResponse Create(bool successful, string? reason = null) { return new ErrorResponse(successful, reason); } @@ -91,7 +91,7 @@ namespace Wabbajack public interface IErrorResponse { bool Succeeded { get; } - Exception Exception { get; } + Exception? Exception { get; } string Reason { get; } } } diff --git a/Wabbajack.Common/Error States/GetResponse.cs b/Wabbajack.Common/Error States/GetResponse.cs index 1a5183d6..8b80bad4 100644 --- a/Wabbajack.Common/Error States/GetResponse.cs +++ b/Wabbajack.Common/Error States/GetResponse.cs @@ -8,7 +8,7 @@ namespace Wabbajack public readonly T Value; public readonly bool Succeeded; - public readonly Exception Exception; + public readonly Exception? Exception; private readonly string _reason; public bool Failed => !Succeeded; @@ -25,17 +25,17 @@ namespace Wabbajack } bool IErrorResponse.Succeeded => Succeeded; - Exception IErrorResponse.Exception => Exception; + Exception? IErrorResponse.Exception => Exception; private GetResponse( bool succeeded, - T val = default(T), - string reason = null, - Exception ex = null) + T val = default, + string? reason = null, + Exception? ex = null) { Value = val; Succeeded = succeeded; - _reason = reason; + _reason = reason ?? string.Empty; Exception = ex; } @@ -45,7 +45,7 @@ namespace Wabbajack && Equals(Value, other.Value); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is GetResponse rhs)) return false; return Equals(rhs); @@ -126,7 +126,7 @@ namespace Wabbajack return new GetResponse(false, val); } - public static GetResponse Create(bool successful, T val = default(T), string reason = null) + public static GetResponse Create(bool successful, T val = default(T), string? reason = null) { return new GetResponse(successful, val, reason); } diff --git a/Wabbajack.Common/Extensions/DictionaryExt.cs b/Wabbajack.Common/Extensions/DictionaryExt.cs index 2dcf9d0f..64ea3f03 100644 --- a/Wabbajack.Common/Extensions/DictionaryExt.cs +++ b/Wabbajack.Common/Extensions/DictionaryExt.cs @@ -6,12 +6,14 @@ namespace Wabbajack public static class DictionaryExt { public static V TryCreate(this IDictionary dict, K key) + where K : notnull where V : new() { return dict.TryCreate(key, () => new V()); } public static V TryCreate(this IDictionary dict, K key, Func create) + where K : notnull { if (dict.TryGetValue(key, out var val)) return val; var ret = create(); @@ -20,6 +22,7 @@ namespace Wabbajack } public static void Add(this IDictionary dict, IEnumerable> vals) + where K : notnull { foreach (var val in vals) { @@ -28,6 +31,7 @@ namespace Wabbajack } public static void Set(this IDictionary dict, IEnumerable> vals) + where K : notnull { foreach (var val in vals) { diff --git a/Wabbajack.Common/Extensions/EnumExt.cs b/Wabbajack.Common/Extensions/EnumExt.cs index bdd88847..b16515dc 100644 --- a/Wabbajack.Common/Extensions/EnumExt.cs +++ b/Wabbajack.Common/Extensions/EnumExt.cs @@ -21,8 +21,8 @@ namespace Wabbajack.Common throw new ArgumentException("T must be an Enum"); } - var attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false); - return attributes.Length > 0 ? attributes[0].Description : val.ToString(); + var attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()!)!.GetCustomAttributes(typeof(DescriptionAttribute), false); + return attributes.Length > 0 ? attributes[0].Description : val.ToString()!; } } } diff --git a/Wabbajack.Common/Extensions/EnumerableExt.cs b/Wabbajack.Common/Extensions/EnumerableExt.cs index fc874b2e..e93b6c03 100644 --- a/Wabbajack.Common/Extensions/EnumerableExt.cs +++ b/Wabbajack.Common/Extensions/EnumerableExt.cs @@ -11,9 +11,6 @@ namespace Wabbajack public static IEnumerable Shuffle(this IEnumerable source, Random rng) { - if (source == null) throw new ArgumentNullException("source"); - if (rng == null) throw new ArgumentNullException("rng"); - return source.ShuffleIterator(rng); } @@ -30,5 +27,11 @@ namespace Wabbajack } } #endregion + + public static IEnumerable Cons(this IEnumerable coll, T next) + { + yield return next; + foreach (var itm in coll) yield return itm; + } } } diff --git a/Wabbajack.Common/Extensions/RxExt.cs b/Wabbajack.Common/Extensions/RxExt.cs index ddc3f1fe..40d73602 100644 --- a/Wabbajack.Common/Extensions/RxExt.cs +++ b/Wabbajack.Common/Extensions/RxExt.cs @@ -16,10 +16,12 @@ namespace Wabbajack /// /// /// Source events that are not null - public static IObservable NotNull(this IObservable source) + public static IObservable NotNull(this IObservable source) where T : class { - return source.Where(u => u != null); + return source + .Where(u => u != null) + .Select(u => u!); } /// @@ -88,9 +90,9 @@ namespace Wabbajack /// Inspiration: /// http://reactivex.io/documentation/operators/debounce.html /// https://stackoverflow.com/questions/20034476/how-can-i-use-reactive-extensions-to-throttle-events-using-a-max-window-size - public static IObservable Debounce(this IObservable source, TimeSpan interval, IScheduler scheduler = null) + public static IObservable Debounce(this IObservable source, TimeSpan interval, IScheduler? scheduler = null) { - scheduler = scheduler ?? Scheduler.Default; + scheduler ??= Scheduler.Default; return Observable.Create(o => { var hasValue = false; @@ -218,8 +220,8 @@ namespace Wabbajack .StartWith(false)); } - public static IObservable DisposeOld(this IObservable source) - where T : IDisposable + public static IObservable DisposeOld(this IObservable source) + where T : class, IDisposable { return source .StartWith(default(T)) diff --git a/Wabbajack.Common/Extensions/TaskExt.cs b/Wabbajack.Common/Extensions/TaskExt.cs index b81d42f7..35a8a177 100644 --- a/Wabbajack.Common/Extensions/TaskExt.cs +++ b/Wabbajack.Common/Extensions/TaskExt.cs @@ -5,7 +5,7 @@ namespace Wabbajack { public static class TaskExt { - public static async void FireAndForget(this Task task, Action onException = null) + public static async void FireAndForget(this Task task, Action? onException = null) { try { diff --git a/Wabbajack.Common/GameMetaData.cs b/Wabbajack.Common/GameMetaData.cs index 8730f905..80b70bb5 100644 --- a/Wabbajack.Common/GameMetaData.cs +++ b/Wabbajack.Common/GameMetaData.cs @@ -58,45 +58,46 @@ namespace Wabbajack.Common public class GameMetaData { public ModManager SupportedModManager { get; internal set; } - public string MO2ArchiveName { get; internal set; } + public string? MO2ArchiveName { get; internal set; } public Game Game { get; internal set; } - public string NexusName { get; internal set; } + public string? NexusName { get; internal set; } // Nexus DB id for the game, used in some specific situations public long NexusGameId { get; internal set; } - public string MO2Name { get; internal set; } + public string? MO2Name { get; internal set; } public string HumanFriendlyGameName => Game.GetDescription(); - public string GameLocationRegistryKey { get; internal set; } + public string? GameLocationRegistryKey { get; internal set; } // to get steam ids: https://steamdb.info - public List SteamIDs { get; internal set; } + public List? SteamIDs { get; internal set; } // to get gog ids: https://www.gogdb.org - public List GOGIDs { get; internal set; } + public List? GOGIDs { get; internal set; } // these are additional folders when a game installs mods outside the game folder - public List AdditionalFolders { get; internal set; } + public List? AdditionalFolders { get; internal set; } // file to check if the game is present, useful when steamIds and gogIds dont help - public List RequiredFiles { get; internal set; } + public List? RequiredFiles { get; internal set; } public bool Disabled { get; internal set; } - + // Games that this game are commonly confused with, for example Skyrim SE vs Skyrim LE - public Game[] CommonlyConfusedWith { get; set; } + public Game[] CommonlyConfusedWith { get; set; } = Array.Empty(); public string InstalledVersion { get { - if (GameLocation() == null) + AbsolutePath? gameLoc = GameLocation(); + if (gameLoc == null) throw new GameNotInstalledException(this); if (MainExecutable == null) throw new NotImplementedException(); - return FileVersionInfo.GetVersionInfo((string)GameLocation()?.Combine(MainExecutable)).ProductVersion; + return FileVersionInfo.GetVersionInfo((string)gameLoc.Value.Combine(MainExecutable)).ProductVersion; } } public bool IsInstalled => GameLocation() != null; - public string MainExecutable { get; internal set; } + public string? MainExecutable { get; internal set; } public AbsolutePath? GameLocation() { @@ -114,14 +115,14 @@ namespace Wabbajack.Common public static class EnumExtensions { public static string GetDescription(this T enumerationValue) - where T : struct + where T : Enum { var type = enumerationValue.GetType(); if(!type.IsEnum) { throw new ArgumentException($"{nameof(enumerationValue)} must be of Enum type", nameof(enumerationValue)); } - var memberInfo = type.GetMember(enumerationValue.ToString()); + var memberInfo = type.GetMember(enumerationValue.ToString()!); if(memberInfo.Length > 0) { var attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); @@ -131,7 +132,7 @@ namespace Wabbajack.Common return ((DescriptionAttribute)attrs[0]).Description; } } - return enumerationValue.ToString(); + return enumerationValue.ToString()!; } } @@ -158,12 +159,11 @@ namespace Wabbajack.Common /// Tries to parse game data from an arbitrary string. Tries first via parsing as a game Enum, then by Nexus name, /// /// - public static GameMetaData GetByFuzzyName(string someName) + public static GameMetaData? GetByFuzzyName(string someName) { + if (Enum.TryParse(typeof(Game), someName, true, out var metadata)) return ((Game)metadata!).MetaData(); - if (Enum.TryParse(typeof(Game), someName, true, out var metadata)) return ((Game)metadata).MetaData(); - - GameMetaData result = null; + GameMetaData? result = null; result = GetByNexusName(someName); if (result != null) return result; diff --git a/Wabbajack.Common/Hash.cs b/Wabbajack.Common/Hash.cs index 5acdc7a4..59420d1b 100644 --- a/Wabbajack.Common/Hash.cs +++ b/Wabbajack.Common/Hash.cs @@ -1,5 +1,4 @@ -#nullable enable -using System; +using System; using System.Collections.Generic; using System.Data.HashFunction.xxHash; using System.IO; diff --git a/Wabbajack.Common/Json.cs b/Wabbajack.Common/Json.cs index 1ce31593..f8bb69c1 100644 --- a/Wabbajack.Common/Json.cs +++ b/Wabbajack.Common/Json.cs @@ -52,7 +52,7 @@ namespace Wabbajack.Common new JsonSerializerSettings { TypeNameHandling = handling, TypeNameAssemblyFormatHandling = format, Converters = Converters - }); + })!; } public static T FromJSONString(this string data, @@ -63,7 +63,7 @@ namespace Wabbajack.Common new JsonSerializerSettings { TypeNameHandling = handling, TypeNameAssemblyFormatHandling = format, Converters = Converters - }); + })!; } public static T FromJSON(this Stream data) @@ -72,7 +72,7 @@ namespace Wabbajack.Common try { return JsonConvert.DeserializeObject(s, - new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto, Converters = Converters}); + new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto, Converters = Converters})!; } catch (JsonSerializationException) { @@ -95,7 +95,7 @@ namespace Wabbajack.Common public override Hash ReadJson(JsonReader reader, Type objectType, Hash existingValue, bool hasExistingValue, JsonSerializer serializer) { - return Hash.FromBase64((string)reader.Value); + return Hash.FromBase64((string)reader.Value!); } } @@ -110,7 +110,7 @@ namespace Wabbajack.Common bool hasExistingValue, JsonSerializer serializer) { - return (RelativePath)(string)reader.Value; + return (RelativePath)(string)reader.Value!; } } @@ -125,7 +125,7 @@ namespace Wabbajack.Common bool hasExistingValue, JsonSerializer serializer) { - return (AbsolutePath)(string)reader.Value; + return (AbsolutePath)(string)reader.Value!; } } @@ -133,7 +133,7 @@ namespace Wabbajack.Common { public override Percent ReadJson(JsonReader reader, Type objectType, Percent existingValue, bool hasExistingValue, JsonSerializer serializer) { - double d = (double)reader.Value; + double d = (double)reader.Value!; return Percent.FactoryPutInRange(d); } @@ -162,13 +162,13 @@ namespace Wabbajack.Common throw new JsonException("Invalid JSON state while reading Hash Relative Path"); reader.Read(); - var hash = Hash.FromBase64((string)reader.Value); + var hash = Hash.FromBase64((string)reader.Value!); var paths = new List(); reader.Read(); while (reader.TokenType != JsonToken.EndArray) { - paths.Add((RelativePath)(string)reader.Value); + paths.Add((RelativePath)(string)reader.Value!); reader.Read(); } @@ -195,13 +195,13 @@ namespace Wabbajack.Common throw new JsonException("Invalid JSON state while reading Hash Relative Path"); reader.Read(); - var abs = (AbsolutePath)(string)reader.Value; + var abs = (AbsolutePath)(string)reader.Value!; var paths = new List(); reader.Read(); while (reader.TokenType != JsonToken.EndArray) { - paths.Add((RelativePath)(string)reader.Value); + paths.Add((RelativePath)(string)reader.Value!); reader.Read(); } @@ -228,7 +228,13 @@ namespace Wabbajack.Common return (Game)i; } - return GameRegistry.GetByFuzzyName(str).Game; + GameMetaData? game = GameRegistry.GetByFuzzyName(str); + if (game == null) + { + throw new ArgumentException($"Could not convert {str} to a Game type."); + } + + return game.Game; } } } diff --git a/Wabbajack.Common/KnownFolders/KnownFolder.cs b/Wabbajack.Common/KnownFolders/KnownFolder.cs index 4beebe27..c9713798 100644 --- a/Wabbajack.Common/KnownFolders/KnownFolder.cs +++ b/Wabbajack.Common/KnownFolders/KnownFolder.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using System.Security.Principal; +#nullable disable namespace Wabbajack.Common.IO { diff --git a/Wabbajack.Common/KnownFolders/KnownFolderType.cs b/Wabbajack.Common/KnownFolders/KnownFolderType.cs index 679d832f..87aa1aca 100644 --- a/Wabbajack.Common/KnownFolders/KnownFolderType.cs +++ b/Wabbajack.Common/KnownFolders/KnownFolderType.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +#nullable disable namespace Wabbajack.Common.IO { diff --git a/Wabbajack.Common/KnownFolders/KnownFolders.cs b/Wabbajack.Common/KnownFolders/KnownFolders.cs index 0ac603ce..623a880f 100644 --- a/Wabbajack.Common/KnownFolders/KnownFolders.cs +++ b/Wabbajack.Common/KnownFolders/KnownFolders.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; +#nullable disable namespace Wabbajack.Common.IO { diff --git a/Wabbajack.Common/MessagePack.cs b/Wabbajack.Common/MessagePack.cs index 32ad9723..08a7a5cc 100644 --- a/Wabbajack.Common/MessagePack.cs +++ b/Wabbajack.Common/MessagePack.cs @@ -11,8 +11,8 @@ namespace Wabbajack.Common { public partial class Utils { - private static MessagePackSerializerOptions _messagePackOptions; - private static IFormatterResolver _resolver; + private static MessagePackSerializerOptions? _messagePackOptions; + private static IFormatterResolver? _resolver; private static void MessagePackInit() { diff --git a/Wabbajack.Common/ModListAssociationManager1.cs b/Wabbajack.Common/ModListAssociationManager.cs similarity index 96% rename from Wabbajack.Common/ModListAssociationManager1.cs rename to Wabbajack.Common/ModListAssociationManager.cs index 14f428fa..0f425a53 100644 --- a/Wabbajack.Common/ModListAssociationManager1.cs +++ b/Wabbajack.Common/ModListAssociationManager.cs @@ -39,7 +39,7 @@ namespace Wabbajack.Common var tempKey = progIDKey?.OpenSubKey("shell\\open\\command"); if (progIDKey == null || tempKey == null) return true; var value = tempKey.GetValue(""); - return value == null || !value.ToString().Equals($"\"{execPath}\" -i=\"%1\""); + return value == null || !string.Equals(value.ToString(), $"\"{execPath}\" -i=\"%1\""); } public static bool IsAssociated() diff --git a/Wabbajack.Common/Paths.cs b/Wabbajack.Common/Paths.cs index 70884203..72f5b13f 100644 --- a/Wabbajack.Common/Paths.cs +++ b/Wabbajack.Common/Paths.cs @@ -33,7 +33,7 @@ namespace Wabbajack.Common return string.Equals(_path, other._path, StringComparison.InvariantCultureIgnoreCase); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is AbsolutePath other && Equals(other); } @@ -42,7 +42,7 @@ namespace Wabbajack.Common public override int GetHashCode() { - return _path?.GetHashCode(StringComparison.InvariantCultureIgnoreCase) ?? 0; + return _path.GetHashCode(StringComparison.InvariantCultureIgnoreCase); } public override string ToString() @@ -50,11 +50,12 @@ namespace Wabbajack.Common return _path; } - private readonly string _path; + private readonly string _nullable_path; + private string _path => _nullable_path ?? string.Empty; public AbsolutePath(string path, bool skipValidation = false) { - _path = path.Replace("/", "\\").TrimEnd('\\'); + _nullable_path = path.Replace("/", "\\").TrimEnd('\\'); if (!skipValidation) { ValidateAbsolutePath(); @@ -63,7 +64,7 @@ namespace Wabbajack.Common public AbsolutePath(AbsolutePath path) { - _path = path._path; + _nullable_path = path._path; } private void ValidateAbsolutePath() @@ -150,7 +151,8 @@ namespace Wabbajack.Common var location = Assembly.GetEntryAssembly()?.Location ?? null; if (location == null) location = Assembly.GetExecutingAssembly().Location ?? null; - + if (location == null) + throw new ArgumentException("Could not find entry point."); return ((AbsolutePath)location).Parent; } } @@ -264,7 +266,7 @@ namespace Wabbajack.Common public AbsolutePath Combine(params RelativePath[] paths) { - return new AbsolutePath(Path.Combine(paths.Select(s => (string)s).Where(s => s != null).Cons(_path).ToArray())); + return new AbsolutePath(Path.Combine(paths.Select(s => (string)s).Cons(_path).ToArray())); } public AbsolutePath Combine(params string[] paths) @@ -371,23 +373,24 @@ namespace Wabbajack.Common public struct RelativePath : IPath, IEquatable, IComparable { - private readonly string _path; + private readonly string? _nullable_path; + private string _path => _nullable_path ?? string.Empty; public RelativePath(string path) { if (string.IsNullOrWhiteSpace(path)) { - _path = null; + _nullable_path = null; return; } var trimmed = path.Replace("/", "\\").Trim('\\'); if (string.IsNullOrEmpty(trimmed)) { - _path = null; + _nullable_path = null; return; } - _path = trimmed; + _nullable_path = trimmed; Validate(); } @@ -400,7 +403,7 @@ namespace Wabbajack.Common public override int GetHashCode() { - return _path?.GetHashCode(StringComparison.InvariantCultureIgnoreCase) ?? 0; + return _path.GetHashCode(StringComparison.InvariantCultureIgnoreCase); } public static RelativePath RandomFileName() @@ -418,7 +421,7 @@ namespace Wabbajack.Common public AbsolutePath RelativeTo(AbsolutePath abs) { - return _path == null ? abs : new AbsolutePath(Path.Combine((string)abs, _path)); + return new AbsolutePath(Path.Combine((string)abs, _path)); } public AbsolutePath RelativeToEntryPoint() @@ -470,7 +473,7 @@ namespace Wabbajack.Common return string.Equals(_path, other._path, StringComparison.InvariantCultureIgnoreCase); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is RelativePath other && Equals(other); } @@ -586,7 +589,7 @@ namespace Wabbajack.Common return string.Equals(_extension, other._extension, StringComparison.InvariantCultureIgnoreCase); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Extension other && Equals(other); } @@ -603,23 +606,24 @@ namespace Wabbajack.Common #endregion - private readonly string _extension; + private readonly string? _nullable_extension; + private string _extension => _nullable_extension ?? string.Empty; public Extension(string extension) { if (string.IsNullOrWhiteSpace(extension)) { - _extension = None._extension; + _nullable_extension = None._extension; return; } - _extension = string.Intern(extension); + _nullable_extension = string.Intern(extension); Validate(); } private Extension(string extension, bool validate) { - _extension = string.Intern(extension); + _nullable_extension = string.Intern(extension); if (validate) { Validate(); @@ -628,7 +632,7 @@ namespace Wabbajack.Common public Extension(Extension other) { - _extension = other._extension; + _nullable_extension = other._extension; } private void Validate() @@ -652,16 +656,6 @@ namespace Wabbajack.Common public static bool operator ==(Extension a, Extension b) { // Super fast comparison because extensions are interned - if ((object)a == null && (object)b == null) - { - return true; - } - - if ((object)a == null || (object)b == null) - { - return false; - } - return ReferenceEquals(a._extension, b._extension); } @@ -726,7 +720,7 @@ namespace Wabbajack.Common return this == other; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is HashRelativePath other && Equals(other); } @@ -772,7 +766,6 @@ namespace Wabbajack.Common public static bool operator ==(FullPath a, FullPath b) { - if (a.Paths == null || b.Paths == null) return false; if (a.Base != b.Base || a.Paths.Length != b.Paths.Length) { return false; @@ -799,7 +792,7 @@ namespace Wabbajack.Common return this == other; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is FullPath other && Equals(other); } diff --git a/Wabbajack.Common/ProcessHelper.cs b/Wabbajack.Common/ProcessHelper.cs index 7c0639b7..fb9f5251 100644 --- a/Wabbajack.Common/ProcessHelper.cs +++ b/Wabbajack.Common/ProcessHelper.cs @@ -15,9 +15,9 @@ namespace Wabbajack.Common Output, Error, } - - public string Path { get; set; } - public IEnumerable Arguments { get; set; } + + public string Path { get; set; } = string.Empty; + public IEnumerable Arguments { get; set; } = Enumerable.Empty(); public bool LogError { get; set; } = true; diff --git a/Wabbajack.Common/SplittingStream.cs b/Wabbajack.Common/SplittingStream.cs index 723c536e..d4eed888 100644 --- a/Wabbajack.Common/SplittingStream.cs +++ b/Wabbajack.Common/SplittingStream.cs @@ -68,4 +68,4 @@ namespace Wabbajack.Common } } } -} \ No newline at end of file +} diff --git a/Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs b/Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs index bb110f02..7bb27e48 100644 --- a/Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs +++ b/Wabbajack.Common/StatusFeed/Errors/FileExtractionError.cs @@ -10,8 +10,8 @@ namespace Wabbajack.Common.StatusFeed.Errors { private string _filename; private string _destination; - public override string ShortDescription { get; } - public override string ExtendedDescription { get; } + public override string ShortDescription { get; } = string.Empty; + public override string ExtendedDescription { get; } = string.Empty; public FileExtractionError(string filename, string destination) { diff --git a/Wabbajack.Common/StatusFeed/Errors/GenericException.cs b/Wabbajack.Common/StatusFeed/Errors/GenericException.cs index 5d22fcf1..340da4b5 100644 --- a/Wabbajack.Common/StatusFeed/Errors/GenericException.cs +++ b/Wabbajack.Common/StatusFeed/Errors/GenericException.cs @@ -8,19 +8,19 @@ namespace Wabbajack.Common.StatusFeed.Errors { public class GenericException : IException { - public string ExtraMessage { get; } + public string ExtraMessage { get; } = string.Empty; public DateTime Timestamp { get; } = DateTime.Now; - public string ShortDescription => ExtraMessage == null ? Exception?.Message : $"{ExtraMessage} - {Exception?.Message}"; + public string ShortDescription => string.IsNullOrWhiteSpace(ExtraMessage) ? Exception?.Message ?? string.Empty : $"{ExtraMessage} - {Exception?.Message}"; - public string ExtendedDescription => ExtraMessage == null ? Exception?.ToString() : $"{ExtraMessage} - {Exception?.ToString()}"; + public string ExtendedDescription => string.IsNullOrWhiteSpace(ExtraMessage) ? Exception?.ToString() ?? string.Empty : $"{ExtraMessage} - {Exception?.ToString()}"; public Exception Exception { get; } - public GenericException(Exception exception, string extraMessage = null) + public GenericException(Exception exception, string? extraMessage = null) { - ExtraMessage = extraMessage; + ExtraMessage = extraMessage ?? string.Empty; Exception = exception; } } diff --git a/Wabbajack.Common/StatusFeed/GenericInfo.cs b/Wabbajack.Common/StatusFeed/GenericInfo.cs index ede42205..fcb3aa5d 100644 --- a/Wabbajack.Common/StatusFeed/GenericInfo.cs +++ b/Wabbajack.Common/StatusFeed/GenericInfo.cs @@ -12,10 +12,10 @@ namespace Wabbajack.Common.StatusFeed private readonly string _extendedDescription; public override string ExtendedDescription => _extendedDescription ?? ShortDescription; - public GenericInfo(string short_description, string long_description = null) + public GenericInfo(string short_description, string? long_description = null) { ShortDescription = short_description; - _extendedDescription = long_description; + _extendedDescription = long_description ?? string.Empty; } public override string ToString() diff --git a/Wabbajack.Common/StatusFileStream.cs b/Wabbajack.Common/StatusFileStream.cs index df2c70be..723c0b43 100644 --- a/Wabbajack.Common/StatusFileStream.cs +++ b/Wabbajack.Common/StatusFileStream.cs @@ -6,9 +6,9 @@ namespace Wabbajack.Common { private string _message; private Stream _inner; - private WorkQueue _queue; + private WorkQueue? _queue; - public StatusFileStream(Stream fs, string message, WorkQueue queue = null) + public StatusFileStream(Stream fs, string message, WorkQueue? queue = null) { _queue = queue; _inner = fs; diff --git a/Wabbajack.Common/StatusUpdate.cs b/Wabbajack.Common/StatusUpdateTracker.cs similarity index 100% rename from Wabbajack.Common/StatusUpdate.cs rename to Wabbajack.Common/StatusUpdateTracker.cs diff --git a/Wabbajack.Common/StoreHandlers/GOGHandler.cs b/Wabbajack.Common/StoreHandlers/GOGHandler.cs index 6cfe2581..8634688e 100644 --- a/Wabbajack.Common/StoreHandlers/GOGHandler.cs +++ b/Wabbajack.Common/StoreHandlers/GOGHandler.cs @@ -10,21 +10,17 @@ namespace Wabbajack.Common.StoreHandlers public class GOGGame : AStoreGame { public override Game Game { get; internal set; } - public override string Name { get; internal set; } - public override AbsolutePath Path { get; internal set; } - public override int ID { get; internal set; } public override StoreType Type { get; internal set; } = StoreType.GOG; } public class GOGHandler : AStoreHandler { - public override List Games { get; set; } public override StoreType Type { get; internal set; } private const string GOGRegKey = @"Software\GOG.com\Games"; private const string GOG64RegKey = @"Software\WOW6432Node\GOG.com\Games"; - private RegistryKey GOGKey { get; set; } + private RegistryKey? GOGKey { get; set; } public override bool Init() { @@ -56,9 +52,11 @@ namespace Wabbajack.Common.StoreHandlers public override bool LoadAllGames() { - if(Games == null) - Games = new List(); - + if (GOGKey == null) + { + Utils.Error("GOGHandler could not read from registry!"); + return false; + } try { string[] keys = GOGKey.GetSubKeyNames(); @@ -86,7 +84,7 @@ namespace Wabbajack.Common.StoreHandlers return; } - var gameName = gameNameValue.ToString(); + var gameName = gameNameValue.ToString() ?? string.Empty; var pathValue = subKey.GetValue("PATH"); if (pathValue == null) @@ -95,7 +93,7 @@ namespace Wabbajack.Common.StoreHandlers return; } - var path = pathValue.ToString(); + var path = pathValue.ToString() ?? string.Empty; var game = new GOGGame { diff --git a/Wabbajack.Common/StoreHandlers/SteamHandler.cs b/Wabbajack.Common/StoreHandlers/SteamHandler.cs index 026e80b9..c84e7794 100644 --- a/Wabbajack.Common/StoreHandlers/SteamHandler.cs +++ b/Wabbajack.Common/StoreHandlers/SteamHandler.cs @@ -11,33 +11,29 @@ namespace Wabbajack.Common.StoreHandlers public class SteamGame : AStoreGame { public override Game Game { get; internal set; } - public override string Name { get; internal set; } - public override AbsolutePath Path { get; internal set; } - public override int ID { get; internal set; } public override StoreType Type { get; internal set; } = StoreType.STEAM; - public string Universe; + public string Universe = string.Empty; - public List WorkshopItems; - public int WorkshopItemsSize; + public readonly List WorkshopItems = new List(); + public int WorkshopItemsSizeOnDisk; } public class SteamWorkshopItem { - public SteamGame Game; + public SteamGame? Game; public int ItemID; public int Size; } public class SteamHandler : AStoreHandler { - public override List Games { get; set; } public override StoreType Type { get; internal set; } = StoreType.STEAM; private const string SteamRegKey = @"Software\Valve\Steam"; - public string SteamPath { get; set; } - private List SteamUniverses { get; set; } + public string SteamPath { get; set; } = string.Empty; + private List? SteamUniverses { get; set; } private string SteamConfig => Path.Combine(SteamPath, "config", "config.vdf"); @@ -54,7 +50,7 @@ namespace Wabbajack.Common.StoreHandlers return false; } - SteamPath = steamPathKey.ToString(); + SteamPath = steamPathKey.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(SteamPath)) { Utils.Error(new StoreException("Path to the Steam Directory from registry is Null or Empty!")); @@ -86,9 +82,9 @@ namespace Wabbajack.Common.StoreHandlers return false; } - private void LoadUniverses() + private List LoadUniverses() { - SteamUniverses = new List(); + var ret = new List(); File.ReadAllLines(SteamConfig).Do(l => { @@ -100,22 +96,24 @@ namespace Wabbajack.Common.StoreHandlers Utils.Log($"Directory {s} does not exist, skipping"); return; } - - SteamUniverses.Add(s); + + ret.Add(s); Utils.Log($"Steam Library found at {s}"); }); - Utils.Log($"Total number of Steam Libraries found: {SteamUniverses.Count}"); + Utils.Log($"Total number of Steam Libraries found: {ret.Count}"); // Default path in the Steam folder isn't in the configs - if(Directory.Exists(Path.Combine(SteamPath, "steamapps"))) - SteamUniverses.Add(Path.Combine(SteamPath, "steamapps")); + if (Directory.Exists(Path.Combine(SteamPath, "steamapps"))) + ret.Add(Path.Combine(SteamPath, "steamapps")); + + return ret; } public override bool LoadAllGames() { - if(SteamUniverses == null) - LoadUniverses(); + if (SteamUniverses == null) + SteamUniverses = LoadUniverses(); if (SteamUniverses.Count == 0) { @@ -123,9 +121,6 @@ namespace Wabbajack.Common.StoreHandlers return false; } - if(Games == null) - Games = new List(); - SteamUniverses.Do(u => { Utils.Log($"Searching for Steam Games in {u}"); @@ -188,9 +183,6 @@ namespace Wabbajack.Common.StoreHandlers private static void LoadWorkshopItems(SteamGame game) { - if(game.WorkshopItems == null) - game.WorkshopItems = new List(); - var workshop = Path.Combine(game.Universe, "workshop"); if (!Directory.Exists(workshop)) return; @@ -210,13 +202,13 @@ namespace Wabbajack.Common.StoreHandlers var bracketStart = 0; var bracketEnd = 0; - var currentItem = new SteamWorkshopItem(); + SteamWorkshopItem? currentItem = new SteamWorkshopItem(); lines.Do(l => { if (end) return; - if(currentItem == null) + if (currentItem == null) currentItem = new SteamWorkshopItem(); var currentLine = lines.IndexOf(l); @@ -239,7 +231,7 @@ namespace Wabbajack.Common.StoreHandlers if (!int.TryParse(GetVdfValue(l), out var sizeOnDisk)) return; - game.WorkshopItemsSize += sizeOnDisk; + game.WorkshopItemsSizeOnDisk += sizeOnDisk; } if (l.ContainsCaseInsensitive("\"WorkshopItemsInstalled\"")) diff --git a/Wabbajack.Common/StoreHandlers/StoreHandler.cs b/Wabbajack.Common/StoreHandlers/StoreHandler.cs index 89d374d8..52aaf5c5 100644 --- a/Wabbajack.Common/StoreHandlers/StoreHandler.cs +++ b/Wabbajack.Common/StoreHandlers/StoreHandler.cs @@ -61,15 +61,15 @@ namespace Wabbajack.Common.StoreHandlers public abstract class AStoreGame { public abstract Game Game { get; internal set; } - public abstract string Name { get; internal set; } - public abstract AbsolutePath Path { get; internal set; } - public abstract int ID { get; internal set; } + public virtual string Name { get; internal set; } = string.Empty; + public virtual AbsolutePath Path { get; internal set; } + public virtual int ID { get; internal set; } public abstract StoreType Type { get; internal set; } } public abstract class AStoreHandler { - public abstract List Games { get; set; } + public List Games { get; } = new List(); public abstract StoreType Type { get; internal set; } diff --git a/Wabbajack.Common/Util/AsyncLock.cs b/Wabbajack.Common/Util/AsyncLock.cs index eb14e5cb..0474ece8 100644 --- a/Wabbajack.Common/Util/AsyncLock.cs +++ b/Wabbajack.Common/Util/AsyncLock.cs @@ -10,7 +10,7 @@ namespace Wabbajack.Common { public class AsyncLock { - private SemaphoreSlim _lock = new SemaphoreSlim(1, 1); + private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); public async Task Wait() { diff --git a/Wabbajack.Common/Util/DiskSlabAllocator.cs b/Wabbajack.Common/Util/DiskSlabAllocator.cs index 57f217bf..baf3a5ef 100644 --- a/Wabbajack.Common/Util/DiskSlabAllocator.cs +++ b/Wabbajack.Common/Util/DiskSlabAllocator.cs @@ -43,9 +43,9 @@ namespace Wabbajack.Common public void Dispose() { _allocated.Do(s => s.Dispose()); - _mmap?.Dispose(); - _fileStream?.Dispose(); - _file?.Dispose(); + _mmap.Dispose(); + _fileStream.Dispose(); + _file.Dispose(); } } } diff --git a/Wabbajack.Common/Util/Percent.cs b/Wabbajack.Common/Util/Percent.cs index e1cc4414..bcd37dfb 100644 --- a/Wabbajack.Common/Util/Percent.cs +++ b/Wabbajack.Common/Util/Percent.cs @@ -142,7 +142,7 @@ namespace Wabbajack.Common return new Percent(percent, check: false); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is Percent rhs)) return false; return Equals(rhs); @@ -191,7 +191,7 @@ namespace Wabbajack.Common } } - public int CompareTo(object obj) + public int CompareTo(object? obj) { if (obj is Percent rhs) { diff --git a/Wabbajack.Common/Util/TempFile.cs b/Wabbajack.Common/Util/TempFile.cs index 43349b3b..0022151b 100644 --- a/Wabbajack.Common/Util/TempFile.cs +++ b/Wabbajack.Common/Util/TempFile.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using AlphaPath = Alphaleonis.Win32.Filesystem.Path; - namespace Wabbajack.Common { diff --git a/Wabbajack.Common/Utils.cs b/Wabbajack.Common/Utils.cs index daeaf9e0..9b916c55 100644 --- a/Wabbajack.Common/Utils.cs +++ b/Wabbajack.Common/Utils.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Data.HashFunction.xxHash; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net.Http; @@ -132,12 +133,12 @@ namespace Wabbajack.Common Log(errMessage); } - public static void Error(Exception ex, string extraMessage = null) + public static void Error(Exception ex, string? extraMessage = null) { Log(new GenericException(ex, extraMessage)); } - public static void ErrorThrow(Exception ex, string extraMessage = null) + public static void ErrorThrow(Exception ex, string? extraMessage = null) { Error(ex, extraMessage); throw ex; @@ -231,29 +232,21 @@ namespace Wabbajack.Common Status(status, Percent.FactoryPutInRange(totalRead, maxSize)); } } - public static string xxHash(this byte[] data, bool nullOnIOError = false) + public static string xxHash(this byte[] data) { - try + var hash = new xxHashConfig(); + hash.HashSizeInBits = 64; + hash.Seed = 0x42; + using (var fs = new MemoryStream(data)) { - var hash = new xxHashConfig(); - hash.HashSizeInBits = 64; - hash.Seed = 0x42; - using (var fs = new MemoryStream(data)) + var config = new xxHashConfig(); + config.HashSizeInBits = 64; + using (var f = new StatusFileStream(fs, $"Hashing memory stream")) { - var config = new xxHashConfig(); - config.HashSizeInBits = 64; - using (var f = new StatusFileStream(fs, $"Hashing memory stream")) - { - var value = xxHashFactory.Instance.Create(config).ComputeHash(f); - return value.AsBase64String(); - } + var value = xxHashFactory.Instance.Create(config).ComputeHash(f); + return value.AsBase64String(); } } - catch (IOException ex) - { - if (nullOnIOError) return null; - throw ex; - } } /// @@ -673,7 +666,9 @@ namespace Wabbajack.Common return a[a.Length - 1]; } + [return: MaybeNull] public static V GetOrDefault(this IDictionary dict, K key) + where K : notnull { if (dict.TryGetValue(key, out var v)) return v; return default; @@ -776,7 +771,7 @@ namespace Wabbajack.Common } } - public static bool TryGetPatch(Hash foundHash, Hash fileHash, out byte[] ePatch) + public static bool TryGetPatch(Hash foundHash, Hash fileHash, [MaybeNullWhen(false)] out byte[] ePatch) { var patchName = Consts.PatchCacheFolder.Combine($"{foundHash.ToHex()}_{fileHash.ToHex()}.patch"); if (patchName.Exists) @@ -809,17 +804,6 @@ namespace Wabbajack.Common } - /* - public static void Warning(string s) - { - Log($"WARNING: {s}"); - }*/ - - public static TV GetOrDefault(this Dictionary dict, TK key) - { - return dict.TryGetValue(key, out var result) ? result : default; - } - public static IEnumerable ButLast(this IEnumerable coll) { var lst = coll.ToList(); @@ -1097,7 +1081,7 @@ namespace Wabbajack.Common public class NexusErrorResponse { public int code; - public string message; + public string message = string.Empty; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj index 74c4e330..eb43a78f 100644 --- a/Wabbajack.Common/Wabbajack.Common.csproj +++ b/Wabbajack.Common/Wabbajack.Common.csproj @@ -4,7 +4,7 @@ netcoreapp3.1 x64 win10-x64 - + enable diff --git a/Wabbajack.Common/WorkQueue.cs b/Wabbajack.Common/WorkQueue.cs index 360552e0..ceab2e05 100644 --- a/Wabbajack.Common/WorkQueue.cs +++ b/Wabbajack.Common/WorkQueue.cs @@ -25,7 +25,7 @@ namespace Wabbajack.Common public static bool WorkerThread => AsyncLocalCurrentQueue.Value != null; public bool IsWorkerThread => WorkerThread; - internal static readonly AsyncLocal AsyncLocalCurrentQueue = new AsyncLocal(); + internal static readonly AsyncLocal AsyncLocalCurrentQueue = new AsyncLocal(); private readonly Subject _Status = new Subject(); public IObservable Status => _Status; @@ -194,7 +194,7 @@ namespace Wabbajack.Common public class CPUStatus { public Percent ProgressPercent { get; internal set; } - public string Msg { get; internal set; } + public string Msg { get; internal set; } = string.Empty; public int ID { get; internal set; } public bool IsWorking { get; internal set; } }