diff --git a/BSIPA-ModList/UI/WarningUI.cs b/BSIPA-ModList/UI/WarningUI.cs index 4a770953..77457776 100644 --- a/BSIPA-ModList/UI/WarningUI.cs +++ b/BSIPA-ModList/UI/WarningUI.cs @@ -86,9 +86,9 @@ namespace BSIPA_ModList.UI _warningsQueue.Clear(); - var enabledPlugins = PluginManager.AllPlugins.Select(p => p.Metadata).Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version); - var ignoredPlugins = PluginLoader.ignoredPlugins.Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version); - var disabledPlugins = PluginManager.DisabledPlugins.Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version); + var enabledPlugins = PluginManager.AllPlugins.Select(p => p.Metadata).NonNull(x => x.Id).ToDictionary(x => x.Id, y => y.Version); + var ignoredPlugins = PluginLoader.ignoredPlugins.NonNull(x => x.Id).ToDictionary(x => x.Id, y => y.Version); + var disabledPlugins = PluginManager.DisabledPlugins.NonNull(x => x.Id).ToDictionary(x => x.Id, y => y.Version); // iterate only disabled and ignored, as thats where missing deps can end up foreach (var meta in PluginManager.DisabledPlugins.Concat(PluginLoader.ignoredPlugins)) diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs index 8f924af7..884133e1 100644 --- a/IPA.Loader/Loader/PluginLoader.cs +++ b/IPA.Loader/Loader/PluginLoader.cs @@ -311,7 +311,7 @@ namespace IPA.Loader if (!meta.IsSelf) { var resc = meta.PluginType.Module.Resources.Select(r => r as EmbeddedResource) - .Where(r => r != null) + .NonNull() .FirstOrDefault(r => r.Name == name); if (resc == null) { @@ -488,7 +488,7 @@ namespace IPA.Loader { var metadata = new List(); var pluginsToLoad = new Dictionary(); - var disabledLookup = DisabledPlugins.Where(m => m.Id != null).ToDictionary(m => m.Id, m => m.Version); + var disabledLookup = DisabledPlugins.NonNull(m => m.Id).ToDictionary(m => m.Id, m => m.Version); foreach (var meta in PluginsMetadata) { bool load = true; @@ -705,7 +705,7 @@ namespace IPA.Loader { InitFeatures(); DisabledPlugins.ForEach(Load); // make sure they get loaded into memory so their metadata and stuff can be read more easily - return PluginsMetadata.Select(InitPlugin).Where(p => p != null).ToList(); + return PluginsMetadata.Select(InitPlugin).NonNull().ToList(); } } } \ No newline at end of file diff --git a/IPA.Loader/Updating/BeatMods/Updater.cs b/IPA.Loader/Updating/BeatMods/Updater.cs index 2aef1cfa..31c36e3b 100644 --- a/IPA.Loader/Updating/BeatMods/Updater.cs +++ b/IPA.Loader/Updating/BeatMods/Updater.cs @@ -395,7 +395,7 @@ namespace IPA.Updating.BeatMods } var ver = modsMatching.Value - .Where(nullCheck => nullCheck != null) // entry is not null + .NonNull() // entry is not null .Where(versionCheck => versionCheck.GameVersion == BeatSaber.GameVersion) // game version matches .Where(approvalCheck => approvalCheck.Status == ApiEndpoint.Mod.ApprovedStatus) // version approved // TODO: fix; it seems wrong somehow diff --git a/IPA.Loader/Utilities/Utils.cs b/IPA.Loader/Utilities/Utils.cs index b3205068..bfa153e1 100644 --- a/IPA.Loader/Utilities/Utils.cs +++ b/IPA.Loader/Utilities/Utils.cs @@ -178,7 +178,7 @@ namespace IPA.Utilities /// /// the left value /// the right value - /// -1 if l is less than r, 0 if they are equal in the numeric portion, or 1 if l is greater than r + /// < 0 if l is less than r, 0 if they are equal in the numeric portion, or > 0 if l is greater than r public static int VersionCompareNoPrerelease(SemVer.Version l, SemVer.Version r) { var cmpVal = l.Major - r.Major; @@ -188,10 +188,42 @@ namespace IPA.Utilities cmpVal = l.Patch - r.Patch; return cmpVal; } + + /// + /// LINQ extension method that filters elements out of an enumeration. + /// + /// 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); + + /// + /// LINQ extension method that filters elements out of an enumeration based on a converter. + /// + /// the type of the enumeration + /// the type to compare to null + /// the enumeration to filter + /// the predicate to select for filtering + /// a filtered enumerable + public static IEnumerable NonNull(this IEnumerable self, Func pred) where T : class where U : class + => self.Where(o => pred(o) != null); + + /// + /// LINQ extension method that filters elements from an enumeration of nullable types. + /// + /// the underlying type of the nullable enumeration + /// 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); + + + internal static bool HasInterface(this TypeDefinition type, string interfaceFullName) { - return (type.Interfaces.Any(i => i.InterfaceType.FullName == interfaceFullName) - || type.Interfaces.Any(t => HasInterface(t.InterfaceType.Resolve(), interfaceFullName))); + return (type?.Interfaces?.Any(i => i.InterfaceType.FullName == interfaceFullName) ?? false) + || (type?.Interfaces?.Any(t => HasInterface(t?.InterfaceType?.Resolve(), interfaceFullName)) ?? false); } #if NET4 diff --git a/Refs/UnityEngine.CoreModule.Net4.dll b/Refs/UnityEngine.CoreModule.Net4.dll index 6362cdf1..158ef534 100644 Binary files a/Refs/UnityEngine.CoreModule.Net4.dll and b/Refs/UnityEngine.CoreModule.Net4.dll differ