diff --git a/IPA.Loader/Loader/Features/Feature.cs b/IPA.Loader/Loader/Features/Feature.cs index df70401e..d354bb6f 100644 --- a/IPA.Loader/Loader/Features/Feature.cs +++ b/IPA.Loader/Loader/Features/Feature.cs @@ -1,9 +1,8 @@ -using Mono.Cecil; +#nullable enable using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; -using System.Reflection; -using System.Text; +using System.Diagnostics.CodeAnalysis; #if NET3 using Net3_Proxy; #endif @@ -35,7 +34,7 @@ namespace IPA.Loader.Features /// This should also be set whenever either returns false. /// /// the message to show when the feature is marked invalid - public virtual string InvalidMessage { get; protected set; } + public virtual string? InvalidMessage { get; protected set; } /// /// Called before a plugin's `Init` method is called. This will not be called if there is no `Init` method. This should never throw an exception. An exception will abort the loading of the plugin with an error. @@ -65,6 +64,7 @@ namespace IPA.Loader.Features // TODO: rework features to take arguments as JSON objects + [SuppressMessage("Nullability", "CS8618", Justification = "Reset sets those fields.")] static Feature() { Reset(); @@ -72,18 +72,18 @@ namespace IPA.Loader.Features internal static void Reset() { - featureTypes = new Dictionary + featureTypes = new() { { "IPA.DefineFeature", typeof(DefineFeature) } }; - featureDelcarers = new Dictionary + featureDelcarers = new() { { "IPA.DefineFeature", null } }; } private static Dictionary featureTypes; - private static Dictionary featureDelcarers; + private static Dictionary featureDelcarers; internal static bool HasFeature(string name) => featureTypes.ContainsKey(name); @@ -123,7 +123,7 @@ namespace IPA.Loader.Features } } - internal string FeatureName; + internal string FeatureName = null!; internal class Instance { @@ -139,8 +139,8 @@ namespace IPA.Loader.Features type = null; } - private Type type; - public bool TryGetDefiningPlugin(out PluginMetadata plugin) + private Type? type; + public bool TryGetDefiningPlugin(out PluginMetadata? plugin) { return featureDelcarers.TryGetValue(Name, out plugin); } @@ -173,101 +173,5 @@ namespace IPA.Loader.Features return result; } } - - /* - // returns false with both outs null for no such feature - internal static bool TryParseFeature(string featureString, PluginMetadata plugin, - out Feature feature, out Exception failException, out bool featureValid, out Instance parsed, - Instance? preParsed = null) - { - failException = null; - feature = null; - featureValid = false; - - if (preParsed == null) - { - var builder = new StringBuilder(); - string name = null; - var parameters = new List(); - - bool escape = false; - int parens = 0; - bool removeWhitespace = true; - foreach (var chr in featureString) - { - if (escape) - { - builder.Append(chr); - escape = false; - } - else - { - switch (chr) - { - case '\\': - escape = true; - break; - case '(': - parens++; - if (parens != 1) goto default; - removeWhitespace = true; - name = builder.ToString(); - builder.Clear(); - break; - case ')': - parens--; - if (parens != 0) goto default; - goto case ','; - case ',': - if (parens > 1) goto default; - parameters.Add(builder.ToString()); - builder.Clear(); - removeWhitespace = true; - break; - default: - if (removeWhitespace && !char.IsWhiteSpace(chr)) - removeWhitespace = false; - if (!removeWhitespace) - builder.Append(chr); - break; - } - } - } - - if (name == null) - name = builder.ToString(); - - parsed = new Instance(name, parameters.ToArray()); - - if (parens != 0) - { - failException = new Exception("Malformed feature definition"); - return false; - } - } - else - parsed = preParsed.Value; - - if (!featureTypes.TryGetValue(parsed.Name, out var featureType)) - return false; - - try - { - if (!(Activator.CreateInstance(featureType) is Feature aFeature)) - { - failException = new InvalidCastException("Feature type not a subtype of Feature"); - return false; - } - - featureValid = aFeature.Initialize(plugin, TODO); - feature = aFeature; - return true; - } - catch (Exception e) - { - failException = e; - return false; - } - }*/ } } \ No newline at end of file diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs index 679b4bb9..bab9cfba 100644 --- a/IPA.Loader/Loader/PluginLoader.cs +++ b/IPA.Loader/Loader/PluginLoader.cs @@ -1,4 +1,5 @@ -using IPA.Config; +#nullable enable +using IPA.Config; using IPA.Loader.Features; using IPA.Logging; using IPA.Utilities; @@ -32,7 +33,7 @@ namespace IPA.Loader internal partial class PluginLoader { - internal static PluginMetadata SelfMeta; + internal static PluginMetadata SelfMeta = null!; internal static Task LoadTask() => TaskEx.Run(() => @@ -40,6 +41,9 @@ namespace IPA.Loader YeetIfNeeded(); LoadMetadata(); + + // old loader system +#if false Resolve(); InitFeatures(); ComputeLoadOrder(); @@ -47,6 +51,7 @@ namespace IPA.Loader FilterWithoutFiles(); ResolveDependencies(); +#endif }); internal static void YeetIfNeeded() @@ -68,10 +73,10 @@ namespace IPA.Loader } } - internal static List PluginsMetadata = new List(); - internal static List DisabledPlugins = new List(); + internal static List PluginsMetadata = new(); + internal static List DisabledPlugins = new(); - private static readonly Regex embeddedTextDescriptionPattern = new Regex(@"#!\[(.+)\]", RegexOptions.Compiled | RegexOptions.Singleline); + private static readonly Regex embeddedTextDescriptionPattern = new(@"#!\[(.+)\]", RegexOptions.Compiled | RegexOptions.Singleline); internal static void LoadMetadata() { @@ -130,7 +135,7 @@ namespace IPA.Loader foreach (var resource in pluginModule.Resources) { const string manifestSuffix = ".manifest.json"; - if (!(resource is EmbeddedResource embedded) || + if (resource is not EmbeddedResource embedded || !embedded.Name.EndsWith(manifestSuffix)) continue; pluginNs = embedded.Name.Substring(0, embedded.Name.Length - manifestSuffix.Length); @@ -297,6 +302,7 @@ namespace IPA.Loader } } + #region Ignore stuff /// /// An enum that represents several categories of ignore reasons that the loader may encounter. /// @@ -372,15 +378,15 @@ namespace IPA.Loader /// Gets the textual description of the particular ignore reason. This will typically /// include details about why the plugin was ignored, if it is present. /// - public string ReasonText { get; internal set; } + public string? ReasonText { get; internal set; } /// /// Gets the that caused this plugin to be ignored, if any. /// - public Exception Error { get; internal set; } + public Exception? Error { get; internal set; } /// /// Gets the metadata of the plugin that this ignore was related to, if any. /// - public PluginMetadata RelatedTo { get; internal set; } + public PluginMetadata? RelatedTo { get; internal set; } /// /// Initializes an with the provided data. /// @@ -388,7 +394,7 @@ namespace IPA.Loader /// the textual description of this ignore reason, if any /// the that caused this , if any /// the this reason is related to, if any - public IgnoreReason(Reason reason, string reasonText = null, Exception error = null, PluginMetadata relatedTo = null) + public IgnoreReason(Reason reason, string? reasonText = null, Exception? error = null, PluginMetadata? relatedTo = null) { Reason = reason; ReasonText = reasonText; @@ -412,10 +418,10 @@ namespace IPA.Loader public override int GetHashCode() { int hashCode = 778404373; - hashCode = hashCode * -1521134295 + Reason.GetHashCode(); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ReasonText); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Error); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(RelatedTo); + hashCode = (hashCode * -1521134295) + Reason.GetHashCode(); + hashCode = (hashCode * -1521134295) + ReasonText?.GetHashCode() ?? 0; + hashCode = (hashCode * -1521134295) + Error?.GetHashCode() ?? 0; + hashCode = (hashCode * -1521134295) + RelatedTo?.GetHashCode() ?? 0; return hashCode; } @@ -437,13 +443,15 @@ namespace IPA.Loader public static bool operator !=(IgnoreReason left, IgnoreReason right) => !(left == right); } + #endregion internal partial class PluginLoader { // keep track of these for the updater; it should still be able to update mods not loaded // the thing -> the reason - internal static Dictionary ignoredPlugins = new Dictionary(); + internal static Dictionary ignoredPlugins = new(); +#if false internal static void Resolve() { // resolves duplicates and conflicts, etc PluginsMetadata.Sort((a, b) => b.Version.CompareTo(a.Version)); @@ -706,6 +714,7 @@ namespace IPA.Loader DisabledConfig.Instance.Changed(); PluginsMetadata = metadata; } +#endif internal static void InitFeatures() { @@ -726,7 +735,7 @@ namespace IPA.Loader } else { // this is literally any other feature, so we want to delay its initialization - meta.UnloadedFeatures.Add(feature); + _ = meta.UnloadedFeatures.Add(feature); } } } @@ -740,10 +749,13 @@ namespace IPA.Loader { if (plugin != meta) { // if the feature is not applied to the defining feature - meta.LoadsAfter.Add(plugin); + _ = meta.LoadsAfter.Add(plugin); } - plugin.CreateFeaturesWhenLoaded.Add(feature); + if (plugin != null) + { + plugin.CreateFeaturesWhenLoaded.Add(feature); + } } else { @@ -776,11 +788,11 @@ namespace IPA.Loader internal static void Load(PluginMetadata meta) { - if (meta.Assembly == null && meta.PluginType != null) + if (meta is { Assembly: null, PluginType: not null }) meta.Assembly = Assembly.LoadFrom(meta.File.FullName); } - internal static PluginExecutor InitPlugin(PluginMetadata meta, IEnumerable alreadyLoaded) + internal static PluginExecutor? InitPlugin(PluginMetadata meta, IEnumerable alreadyLoaded) { if (meta.Manifest.GameVersion != UnityGame.GameVersion) Logger.loader.Warn($"Mod {meta.Name} developed for game version {meta.Manifest.GameVersion}, so it may not work properly."); @@ -870,7 +882,7 @@ namespace IPA.Loader else { feature.AppliedTo.InternalFeatures.Add(inst); - feature.AppliedTo.UnloadedFeatures.Remove(feature); + _ = feature.AppliedTo.UnloadedFeatures.Remove(feature); } } meta.CreateFeaturesWhenLoaded.Clear(); // if a plugin is loaded twice, for the moment, we don't want to create the feature twice @@ -905,7 +917,7 @@ namespace IPA.Loader if (exec != null) { list.Add(exec); - loaded.Add(meta); + _ = loaded.Add(meta); } } catch (Exception e) diff --git a/IPA.Loader/Utilities/EnumerableExtensions.cs b/IPA.Loader/Utilities/EnumerableExtensions.cs index fa2978dc..bf74bc63 100644 --- a/IPA.Loader/Utilities/EnumerableExtensions.cs +++ b/IPA.Loader/Utilities/EnumerableExtensions.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -33,7 +34,7 @@ namespace IPA.Utilities this.first = first; } - public PrependEnumerator GetEnumerator() => new PrependEnumerator(this); + public PrependEnumerator GetEnumerator() => new(this); public struct PrependEnumerator : IEnumerator { @@ -45,12 +46,12 @@ namespace IPA.Utilities this.enumerable = enumerable; restEnum = enumerable.rest.GetEnumerator(); state = 0; - Current = default; + Current = default!; } public T Current { get; private set; } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; public void Dispose() => restEnum.Dispose(); @@ -109,7 +110,7 @@ namespace IPA.Utilities this.last = last; } - public AppendEnumerator GetEnumerator() => new AppendEnumerator(this); + public AppendEnumerator GetEnumerator() => new(this); public struct AppendEnumerator : IEnumerator { @@ -121,12 +122,12 @@ namespace IPA.Utilities this.enumerable = enumerable; restEnum = enumerable.rest.GetEnumerator(); state = 0; - Current = default; + Current = default!; } public T Current { get; private set; } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; public void Dispose() => restEnum.Dispose(); @@ -170,8 +171,8 @@ namespace IPA.Utilities /// the type of the enumeration /// the enumeration to filter /// a filtered enumerable - public static IEnumerable NonNull(this IEnumerable self) where T : class - => self.Where(o => o != null); + public static IEnumerable NonNull(this IEnumerable self) where T : class + => self.Where(o => o != null)!; /// /// LINQ-style extension method that filters elements out of an enumeration based on a converter. @@ -181,7 +182,7 @@ namespace IPA.Utilities /// the enumeration to filter /// the predicate to select for filtering /// a filtered enumerable - public static IEnumerable NonNull(this IEnumerable self, Func pred) where U : class + public static IEnumerable NonNull(this IEnumerable self, Func pred) where U : class => self.Where(o => pred(o) != null); /// @@ -191,7 +192,7 @@ namespace IPA.Utilities /// the enumeration to filter /// a filtered enumerable public static IEnumerable NonNull(this IEnumerable self) where T : struct - => self.Where(o => o != null).Select(o => o.Value); + => self.Where(o => o != null).Select(o => o!.Value); /// /// LINQ-style extension method that filters elements out of an enumeration based on a converter to a nullable type.