Remove some warnings about nullable.

This commit is contained in:
Ottermandias 2021-02-21 16:08:08 +01:00
parent 3f9d97f65f
commit ef2f2cff5c
26 changed files with 330 additions and 352 deletions

View file

@ -13,10 +13,10 @@ namespace Penumbra.API
public ModsController( Plugin plugin ) => _plugin = plugin; public ModsController( Plugin plugin ) => _plugin = plugin;
[Route( HttpVerbs.Get, "/mods" )] [Route( HttpVerbs.Get, "/mods" )]
public object GetMods() public object? GetMods()
{ {
var modManager = Service< ModManager >.Get(); var modManager = Service< ModManager >.Get();
return modManager.Mods.ModSettings.Select( x => new return modManager.Mods?.ModSettings.Select( x => new
{ {
x.Enabled, x.Enabled,
x.Priority, x.Priority,

View file

@ -27,7 +27,7 @@ namespace Penumbra
// the below exist just to make saving less cumbersome // the below exist just to make saving less cumbersome
[NonSerialized] [NonSerialized]
private DalamudPluginInterface _pluginInterface; private DalamudPluginInterface? _pluginInterface;
public void Initialize( DalamudPluginInterface pluginInterface ) public void Initialize( DalamudPluginInterface pluginInterface )
{ {
@ -36,7 +36,7 @@ namespace Penumbra
public void Save() public void Save()
{ {
_pluginInterface.SavePluginConfig( this ); _pluginInterface?.SavePluginConfig( this );
} }
} }
} }

View file

@ -38,12 +38,12 @@ namespace Penumbra.Hooks
uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown ); uint* pResourceHash, char* pPath, void* pUnknown, bool isUnknown );
// Hooks // Hooks
public IHook< GetResourceSyncPrototype > GetResourceSyncHook { get; private set; } public IHook< GetResourceSyncPrototype >? GetResourceSyncHook { get; private set; }
public IHook< GetResourceAsyncPrototype > GetResourceAsyncHook { get; private set; } public IHook< GetResourceAsyncPrototype >? GetResourceAsyncHook { get; private set; }
public IHook< ReadSqpackPrototype > ReadSqpackHook { get; private set; } public IHook< ReadSqpackPrototype >? ReadSqpackHook { get; private set; }
// Unmanaged functions // Unmanaged functions
public ReadFilePrototype ReadFile { get; private set; } public ReadFilePrototype? ReadFile { get; private set; }
public bool LogAllFiles = false; public bool LogAllFiles = false;
@ -57,7 +57,7 @@ namespace Penumbra.Hooks
public unsafe void Init() public unsafe void Init()
{ {
var scanner = Plugin.PluginInterface.TargetModuleScanner; var scanner = Plugin!.PluginInterface!.TargetModuleScanner;
var readFileAddress = var readFileAddress =
scanner.ScanText( "E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3 BA 05" ); scanner.ScanText( "E8 ?? ?? ?? ?? 84 C0 0F 84 ?? 00 00 00 4C 8B C3 BA 05" );
@ -108,9 +108,24 @@ namespace Penumbra.Hooks
char* pPath, char* pPath,
void* pUnknown, void* pUnknown,
bool isUnknown 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( private unsafe void* GetResourceHandler(
bool isSync, bool isSync,
@ -132,12 +147,12 @@ namespace Penumbra.Hooks
var modManager = Service< ModManager >.Get(); 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 ); 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 :( // path must be < 260 because statically defined array length :(
if( replacementPath == null || replacementPath.Length >= 260 ) if( replacementPath == null || replacementPath.Length >= 260 )
@ -170,9 +185,9 @@ namespace Penumbra.Hooks
var isRooted = Path.IsPathRooted( gameFsPath ); 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 #if DEBUG
@ -201,6 +216,12 @@ namespace Penumbra.Hooks
return; 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(); ReadSqpackHook.Activate();
GetResourceSyncHook.Activate(); GetResourceSyncHook.Activate();
GetResourceAsyncHook.Activate(); GetResourceAsyncHook.Activate();
@ -219,23 +240,16 @@ namespace Penumbra.Hooks
return; return;
} }
ReadSqpackHook.Disable(); ReadSqpackHook?.Disable();
GetResourceSyncHook.Disable(); GetResourceSyncHook?.Disable();
GetResourceAsyncHook.Disable(); GetResourceAsyncHook?.Disable();
IsEnabled = false; IsEnabled = false;
} }
public void Dispose() public void Dispose()
{ {
if( IsEnabled ) Disable();
{
Disable();
}
// ReadSqpackHook.Disable();
// GetResourceSyncHook.Disable();
// GetResourceAsyncHook.Disable();
} }
} }
} }

View file

