mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-02 13:53:42 +01:00
Use GamePath and RelPath where appropriate
This commit is contained in:
parent
ee280994ce
commit
44670198ab
11 changed files with 138 additions and 162 deletions
|
|
@ -114,16 +114,19 @@ namespace Penumbra.Hooks
|
||||||
{
|
{
|
||||||
if( GetResourceSyncHook == null )
|
if( GetResourceSyncHook == null )
|
||||||
{
|
{
|
||||||
PluginLog.Error("[GetResourceHandler] GetResourceSync is null." );
|
PluginLog.Error( "[GetResourceHandler] GetResourceSync is null." );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetResourceSyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown );
|
return GetResourceSyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( GetResourceAsyncHook == null )
|
if( GetResourceAsyncHook == null )
|
||||||
{
|
{
|
||||||
PluginLog.Error("[GetResourceHandler] GetResourceAsync is null." );
|
PluginLog.Error( "[GetResourceHandler] GetResourceAsync is null." );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetResourceAsyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
return GetResourceAsyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,7 +141,7 @@ namespace Penumbra.Hooks
|
||||||
bool isUnknown
|
bool isUnknown
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var gameFsPath = Marshal.PtrToStringAnsi( new IntPtr( pPath ) );
|
var gameFsPath = GamePath.GenerateUncheckedLower( Marshal.PtrToStringAnsi( new IntPtr( pPath ) )! );
|
||||||
|
|
||||||
if( LogAllFiles )
|
if( LogAllFiles )
|
||||||
{
|
{
|
||||||
|
|
@ -152,16 +155,15 @@ namespace Penumbra.Hooks
|
||||||
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 )
|
||||||
{
|
{
|
||||||
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
||||||
}
|
}
|
||||||
|
|
||||||
var cleanPath = replacementPath.Replace( '\\', '/' );
|
var path = Encoding.ASCII.GetBytes( replacementPath );
|
||||||
var path = Encoding.ASCII.GetBytes( cleanPath );
|
|
||||||
|
|
||||||
var bPath = stackalloc byte[path.Length + 1];
|
var bPath = stackalloc byte[path.Length + 1];
|
||||||
Marshal.Copy( path, 0, new IntPtr( bPath ), path.Length );
|
Marshal.Copy( path, 0, new IntPtr( bPath ), path.Length );
|
||||||
|
|
@ -185,7 +187,7 @@ namespace Penumbra.Hooks
|
||||||
|
|
||||||
var isRooted = Path.IsPathRooted( gameFsPath );
|
var isRooted = Path.IsPathRooted( gameFsPath );
|
||||||
|
|
||||||
if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted || ReadFile == null)
|
if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted || ReadFile == null )
|
||||||
{
|
{
|
||||||
return ReadSqpackHook?.OriginalFunction( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
return ReadSqpackHook?.OriginalFunction( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
@ -216,9 +218,9 @@ namespace Penumbra.Hooks
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ReadSqpackHook == null || GetResourceSyncHook == null || GetResourceAsyncHook == null)
|
if( ReadSqpackHook == null || GetResourceSyncHook == null || GetResourceAsyncHook == null )
|
||||||
{
|
{
|
||||||
PluginLog.Error("[GetResourceHandler] Could not activate hooks because at least one was not set." );
|
PluginLog.Error( "[GetResourceHandler] Could not activate hooks because at least one was not set." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,7 +231,7 @@ namespace Penumbra.Hooks
|
||||||
ReadSqpackHook.Enable();
|
ReadSqpackHook.Enable();
|
||||||
GetResourceSyncHook.Enable();
|
GetResourceSyncHook.Enable();
|
||||||
GetResourceAsyncHook.Enable();
|
GetResourceAsyncHook.Enable();
|
||||||
|
|
||||||
IsEnabled = true;
|
IsEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ using Lumina.Data;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Penumbra.Importer.Models;
|
using Penumbra.Importer.Models;
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Importer
|
namespace Penumbra.Importer
|
||||||
{
|
{
|
||||||
|
|
@ -261,15 +262,14 @@ namespace Penumbra.Importer
|
||||||
{
|
{
|
||||||
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< RelPath, HashSet< GamePath > >()
|
||||||
};
|
};
|
||||||
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 ) )
|
||||||
{
|
{
|
||||||
option.AddFile( file.FullName.Substring( baseFolder.FullName.Length ).TrimStart( '\\' ),
|
option.AddFile( new RelPath( file, baseFolder ), new GamePath( file, optDir ) );
|
||||||
file.FullName.Substring( optDir.FullName.Length ).TrimStart( '\\' ).Replace( '\\', '/' ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Models
|
namespace Penumbra.Models
|
||||||
{
|
{
|
||||||
public class Deduplicator
|
public class Deduplicator
|
||||||
{
|
{
|
||||||
private readonly DirectoryInfo _baseDir;
|
private readonly DirectoryInfo _baseDir;
|
||||||
private readonly int _baseDirLength;
|
|
||||||
private readonly ModMeta _mod;
|
private readonly ModMeta _mod;
|
||||||
private SHA256? _hasher;
|
private SHA256? _hasher;
|
||||||
|
|
||||||
|
|
@ -24,10 +24,8 @@ namespace Penumbra.Models
|
||||||
|
|
||||||
public Deduplicator( DirectoryInfo baseDir, ModMeta mod )
|
public Deduplicator( DirectoryInfo baseDir, ModMeta mod )
|
||||||
{
|
{
|
||||||
_baseDir = baseDir;
|
_baseDir = baseDir;
|
||||||
_baseDirLength = baseDir.FullName.Length;
|
_mod = mod;
|
||||||
_mod = mod;
|
|
||||||
|
|
||||||
BuildDict();
|
BuildDict();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,8 +87,8 @@ namespace Penumbra.Models
|
||||||
|
|
||||||
private void ReplaceFile( FileInfo f1, FileInfo f2 )
|
private void ReplaceFile( FileInfo f1, FileInfo f2 )
|
||||||
{
|
{
|
||||||
var relName1 = f1.FullName.Substring( _baseDirLength ).TrimStart( '\\' );
|
RelPath relName1 = new( f1, _baseDir );
|
||||||
var relName2 = f2.FullName.Substring( _baseDirLength ).TrimStart( '\\' );
|
RelPath relName2 = new( f2, _baseDir );
|
||||||
|
|
||||||
var inOption = false;
|
var inOption = false;
|
||||||
foreach( var group in _mod.Groups.Select( g => g.Value.Options ) )
|
foreach( var group in _mod.Groups.Select( g => g.Value.Options ) )
|
||||||
|
|
@ -125,15 +123,15 @@ namespace Penumbra.Models
|
||||||
{
|
{
|
||||||
OptionName = "Required",
|
OptionName = "Required",
|
||||||
OptionDesc = "",
|
OptionDesc = "",
|
||||||
OptionFiles = new Dictionary< string, HashSet< string > >()
|
OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_mod.Groups.Add( duplicates, info );
|
_mod.Groups.Add( duplicates, info );
|
||||||
}
|
}
|
||||||
|
|
||||||
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, relName2.Replace( '\\', '/' ) );
|
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, new GamePath( relName2 ) );
|
||||||
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, relName1.Replace( '\\', '/' ) );
|
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, new GamePath( relName1 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginLog.Information( $"File {relName1} and {relName2} are identical. Deleting the second." );
|
PluginLog.Information( $"File {relName1} and {relName2} are identical. Deleting the second." );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Models
|
namespace Penumbra.Models
|
||||||
{
|
{
|
||||||
|
|
@ -14,17 +15,17 @@ namespace Penumbra.Models
|
||||||
public string OptionName;
|
public string OptionName;
|
||||||
public string OptionDesc;
|
public string OptionDesc;
|
||||||
|
|
||||||
[JsonProperty( ItemConverterType = typeof( Util.SingleOrArrayConverter< string > ) )]
|
[JsonProperty( ItemConverterType = typeof( SingleOrArrayConverter< GamePath > ) )]
|
||||||
public Dictionary< string, HashSet< string > > OptionFiles;
|
public Dictionary< RelPath, HashSet< GamePath > > OptionFiles;
|
||||||
|
|
||||||
public bool AddFile( string filePath, string gamePath )
|
public bool AddFile( RelPath filePath, GamePath gamePath )
|
||||||
{
|
{
|
||||||
if( OptionFiles.TryGetValue( filePath, out var set ) )
|
if( OptionFiles.TryGetValue( filePath, out var set ) )
|
||||||
{
|
{
|
||||||
return set.Add( gamePath );
|
return set.Add( gamePath );
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionFiles[ filePath ] = new HashSet< string >() { gamePath };
|
OptionFiles[ filePath ] = new HashSet< GamePath >() { gamePath };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Models
|
namespace Penumbra.Models
|
||||||
{
|
{
|
||||||
|
|
@ -19,7 +20,7 @@ namespace Penumbra.Models
|
||||||
|
|
||||||
public List< string > ChangedItems { get; set; } = new();
|
public List< string > ChangedItems { get; set; } = new();
|
||||||
|
|
||||||
public Dictionary< string, string > FileSwaps { get; } = new();
|
public Dictionary< GamePath, GamePath > FileSwaps { get; } = new();
|
||||||
|
|
||||||
public Dictionary< string, OptionGroup > Groups { get; set; } = new();
|
public Dictionary< string, OptionGroup > Groups { get; set; } = new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,52 +4,37 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Mods
|
namespace Penumbra.Mods
|
||||||
{
|
{
|
||||||
public class ModManager : IDisposable
|
public class ModManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Plugin _plugin;
|
private readonly Plugin _plugin;
|
||||||
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
|
public readonly Dictionary< GamePath, FileInfo > ResolvedFiles = new();
|
||||||
public readonly Dictionary< string, string > SwappedFiles = new();
|
public readonly Dictionary< GamePath, GamePath > SwappedFiles = new();
|
||||||
|
|
||||||
public ModCollection? Mods { get; set; }
|
public ModCollection? Mods { get; set; }
|
||||||
private DirectoryInfo? _basePath;
|
private DirectoryInfo? _basePath;
|
||||||
|
|
||||||
public ModManager( Plugin plugin )
|
public ModManager( Plugin plugin )
|
||||||
=> _plugin = plugin;
|
=> _plugin = plugin;
|
||||||
|
|
||||||
public void DiscoverMods()
|
public void DiscoverMods()
|
||||||
|
=> DiscoverMods( _basePath );
|
||||||
|
|
||||||
|
public void DiscoverMods( string? basePath )
|
||||||
|
=> DiscoverMods( basePath == null ? null : new DirectoryInfo( basePath ) );
|
||||||
|
|
||||||
|
public void DiscoverMods( DirectoryInfo? basePath )
|
||||||
{
|
{
|
||||||
if( _basePath == null )
|
_basePath = basePath;
|
||||||
{
|
if( basePath == null || !basePath.Exists )
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DiscoverMods( _basePath );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void DiscoverMods( string basePath )
|
|
||||||
{
|
|
||||||
DiscoverMods( new DirectoryInfo( basePath ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DiscoverMods( DirectoryInfo basePath )
|
|
||||||
{
|
|
||||||
if( basePath == null )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !basePath.Exists )
|
|
||||||
{
|
{
|
||||||
Mods = null;
|
Mods = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_basePath = basePath;
|
|
||||||
|
|
||||||
// FileSystemPasta();
|
// FileSystemPasta();
|
||||||
|
|
||||||
Mods = new ModCollection( basePath );
|
Mods = new ModCollection( basePath );
|
||||||
|
|
@ -69,7 +54,7 @@ namespace Penumbra.Mods
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var registeredFiles = new Dictionary< string, string >();
|
var registeredFiles = new Dictionary< GamePath, string >();
|
||||||
|
|
||||||
foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin!.Configuration!.InvertModListOrder ) )
|
foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin!.Configuration!.InvertModListOrder ) )
|
||||||
{
|
{
|
||||||
|
|
@ -82,15 +67,15 @@ namespace Penumbra.Mods
|
||||||
_plugin!.GameUtils!.ReloadPlayerResources();
|
_plugin!.GameUtils!.ReloadPlayerResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessSwappedFiles( Dictionary< string, string > registeredFiles, ResourceMod mod, ModInfo settings )
|
private void ProcessSwappedFiles( Dictionary< GamePath, string > registeredFiles, ResourceMod mod, ModInfo settings )
|
||||||
{
|
{
|
||||||
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
|
||||||
if( !SwappedFiles.ContainsKey( swap.Value ) )
|
if( !SwappedFiles.ContainsKey( swap.Value ) )
|
||||||
{
|
{
|
||||||
SwappedFiles[ swap.Key.ToLowerInvariant() ] = swap.Value;
|
SwappedFiles[ swap.Key ] = swap.Value;
|
||||||
registeredFiles[ swap.Key ] = mod.Meta.Name;
|
registeredFiles[ swap.Key ] = mod.Meta.Name;
|
||||||
}
|
}
|
||||||
else if( registeredFiles.TryGetValue( swap.Key, out var modName ) )
|
else if( registeredFiles.TryGetValue( swap.Key, out var modName ) )
|
||||||
{
|
{
|
||||||
|
|
@ -99,18 +84,13 @@ namespace Penumbra.Mods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessModFiles( Dictionary< string, string > registeredFiles, ResourceMod mod, ModInfo settings )
|
private void ProcessModFiles( Dictionary< GamePath, string > registeredFiles, ResourceMod mod, ModInfo settings )
|
||||||
{
|
{
|
||||||
var baseDir = mod.ModBasePath.FullName;
|
|
||||||
|
|
||||||
foreach( var file in mod.ModFiles )
|
foreach( var file in mod.ModFiles )
|
||||||
{
|
{
|
||||||
var relativeFilePath = file.FullName.Substring( baseDir.Length ).TrimStart( '\\' );
|
RelPath relativeFilePath = new( file, mod.ModBasePath );
|
||||||
|
var doNotAdd = false;
|
||||||
var doNotAdd = false;
|
foreach( var group in mod.Meta.Groups.Values )
|
||||||
|
|
||||||
HashSet< string > paths;
|
|
||||||
foreach( var group in mod.Meta.Groups.Select( G => G.Value ) )
|
|
||||||
{
|
{
|
||||||
if( !settings.Conf.TryGetValue( group.GroupName, out var setting )
|
if( !settings.Conf.TryGetValue( group.GroupName, out var setting )
|
||||||
|| group.SelectionType == SelectType.Single
|
|| group.SelectionType == SelectType.Single
|
||||||
|
|
@ -131,20 +111,18 @@ namespace Penumbra.Mods
|
||||||
settings.Conf[ group.GroupName ] &= ( 1 << group.Options.Count ) - 1;
|
settings.Conf[ group.GroupName ] &= ( 1 << group.Options.Count ) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet< GamePath > paths;
|
||||||
switch( group.SelectionType )
|
switch( group.SelectionType )
|
||||||
{
|
{
|
||||||
case SelectType.Single:
|
case SelectType.Single:
|
||||||
if( group.Options[ setting ].OptionFiles.TryGetValue( relativeFilePath, out paths ) )
|
if( group.Options[ setting ].OptionFiles.TryGetValue( relativeFilePath, out paths ) )
|
||||||
{
|
{
|
||||||
AddFiles( paths, out doNotAdd, file, registeredFiles, mod );
|
doNotAdd |= AddFiles( paths, file, registeredFiles, mod );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( group.Options.Where( ( o, i ) => i != setting )
|
doNotAdd |= group.Options.Where( ( o, i ) => i != setting )
|
||||||
.Any( option => option.OptionFiles.ContainsKey( relativeFilePath ) ) )
|
.Any( option => option.OptionFiles.ContainsKey( relativeFilePath ) );
|
||||||
{
|
|
||||||
doNotAdd = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -155,12 +133,12 @@ namespace Penumbra.Mods
|
||||||
{
|
{
|
||||||
if( group.Options[ i ].OptionFiles.TryGetValue( relativeFilePath, out paths ) )
|
if( group.Options[ i ].OptionFiles.TryGetValue( relativeFilePath, out paths ) )
|
||||||
{
|
{
|
||||||
AddFiles( paths, out doNotAdd, file, registeredFiles, mod );
|
doNotAdd |= AddFiles( paths, file, registeredFiles, mod );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( group.Options[ i ].OptionFiles.ContainsKey( relativeFilePath ) )
|
else
|
||||||
{
|
{
|
||||||
doNotAdd = true;
|
doNotAdd |= group.Options[ i ].OptionFiles.ContainsKey( relativeFilePath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,27 +148,27 @@ namespace Penumbra.Mods
|
||||||
|
|
||||||
if( !doNotAdd )
|
if( !doNotAdd )
|
||||||
{
|
{
|
||||||
AddFiles( new HashSet< string > { relativeFilePath.Replace( '\\', '/' ) }, out doNotAdd, file, registeredFiles, mod );
|
AddFiles( new GamePath[] { new( relativeFilePath ) }, file, registeredFiles, mod );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddFiles( HashSet< string > gamePaths, out bool doNotAdd, FileInfo file, Dictionary< string, string > registeredFiles,
|
private bool AddFiles( IEnumerable< GamePath > gamePaths, FileInfo file, Dictionary< GamePath, string > registeredFiles,
|
||||||
ResourceMod mod )
|
ResourceMod mod )
|
||||||
{
|
{
|
||||||
doNotAdd = true;
|
|
||||||
foreach( var gamePath in gamePaths )
|
foreach( var gamePath in gamePaths )
|
||||||
{
|
{
|
||||||
if( !ResolvedFiles.ContainsKey( gamePath ) )
|
if( !ResolvedFiles.ContainsKey( gamePath ) )
|
||||||
{
|
{
|
||||||
ResolvedFiles[ gamePath.ToLowerInvariant() ] = file;
|
ResolvedFiles[ gamePath ] = file;
|
||||||
registeredFiles[ gamePath ] = mod.Meta.Name;
|
registeredFiles[ gamePath ] = mod.Meta.Name;
|
||||||
}
|
}
|
||||||
else if( registeredFiles.TryGetValue( gamePath, out var modName ) )
|
else if( registeredFiles.TryGetValue( gamePath, out var modName ) )
|
||||||
{
|
{
|
||||||
mod.AddConflict( modName, gamePath );
|
mod.AddConflict( modName, gamePath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeModPriority( ModInfo info, bool up = false )
|
public void ChangeModPriority( ModInfo info, bool up = false )
|
||||||
|
|
@ -216,7 +194,7 @@ namespace Penumbra.Mods
|
||||||
DiscoverMods();
|
DiscoverMods();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileInfo? GetCandidateForGameFile( string gameResourcePath )
|
public FileInfo? GetCandidateForGameFile( GamePath gameResourcePath )
|
||||||
{
|
{
|
||||||
var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate );
|
var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate );
|
||||||
if( !val )
|
if( !val )
|
||||||
|
|
@ -232,15 +210,11 @@ namespace Penumbra.Mods
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetSwappedFilePath( string gameResourcePath )
|
public GamePath? GetSwappedFilePath( GamePath 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( GamePath gameResourcePath )
|
||||||
{
|
=> GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath ) ?? null;
|
||||||
gameResourcePath = gameResourcePath.ToLowerInvariant();
|
|
||||||
|
|
||||||
return GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Mods
|
namespace Penumbra.Mods
|
||||||
{
|
{
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Penumbra.Mods
|
||||||
|
|
||||||
public List< FileInfo > ModFiles { get; } = new();
|
public List< FileInfo > ModFiles { get; } = new();
|
||||||
|
|
||||||
public Dictionary< string, List< string > > FileConflicts { get; } = new();
|
public Dictionary< string, List< GamePath > > FileConflicts { get; } = new();
|
||||||
|
|
||||||
public void RefreshModFiles()
|
public void RefreshModFiles()
|
||||||
{
|
{
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Penumbra.Mods
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddConflict( string modName, string path )
|
public void AddConflict( string modName, GamePath path )
|
||||||
{
|
{
|
||||||
if( FileConflicts.TryGetValue( modName, out var arr ) )
|
if( FileConflicts.TryGetValue( modName, out var arr ) )
|
||||||
{
|
{
|
||||||
|
|
@ -45,10 +45,7 @@ namespace Penumbra.Mods
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileConflicts[ modName ] = new List< string >
|
FileConflicts[ modName ] = new List< GamePath > { path };
|
||||||
{
|
|
||||||
path
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.UI
|
namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
|
|
@ -12,8 +14,7 @@ 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 float _maxGamePath;
|
||||||
private float _maxGamePath;
|
|
||||||
|
|
||||||
public TabEffective( SettingsInterface ui )
|
public TabEffective( SettingsInterface ui )
|
||||||
{
|
{
|
||||||
|
|
@ -24,24 +25,24 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
if( advanced )
|
if( advanced )
|
||||||
{
|
{
|
||||||
_fileList = _mods.ResolvedFiles.Select( P => ( P.Value.FullName, P.Key ) ).ToArray();
|
_maxGamePath = TextSizePadding + ( _mods.ResolvedFiles.Count > 0
|
||||||
_maxGamePath = ( _fileList.Length > 0 ? _fileList.Max( P => ImGui.CalcTextSize( P.Item2 ).X ) : 0f ) + TextSizePadding;
|
? _mods.ResolvedFiles.Keys.Max( f => ImGui.CalcTextSize( f ).X )
|
||||||
|
: 0f );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_fileList = null;
|
|
||||||
_maxGamePath = 0f;
|
_maxGamePath = 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawFileLine( (string, string) file )
|
private void DrawFileLine( FileInfo file, GamePath path )
|
||||||
{
|
{
|
||||||
ImGui.Selectable( file.Item2 );
|
ImGui.Selectable( path );
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.SetCursorPosX( _maxGamePath );
|
ImGui.SetCursorPosX( _maxGamePath );
|
||||||
ImGui.TextUnformatted( " <-- " );
|
ImGui.TextUnformatted( " <-- " );
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Selectable( file.Item1 );
|
ImGui.Selectable( file.FullName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
|
|
@ -54,9 +55,9 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) )
|
if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) )
|
||||||
{
|
{
|
||||||
foreach( var file in _fileList ?? Enumerable.Empty<(string, string)>() )
|
foreach( var file in _mods.ResolvedFiles )
|
||||||
{
|
{
|
||||||
DrawFileLine( file );
|
DrawFileLine( file.Value, file.Key );
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.ListBoxFooter();
|
ImGui.ListBoxFooter();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.UI
|
namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
internal static class Extension
|
internal static class ListRemoveExtension
|
||||||
{
|
{
|
||||||
// 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 )
|
||||||
|
|
@ -53,16 +55,16 @@ 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;
|
||||||
private int _selectedGroupIndex = 0;
|
private int _selectedGroupIndex;
|
||||||
private OptionGroup? _selectedGroup = null;
|
private OptionGroup? _selectedGroup;
|
||||||
private int _selectedOptionIndex = 0;
|
private int _selectedOptionIndex;
|
||||||
private Option? _selectedOption = null;
|
private Option? _selectedOption;
|
||||||
private (string label, string name)[]? _changedItemsList = null;
|
private (string label, string name)[]? _changedItemsList;
|
||||||
private float? _fileSwapOffset = null;
|
private float? _fileSwapOffset;
|
||||||
private string _currentGamePaths = "";
|
private string _currentGamePaths = "";
|
||||||
|
|
||||||
private (string name, bool selected, uint color, string relName)[]? _fullFilenameList = null;
|
private (FileInfo name, bool selected, uint color, RelPath relName)[]? _fullFilenameList;
|
||||||
|
|
||||||
private readonly Selector _selector;
|
private readonly Selector _selector;
|
||||||
private readonly SettingsInterface _base;
|
private readonly SettingsInterface _base;
|
||||||
|
|
@ -72,7 +74,7 @@ namespace Penumbra.UI
|
||||||
// Not using the properties here because we need it to be not null forgiving in this case.
|
// 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;
|
var numGroups = _selector.Mod()?.Mod.Meta.Groups.Count ?? 0;
|
||||||
_selectedGroupIndex = idx;
|
_selectedGroupIndex = idx;
|
||||||
if( _selectedGroupIndex >= numGroups)
|
if( _selectedGroupIndex >= numGroups )
|
||||||
{
|
{
|
||||||
_selectedGroupIndex = 0;
|
_selectedGroupIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +89,8 @@ namespace Penumbra.UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectGroup() => SelectGroup( _selectedGroupIndex );
|
private void SelectGroup()
|
||||||
|
=> SelectGroup( _selectedGroupIndex );
|
||||||
|
|
||||||
private void SelectOption( int idx )
|
private void SelectOption( int idx )
|
||||||
{
|
{
|
||||||
|
|
@ -107,7 +110,8 @@ namespace Penumbra.UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectOption() => SelectOption( _selectedOptionIndex );
|
private void SelectOption()
|
||||||
|
=> SelectOption( _selectedOptionIndex );
|
||||||
|
|
||||||
public void ResetState()
|
public void ResetState()
|
||||||
{
|
{
|
||||||
|
|
@ -191,7 +195,8 @@ namespace Penumbra.UI
|
||||||
ImGui.SetNextItemWidth( -1 );
|
ImGui.SetNextItemWidth( -1 );
|
||||||
if( ImGui.ListBoxHeader( LabelChangedItemsHeader, AutoFillSize ) )
|
if( ImGui.ListBoxHeader( LabelChangedItemsHeader, AutoFillSize ) )
|
||||||
{
|
{
|
||||||
_changedItemsList ??= Meta.ChangedItems.Select( ( I, index ) => ( $"{LabelChangedItemIdx}{index}", I ) ).ToArray();
|
_changedItemsList ??= Meta.ChangedItems
|
||||||
|
.Select( ( I, index ) => ( $"{LabelChangedItemIdx}{index}", I ) ).ToArray();
|
||||||
|
|
||||||
for( var i = 0; i < Meta.ChangedItems.Count; ++i )
|
for( var i = 0; i < Meta.ChangedItems.Count; ++i )
|
||||||
{
|
{
|
||||||
|
|
@ -207,13 +212,11 @@ namespace Penumbra.UI
|
||||||
if( _editMode )
|
if( _editMode )
|
||||||
{
|
{
|
||||||
ImGui.SetNextItemWidth( -1 );
|
ImGui.SetNextItemWidth( -1 );
|
||||||
if( ImGui.InputText( LabelChangedItemNew, ref newItem, 128, flags ) )
|
if( ImGui.InputText( LabelChangedItemNew, ref newItem, 128, flags )
|
||||||
|
&& newItem.Length > 0 )
|
||||||
{
|
{
|
||||||
if( newItem.Length > 0 )
|
Meta.ChangedItems.Add( newItem );
|
||||||
{
|
_selector.SaveCurrentMod();
|
||||||
Meta.ChangedItems.Add( newItem );
|
|
||||||
_selector.SaveCurrentMod();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,12 +233,7 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
private void DrawConflictTab()
|
private void DrawConflictTab()
|
||||||
{
|
{
|
||||||
if( !Mod.Mod.FileConflicts.Any() )
|
if( !Mod.Mod.FileConflicts.Any() || !ImGui.BeginTabItem( LabelConflictsTab ) )
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !ImGui.BeginTabItem( LabelConflictsTab ) )
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -275,7 +273,8 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
if( ImGui.BeginTabItem( LabelFileSwapTab ) )
|
if( ImGui.BeginTabItem( LabelFileSwapTab ) )
|
||||||
{
|
{
|
||||||
_fileSwapOffset ??= Meta.FileSwaps.Max( P => ImGui.CalcTextSize( P.Key ).X ) + TextSizePadding;
|
_fileSwapOffset ??= Meta.FileSwaps
|
||||||
|
.Max( P => ImGui.CalcTextSize( P.Key ).X ) + TextSizePadding;
|
||||||
|
|
||||||
ImGui.SetNextItemWidth( -1 );
|
ImGui.SetNextItemWidth( -1 );
|
||||||
if( ImGui.ListBoxHeader( LabelFileSwapHeader, AutoFillSize ) )
|
if( ImGui.ListBoxHeader( LabelFileSwapHeader, AutoFillSize ) )
|
||||||
|
|
@ -308,7 +307,8 @@ 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, false, ColorGreen, new RelPath( F, Mod.Mod.ModBasePath ) ) ).ToArray();
|
||||||
|
|
||||||
if( Meta.Groups.Count == 0 )
|
if( Meta.Groups.Count == 0 )
|
||||||
{
|
{
|
||||||
|
|
@ -317,12 +317,6 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i )
|
for( var i = 0; i < Mod.Mod.ModFiles.Count; ++i )
|
||||||
{
|
{
|
||||||
_fullFilenameList[ i ].relName = _fullFilenameList[ i ].name.Substring( len ).TrimStart( '\\' );
|
|
||||||
if( Meta.Groups == null )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach( var group in Meta.Groups.Values )
|
foreach( var group in Meta.Groups.Values )
|
||||||
{
|
{
|
||||||
var inAll = true;
|
var inAll = true;
|
||||||
|
|
@ -365,7 +359,7 @@ namespace Penumbra.UI
|
||||||
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.FullName );
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,8 +382,8 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
var option = ( Option )_selectedOption;
|
var option = ( Option )_selectedOption;
|
||||||
|
|
||||||
var gamePaths = _currentGamePaths.Split( ';' );
|
var gamePaths = _currentGamePaths.Split( ';' ).Select( P => new GamePath( P ) ).ToArray();
|
||||||
if( gamePaths.Length == 0 || gamePaths[ 0 ].Length == 0 )
|
if( gamePaths.Length == 0 || ( ( string )gamePaths[ 0 ] ).Length == 0 )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -403,27 +397,28 @@ namespace Penumbra.UI
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = _fullFilenameList[ i ].relName;
|
var relName = _fullFilenameList[ i ].relName;
|
||||||
if( defaultIndex >= 0 )
|
if( defaultIndex >= 0 )
|
||||||
{
|
{
|
||||||
gamePaths[ ( int )defaultIndex ] = fileName.Replace( '\\', '/' );
|
gamePaths[ defaultIndex ] = new GamePath( relName );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( remove && option.OptionFiles.TryGetValue( fileName, out var setPaths ) )
|
if( remove && option.OptionFiles.TryGetValue( relName, out var setPaths ) )
|
||||||
{
|
{
|
||||||
if( setPaths.RemoveWhere( P => gamePaths.Contains( P ) ) > 0 )
|
if( setPaths.RemoveWhere( P => gamePaths.Contains( P ) ) > 0 )
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( setPaths.Count == 0 && option.OptionFiles.Remove( fileName ) )
|
if( setPaths.Count == 0 && option.OptionFiles.Remove( relName ) )
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
changed = gamePaths.Aggregate( changed, ( current, gamePath ) => current | option.AddFile( fileName, gamePath ) );
|
changed = gamePaths
|
||||||
|
.Aggregate( changed, ( current, gamePath ) => current | option.AddFile( relName, gamePath ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,7 +498,7 @@ namespace Penumbra.UI
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.PushStyleColor( ImGuiCol.Text, loc );
|
ImGui.PushStyleColor( ImGuiCol.Text, loc );
|
||||||
ImGui.Selectable( _fullFilenameList[ idx ].name, ref _fullFilenameList[ idx ].selected );
|
ImGui.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected );
|
||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -514,22 +509,28 @@ namespace Penumbra.UI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = _fullFilenameList![ idx ].relName;
|
var fileName = _fullFilenameList![ idx ].relName;
|
||||||
if( ( ( Option )_selectedOption ).OptionFiles.TryGetValue( fileName, out var gamePaths ) )
|
var optionFiles = ( ( Option )_selectedOption ).OptionFiles;
|
||||||
|
if( optionFiles.TryGetValue( fileName, out var gamePaths ) )
|
||||||
{
|
{
|
||||||
Selectable( 0, ColorGreen );
|
Selectable( 0, ColorGreen );
|
||||||
|
|
||||||
ImGui.Indent( indent );
|
ImGui.Indent( indent );
|
||||||
foreach( var gamePath in gamePaths )
|
var tmpPaths = gamePaths.ToArray();
|
||||||
|
foreach( var gamePath in tmpPaths )
|
||||||
{
|
{
|
||||||
var tmp = gamePath;
|
string tmp = gamePath;
|
||||||
if( ImGui.InputText( $"##{fileName}_{gamePath}", ref tmp, 128, ImGuiInputTextFlags.EnterReturnsTrue )
|
if( ImGui.InputText( $"##{fileName}_{gamePath}", ref tmp, 128, ImGuiInputTextFlags.EnterReturnsTrue )
|
||||||
&& tmp != gamePath )
|
&& tmp != gamePath )
|
||||||
{
|
{
|
||||||
gamePaths.Remove( gamePath );
|
gamePaths.Remove( gamePath );
|
||||||
if( tmp.Length > 0 )
|
if( tmp.Length > 0 )
|
||||||
{
|
{
|
||||||
gamePaths.Add( tmp );
|
gamePaths.Add( new GamePath( tmp ) );
|
||||||
|
}
|
||||||
|
else if( gamePaths.Count == 0 )
|
||||||
|
{
|
||||||
|
optionFiles.Remove( fileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
_selector.SaveCurrentMod();
|
_selector.SaveCurrentMod();
|
||||||
|
|
@ -547,7 +548,6 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
private void DrawMultiSelectorCheckBox( OptionGroup group, int idx, int flag, string label )
|
private void DrawMultiSelectorCheckBox( OptionGroup group, int idx, int flag, string label )
|
||||||
{
|
{
|
||||||
var opt = group.Options[ idx ];
|
|
||||||
var enabled = ( flag & ( 1 << idx ) ) != 0;
|
var enabled = ( flag & ( 1 << idx ) ) != 0;
|
||||||
var oldEnabled = enabled;
|
var oldEnabled = enabled;
|
||||||
if( ImGui.Checkbox( label, ref enabled ) && oldEnabled != enabled )
|
if( ImGui.Checkbox( label, ref enabled ) && oldEnabled != enabled )
|
||||||
|
|
@ -601,8 +601,6 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
DrawMultiSelector( g );
|
DrawMultiSelector( g );
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawConfigurationTab()
|
private void DrawConfigurationTab()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Penumbra.Models;
|
using Penumbra.Models;
|
||||||
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.UI
|
namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
|
|
@ -134,7 +135,7 @@ namespace Penumbra.UI
|
||||||
&& newOption.Length != 0 )
|
&& newOption.Length != 0 )
|
||||||
{
|
{
|
||||||
group.Options.Add( new Option()
|
group.Options.Add( new Option()
|
||||||
{ OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< string, HashSet< string > >() } );
|
{ OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
|
||||||
_selector.SaveCurrentMod();
|
_selector.SaveCurrentMod();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -232,7 +233,7 @@ namespace Penumbra.UI
|
||||||
modChanged = true;
|
modChanged = true;
|
||||||
Mod.Conf[ group.GroupName ] = code;
|
Mod.Conf[ group.GroupName ] = code;
|
||||||
group.Options.Add( new Option()
|
group.Options.Add( new Option()
|
||||||
{ OptionName = newName, OptionDesc = "", OptionFiles = new Dictionary< string, HashSet< string > >() } );
|
{ OptionName = newName, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@ namespace Penumbra.Util
|
||||||
public static GamePath GenerateUnchecked( string path )
|
public static GamePath GenerateUnchecked( string path )
|
||||||
=> new( path, true );
|
=> new( path, true );
|
||||||
|
|
||||||
|
public static GamePath GenerateUncheckedLower( string path )
|
||||||
|
=> new( Lower(path), true );
|
||||||
|
|
||||||
public static implicit operator bool( GamePath gamePath )
|
public static implicit operator bool( GamePath gamePath )
|
||||||
=> gamePath._path.Length > 0;
|
=> gamePath._path.Length > 0;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue