From ef2f2cff5c26246a3b29cd9242555e0b1151e2ea Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sun, 21 Feb 2021 16:08:08 +0100 Subject: [PATCH] Remove some warnings about nullable. --- Penumbra/API/ModsController.cs | 4 +- Penumbra/Configuration.cs | 4 +- Penumbra/Hooks/ResourceLoader.cs | 62 +++++++---- Penumbra/Hooks/SoundShit.cs | 2 +- Penumbra/Importer/Models/ExtendedModPack.cs | 30 ++--- Penumbra/Importer/Models/SimpleModPack.cs | 22 ++-- Penumbra/Importer/TexToolsImport.cs | 51 +++++---- Penumbra/Models/Deduplicator.cs | 6 +- Penumbra/Models/GroupInformation.cs | 2 +- Penumbra/Models/ModInfo.cs | 7 +- Penumbra/Models/ModMeta.cs | 16 ++- Penumbra/Mods/ModCollection.cs | 47 ++++---- Penumbra/Mods/ModManager.cs | 43 ++++---- Penumbra/Mods/ResourceMod.cs | 26 ++--- Penumbra/Plugin.cs | 45 ++++---- Penumbra/UI/LaunchButton.cs | 2 +- Penumbra/UI/SettingsInterface.cs | 2 +- Penumbra/UI/SettingsMenu.cs | 2 +- Penumbra/UI/TabEffective.cs | 8 +- Penumbra/UI/TabImport.cs | 4 +- Penumbra/UI/TabInstalledDetails.cs | 61 +++++----- Penumbra/UI/TabInstalledDetailsEdit.cs | 20 ++-- Penumbra/UI/TabInstalledModPanel.cs | 38 +++---- Penumbra/UI/TabInstalledSelector.cs | 116 ++++++++++---------- Penumbra/UI/TabSettings.cs | 8 +- Penumbra/Util/SingleOrArrayConverter.cs | 54 ++++----- 26 files changed, 330 insertions(+), 352 deletions(-) diff --git a/Penumbra/API/ModsController.cs b/Penumbra/API/ModsController.cs index 1c38b37f..f466b476 100644 --- a/Penumbra/API/ModsController.cs +++ b/Penumbra/API/ModsController.cs @@ -13,10 +13,10 @@ namespace Penumbra.API public ModsController( Plugin plugin ) => _plugin = plugin; [Route( HttpVerbs.Get, "/mods" )] - public object GetMods() + public object? GetMods() { var modManager = Service< ModManager >.Get(); - return modManager.Mods.ModSettings.Select( x => new + return modManager.Mods?.ModSettings.Select( x => new { x.Enabled, x.Priority, diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 09dc4219..e1084499 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -27,7 +27,7 @@ namespace Penumbra // the below exist just to make saving less cumbersome [NonSerialized] - private DalamudPluginInterface _pluginInterface; + private DalamudPluginInterface? _pluginInterface; public void Initialize( DalamudPluginInterface pluginInterface ) { @@ -36,7 +36,7 @@ namespace Penumbra public void Save() { - _pluginInterface.SavePluginConfig( this ); + _pluginInterface?.SavePluginConfig( this ); } } } \ No newline at end of file diff --git a/Penumbra/Hooks/ResourceLoader.cs b/Penumbra/Hooks/ResourceLoader.cs index 747df092..86c36bc1 100644 --- a/Penumbra/Hooks/ResourceLoader.cs +++ b/Penumbra/Hooks/ResourceLoader.cs @@ -38,12 +38,12 @@ namespace Penumbra.Hooks uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown ); // Hooks - public IHook< GetResourceSyncPrototype > GetResourceSyncHook { get; private set; } - public IHook< GetResourceAsyncPrototype > GetResourceAsyncHook { get; private set; } - public IHook< ReadSqpackPrototype > ReadSqpackHook { get; private set; } + public IHook< GetResourceSyncPrototype >? GetResourceSyncHook { get; private set; } + public IHook< GetResourceAsyncPrototype >? GetResourceAsyncHook { get; private set; } + public IHook< ReadSqpackPrototype >? ReadSqpackHook { get; private set; } // Unmanaged functions - public ReadFilePrototype ReadFile { get; private set; } + public ReadFilePrototype? ReadFile { get; private set; } public bool LogAllFiles = false; @@ -57,7 +57,7 @@ namespace Penumbra.Hooks public unsafe void Init() { - var scanner = Plugin.PluginInterface.TargetModuleScanner; + var scanner = Plugin!.PluginInterface!.TargetModuleScanner; var readFileAddress = scanner.ScanText( "E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3 BA 05" ); @@ -108,9 +108,24 @@ namespace Penumbra.Hooks char* pPath, void* pUnknown, bool isUnknown - ) => isSync - ? GetResourceSyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown ) - : GetResourceAsyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown ); + ) + { + if( isSync ) + { + if( GetResourceSyncHook == null ) + { + PluginLog.Error("[GetResourceHandler] GetResourceSync is null." ); + return null; + } + return GetResourceSyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown ); + } + if( GetResourceAsyncHook == null ) + { + PluginLog.Error("[GetResourceHandler] GetResourceAsync is null." ); + return null; + } + return GetResourceAsyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown ); + } private unsafe void* GetResourceHandler( bool isSync, @@ -132,12 +147,12 @@ namespace Penumbra.Hooks var modManager = Service< ModManager >.Get(); - if( !Plugin.Configuration.IsEnabled || modManager == null ) + if( !Plugin!.Configuration!.IsEnabled || modManager == null ) { return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown ); } - var replacementPath = modManager.ResolveSwappedOrReplacementFilePath( gameFsPath ); + var replacementPath = modManager.ResolveSwappedOrReplacementFilePath( gameFsPath! ); // path must be < 260 because statically defined array length :( if( replacementPath == null || replacementPath.Length >= 260 ) @@ -170,9 +185,9 @@ namespace Penumbra.Hooks var isRooted = Path.IsPathRooted( gameFsPath ); - if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted ) + if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted || ReadFile == null) { - return ReadSqpackHook.OriginalFunction( pFileHandler, pFileDesc, priority, isSync ); + return ReadSqpackHook?.OriginalFunction( pFileHandler, pFileDesc, priority, isSync ) ?? 0; } #if DEBUG @@ -201,6 +216,12 @@ namespace Penumbra.Hooks return; } + if( ReadSqpackHook == null || GetResourceSyncHook == null || GetResourceAsyncHook == null) + { + PluginLog.Error("[GetResourceHandler] Could not activate hooks because at least one was not set." ); + return; + } + ReadSqpackHook.Activate(); GetResourceSyncHook.Activate(); GetResourceAsyncHook.Activate(); @@ -208,7 +229,7 @@ namespace Penumbra.Hooks ReadSqpackHook.Enable(); GetResourceSyncHook.Enable(); GetResourceAsyncHook.Enable(); - + IsEnabled = true; } @@ -219,23 +240,16 @@ namespace Penumbra.Hooks return; } - ReadSqpackHook.Disable(); - GetResourceSyncHook.Disable(); - GetResourceAsyncHook.Disable(); + ReadSqpackHook?.Disable(); + GetResourceSyncHook?.Disable(); + GetResourceAsyncHook?.Disable(); IsEnabled = false; } public void Dispose() { - if( IsEnabled ) - { - Disable(); - } - - // ReadSqpackHook.Disable(); - // GetResourceSyncHook.Disable(); - // GetResourceAsyncHook.Disable(); + Disable(); } } } \ No newline at end of file diff --git a/Penumbra/Hooks/SoundShit.cs b/Penumbra/Hooks/SoundShit.cs index d7e358e0..de50eafd 100644 --- a/Penumbra/Hooks/SoundShit.cs +++ b/Penumbra/Hooks/SoundShit.cs @@ -13,7 +13,7 @@ namespace Penumbra.Hooks public SoundShit( Plugin plugin ) { - var scanner = plugin.PluginInterface.TargetModuleScanner; + var scanner = plugin!.PluginInterface!.TargetModuleScanner; var fw = plugin.PluginInterface.Framework.Address.BaseAddress; diff --git a/Penumbra/Importer/Models/ExtendedModPack.cs b/Penumbra/Importer/Models/ExtendedModPack.cs index 105cdee0..1696012b 100644 --- a/Penumbra/Importer/Models/ExtendedModPack.cs +++ b/Penumbra/Importer/Models/ExtendedModPack.cs @@ -5,36 +5,36 @@ namespace Penumbra.Importer.Models { internal class OptionList { - public string Name { get; set; } - public string Description { get; set; } - public string ImagePath { get; set; } - public List< SimpleMod > ModsJsons { get; set; } - public string GroupName { get; set; } + public string? Name { get; set; } + public string? Description { get; set; } + public string? ImagePath { get; set; } + public List< SimpleMod >? ModsJsons { get; set; } + public string? GroupName { get; set; } public SelectType SelectionType { get; set; } public bool IsChecked { get; set; } } internal class ModGroup { - public string GroupName { get; set; } + public string? GroupName { get; set; } public SelectType SelectionType { get; set; } - public List< OptionList > OptionList { get; set; } + public List< OptionList >? OptionList { get; set; } } internal class ModPackPage { public int PageIndex { get; set; } - public List< ModGroup > ModGroups { get; set; } + public List< ModGroup >? ModGroups { get; set; } } internal class ExtendedModPack { - public string TTMPVersion { get; set; } - public string Name { get; set; } - public string Author { get; set; } - public string Version { get; set; } - public string Description { get; set; } - public List< ModPackPage > ModPackPages { get; set; } - public List< SimpleMod > SimpleModsList { get; set; } + public string? TTMPVersion { get; set; } + public string? Name { get; set; } + public string? Author { get; set; } + public string? Version { get; set; } + public string? Description { get; set; } + public List< ModPackPage >? ModPackPages { get; set; } + public List< SimpleMod >? SimpleModsList { get; set; } } } \ No newline at end of file diff --git a/Penumbra/Importer/Models/SimpleModPack.cs b/Penumbra/Importer/Models/SimpleModPack.cs index 332e18c0..1b3f9e4e 100644 --- a/Penumbra/Importer/Models/SimpleModPack.cs +++ b/Penumbra/Importer/Models/SimpleModPack.cs @@ -4,22 +4,22 @@ namespace Penumbra.Importer.Models { internal class SimpleModPack { - public string TTMPVersion { get; set; } - public string Name { get; set; } - public string Author { get; set; } - public string Version { get; set; } - public string Description { get; set; } - public List< SimpleMod > SimpleModsList { get; set; } + public string? TTMPVersion { get; set; } + public string? Name { get; set; } + public string? Author { get; set; } + public string? Version { get; set; } + public string? Description { get; set; } + public List< SimpleMod >? SimpleModsList { get; set; } } internal class SimpleMod { - public string Name { get; set; } - public string Category { get; set; } - public string FullPath { get; set; } + public string? Name { get; set; } + public string? Category { get; set; } + public string? FullPath { get; set; } public long ModOffset { get; set; } public long ModSize { get; set; } - public string DatFile { get; set; } - public object ModPackEntry { get; set; } + public string? DatFile { get; set; } + public object? ModPackEntry { get; set; } } } \ No newline at end of file diff --git a/Penumbra/Importer/TexToolsImport.cs b/Penumbra/Importer/TexToolsImport.cs index d650a326..0dcdceed 100644 --- a/Penumbra/Importer/TexToolsImport.cs +++ b/Penumbra/Importer/TexToolsImport.cs @@ -38,7 +38,7 @@ namespace Penumbra.Importer } } - public string CurrentModPack { get; private set; } + public string? CurrentModPack { get; private set; } public TexToolsImport( DirectoryInfo outDirectory ) { @@ -145,6 +145,12 @@ namespace Penumbra.Importer { var modList = JsonConvert.DeserializeObject< SimpleModPack >( modRaw ); + if( modList?.TTMPVersion == null ) + { + PluginLog.Error( "Could not extract V2 Modpack. No version given." ); + return; + } + if( modList.TTMPVersion.EndsWith( "s" ) ) { ImportSimpleV2ModPack( extractedModPack, modList ); @@ -164,11 +170,11 @@ namespace Penumbra.Importer // Create a new ModMeta from the TTMP modlist info var modMeta = new ModMeta { - Author = modList.Author, - Name = modList.Name, + Author = modList.Author ?? "Unknown", + Name = modList.Name ?? "New Mod", Description = string.IsNullOrEmpty( modList.Description ) ? "Mod imported from TexTools mod pack" - : modList.Description + : modList.Description! }; // Open the mod data file from the modpack as a SqPackStream @@ -181,7 +187,7 @@ namespace Penumbra.Importer File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ), JsonConvert.SerializeObject( modMeta ) ); - ExtractSimpleModList( newModFolder, modList.SimpleModsList, modData ); + ExtractSimpleModList( newModFolder, modList.SimpleModsList ?? Enumerable.Empty< SimpleMod >(), modData ); } private void ImportExtendedV2ModPack( ZipFile extractedModPack, string modRaw ) @@ -193,12 +199,12 @@ namespace Penumbra.Importer // Create a new ModMeta from the TTMP modlist info var modMeta = new ModMeta { - Author = modList.Author, - Name = modList.Name, + Author = modList.Author ?? "Unknown", + Name = modList.Name ?? "New Mod", Description = string.IsNullOrEmpty( modList.Description ) ? "Mod imported from TexTools mod pack" - : modList.Description, - Version = modList.Version + : modList.Description ?? "", + Version = modList.Version ?? "" }; // Open the mod data file from the modpack as a SqPackStream @@ -222,13 +228,14 @@ namespace Penumbra.Importer } // Iterate through all pages - foreach( var group in modList.ModPackPages.SelectMany( page => page.ModGroups ) ) + foreach( var group in modList.ModPackPages.SelectMany( page => page.ModGroups ) + .Where( group => group.GroupName != null && group.OptionList != null ) ) { - var groupFolder = new DirectoryInfo( Path.Combine( newModFolder.FullName, group.GroupName.ReplaceInvalidPathSymbols() ) ); - foreach( var option in group.OptionList ) + var groupFolder = new DirectoryInfo( Path.Combine( newModFolder.FullName, group.GroupName!.ReplaceInvalidPathSymbols() ) ); + foreach( var option in group.OptionList!.Where( option => option.Name != null && option.ModsJsons != null ) ) { - var optionFolder = new DirectoryInfo( Path.Combine( groupFolder.FullName, option.Name.ReplaceInvalidPathSymbols() ) ); - ExtractSimpleModList( optionFolder, option.ModsJsons, modData ); + var optionFolder = new DirectoryInfo( Path.Combine( groupFolder.FullName, option.Name!.ReplaceInvalidPathSymbols() ) ); + ExtractSimpleModList( optionFolder, option.ModsJsons!, modData ); } AddMeta( newModFolder, groupFolder, group, modMeta ); @@ -242,21 +249,21 @@ namespace Penumbra.Importer private static void AddMeta( DirectoryInfo baseFolder, DirectoryInfo groupFolder, ModGroup group, ModMeta meta ) { - var Inf = new InstallerInfo + var inf = new InstallerInfo { SelectionType = group.SelectionType, - GroupName = group.GroupName, + GroupName = group.GroupName!, Options = new List< Option >() }; - foreach( var opt in group.OptionList ) + foreach( var opt in group.OptionList! ) { var option = new Option { - OptionName = opt.Name, - OptionDesc = string.IsNullOrEmpty( opt.Description ) ? "" : opt.Description, + OptionName = opt.Name!, + OptionDesc = string.IsNullOrEmpty( opt.Description ) ? "" : opt.Description!, OptionFiles = new Dictionary< string, HashSet< string > >() }; - var optDir = new DirectoryInfo( Path.Combine( groupFolder.FullName, opt.Name.ReplaceInvalidPathSymbols() ) ); + var optDir = new DirectoryInfo( Path.Combine( groupFolder.FullName, opt.Name!.ReplaceInvalidPathSymbols() ) ); if( optDir.Exists ) { foreach( var file in optDir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) ) @@ -266,10 +273,10 @@ namespace Penumbra.Importer } } - Inf.Options.Add( option ); + inf.Options.Add( option ); } - meta.Groups.Add( group.GroupName, Inf ); + meta.Groups.Add( group.GroupName!, inf ); } private void ImportMetaModPack( FileInfo file ) diff --git a/Penumbra/Models/Deduplicator.cs b/Penumbra/Models/Deduplicator.cs index 7db60162..9c157637 100644 --- a/Penumbra/Models/Deduplicator.cs +++ b/Penumbra/Models/Deduplicator.cs @@ -12,14 +12,14 @@ namespace Penumbra.Models private readonly DirectoryInfo _baseDir; private readonly int _baseDirLength; private readonly ModMeta _mod; - private SHA256 _hasher; + private SHA256? _hasher; private readonly Dictionary< long, List< FileInfo > > _filesBySize = new(); - private ref SHA256 Sha() + private SHA256 Sha() { _hasher ??= SHA256.Create(); - return ref _hasher; + return _hasher; } public Deduplicator( DirectoryInfo baseDir, ModMeta mod ) diff --git a/Penumbra/Models/GroupInformation.cs b/Penumbra/Models/GroupInformation.cs index 7be2850f..cee5ed5f 100644 --- a/Penumbra/Models/GroupInformation.cs +++ b/Penumbra/Models/GroupInformation.cs @@ -14,7 +14,7 @@ namespace Penumbra.Models public string OptionName; public string OptionDesc; - [JsonProperty( ItemConverterType = typeof( SingleOrArrayConverter< string > ) )] + [JsonProperty( ItemConverterType = typeof( Util.SingleOrArrayConverter< string > ) )] public Dictionary< string, HashSet< string > > OptionFiles; public bool AddFile( string filePath, string gamePath ) diff --git a/Penumbra/Models/ModInfo.cs b/Penumbra/Models/ModInfo.cs index 28fc0a03..369085a9 100644 --- a/Penumbra/Models/ModInfo.cs +++ b/Penumbra/Models/ModInfo.cs @@ -6,10 +6,13 @@ namespace Penumbra.Models { public class ModInfo { - public string FolderName { get; set; } + public ModInfo( ResourceMod mod ) + => Mod = mod; + + public string FolderName { get; set; } = ""; public bool Enabled { get; set; } public int Priority { get; set; } - public Dictionary< string, int > Conf { get; set; } + public Dictionary< string, int > Conf { get; set; } = new(); [JsonIgnore] public ResourceMod Mod { get; set; } diff --git a/Penumbra/Models/ModMeta.cs b/Penumbra/Models/ModMeta.cs index cc78d14b..81441abf 100644 --- a/Penumbra/Models/ModMeta.cs +++ b/Penumbra/Models/ModMeta.cs @@ -9,13 +9,13 @@ namespace Penumbra.Models public class ModMeta { public uint FileVersion { get; set; } - public string Name { get; set; } - public string Author { get; set; } - public string Description { get; set; } + public string Name { get; set; } = "Mod"; + public string Author { get; set; } = ""; + public string Description { get; set; } = ""; - public string Version { get; set; } + public string Version { get; set; } = ""; - public string Website { get; set; } + public string Website { get; set; } = ""; public List< string > ChangedItems { get; set; } = new(); @@ -26,14 +26,12 @@ namespace Penumbra.Models [JsonIgnore] public bool HasGroupWithConfig { get; set; } = false; - public static ModMeta LoadFromFile( string filePath ) + public static ModMeta? LoadFromFile( string filePath ) { try { var meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( filePath ) ); - meta.HasGroupWithConfig = - meta.Groups != null - && meta.Groups.Count > 0 + meta.HasGroupWithConfig = meta.Groups.Count > 0 && meta.Groups.Values.Any( G => G.SelectionType == SelectType.Multi || G.Options.Count > 1 ); return meta; diff --git a/Penumbra/Mods/ModCollection.cs b/Penumbra/Mods/ModCollection.cs index b2fda057..6973b421 100644 --- a/Penumbra/Mods/ModCollection.cs +++ b/Penumbra/Mods/ModCollection.cs @@ -12,11 +12,12 @@ namespace Penumbra.Mods { private readonly DirectoryInfo _basePath; - public List< ModInfo > ModSettings { get; set; } - public ResourceMod[] EnabledMods { get; set; } + public List< ModInfo >? ModSettings { get; set; } + public ResourceMod[]? EnabledMods { get; set; } - public ModCollection( DirectoryInfo basePath ) => _basePath = basePath; + public ModCollection( DirectoryInfo basePath ) + => _basePath = basePath; public void Load( bool invertOrder = false ) { @@ -61,20 +62,10 @@ namespace Penumbra.Mods continue; } - var meta = ModMeta.LoadFromFile( metaFile.FullName ); - if( meta == null ) - { - PluginLog.LogError( "mod meta is invalid for resource mod: {ResourceModFile}", metaFile.FullName ); - continue; - } + var meta = ModMeta.LoadFromFile( metaFile.FullName ) ?? new ModMeta(); - var mod = new ResourceMod - { - Meta = meta, - ModBasePath = modDir - }; - - var modEntry = FindOrCreateModSettings( mod ); + var mod = new ResourceMod( meta, modDir ); + FindOrCreateModSettings( mod ); foundMods.Add( modDir.Name ); mod.RefreshModFiles(); } @@ -142,9 +133,9 @@ namespace Penumbra.Mods } - public ModInfo FindModSettings( string name ) + public ModInfo? FindModSettings( string name ) { - var settings = ModSettings.FirstOrDefault( + var settings = ModSettings?.FirstOrDefault( x => string.Equals( x.FolderName, name, StringComparison.InvariantCultureIgnoreCase ) ); #if DEBUG @@ -155,18 +146,17 @@ namespace Penumbra.Mods public ModInfo AddModSettings( ResourceMod mod ) { - var entry = new ModInfo + var entry = new ModInfo(mod) { - Priority = ModSettings.Count, + Priority = ModSettings?.Count ?? 0, FolderName = mod.ModBasePath.Name, Enabled = true, - Mod = mod }; #if DEBUG PluginLog.Information( "creating mod settings {ModName}", entry.FolderName ); #endif - + ModSettings ??= new List< ModInfo >(); ModSettings.Add( entry ); return entry; } @@ -174,19 +164,20 @@ namespace Penumbra.Mods public ModInfo FindOrCreateModSettings( ResourceMod mod ) { var settings = FindModSettings( mod.ModBasePath.Name ); - if( settings != null ) + if( settings == null ) { - settings.Mod = mod; - return settings; + return AddModSettings( mod ); } - return AddModSettings( mod ); + settings.Mod = mod; + return settings; + } public IEnumerable< ModInfo > GetOrderedAndEnabledModSettings( bool invertOrder = false ) { - var query = ModSettings - .Where( x => x.Enabled ); + var query = ModSettings? + .Where( x => x.Enabled ) ?? Enumerable.Empty(); if( !invertOrder ) { diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index f2dd88d4..043b5dff 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -13,11 +13,11 @@ namespace Penumbra.Mods public readonly Dictionary< string, FileInfo > ResolvedFiles = new(); public readonly Dictionary< string, string > SwappedFiles = new(); - public ModCollection Mods { get; set; } + public ModCollection? Mods { get; set; } + private DirectoryInfo? _basePath; - private DirectoryInfo _basePath; - - public ModManager( Plugin plugin ) => _plugin = plugin; + public ModManager( Plugin plugin ) + => _plugin = plugin; public void DiscoverMods() { @@ -104,31 +104,26 @@ namespace Penumbra.Mods ResolvedFiles.Clear(); SwappedFiles.Clear(); + if( Mods == null ) + { + return; + } + var registeredFiles = new Dictionary< string, string >(); - foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin.Configuration.InvertModListOrder ) ) + foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin!.Configuration!.InvertModListOrder ) ) { - mod.FileConflicts?.Clear(); - if( settings.Conf == null ) - { - settings.Conf = new Dictionary< string, int >(); - Mods.Save(); - } + mod.FileConflicts.Clear(); ProcessModFiles( registeredFiles, mod, settings ); ProcessSwappedFiles( registeredFiles, mod, settings ); } - _plugin.GameUtils.ReloadPlayerResources(); + _plugin!.GameUtils!.ReloadPlayerResources(); } private void ProcessSwappedFiles( Dictionary< string, string > registeredFiles, ResourceMod mod, ModInfo settings ) { - if( mod?.Meta?.FileSwaps == null ) - { - return; - } - foreach( var swap in mod.Meta.FileSwaps ) { // just assume people put not fucked paths in here lol @@ -162,7 +157,7 @@ namespace Penumbra.Mods && settings.Conf[ group.GroupName ] >= group.Options.Count ) { settings.Conf[ group.GroupName ] = 0; - Mods.Save(); + Mods!.Save(); setting = 0; } @@ -240,13 +235,13 @@ namespace Penumbra.Mods public void ChangeModPriority( ModInfo info, bool up = false ) { - Mods.ReorderMod( info, up ); + Mods!.ReorderMod( info, up ); CalculateEffectiveFileList(); } - public void DeleteMod( ResourceMod mod ) + public void DeleteMod( ResourceMod? mod ) { - if( mod?.ModBasePath?.Exists ?? false ) + if( mod?.ModBasePath.Exists ?? false ) { try { @@ -261,7 +256,7 @@ namespace Penumbra.Mods DiscoverMods(); } - public FileInfo GetCandidateForGameFile( string gameResourcePath ) + public FileInfo? GetCandidateForGameFile( string gameResourcePath ) { var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate ); if( !val ) @@ -277,10 +272,10 @@ namespace Penumbra.Mods return candidate; } - public string GetSwappedFilePath( string gameResourcePath ) + public string? GetSwappedFilePath( string gameResourcePath ) => SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null; - public string ResolveSwappedOrReplacementFilePath( string gameResourcePath ) + public string? ResolveSwappedOrReplacementFilePath( string gameResourcePath ) { gameResourcePath = gameResourcePath.ToLowerInvariant(); diff --git a/Penumbra/Mods/ResourceMod.cs b/Penumbra/Mods/ResourceMod.cs index 71906e07..55ec3028 100644 --- a/Penumbra/Mods/ResourceMod.cs +++ b/Penumbra/Mods/ResourceMod.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using Dalamud.Plugin; using Penumbra.Models; @@ -7,6 +8,12 @@ namespace Penumbra.Mods { public class ResourceMod { + public ResourceMod( ModMeta meta, DirectoryInfo dir ) + { + Meta = meta; + ModBasePath = dir; + } + public ModMeta Meta { get; set; } public DirectoryInfo ModBasePath { get; set; } @@ -17,26 +24,13 @@ namespace Penumbra.Mods public void RefreshModFiles() { - if( ModBasePath == null ) - { - PluginLog.LogError( "no basepath has been set on {ResourceModName}", Meta.Name ); - return; - } - ModFiles.Clear(); // we don't care about any _files_ in the root dir, but any folders should be a game folder/file combo - foreach( var dir in ModBasePath.EnumerateDirectories() ) + foreach( var file in ModBasePath.EnumerateDirectories() + .SelectMany( dir => dir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) ) ) { - foreach( var file in dir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) ) - { - ModFiles.Add( file ); - } + ModFiles.Add( file ); } - - // Only add if not in a sub-folder, otherwise it was already added. - //foreach( var pair in Meta.Groups.FileToGameAndGroup ) - // if (pair.Key.IndexOfAny(new[]{'/', '\\'}) < 0) - // ModFiles.Add( new FileInfo(Path.Combine(ModBasePath.FullName, pair.Key)) ); } public void AddConflict( string modName, string path ) diff --git a/Penumbra/Plugin.cs b/Penumbra/Plugin.cs index 2fd71c91..fe8b5c64 100644 --- a/Penumbra/Plugin.cs +++ b/Penumbra/Plugin.cs @@ -13,24 +13,25 @@ namespace Penumbra { public class Plugin : IDalamudPlugin { - public string Name => "Penumbra"; + public string Name { get; } + public string PluginDebugTitleStr { get; } + + public Plugin() + { + Name = "Penumbra"; + PluginDebugTitleStr = $"{Name} - Debug Build"; + } private const string CommandName = "/penumbra"; - public DalamudPluginInterface PluginInterface { get; set; } + public DalamudPluginInterface? PluginInterface { get; set; } + public Configuration? Configuration { get; set; } + public ResourceLoader? ResourceLoader { get; set; } + public SettingsInterface? SettingsInterface { get; set; } + public GameUtils? GameUtils { get; set; } + public SoundShit? SoundShit { get; set; } - public Configuration Configuration { get; set; } - - public ResourceLoader ResourceLoader { get; set; } - - public SettingsInterface SettingsInterface { get; set; } - - public GameUtils GameUtils { get; set; } - public SoundShit SoundShit { get; set; } - - public string PluginDebugTitleStr { get; private set; } - - private WebServer _webServer; + private WebServer? _webServer; public void Initialize( DalamudPluginInterface pluginInterface ) { @@ -61,8 +62,6 @@ namespace Penumbra PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw; - PluginDebugTitleStr = $"{Name} - Debug Build"; - if( Configuration.EnableHttpApi ) { CreateWebServer(); @@ -97,12 +96,12 @@ namespace Penumbra { // ModManager?.Dispose(); - PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw; + PluginInterface!.UiBuilder.OnBuildUi -= SettingsInterface!.Draw; PluginInterface.CommandManager.RemoveHandler( CommandName ); PluginInterface.Dispose(); - ResourceLoader.Dispose(); + ResourceLoader?.Dispose(); ShutdownWebServer(); } @@ -117,8 +116,8 @@ namespace Penumbra case "reload": { Service< ModManager >.Get().DiscoverMods(); - PluginInterface.Framework.Gui.Chat.Print( - $"Reloaded Penumbra mods. You have {Service< ModManager >.Get().Mods.ModSettings.Count} mods, {Service< ModManager >.Get().Mods.EnabledMods.Length} of which are enabled." + PluginInterface!.Framework.Gui.Chat.Print( + $"Reloaded Penumbra mods. You have {Service< ModManager >.Get()?.Mods?.ModSettings?.Count ?? 0} mods, {Service< ModManager >.Get()?.Mods?.EnabledMods?.Length ?? 0} of which are enabled." ); break; } @@ -126,11 +125,11 @@ namespace Penumbra { if( args.Length > 1 ) { - RefreshActors.RedrawSpecific( PluginInterface.ClientState.Actors, string.Join( " ", args.Skip( 1 ) ) ); + RefreshActors.RedrawSpecific( PluginInterface!.ClientState.Actors, string.Join( " ", args.Skip( 1 ) ) ); } else { - RefreshActors.RedrawAll( PluginInterface.ClientState.Actors ); + RefreshActors.RedrawAll( PluginInterface!.ClientState.Actors ); } break; @@ -140,7 +139,7 @@ namespace Penumbra return; } - SettingsInterface.FlipVisibility(); + SettingsInterface!.FlipVisibility(); } } } \ No newline at end of file diff --git a/Penumbra/UI/LaunchButton.cs b/Penumbra/UI/LaunchButton.cs index 72ad85b3..6699e3f2 100644 --- a/Penumbra/UI/LaunchButton.cs +++ b/Penumbra/UI/LaunchButton.cs @@ -32,7 +32,7 @@ namespace Penumbra.UI public ManageModsButton( SettingsInterface ui ) { _base = ui; - _condition = ui._plugin.PluginInterface.ClientState.Condition; + _condition = ui._plugin!.PluginInterface!.ClientState.Condition; } public void Draw() diff --git a/Penumbra/UI/SettingsInterface.cs b/Penumbra/UI/SettingsInterface.cs index 19b5c884..362c44b3 100644 --- a/Penumbra/UI/SettingsInterface.cs +++ b/Penumbra/UI/SettingsInterface.cs @@ -39,7 +39,7 @@ namespace Penumbra.UI _menu.InstalledTab.Selector.ResetModNamesLower(); _menu.InstalledTab.Selector.ClearSelection(); // create the directory if it doesn't exist - Directory.CreateDirectory( _plugin.Configuration.CurrentCollection ); + Directory.CreateDirectory( _plugin!.Configuration!.CurrentCollection ); var modManager = Service< ModManager >.Get(); modManager.DiscoverMods( _plugin.Configuration.CurrentCollection ); diff --git a/Penumbra/UI/SettingsMenu.cs b/Penumbra/UI/SettingsMenu.cs index a1b75d54..cf7fb728 100644 --- a/Penumbra/UI/SettingsMenu.cs +++ b/Penumbra/UI/SettingsMenu.cs @@ -64,7 +64,7 @@ namespace Penumbra.UI _browserTab.Draw(); InstalledTab.Draw(); - if( _base._plugin.Configuration.ShowAdvanced ) + if( _base._plugin!.Configuration!.ShowAdvanced ) { EffectiveTab.Draw(); } diff --git a/Penumbra/UI/TabEffective.cs b/Penumbra/UI/TabEffective.cs index e22c8978..bf8cd638 100644 --- a/Penumbra/UI/TabEffective.cs +++ b/Penumbra/UI/TabEffective.cs @@ -12,12 +12,12 @@ namespace Penumbra.UI private const float TextSizePadding = 5f; private ModManager _mods => Service< ModManager >.Get(); - private (string, string)[] _fileList; - private float _maxGamePath; + private (string, string)[]? _fileList; + private float _maxGamePath; public TabEffective( SettingsInterface ui ) { - RebuildFileList( ui._plugin.Configuration.ShowAdvanced ); + RebuildFileList( ui._plugin!.Configuration!.ShowAdvanced ); } public void RebuildFileList( bool advanced ) @@ -54,7 +54,7 @@ namespace Penumbra.UI if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) ) { - foreach( var file in _fileList ) + foreach( var file in _fileList ?? Enumerable.Empty<(string, string)>() ) { DrawFileLine( file ); } diff --git a/Penumbra/UI/TabImport.cs b/Penumbra/UI/TabImport.cs index 8c2d3aa8..0600431f 100644 --- a/Penumbra/UI/TabImport.cs +++ b/Penumbra/UI/TabImport.cs @@ -27,7 +27,7 @@ namespace Penumbra.UI private bool _isImportRunning = false; private bool _hasError = false; - private TexToolsImport _texToolsImport = null!; + private TexToolsImport? _texToolsImport; private readonly SettingsInterface _base; public TabImport( SettingsInterface ui ) => _base = ui; @@ -59,7 +59,7 @@ namespace Penumbra.UI try { - _texToolsImport = new TexToolsImport( new DirectoryInfo( _base._plugin.Configuration.CurrentCollection ) ); + _texToolsImport = new TexToolsImport( new DirectoryInfo( _base._plugin!.Configuration!.CurrentCollection ) ); _texToolsImport.ImportModPack( new FileInfo( fileName ) ); PluginLog.Log( $"-> {fileName} OK!" ); diff --git a/Penumbra/UI/TabInstalledDetails.cs b/Penumbra/UI/TabInstalledDetails.cs index cad534d2..d2492e06 100644 --- a/Penumbra/UI/TabInstalledDetails.cs +++ b/Penumbra/UI/TabInstalledDetails.cs @@ -11,7 +11,7 @@ namespace Penumbra.UI // Remove the entry at idx from the list if the new string is empty, otherwise replace it. public static void RemoveOrChange( this List< string > list, string newString, int idx ) { - if( newString?.Length == 0 ) + if( newString.Length == 0 ) { list.RemoveAt( idx ); } @@ -53,29 +53,31 @@ namespace Penumbra.UI private const uint ColorYellow = 0xFF00C8C8; private const uint ColorRed = 0xFF0000C8; - private bool _editMode = false; - private int _selectedGroupIndex = 0; - private InstallerInfo? _selectedGroup = null; - private int _selectedOptionIndex = 0; - private Option? _selectedOption = null; - private (string label, string name)[] _changedItemsList = null; - private float? _fileSwapOffset = null; - private string _currentGamePaths = ""; + private bool _editMode = false; + private int _selectedGroupIndex = 0; + private InstallerInfo? _selectedGroup = null; + private int _selectedOptionIndex = 0; + private Option? _selectedOption = null; + private (string label, string name)[]? _changedItemsList = null; + private float? _fileSwapOffset = null; + private string _currentGamePaths = ""; - private (string name, bool selected, uint color, string relName)[] _fullFilenameList = null; + private (string name, bool selected, uint color, string relName)[]? _fullFilenameList = null; private readonly Selector _selector; private readonly SettingsInterface _base; private void SelectGroup( int idx ) { + // Not using the properties here because we need it to be not null forgiving in this case. + var numGroups = _selector.Mod()?.Mod.Meta.Groups.Count ?? 0; _selectedGroupIndex = idx; - if( _selectedGroupIndex >= Meta?.Groups?.Count ) + if( _selectedGroupIndex >= numGroups) { _selectedGroupIndex = 0; } - if( Meta?.Groups?.Count > 0 ) + if( numGroups > 0 ) { _selectedGroup = Meta.Groups.ElementAt( _selectedGroupIndex ).Value; } @@ -123,20 +125,21 @@ namespace Penumbra.UI ResetState(); } - private ModInfo Mod => _selector.Mod(); - private ModMeta Meta => Mod?.Mod?.Meta; + // This is only drawn when we have a mod selected, so we can forgive nulls. + private ModInfo Mod => _selector.Mod()!; + private ModMeta Meta => Mod.Mod.Meta; private void Save() { var modManager = Service< ModManager >.Get(); - modManager.Mods.Save(); + modManager.Mods?.Save(); modManager.CalculateEffectiveFileList(); - _base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); + _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced ); } private void DrawAboutTab() { - if( !_editMode && ( Meta.Description?.Length ?? 0 ) == 0 ) + if( !_editMode && Meta.Description.Length == 0 ) { return; } @@ -174,13 +177,11 @@ namespace Penumbra.UI private void DrawChangedItemsTab() { - if( !_editMode && ( Meta.ChangedItems?.Count ?? 0 ) == 0 ) + if( !_editMode && Meta.ChangedItems.Count == 0 ) { return; } - Meta.ChangedItems ??= new List< string >(); - var flags = _editMode ? ImGuiInputTextFlags.EnterReturnsTrue : ImGuiInputTextFlags.ReadOnly; @@ -210,15 +211,7 @@ namespace Penumbra.UI { if( newItem.Length > 0 ) { - if( Meta.ChangedItems == null ) - { - Meta.ChangedItems = new List< string >() { newItem }; - } - else - { - Meta.ChangedItems.Add( newItem ); - } - + Meta.ChangedItems.Add( newItem ); _selector.SaveCurrentMod(); } } @@ -317,7 +310,7 @@ namespace Penumbra.UI var len = Mod.Mod.ModBasePath.FullName.Length; _fullFilenameList = Mod.Mod.ModFiles.Select( F => ( F.FullName, false, ColorGreen, "" ) ).ToArray(); - if( Meta.Groups?.Count == 0 ) + if( Meta.Groups.Count == 0 ) { return; } @@ -369,7 +362,7 @@ namespace Penumbra.UI if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize ) ) { UpdateFilenameList(); - foreach( var file in _fullFilenameList ) + foreach( var file in _fullFilenameList! ) { ImGui.PushStyleColor( ImGuiCol.Text, file.color ); ImGui.Selectable( file.name ); @@ -405,7 +398,7 @@ namespace Penumbra.UI var changed = false; for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i ) { - if( !_fullFilenameList[ i ].selected ) + if( !_fullFilenameList![ i ].selected ) { continue; } @@ -503,7 +496,7 @@ namespace Penumbra.UI { void Selectable( uint colorNormal, uint colorReplace ) { - var loc = _fullFilenameList[ idx ].color; + var loc = _fullFilenameList![ idx ].color; if( loc == colorNormal ) { loc = colorReplace; @@ -521,7 +514,7 @@ namespace Penumbra.UI return; } - var fileName = _fullFilenameList[ idx ].relName; + var fileName = _fullFilenameList![ idx ].relName; if( ( ( Option )_selectedOption ).OptionFiles.TryGetValue( fileName, out var gamePaths ) ) { Selectable( 0, ColorGreen ); diff --git a/Penumbra/UI/TabInstalledDetailsEdit.cs b/Penumbra/UI/TabInstalledDetailsEdit.cs index c22d7e35..565a345e 100644 --- a/Penumbra/UI/TabInstalledDetailsEdit.cs +++ b/Penumbra/UI/TabInstalledDetailsEdit.cs @@ -36,7 +36,7 @@ namespace Penumbra.UI private bool DrawEditGroupSelector() { ImGui.SetNextItemWidth( OptionSelectionWidth ); - if( Meta.Groups.Count == 0 ) + if( Meta!.Groups.Count == 0 ) { ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 ); return false; @@ -63,7 +63,7 @@ namespace Penumbra.UI return false; } - var group = ( InstallerInfo )_selectedGroup; + var group = ( InstallerInfo )_selectedGroup!; if( ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, group.Options.Select( O => O.OptionName ).ToArray(), group.Options.Count ) ) { @@ -86,7 +86,7 @@ namespace Penumbra.UI ImGui.SetNextItemWidth( -1 ); if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize - new Vector2( 0, 1.5f * ImGui.GetTextLineHeight() ) ) ) { - for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i ) + for( var i = 0; i < Mod!.Mod.ModFiles.Count; ++i ) { DrawFileAndGamePaths( i ); } @@ -107,9 +107,9 @@ namespace Penumbra.UI { var groupName = group.GroupName; if( ImGuiCustom.BeginFramedGroupEdit( ref groupName ) - && groupName != group.GroupName && !Meta.Groups.ContainsKey( groupName ) ) + && groupName != group.GroupName && !Meta!.Groups.ContainsKey( groupName ) ) { - var oldConf = Mod.Conf[ group.GroupName ]; + var oldConf = Mod!.Conf[ group.GroupName ]; Meta.Groups.Remove( group.GroupName ); Mod.Conf.Remove( group.GroupName ); if( groupName.Length > 0 ) @@ -142,7 +142,7 @@ namespace Penumbra.UI private void DrawMultiSelectorEdit( InstallerInfo group ) { var nameBoxStart = CheckMarkSize; - var flag = Mod.Conf[ group.GroupName ]; + var flag = Mod!.Conf[ group.GroupName ]; var modChanged = DrawMultiSelectorEditBegin( group ); @@ -194,9 +194,9 @@ namespace Penumbra.UI { var groupName = group.GroupName; if( ImGui.InputText( $"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) - && !Meta.Groups.ContainsKey( groupName ) ) + && !Meta!.Groups.ContainsKey( groupName ) ) { - var oldConf = Mod.Conf[ group.GroupName ]; + var oldConf = Mod!.Conf[ group.GroupName ]; if( groupName != group.GroupName ) { Meta.Groups.Remove( group.GroupName ); @@ -218,7 +218,7 @@ namespace Penumbra.UI private float DrawSingleSelectorEdit( InstallerInfo group ) { - var code = Mod.Conf[ group.GroupName ]; + var code = Mod!.Conf[ group.GroupName ]; var selectionChanged = false; var modChanged = false; if( ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName, @@ -283,7 +283,7 @@ namespace Penumbra.UI private void AddNewGroup( string newGroup, SelectType selectType ) { - if( Meta.Groups.ContainsKey( newGroup ) || newGroup.Length <= 0 ) + if( Meta!.Groups.ContainsKey( newGroup ) || newGroup.Length <= 0 ) { return; } diff --git a/Penumbra/UI/TabInstalledModPanel.cs b/Penumbra/UI/TabInstalledModPanel.cs index 6315fb0d..6858db68 100644 --- a/Penumbra/UI/TabInstalledModPanel.cs +++ b/Penumbra/UI/TabInstalledModPanel.cs @@ -48,15 +48,15 @@ namespace Penumbra.UI _base = ui; _selector = s; Details = new PluginDetails( _base, _selector ); - _currentWebsite = Meta?.Website; + _currentWebsite = Meta?.Website ?? ""; } - private ModInfo Mod => _selector.Mod(); - private ModMeta Meta => Mod?.Mod.Meta; + private ModInfo? Mod => _selector.Mod(); + private ModMeta? Meta => Mod?.Mod.Meta; private void DrawName() { - var name = Meta.Name; + var name = Meta!.Name; if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) && name.Length > 0 && name != Meta.Name ) { @@ -74,11 +74,11 @@ namespace Penumbra.UI ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); ImGui.SameLine(); - var version = Meta.Version ?? ""; + var version = Meta!.Version; if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) && version != Meta.Version ) { - Meta.Version = version.Length > 0 ? version : null; + Meta.Version = version; _selector.SaveCurrentMod(); } @@ -87,7 +87,7 @@ namespace Penumbra.UI ImGui.PopStyleVar(); ImGui.EndGroup(); } - else if( ( Meta.Version?.Length ?? 0 ) > 0 ) + else if( Meta!.Version.Length > 0 ) { ImGui.Text( $"(Version {Meta.Version})" ); } @@ -99,11 +99,11 @@ namespace Penumbra.UI ImGui.TextColored( GreyColor, "by" ); ImGui.SameLine(); - var author = Meta.Author ?? ""; + var author = Meta!.Author; if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) && author != Meta.Author ) { - Meta.Author = author.Length > 0 ? author : null; + Meta.Author = author; _selector.SaveCurrentMod(); } @@ -117,15 +117,15 @@ namespace Penumbra.UI { ImGui.TextColored( GreyColor, "from" ); ImGui.SameLine(); - var website = Meta.Website ?? ""; + var website = Meta!.Website; if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) && website != Meta.Website ) { - Meta.Website = website.Length > 0 ? website : null; + Meta.Website = website; _selector.SaveCurrentMod(); } } - else if( ( Meta.Website?.Length ?? 0 ) > 0 ) + else if( Meta!.Website.Length > 0 ) { if( _currentWebsite != Meta.Website ) { @@ -181,14 +181,14 @@ namespace Penumbra.UI private void DrawEnabledMark() { - var enabled = Mod.Enabled; + var enabled = Mod!.Enabled; if( ImGui.Checkbox( LabelModEnabled, ref enabled ) ) { Mod.Enabled = enabled; var modManager = Service< ModManager >.Get(); - modManager.Mods.Save(); + modManager.Mods!.Save(); modManager.CalculateEffectiveFileList(); - _base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); + _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced ); } } @@ -201,7 +201,7 @@ namespace Penumbra.UI { if( ImGui.Button( ButtonOpenModFolder ) ) { - Process.Start( Mod.Mod.ModBasePath.FullName ); + Process.Start( Mod!.Mod.ModBasePath.FullName ); } if( ImGui.IsItemHovered() ) @@ -240,11 +240,11 @@ namespace Penumbra.UI { if( ImGui.Button( ButtonDeduplicate ) ) { - new Deduplicator( Mod.Mod.ModBasePath, Meta ).Run(); + new Deduplicator( Mod!.Mod.ModBasePath, Meta! ).Run(); _selector.SaveCurrentMod(); Mod.Mod.RefreshModFiles(); Service< ModManager >.Get().CalculateEffectiveFileList(); - _base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); + _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced ); } if( ImGui.IsItemHovered() ) @@ -285,7 +285,7 @@ namespace Penumbra.UI ImGuiCustom.VerticalDistance( HeaderLineDistance ); DrawEnabledMark(); - if( _base._plugin.Configuration.ShowAdvanced ) + if( _base._plugin!.Configuration!.ShowAdvanced ) { ImGui.SameLine(); DrawEditableMark(); diff --git a/Penumbra/UI/TabInstalledSelector.cs b/Penumbra/UI/TabInstalledSelector.cs index b0ac4045..cd7a796b 100644 --- a/Penumbra/UI/TabInstalledSelector.cs +++ b/Penumbra/UI/TabInstalledSelector.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Numerics; using Dalamud.Interface; using ImGuiNET; +using ImGuiScene; using Newtonsoft.Json; using Penumbra.Models; using Penumbra.Mods; @@ -32,13 +33,13 @@ namespace Penumbra.UI private static readonly string ArrowDownString = FontAwesomeIcon.ArrowDown.ToIconString(); private readonly SettingsInterface _base; - private ModCollection Mods => Service< ModManager >.Get().Mods; + private ModCollection? Mods => Service< ModManager >.Get().Mods; - private ModInfo _mod; - private int _index; - private int? _deleteIndex; - private string _modFilter = ""; - private string[] _modNamesLower; + private ModInfo? _mod; + private int _index; + private int? _deleteIndex; + private string _modFilter = ""; + private string[]? _modNamesLower; public Selector( SettingsInterface ui ) @@ -49,7 +50,8 @@ namespace Penumbra.UI public void ResetModNamesLower() { - _modNamesLower = Mods?.ModSettings?.Select( I => I.Mod.Meta.Name.ToLowerInvariant() ).ToArray() ?? new string[]{}; + _modNamesLower = Mods?.ModSettings?.Where(I => I.Mod != null) + .Select( I => I.Mod!.Meta.Name.ToLowerInvariant() ).ToArray() ?? new string[]{}; } private void DrawPriorityChangeButton( string iconString, bool up, int unavailableWhen ) @@ -60,8 +62,8 @@ namespace Penumbra.UI if( ImGui.Button( iconString, SelectorButtonSizes ) ) { SetSelection( _index ); - Service< ModManager >.Get().ChangeModPriority( _mod, up ); - _modNamesLower.Swap( _index, _index + ( up ? 1 : -1 ) ); + Service< ModManager >.Get().ChangeModPriority( _mod!, up ); + _modNamesLower!.Swap( _index, _index + ( up ? 1 : -1 ) ); _index += up ? 1 : -1; } } @@ -77,7 +79,7 @@ namespace Penumbra.UI if( ImGui.IsItemHovered() ) { ImGui.SetTooltip( - _base._plugin.Configuration.InvertModListOrder ^ up ? TooltipMoveDown : TooltipMoveUp + _base._plugin!.Configuration!.InvertModListOrder ^ up ? TooltipMoveDown : TooltipMoveUp ); } } @@ -139,7 +141,7 @@ namespace Penumbra.UI DrawPriorityChangeButton( ArrowUpString, false, 0 ); ImGui.SameLine(); - DrawPriorityChangeButton( ArrowDownString, true, Mods?.ModSettings.Count - 1 ?? 0 ); + DrawPriorityChangeButton( ArrowDownString, true, Mods?.ModSettings?.Count - 1 ?? 0 ); ImGui.SameLine(); DrawModTrashButton(); ImGui.SameLine(); @@ -177,7 +179,7 @@ namespace Penumbra.UI if( ImGui.Button( ButtonYesDelete ) ) { ImGui.CloseCurrentPopup(); - Service< ModManager >.Get().DeleteMod( _mod.Mod ); + Service< ModManager >.Get().DeleteMod( _mod?.Mod ); ClearSelection(); _base.ReloadMods(); } @@ -210,44 +212,47 @@ namespace Penumbra.UI // Inlay selector list ImGui.BeginChild( LabelSelectorList, new Vector2( SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true ); - for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ ) + if( Mods.ModSettings != null ) { - var settings = Mods.ModSettings[ modIndex ]; - var modName = settings.Mod.Meta.Name; - if( _modFilter.Length > 0 && !_modNamesLower[ modIndex ].Contains( _modFilter ) ) + for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ ) { - continue; - } + var settings = Mods.ModSettings[ modIndex ]; + var modName = settings.Mod.Meta.Name; + if( _modFilter.Length > 0 && !_modNamesLower![ modIndex ].Contains( _modFilter ) ) + { + continue; + } - var changedColour = false; - if( !settings.Enabled ) - { - ImGui.PushStyleColor( ImGuiCol.Text, DisabledModColor ); - changedColour = true; - } - else if( settings.Mod.FileConflicts.Any() ) - { - ImGui.PushStyleColor( ImGuiCol.Text, ConflictingModColor ); - changedColour = true; - } + var changedColour = false; + if( !settings.Enabled ) + { + ImGui.PushStyleColor( ImGuiCol.Text, DisabledModColor ); + changedColour = true; + } + else if( settings.Mod.FileConflicts.Any() ) + { + ImGui.PushStyleColor( ImGuiCol.Text, ConflictingModColor ); + changedColour = true; + } #if DEBUG - var selected = ImGui.Selectable( - $"id={modIndex} {modName}", - modIndex == _index - ); + var selected = ImGui.Selectable( + $"id={modIndex} {modName}", + modIndex == _index + ); #else - var selected = ImGui.Selectable( modName, modIndex == _index ); + var selected = ImGui.Selectable( modName, modIndex == _index ); #endif - if( changedColour ) - { - ImGui.PopStyleColor(); - } + if( changedColour ) + { + ImGui.PopStyleColor(); + } - if( selected ) - { - SetSelection( modIndex, settings ); + if( selected ) + { + SetSelection( modIndex, settings ); + } } } @@ -259,9 +264,9 @@ namespace Penumbra.UI DrawDeleteModal(); } - public ModInfo Mod() => _mod; + public ModInfo? Mod() => _mod; - private void SetSelection( int idx, ModInfo info ) + private void SetSelection( int idx, ModInfo? info ) { _mod = info; if( idx != _index ) @@ -286,7 +291,7 @@ namespace Penumbra.UI } else { - SetSelection( idx, Mods.ModSettings[ idx ] ); + SetSelection( idx, Mods!.ModSettings![ idx ] ); } } @@ -294,18 +299,8 @@ namespace Penumbra.UI public void SelectModByName( string name ) { - for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ ) - { - var mod = Mods.ModSettings[ modIndex ]; - - if( mod.Mod.Meta.Name != name ) - { - continue; - } - - SetSelection( modIndex, mod ); - return; - } + var idx = Mods?.ModSettings?.FindIndex( mod => mod.Mod.Meta.Name == name ) ?? -1; + SetSelection( idx ); } private string GetCurrentModMetaFile() @@ -316,18 +311,21 @@ namespace Penumbra.UI var metaPath = GetCurrentModMetaFile(); if( metaPath.Length > 0 && File.Exists( metaPath ) ) { - _mod.Mod.Meta = ModMeta.LoadFromFile( metaPath ) ?? _mod.Mod.Meta; + _mod!.Mod.Meta = ModMeta.LoadFromFile( metaPath ) ?? _mod.Mod.Meta; _base._menu.InstalledTab.ModPanel.Details.ResetState(); } - _mod.Mod.RefreshModFiles(); + _mod!.Mod.RefreshModFiles(); Service< ModManager >.Get().CalculateEffectiveFileList(); - _base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); + _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced ); ResetModNamesLower(); } public string SaveCurrentMod() { + if( _mod == null ) + return ""; + var metaPath = GetCurrentModMetaFile(); if( metaPath.Length > 0 ) { diff --git a/Penumbra/UI/TabSettings.cs b/Penumbra/UI/TabSettings.cs index 8d9984bc..9e328849 100644 --- a/Penumbra/UI/TabSettings.cs +++ b/Penumbra/UI/TabSettings.cs @@ -20,13 +20,13 @@ namespace Penumbra.UI private const string LabelReloadResource = "Reload Player Resource"; private readonly SettingsInterface _base; - private readonly Configuration _config; + private readonly Configuration _config; private bool _configChanged; public TabSettings( SettingsInterface ui ) { _base = ui; - _config = _base._plugin.Configuration; + _config = _base._plugin.Configuration!; _configChanged = false; } @@ -64,7 +64,7 @@ namespace Penumbra.UI { _config.IsEnabled = enabled; _configChanged = true; - Game.RefreshActors.RedrawAll( _base._plugin.PluginInterface.ClientState.Actors ); + Game.RefreshActors.RedrawAll( _base._plugin!.PluginInterface!.ClientState.Actors ); } } @@ -131,7 +131,7 @@ namespace Penumbra.UI { if( ImGui.Button( LabelReloadResource ) ) { - _base._plugin.GameUtils.ReloadPlayerResources(); + _base._plugin!.GameUtils!.ReloadPlayerResources(); } } diff --git a/Penumbra/Util/SingleOrArrayConverter.cs b/Penumbra/Util/SingleOrArrayConverter.cs index 0a73ad7e..638e4da0 100644 --- a/Penumbra/Util/SingleOrArrayConverter.cs +++ b/Penumbra/Util/SingleOrArrayConverter.cs @@ -3,46 +3,32 @@ using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -public class SingleOrArrayConverter< T > : JsonConverter +namespace Penumbra.Util { - public override bool CanConvert( Type objectType ) => objectType == typeof( HashSet< T > ); - - public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) + public class SingleOrArrayConverter< T > : JsonConverter { - var token = JToken.Load( reader ); - return token.Type == JTokenType.Array - ? token.ToObject< HashSet< T > >() - : new HashSet< T > { token.ToObject< T >() }; - } + public override bool CanConvert( Type objectType ) => objectType == typeof( HashSet< T > ); - public override bool CanWrite => false; - - public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) - { - throw new NotImplementedException(); - } -} - -public class DictSingleOrArrayConverter< T, U > : JsonConverter -{ - public override bool CanConvert( Type objectType ) => objectType == typeof( Dictionary< T, HashSet< U > > ); - - public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) - { - var token = JToken.Load( reader ); - - if( token.Type == JTokenType.Array ) + public override object ReadJson( JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer ) { - return token.ToObject< HashSet< T > >(); + var token = JToken.Load( reader ); + + if( token.Type == JTokenType.Array ) + { + return token.ToObject< HashSet< T > >() ?? new HashSet(); + } + + var tmp = token.ToObject< T >(); + return tmp != null + ? new HashSet< T > { tmp } + : new HashSet< T >(); } - return new HashSet< T > { token.ToObject< T >() }; - } + public override bool CanWrite => false; - public override bool CanWrite => false; - - public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) - { - throw new NotImplementedException(); + public override void WriteJson( JsonWriter writer, object? value, JsonSerializer serializer ) + { + throw new NotImplementedException(); + } } } \ No newline at end of file