@ -13,7 +13,7 @@ namespace Penumbra.Hooks
public SoundShit( Plugin plugin ) public SoundShit( Plugin plugin )
{ {
var scanner = plugin.PluginInterface.TargetModuleScanner; var scanner = plugin!.PluginInterface!.TargetModuleScanner;
var fw = plugin.PluginInterface.Framework.Address.BaseAddress; var fw = plugin.PluginInterface.Framework.Address.BaseAddress;

View file

@ -5,36 +5,36 @@ namespace Penumbra.Importer.Models
{ {
internal class OptionList internal class OptionList
{ {
public string Name { get; set; } public string? Name { get; set; }
public string Description { get; set; } public string? Description { get; set; }
public string ImagePath { get; set; } public string? ImagePath { get; set; }
public List< SimpleMod > ModsJsons { get; set; } public List< SimpleMod >? ModsJsons { get; set; }
public string GroupName { get; set; } public string? GroupName { get; set; }
public SelectType SelectionType { get; set; } public SelectType SelectionType { get; set; }
public bool IsChecked { get; set; } public bool IsChecked { get; set; }
} }
internal class ModGroup internal class ModGroup
{ {
public string GroupName { get; set; } public string? GroupName { get; set; }
public SelectType SelectionType { get; set; } public SelectType SelectionType { get; set; }
public List< OptionList > OptionList { get; set; } public List< OptionList >? OptionList { get; set; }
} }
internal class ModPackPage internal class ModPackPage
{ {
public int PageIndex { get; set; } public int PageIndex { get; set; }
public List< ModGroup > ModGroups { get; set; } public List< ModGroup >? ModGroups { get; set; }
} }
internal class ExtendedModPack internal class ExtendedModPack
{ {
public string TTMPVersion { get; set; } public string? TTMPVersion { get; set; }
public string Name { get; set; } public string? Name { get; set; }
public string Author { get; set; } public string? Author { get; set; }
public string Version { get; set; } public string? Version { get; set; }
public string Description { get; set; } public string? Description { get; set; }
public List< ModPackPage > ModPackPages { get; set; } public List< ModPackPage >? ModPackPages { get; set; }
public List< SimpleMod > SimpleModsList { get; set; } public List< SimpleMod >? SimpleModsList { get; set; }
} }
} }

View file

@ -4,22 +4,22 @@ namespace Penumbra.Importer.Models
{ {
internal class SimpleModPack internal class SimpleModPack
{ {
public string TTMPVersion { get; set; } public string? TTMPVersion { get; set; }
public string Name { get; set; } public string? Name { get; set; }
public string Author { get; set; } public string? Author { get; set; }
public string Version { get; set; } public string? Version { get; set; }
public string Description { get; set; } public string? Description { get; set; }
public List< SimpleMod > SimpleModsList { get; set; } public List< SimpleMod >? SimpleModsList { get; set; }
} }
internal class SimpleMod internal class SimpleMod
{ {
public string Name { get; set; } public string? Name { get; set; }
public string Category { get; set; } public string? Category { get; set; }
public string FullPath { get; set; } public string? FullPath { get; set; }
public long ModOffset { get; set; } public long ModOffset { get; set; }
public long ModSize { get; set; } public long ModSize { get; set; }
public string DatFile { get; set; } public string? DatFile { get; set; }
public object ModPackEntry { get; set; } public object? ModPackEntry { get; set; }
} }
} }

View file

@ -38,7 +38,7 @@ namespace Penumbra.Importer
} }
} }
public string CurrentModPack { get; private set; } public string? CurrentModPack { get; private set; }
public TexToolsImport( DirectoryInfo outDirectory ) public TexToolsImport( DirectoryInfo outDirectory )
{ {
@ -145,6 +145,12 @@ namespace Penumbra.Importer
{ {
var modList = JsonConvert.DeserializeObject< SimpleModPack >( modRaw ); 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" ) ) if( modList.TTMPVersion.EndsWith( "s" ) )
{ {
ImportSimpleV2ModPack( extractedModPack, modList ); ImportSimpleV2ModPack( extractedModPack, modList );
@ -164,11 +170,11 @@ namespace Penumbra.Importer
// Create a new ModMeta from the TTMP modlist info // Create a new ModMeta from the TTMP modlist info
var modMeta = new ModMeta var modMeta = new ModMeta
{ {
Author = modList.Author, Author = modList.Author ?? "Unknown",
Name = modList.Name, Name = modList.Name ?? "New Mod",
Description = string.IsNullOrEmpty( modList.Description ) Description = string.IsNullOrEmpty( modList.Description )
? "Mod imported from TexTools mod pack" ? "Mod imported from TexTools mod pack"
: modList.Description : modList.Description!
}; };
// Open the mod data file from the modpack as a SqPackStream // 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" ), File.WriteAllText( Path.Combine( newModFolder.FullName, "meta.json" ),
JsonConvert.SerializeObject( modMeta ) ); JsonConvert.SerializeObject( modMeta ) );
ExtractSimpleModList( newModFolder, modList.SimpleModsList, modData ); ExtractSimpleModList( newModFolder, modList.SimpleModsList ?? Enumerable.Empty< SimpleMod >(), modData );
} }
private void ImportExtendedV2ModPack( ZipFile extractedModPack, string modRaw ) private void ImportExtendedV2ModPack( ZipFile extractedModPack, string modRaw )
@ -193,12 +199,12 @@ namespace Penumbra.Importer
// Create a new ModMeta from the TTMP modlist info // Create a new ModMeta from the TTMP modlist info
var modMeta = new ModMeta var modMeta = new ModMeta
{ {
Author = modList.Author, Author = modList.Author ?? "Unknown",
Name = modList.Name, Name = modList.Name ?? "New Mod",
Description = string.IsNullOrEmpty( modList.Description ) Description = string.IsNullOrEmpty( modList.Description )
? "Mod imported from TexTools mod pack" ? "Mod imported from TexTools mod pack"
: modList.Description, : modList.Description ?? "",
Version = modList.Version Version = modList.Version ?? ""
}; };
// Open the mod data file from the modpack as a SqPackStream // Open the mod data file from the modpack as a SqPackStream
@ -222,13 +228,14 @@ namespace Penumbra.Importer
} }
// Iterate through all pages // 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() ) ); var groupFolder = new DirectoryInfo( Path.Combine( newModFolder.FullName, group.GroupName!.ReplaceInvalidPathSymbols() ) );
foreach( var option in group.OptionList ) 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() ) ); var optionFolder = new DirectoryInfo( Path.Combine( groupFolder.FullName, option.Name!.ReplaceInvalidPathSymbols() ) );
ExtractSimpleModList( optionFolder, option.ModsJsons, modData ); ExtractSimpleModList( optionFolder, option.ModsJsons!, modData );
} }
AddMeta( newModFolder, groupFolder, group, modMeta ); AddMeta( newModFolder, groupFolder, group, modMeta );
@ -242,21 +249,21 @@ namespace Penumbra.Importer
private static void AddMeta( DirectoryInfo baseFolder, DirectoryInfo groupFolder, ModGroup group, ModMeta meta ) private static void AddMeta( DirectoryInfo baseFolder, DirectoryInfo groupFolder, ModGroup group, ModMeta meta )
{ {
var Inf = new InstallerInfo var inf = new InstallerInfo
{ {
SelectionType = group.SelectionType, SelectionType = group.SelectionType,
GroupName = group.GroupName, GroupName = group.GroupName!,
Options = new List< Option >() Options = new List< Option >()
}; };
foreach( var opt in group.OptionList ) foreach( var opt in group.OptionList! )
{ {
var option = new Option var option = new Option
{ {
OptionName = opt.Name, OptionName = opt.Name!,
OptionDesc = string.IsNullOrEmpty( opt.Description ) ? "" : opt.Description, OptionDesc = string.IsNullOrEmpty( opt.Description ) ? "" : opt.Description!,
OptionFiles = new Dictionary< string, HashSet< string > >() 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 ) if( optDir.Exists )
{ {
foreach( var file in optDir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) ) 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 ) private void ImportMetaModPack( FileInfo file )

View file

@ -12,14 +12,14 @@ namespace Penumbra.Models
private readonly DirectoryInfo _baseDir; private readonly DirectoryInfo _baseDir;
private readonly int _baseDirLength; private readonly int _baseDirLength;
private readonly ModMeta _mod; private readonly ModMeta _mod;
private SHA256 _hasher; private SHA256? _hasher;
private readonly Dictionary< long, List< FileInfo > > _filesBySize = new(); private readonly Dictionary< long, List< FileInfo > > _filesBySize = new();
private ref SHA256 Sha() private SHA256 Sha()
{ {
_hasher ??= SHA256.Create(); _hasher ??= SHA256.Create();
return ref _hasher; return _hasher;
} }
public Deduplicator( DirectoryInfo baseDir, ModMeta mod ) public Deduplicator( DirectoryInfo baseDir, ModMeta mod )

View file

@ -14,7 +14,7 @@ namespace Penumbra.Models
public string OptionName; public string OptionName;
public string OptionDesc; public string OptionDesc;
[JsonProperty( ItemConverterType = typeof( SingleOrArrayConverter< string > ) )] [JsonProperty( ItemConverterType = typeof( Util.SingleOrArrayConverter< string > ) )]
public Dictionary< string, HashSet< string > > OptionFiles; public Dictionary< string, HashSet< string > > OptionFiles;
public bool AddFile( string filePath, string gamePath ) public bool AddFile( string filePath, string gamePath )

View file

@ -6,10 +6,13 @@ namespace Penumbra.Models
{ {
public class ModInfo 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 bool Enabled { get; set; }
public int Priority { get; set; } public int Priority { get; set; }
public Dictionary< string, int > Conf { get; set; } public Dictionary< string, int > Conf { get; set; } = new();
[JsonIgnore] [JsonIgnore]
public ResourceMod Mod { get; set; } public ResourceMod Mod { get; set; }

View file

@ -9,13 +9,13 @@ namespace Penumbra.Models
public class ModMeta public class ModMeta
{ {
public uint FileVersion { get; set; } public uint FileVersion { get; set; }
public string Name { get; set; } public string Name { get; set; } = "Mod";
public string Author { get; set; } public string Author { get; set; } = "";
public string Description { 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(); public List< string > ChangedItems { get; set; } = new();
@ -26,14 +26,12 @@ namespace Penumbra.Models
[JsonIgnore] [JsonIgnore]
public bool HasGroupWithConfig { get; set; } = false; public bool HasGroupWithConfig { get; set; } = false;
public static ModMeta LoadFromFile( string filePath ) public static ModMeta? LoadFromFile( string filePath )
{ {
try try
{ {
var meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( filePath ) ); var meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( filePath ) );
meta.HasGroupWithConfig = meta.HasGroupWithConfig = meta.Groups.Count > 0
meta.Groups != null
&& meta.Groups.Count > 0
&& meta.Groups.Values.Any( G => G.SelectionType == SelectType.Multi || G.Options.Count > 1 ); && meta.Groups.Values.Any( G => G.SelectionType == SelectType.Multi || G.Options.Count > 1 );
return meta; return meta;

View file

@ -12,11 +12,12 @@ namespace Penumbra.Mods
{ {
private readonly DirectoryInfo _basePath; private readonly DirectoryInfo _basePath;
public List< ModInfo > ModSettings { get; set; } public List< ModInfo >? ModSettings { get; set; }
public ResourceMod[] EnabledMods { 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 ) public void Load( bool invertOrder = false )
{ {
@ -61,20 +62,10 @@ namespace Penumbra.Mods
continue; continue;
} }
var meta = ModMeta.LoadFromFile( metaFile.FullName ); var meta = ModMeta.LoadFromFile( metaFile.FullName ) ?? new ModMeta();
if( meta == null )
{
PluginLog.LogError( "mod meta is invalid for resource mod: {ResourceModFile}", metaFile.FullName );
continue;
}
var mod = new ResourceMod var mod = new ResourceMod( meta, modDir );
{ FindOrCreateModSettings( mod );
Meta = meta,
ModBasePath = modDir
};
var modEntry = FindOrCreateModSettings( mod );
foundMods.Add( modDir.Name ); foundMods.Add( modDir.Name );
mod.RefreshModFiles(); 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 ) x => string.Equals( x.FolderName, name, StringComparison.InvariantCultureIgnoreCase )
); );
#if DEBUG #if DEBUG
@ -155,18 +146,17 @@ namespace Penumbra.Mods
public ModInfo AddModSettings( ResourceMod mod ) 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, FolderName = mod.ModBasePath.Name,
Enabled = true, Enabled = true,
Mod = mod
}; };
#if DEBUG #if DEBUG
PluginLog.Information( "creating mod settings {ModName}", entry.FolderName ); PluginLog.Information( "creating mod settings {ModName}", entry.FolderName );
#endif #endif
ModSettings ??= new List< ModInfo >();
ModSettings.Add( entry ); ModSettings.Add( entry );
return entry; return entry;
} }
@ -174,19 +164,20 @@ namespace Penumbra.Mods
public ModInfo FindOrCreateModSettings( ResourceMod mod ) public ModInfo FindOrCreateModSettings( ResourceMod mod )
{ {
var settings = FindModSettings( mod.ModBasePath.Name ); var settings = FindModSettings( mod.ModBasePath.Name );
if( settings != null ) if( settings == null )
{ {
settings.Mod = mod; return AddModSettings( mod );
return settings;
} }
return AddModSettings( mod ); settings.Mod = mod;
return settings;
} }
public IEnumerable< ModInfo > GetOrderedAndEnabledModSettings( bool invertOrder = false ) public IEnumerable< ModInfo > GetOrderedAndEnabledModSettings( bool invertOrder = false )
{ {
var query = ModSettings var query = ModSettings?
.Where( x => x.Enabled ); .Where( x => x.Enabled ) ?? Enumerable.Empty<ModInfo>();
if( !invertOrder ) if( !invertOrder )
{ {

View file

@ -13,11 +13,11 @@ namespace Penumbra.Mods
public readonly Dictionary< string, FileInfo > ResolvedFiles = new(); public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
public readonly Dictionary< string, string > SwappedFiles = 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() public void DiscoverMods()
{ {
@ -104,31 +104,26 @@ namespace Penumbra.Mods
ResolvedFiles.Clear(); ResolvedFiles.Clear();
SwappedFiles.Clear(); SwappedFiles.Clear();
if( Mods == null )
{
return;
}
var registeredFiles = new Dictionary< string, string >(); 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(); mod.FileConflicts.Clear();
if( settings.Conf == null )
{
settings.Conf = new Dictionary< string, int >();
Mods.Save();
}
ProcessModFiles( registeredFiles, mod, settings ); ProcessModFiles( registeredFiles, mod, settings );
ProcessSwappedFiles( registeredFiles, mod, settings ); ProcessSwappedFiles( registeredFiles, mod, settings );
} }
_plugin.GameUtils.ReloadPlayerResources(); _plugin!.GameUtils!.ReloadPlayerResources();
} }
private void ProcessSwappedFiles( Dictionary< string, string > registeredFiles, ResourceMod mod, ModInfo settings ) private void ProcessSwappedFiles( Dictionary< string, string > registeredFiles, ResourceMod mod, ModInfo settings )
{ {
if( mod?.Meta?.FileSwaps == null )
{
return;
}
foreach( var swap in mod.Meta.FileSwaps ) foreach( var swap in mod.Meta.FileSwaps )
{ {
// just assume people put not fucked paths in here lol // 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 ] >= group.Options.Count )
{ {
settings.Conf[ group.GroupName ] = 0; settings.Conf[ group.GroupName ] = 0;
Mods.Save(); Mods!.Save();
setting = 0; setting = 0;
} }
@ -240,13 +235,13 @@ namespace Penumbra.Mods
public void ChangeModPriority( ModInfo info, bool up = false ) public void ChangeModPriority( ModInfo info, bool up = false )
{ {
Mods.ReorderMod( info, up ); Mods!.ReorderMod( info, up );
CalculateEffectiveFileList(); CalculateEffectiveFileList();
} }
public void DeleteMod( ResourceMod mod ) public void DeleteMod( ResourceMod? mod )
{ {
if( mod?.ModBasePath?.Exists ?? false ) if( mod?.ModBasePath.Exists ?? false )
{ {
try try
{ {
@ -261,7 +256,7 @@ namespace Penumbra.Mods
DiscoverMods(); DiscoverMods();
} }
public FileInfo GetCandidateForGameFile( string gameResourcePath ) public FileInfo? GetCandidateForGameFile( string gameResourcePath )
{ {
var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate ); var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate );
if( !val ) if( !val )
@ -277,10 +272,10 @@ namespace Penumbra.Mods
return candidate; return candidate;
} }
public string GetSwappedFilePath( string gameResourcePath ) public string? GetSwappedFilePath( string gameResourcePath )
=> SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null; => SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null;
public string ResolveSwappedOrReplacementFilePath( string gameResourcePath ) public string? ResolveSwappedOrReplacementFilePath( string gameResourcePath )
{ {
gameResourcePath = gameResourcePath.ToLowerInvariant(); gameResourcePath = gameResourcePath.ToLowerInvariant();

View file

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using Dalamud.Plugin; using Dalamud.Plugin;
using Penumbra.Models; using Penumbra.Models;
@ -7,6 +8,12 @@ namespace Penumbra.Mods
{ {
public class ResourceMod public class ResourceMod
{ {
public ResourceMod( ModMeta meta, DirectoryInfo dir )
{
Meta = meta;
ModBasePath = dir;
}
public ModMeta Meta { get; set; } public ModMeta Meta { get; set; }
public DirectoryInfo ModBasePath { get; set; } public DirectoryInfo ModBasePath { get; set; }
@ -17,26 +24,13 @@ namespace Penumbra.Mods
public void RefreshModFiles() public void RefreshModFiles()
{ {
if( ModBasePath == null )
{
PluginLog.LogError( "no basepath has been set on {ResourceModName}", Meta.Name );
return;
}
ModFiles.Clear(); ModFiles.Clear();
// we don't care about any _files_ in the root dir, but any folders should be a game folder/file combo // 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 ) public void AddConflict( string modName, string path )

View file

@ -13,24 +13,25 @@ namespace Penumbra
{ {
public class Plugin : IDalamudPlugin 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"; 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; } private WebServer? _webServer;
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;
public void Initialize( DalamudPluginInterface pluginInterface ) public void Initialize( DalamudPluginInterface pluginInterface )
{ {
@ -61,8 +62,6 @@ namespace Penumbra
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw; PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
PluginDebugTitleStr = $"{Name} - Debug Build";
if( Configuration.EnableHttpApi ) if( Configuration.EnableHttpApi )
{ {
CreateWebServer(); CreateWebServer();
@ -97,12 +96,12 @@ namespace Penumbra
{ {
// ModManager?.Dispose(); // ModManager?.Dispose();
PluginInterface.UiBuilder.OnBuildUi -= SettingsInterface.Draw; PluginInterface!.UiBuilder.OnBuildUi -= SettingsInterface!.Draw;
PluginInterface.CommandManager.RemoveHandler( CommandName ); PluginInterface.CommandManager.RemoveHandler( CommandName );
PluginInterface.Dispose(); PluginInterface.Dispose();
ResourceLoader.Dispose(); ResourceLoader?.Dispose();
ShutdownWebServer(); ShutdownWebServer();
} }
@ -117,8 +116,8 @@ namespace Penumbra
case "reload": case "reload":
{ {
Service< ModManager >.Get().DiscoverMods(); Service< ModManager >.Get().DiscoverMods();
PluginInterface.Framework.Gui.Chat.Print( 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." $"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; break;
} }
@ -126,11 +125,11 @@ namespace Penumbra
{ {
if( args.Length > 1 ) 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 else
{ {
RefreshActors.RedrawAll( PluginInterface.ClientState.Actors ); RefreshActors.RedrawAll( PluginInterface!.ClientState.Actors );
} }
break; break;
@ -140,7 +139,7 @@ namespace Penumbra
return; return;
} }
SettingsInterface.FlipVisibility(); SettingsInterface!.FlipVisibility();
} }
} }
} }

View file

@ -32,7 +32,7 @@ namespace Penumbra.UI
public ManageModsButton( SettingsInterface ui ) public ManageModsButton( SettingsInterface ui )
{ {
_base = ui; _base = ui;
_condition = ui._plugin.PluginInterface.ClientState.Condition; _condition = ui._plugin!.PluginInterface!.ClientState.Condition;
} }
public void Draw() public void Draw()

View file

@ -39,7 +39,7 @@ namespace Penumbra.UI
_menu.InstalledTab.Selector.ResetModNamesLower(); _menu.InstalledTab.Selector.ResetModNamesLower();
_menu.InstalledTab.Selector.ClearSelection(); _menu.InstalledTab.Selector.ClearSelection();
// create the directory if it doesn't exist // create the directory if it doesn't exist
Directory.CreateDirectory( _plugin.Configuration.CurrentCollection ); Directory.CreateDirectory( _plugin!.Configuration!.CurrentCollection );
var modManager = Service< ModManager >.Get(); var modManager = Service< ModManager >.Get();
modManager.DiscoverMods( _plugin.Configuration.CurrentCollection ); modManager.DiscoverMods( _plugin.Configuration.CurrentCollection );

View file

@ -64,7 +64,7 @@ namespace Penumbra.UI
_browserTab.Draw(); _browserTab.Draw();
InstalledTab.Draw(); InstalledTab.Draw();
if( _base._plugin.Configuration.ShowAdvanced ) if( _base._plugin!.Configuration!.ShowAdvanced )
{ {
EffectiveTab.Draw(); EffectiveTab.Draw();
} }

View file

@ -12,12 +12,12 @@ namespace Penumbra.UI
private const float TextSizePadding = 5f; private const float TextSizePadding = 5f;
private ModManager _mods => Service< ModManager >.Get(); private ModManager _mods => Service< ModManager >.Get();
private (string, string)[] _fileList; private (string, string)[]? _fileList;
private float _maxGamePath; private float _maxGamePath;
public TabEffective( SettingsInterface ui ) public TabEffective( SettingsInterface ui )
{ {
RebuildFileList( ui._plugin.Configuration.ShowAdvanced ); RebuildFileList( ui._plugin!.Configuration!.ShowAdvanced );
} }
public void RebuildFileList( bool advanced ) public void RebuildFileList( bool advanced )
@ -54,7 +54,7 @@ namespace Penumbra.UI
if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) ) if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) )
{ {
foreach( var file in _fileList ) foreach( var file in _fileList ?? Enumerable.Empty<(string, string)>() )
{ {
DrawFileLine( file ); DrawFileLine( file );
} }

View file

@ -27,7 +27,7 @@ namespace Penumbra.UI
private bool _isImportRunning = false; private bool _isImportRunning = false;
private bool _hasError = false; private bool _hasError = false;
private TexToolsImport _texToolsImport = null!; private TexToolsImport? _texToolsImport;
private readonly SettingsInterface _base; private readonly SettingsInterface _base;
public TabImport( SettingsInterface ui ) => _base = ui; public TabImport( SettingsInterface ui ) => _base = ui;
@ -59,7 +59,7 @@ namespace Penumbra.UI
try try
{ {
_texToolsImport = new TexToolsImport( new DirectoryInfo( _base._plugin.Configuration.CurrentCollection ) ); _texToolsImport = new TexToolsImport( new DirectoryInfo( _base._plugin!.Configuration!.CurrentCollection ) );
_texToolsImport.ImportModPack( new FileInfo( fileName ) ); _texToolsImport.ImportModPack( new FileInfo( fileName ) );
PluginLog.Log( $"-> {fileName} OK!" ); PluginLog.Log( $"-> {fileName} OK!" );

View file

@ -11,7 +11,7 @@ namespace Penumbra.UI
// Remove the entry at idx from the list if the new string is empty, otherwise replace it. // 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 ) public static void RemoveOrChange( this List< string > list, string newString, int idx )
{ {
if( newString?.Length == 0 ) if( newString.Length == 0 )
{ {
list.RemoveAt( idx ); list.RemoveAt( idx );
} }
@ -53,29 +53,31 @@ namespace Penumbra.UI
private const uint ColorYellow = 0xFF00C8C8; private const uint ColorYellow = 0xFF00C8C8;
private const uint ColorRed = 0xFF0000C8; private const uint ColorRed = 0xFF0000C8;
private bool _editMode = false; private bool _editMode = false;
private int _selectedGroupIndex = 0; private int _selectedGroupIndex = 0;
private InstallerInfo? _selectedGroup = null; private InstallerInfo? _selectedGroup = null;
private int _selectedOptionIndex = 0; private int _selectedOptionIndex = 0;
private Option? _selectedOption = null; private Option? _selectedOption = null;
private (string label, string name)[] _changedItemsList = null; private (string label, string name)[]? _changedItemsList = null;
private float? _fileSwapOffset = null; private float? _fileSwapOffset = null;
private string _currentGamePaths = ""; 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 Selector _selector;
private readonly SettingsInterface _base; private readonly SettingsInterface _base;
private void SelectGroup( int idx ) 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; _selectedGroupIndex = idx;
if( _selectedGroupIndex >= Meta?.Groups?.Count ) if( _selectedGroupIndex >= numGroups)
{ {
_selectedGroupIndex = 0; _selectedGroupIndex = 0;
} }
if( Meta?.Groups?.Count > 0 ) if( numGroups > 0 )
{ {
_selectedGroup = Meta.Groups.ElementAt( _selectedGroupIndex ).Value; _selectedGroup = Meta.Groups.ElementAt( _selectedGroupIndex ).Value;
} }
@ -123,20 +125,21 @@ namespace Penumbra.UI
ResetState(); ResetState();
} }
private ModInfo Mod => _selector.Mod(); // This is only drawn when we have a mod selected, so we can forgive nulls.
private ModMeta Meta => Mod?.Mod?.Meta; private ModInfo Mod => _selector.Mod()!;
private ModMeta Meta => Mod.Mod.Meta;
private void Save() private void Save()
{ {
var modManager = Service< ModManager >.Get(); var modManager = Service< ModManager >.Get();
modManager.Mods.Save(); modManager.Mods?.Save();
modManager.CalculateEffectiveFileList(); modManager.CalculateEffectiveFileList();
_base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced );
} }
private void DrawAboutTab() private void DrawAboutTab()
{ {
if( !_editMode && ( Meta.Description?.Length ?? 0 ) == 0 ) if( !_editMode && Meta.Description.Length == 0 )
{ {
return; return;
} }
@ -174,13 +177,11 @@ namespace Penumbra.UI
private void DrawChangedItemsTab() private void DrawChangedItemsTab()
{ {
if( !_editMode && ( Meta.ChangedItems?.Count ?? 0 ) == 0 ) if( !_editMode && Meta.ChangedItems.Count == 0 )
{ {
return; return;
} }
Meta.ChangedItems ??= new List< string >();
var flags = _editMode var flags = _editMode
? ImGuiInputTextFlags.EnterReturnsTrue ? ImGuiInputTextFlags.EnterReturnsTrue
: ImGuiInputTextFlags.ReadOnly; : ImGuiInputTextFlags.ReadOnly;
@ -210,15 +211,7 @@ namespace Penumbra.UI
{ {
if( newItem.Length > 0 ) if( newItem.Length > 0 )
{ {
if( Meta.ChangedItems == null ) Meta.ChangedItems.Add( newItem );
{
Meta.ChangedItems = new List< string >() { newItem };
}
else
{
Meta.ChangedItems.Add( newItem );
}
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
} }
} }
@ -317,7 +310,7 @@ namespace Penumbra.UI
var len = Mod.Mod.ModBasePath.FullName.Length; var len = Mod.Mod.ModBasePath.FullName.Length;
_fullFilenameList = Mod.Mod.ModFiles.Select( F => ( F.FullName, false, ColorGreen, "" ) ).ToArray(); _fullFilenameList = Mod.Mod.ModFiles.Select( F => ( F.FullName, false, ColorGreen, "" ) ).ToArray();
if( Meta.Groups?.Count == 0 ) if( Meta.Groups.Count == 0 )
{ {
return; return;
} }
@ -369,7 +362,7 @@ namespace Penumbra.UI
if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize ) ) if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize ) )
{ {
UpdateFilenameList(); UpdateFilenameList();
foreach( var file in _fullFilenameList ) foreach( var file in _fullFilenameList! )
{ {
ImGui.PushStyleColor( ImGuiCol.Text, file.color ); ImGui.PushStyleColor( ImGuiCol.Text, file.color );
ImGui.Selectable( file.name ); ImGui.Selectable( file.name );
@ -405,7 +398,7 @@ namespace Penumbra.UI
var changed = false; var changed = false;
for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i ) for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i )
{ {
if( !_fullFilenameList[ i ].selected ) if( !_fullFilenameList![ i ].selected )
{ {
continue; continue;
} }
@ -503,7 +496,7 @@ namespace Penumbra.UI
{ {
void Selectable( uint colorNormal, uint colorReplace ) void Selectable( uint colorNormal, uint colorReplace )
{ {
var loc = _fullFilenameList[ idx ].color; var loc = _fullFilenameList![ idx ].color;
if( loc == colorNormal ) if( loc == colorNormal )
{ {
loc = colorReplace; loc = colorReplace;
@ -521,7 +514,7 @@ namespace Penumbra.UI
return; return;
} }
var fileName = _fullFilenameList[ idx ].relName; var fileName = _fullFilenameList![ idx ].relName;
if( ( ( Option )_selectedOption ).OptionFiles.TryGetValue( fileName, out var gamePaths ) ) if( ( ( Option )_selectedOption ).OptionFiles.TryGetValue( fileName, out var gamePaths ) )
{ {
Selectable( 0, ColorGreen ); Selectable( 0, ColorGreen );

View file

@ -36,7 +36,7 @@ namespace Penumbra.UI
private bool DrawEditGroupSelector() private bool DrawEditGroupSelector()
{ {
ImGui.SetNextItemWidth( OptionSelectionWidth ); ImGui.SetNextItemWidth( OptionSelectionWidth );
if( Meta.Groups.Count == 0 ) if( Meta!.Groups.Count == 0 )
{ {
ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 ); ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1 );
return false; return false;
@ -63,7 +63,7 @@ namespace Penumbra.UI
return false; return false;
} }
var group = ( InstallerInfo )_selectedGroup; var group = ( InstallerInfo )_selectedGroup!;
if( ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, group.Options.Select( O => O.OptionName ).ToArray(), if( ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, group.Options.Select( O => O.OptionName ).ToArray(),
group.Options.Count ) ) group.Options.Count ) )
{ {
@ -86,7 +86,7 @@ namespace Penumbra.UI
ImGui.SetNextItemWidth( -1 ); ImGui.SetNextItemWidth( -1 );
if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize - new Vector2( 0, 1.5f * ImGui.GetTextLineHeight() ) ) ) 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 ); DrawFileAndGamePaths( i );
} }
@ -107,9 +107,9 @@ namespace Penumbra.UI
{ {
var groupName = group.GroupName; var groupName = group.GroupName;
if( ImGuiCustom.BeginFramedGroupEdit( ref 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 ); Meta.Groups.Remove( group.GroupName );
Mod.Conf.Remove( group.GroupName ); Mod.Conf.Remove( group.GroupName );
if( groupName.Length > 0 ) if( groupName.Length > 0 )
@ -142,7 +142,7 @@ namespace Penumbra.UI
private void DrawMultiSelectorEdit( InstallerInfo group ) private void DrawMultiSelectorEdit( InstallerInfo group )
{ {
var nameBoxStart = CheckMarkSize; var nameBoxStart = CheckMarkSize;
var flag = Mod.Conf[ group.GroupName ]; var flag = Mod!.Conf[ group.GroupName ];
var modChanged = DrawMultiSelectorEditBegin( group ); var modChanged = DrawMultiSelectorEditBegin( group );
@ -194,9 +194,9 @@ namespace Penumbra.UI
{ {
var groupName = group.GroupName; var groupName = group.GroupName;
if( ImGui.InputText( $"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue ) 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 ) if( groupName != group.GroupName )
{ {
Meta.Groups.Remove( group.GroupName ); Meta.Groups.Remove( group.GroupName );
@ -218,7 +218,7 @@ namespace Penumbra.UI
private float DrawSingleSelectorEdit( InstallerInfo group ) private float DrawSingleSelectorEdit( InstallerInfo group )
{ {
var code = Mod.Conf[ group.GroupName ]; var code = Mod!.Conf[ group.GroupName ];
var selectionChanged = false; var selectionChanged = false;
var modChanged = false; var modChanged = false;
if( ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName, if( ImGuiCustom.RenameableCombo( $"##{group.GroupName}", ref code, out var newName,
@ -283,7 +283,7 @@ namespace Penumbra.UI
private void AddNewGroup( string newGroup, SelectType selectType ) private void AddNewGroup( string newGroup, SelectType selectType )
{ {
if( Meta.Groups.ContainsKey( newGroup ) || newGroup.Length <= 0 ) if( Meta!.Groups.ContainsKey( newGroup ) || newGroup.Length <= 0 )
{ {
return; return;
} }

View file

@ -48,15 +48,15 @@ namespace Penumbra.UI
_base = ui; _base = ui;
_selector = s; _selector = s;
Details = new PluginDetails( _base, _selector ); Details = new PluginDetails( _base, _selector );
_currentWebsite = Meta?.Website; _currentWebsite = Meta?.Website ?? "";
} }
private ModInfo Mod => _selector.Mod(); private ModInfo? Mod => _selector.Mod();
private ModMeta Meta => Mod?.Mod.Meta; private ModMeta? Meta => Mod?.Mod.Meta;
private void DrawName() private void DrawName()
{ {
var name = Meta.Name; var name = Meta!.Name;
if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 ) if( ImGuiCustom.InputOrText( _editMode, LabelEditName, ref name, 64 )
&& name.Length > 0 && name != Meta.Name ) && name.Length > 0 && name != Meta.Name )
{ {
@ -74,11 +74,11 @@ namespace Penumbra.UI
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector ); ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector );
ImGui.SameLine(); ImGui.SameLine();
var version = Meta.Version ?? ""; var version = Meta!.Version;
if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 ) if( ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16 )
&& version != Meta.Version ) && version != Meta.Version )
{ {
Meta.Version = version.Length > 0 ? version : null; Meta.Version = version;
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
} }
@ -87,7 +87,7 @@ namespace Penumbra.UI
ImGui.PopStyleVar(); ImGui.PopStyleVar();
ImGui.EndGroup(); ImGui.EndGroup();
} }
else if( ( Meta.Version?.Length ?? 0 ) > 0 ) else if( Meta!.Version.Length > 0 )
{ {
ImGui.Text( $"(Version {Meta.Version})" ); ImGui.Text( $"(Version {Meta.Version})" );
} }
@ -99,11 +99,11 @@ namespace Penumbra.UI
ImGui.TextColored( GreyColor, "by" ); ImGui.TextColored( GreyColor, "by" );
ImGui.SameLine(); ImGui.SameLine();
var author = Meta.Author ?? ""; var author = Meta!.Author;
if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 ) if( ImGuiCustom.InputOrText( _editMode, LabelEditAuthor, ref author, 64 )
&& author != Meta.Author ) && author != Meta.Author )
{ {
Meta.Author = author.Length > 0 ? author : null; Meta.Author = author;
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
} }
@ -117,15 +117,15 @@ namespace Penumbra.UI
{ {
ImGui.TextColored( GreyColor, "from" ); ImGui.TextColored( GreyColor, "from" );
ImGui.SameLine(); ImGui.SameLine();
var website = Meta.Website ?? ""; var website = Meta!.Website;
if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 ) if( ImGuiCustom.ResizingTextInput( LabelEditWebsite, ref website, 512 )
&& website != Meta.Website ) && website != Meta.Website )
{ {
Meta.Website = website.Length > 0 ? website : null; Meta.Website = website;
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
} }
} }
else if( ( Meta.Website?.Length ?? 0 ) > 0 ) else if( Meta!.Website.Length > 0 )
{ {
if( _currentWebsite != Meta.Website ) if( _currentWebsite != Meta.Website )
{ {
@ -181,14 +181,14 @@ namespace Penumbra.UI
private void DrawEnabledMark() private void DrawEnabledMark()
{ {
var enabled = Mod.Enabled; var enabled = Mod!.Enabled;
if( ImGui.Checkbox( LabelModEnabled, ref enabled ) ) if( ImGui.Checkbox( LabelModEnabled, ref enabled ) )
{ {
Mod.Enabled = enabled; Mod.Enabled = enabled;
var modManager = Service< ModManager >.Get(); var modManager = Service< ModManager >.Get();
modManager.Mods.Save(); modManager.Mods!.Save();
modManager.CalculateEffectiveFileList(); 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 ) ) if( ImGui.Button( ButtonOpenModFolder ) )
{ {
Process.Start( Mod.Mod.ModBasePath.FullName ); Process.Start( Mod!.Mod.ModBasePath.FullName );
} }
if( ImGui.IsItemHovered() ) if( ImGui.IsItemHovered() )
@ -240,11 +240,11 @@ namespace Penumbra.UI
{ {
if( ImGui.Button( ButtonDeduplicate ) ) if( ImGui.Button( ButtonDeduplicate ) )
{ {
new Deduplicator( Mod.Mod.ModBasePath, Meta ).Run(); new Deduplicator( Mod!.Mod.ModBasePath, Meta! ).Run();
_selector.SaveCurrentMod(); _selector.SaveCurrentMod();
Mod.Mod.RefreshModFiles(); Mod.Mod.RefreshModFiles();
Service< ModManager >.Get().CalculateEffectiveFileList(); Service< ModManager >.Get().CalculateEffectiveFileList();
_base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced );
} }
if( ImGui.IsItemHovered() ) if( ImGui.IsItemHovered() )
@ -285,7 +285,7 @@ namespace Penumbra.UI
ImGuiCustom.VerticalDistance( HeaderLineDistance ); ImGuiCustom.VerticalDistance( HeaderLineDistance );
DrawEnabledMark(); DrawEnabledMark();
if( _base._plugin.Configuration.ShowAdvanced ) if( _base._plugin!.Configuration!.ShowAdvanced )
{ {
ImGui.SameLine(); ImGui.SameLine();
DrawEditableMark(); DrawEditableMark();

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using ImGuiScene;
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Models; using Penumbra.Models;
using Penumbra.Mods; using Penumbra.Mods;
@ -32,13 +33,13 @@ namespace Penumbra.UI
private static readonly string ArrowDownString = FontAwesomeIcon.ArrowDown.ToIconString(); private static readonly string ArrowDownString = FontAwesomeIcon.ArrowDown.ToIconString();
private readonly SettingsInterface _base; private readonly SettingsInterface _base;
private ModCollection Mods => Service< ModManager >.Get().Mods; private ModCollection? Mods => Service< ModManager >.Get().Mods;
private ModInfo _mod; private ModInfo? _mod;
private int _index; private int _index;
private int? _deleteIndex; private int? _deleteIndex;
private string _modFilter = ""; private string _modFilter = "";
private string[] _modNamesLower; private string[]? _modNamesLower;
public Selector( SettingsInterface ui ) public Selector( SettingsInterface ui )
@ -49,7 +50,8 @@ namespace Penumbra.UI
public void ResetModNamesLower() 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 ) private void DrawPriorityChangeButton( string iconString, bool up, int unavailableWhen )
@ -60,8 +62,8 @@ namespace Penumbra.UI
if( ImGui.Button( iconString, SelectorButtonSizes ) ) if( ImGui.Button( iconString, SelectorButtonSizes ) )
{ {
SetSelection( _index ); SetSelection( _index );
Service< ModManager >.Get().ChangeModPriority( _mod, up ); Service< ModManager >.Get().ChangeModPriority( _mod!, up );
_modNamesLower.Swap( _index, _index + ( up ? 1 : -1 ) ); _modNamesLower!.Swap( _index, _index + ( up ? 1 : -1 ) );
_index += up ? 1 : -1; _index += up ? 1 : -1;
} }
} }
@ -77,7 +79,7 @@ namespace Penumbra.UI
if( ImGui.IsItemHovered() ) if( ImGui.IsItemHovered() )
{ {
ImGui.SetTooltip( 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 ); DrawPriorityChangeButton( ArrowUpString, false, 0 );
ImGui.SameLine(); ImGui.SameLine();
DrawPriorityChangeButton( ArrowDownString, true, Mods?.ModSettings.Count - 1 ?? 0 ); DrawPriorityChangeButton( ArrowDownString, true, Mods?.ModSettings?.Count - 1 ?? 0 );
ImGui.SameLine(); ImGui.SameLine();
DrawModTrashButton(); DrawModTrashButton();
ImGui.SameLine(); ImGui.SameLine();
@ -177,7 +179,7 @@ namespace Penumbra.UI
if( ImGui.Button( ButtonYesDelete ) ) if( ImGui.Button( ButtonYesDelete ) )
{ {
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
Service< ModManager >.Get().DeleteMod( _mod.Mod ); Service< ModManager >.Get().DeleteMod( _mod?.Mod );
ClearSelection(); ClearSelection();
_base.ReloadMods(); _base.ReloadMods();
} }
@ -210,44 +212,47 @@ namespace Penumbra.UI
// Inlay selector list // Inlay selector list
ImGui.BeginChild( LabelSelectorList, new Vector2( SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true ); 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 ]; for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ )
var modName = settings.Mod.Meta.Name;
if( _modFilter.Length > 0 && !_modNamesLower[ modIndex ].Contains( _modFilter ) )
{ {
continue; var settings = Mods.ModSettings[ modIndex ];
} var modName = settings.Mod.Meta.Name;
if( _modFilter.Length > 0 && !_modNamesLower![ modIndex ].Contains( _modFilter ) )
{
continue;
}
var changedColour = false; var changedColour = false;
if( !settings.Enabled ) if( !settings.Enabled )
{ {
ImGui.PushStyleColor( ImGuiCol.Text, DisabledModColor ); ImGui.PushStyleColor( ImGuiCol.Text, DisabledModColor );
changedColour = true; changedColour = true;
} }
else if( settings.Mod.FileConflicts.Any() ) else if( settings.Mod.FileConflicts.Any() )
{ {
ImGui.PushStyleColor( ImGuiCol.Text, ConflictingModColor ); ImGui.PushStyleColor( ImGuiCol.Text, ConflictingModColor );
changedColour = true; changedColour = true;
} }
#if DEBUG #if DEBUG
var selected = ImGui.Selectable( var selected = ImGui.Selectable(
$"id={modIndex} {modName}", $"id={modIndex} {modName}",
modIndex == _index modIndex == _index
); );
#else #else
var selected = ImGui.Selectable( modName, modIndex == _index ); var selected = ImGui.Selectable( modName, modIndex == _index );
#endif #endif
if( changedColour ) if( changedColour )
{ {
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} }
if( selected ) if( selected )
{ {
SetSelection( modIndex, settings ); SetSelection( modIndex, settings );
}
} }
} }
@ -259,9 +264,9 @@ namespace Penumbra.UI
DrawDeleteModal(); 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; _mod = info;
if( idx != _index ) if( idx != _index )
@ -286,7 +291,7 @@ namespace Penumbra.UI
} }
else else
{ {
SetSelection( idx, Mods.ModSettings[ idx ] ); SetSelection( idx, Mods!.ModSettings![ idx ] );
} }
} }
@ -294,18 +299,8 @@ namespace Penumbra.UI
public void SelectModByName( string name ) public void SelectModByName( string name )
{ {
for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ ) var idx = Mods?.ModSettings?.FindIndex( mod => mod.Mod.Meta.Name == name ) ?? -1;
{ SetSelection( idx );
var mod = Mods.ModSettings[ modIndex ];
if( mod.Mod.Meta.Name != name )
{
continue;
}
SetSelection( modIndex, mod );
return;
}
} }
private string GetCurrentModMetaFile() private string GetCurrentModMetaFile()
@ -316,18 +311,21 @@ namespace Penumbra.UI
var metaPath = GetCurrentModMetaFile(); var metaPath = GetCurrentModMetaFile();
if( metaPath.Length > 0 && File.Exists( metaPath ) ) 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(); _base._menu.InstalledTab.ModPanel.Details.ResetState();
} }
_mod.Mod.RefreshModFiles(); _mod!.Mod.RefreshModFiles();
Service< ModManager >.Get().CalculateEffectiveFileList(); Service< ModManager >.Get().CalculateEffectiveFileList();
_base._menu.EffectiveTab.RebuildFileList( _base._plugin.Configuration.ShowAdvanced ); _base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced );
ResetModNamesLower(); ResetModNamesLower();
} }
public string SaveCurrentMod() public string SaveCurrentMod()
{ {
if( _mod == null )
return "";
var metaPath = GetCurrentModMetaFile(); var metaPath = GetCurrentModMetaFile();
if( metaPath.Length > 0 ) if( metaPath.Length > 0 )
{ {

View file

@ -20,13 +20,13 @@ namespace Penumbra.UI
private const string LabelReloadResource = "Reload Player Resource"; private const string LabelReloadResource = "Reload Player Resource";
private readonly SettingsInterface _base; private readonly SettingsInterface _base;
private readonly Configuration _config; private readonly Configuration _config;
private bool _configChanged; private bool _configChanged;
public TabSettings( SettingsInterface ui ) public TabSettings( SettingsInterface ui )
{ {
_base = ui; _base = ui;
_config = _base._plugin.Configuration; _config = _base._plugin.Configuration!;
_configChanged = false; _configChanged = false;
} }
@ -64,7 +64,7 @@ namespace Penumbra.UI
{ {
_config.IsEnabled = enabled; _config.IsEnabled = enabled;
_configChanged = true; _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 ) ) if( ImGui.Button( LabelReloadResource ) )
{ {
_base._plugin.GameUtils.ReloadPlayerResources(); _base._plugin!.GameUtils!.ReloadPlayerResources();
} }
} }

View file

@ -3,46 +3,32 @@ using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
public class SingleOrArrayConverter< T > : JsonConverter namespace Penumbra.Util
{ {
public override bool CanConvert( Type objectType ) => objectType == typeof( HashSet< T > ); public class SingleOrArrayConverter< T > : JsonConverter
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
{ {
var token = JToken.Load( reader ); public override bool CanConvert( Type objectType ) => objectType == typeof( HashSet< T > );
return token.Type == JTokenType.Array
? token.ToObject< HashSet< T > >()
: new HashSet< T > { token.ToObject< T >() };
}
public override bool CanWrite => false; public override object ReadJson( JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer )
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 )
{ {
return token.ToObject< HashSet< T > >(); var token = JToken.Load( reader );
if( token.Type == JTokenType.Array )
{
return token.ToObject< HashSet< T > >() ?? new HashSet<T>();
}
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 )
{
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} }
} }