Use GamePath and RelPath where appropriate

This commit is contained in:
Ottermandias 2021-02-22 15:28:07 +01:00
parent ee280994ce
commit 44670198ab
11 changed files with 138 additions and 162 deletions

View file

@ -114,16 +114,19 @@ namespace Penumbra.Hooks
{
if( GetResourceSyncHook == null )
{
PluginLog.Error("[GetResourceHandler] GetResourceSync is 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." );
PluginLog.Error( "[GetResourceHandler] GetResourceAsync is null." );
return null;
}
return GetResourceAsyncHook.OriginalFunction( pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
}
@ -138,7 +141,7 @@ namespace Penumbra.Hooks
bool isUnknown
)
{
var gameFsPath = Marshal.PtrToStringAnsi( new IntPtr( pPath ) );
var gameFsPath = GamePath.GenerateUncheckedLower( Marshal.PtrToStringAnsi( new IntPtr( pPath ) )! );
if( LogAllFiles )
{
@ -152,16 +155,15 @@ namespace Penumbra.Hooks
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
}
var replacementPath = modManager.ResolveSwappedOrReplacementFilePath( gameFsPath! );
var replacementPath = modManager.ResolveSwappedOrReplacementFilePath( gameFsPath );
// path must be < 260 because statically defined array length :(
if( replacementPath == null || replacementPath.Length >= 260 )
if( replacementPath == null )
{
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
}
var cleanPath = replacementPath.Replace( '\\', '/' );
var path = Encoding.ASCII.GetBytes( cleanPath );
var path = Encoding.ASCII.GetBytes( replacementPath );
var bPath = stackalloc byte[path.Length + 1];
Marshal.Copy( path, 0, new IntPtr( bPath ), path.Length );
@ -185,7 +187,7 @@ namespace Penumbra.Hooks
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;
}
@ -216,9 +218,9 @@ namespace Penumbra.Hooks
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;
}

View file

@ -9,6 +9,7 @@ using Lumina.Data;
using Newtonsoft.Json;
using Penumbra.Importer.Models;
using Penumbra.Models;
using Penumbra.Util;
namespace Penumbra.Importer
{
@ -261,15 +262,14 @@ namespace Penumbra.Importer
{
OptionName = opt.Name!,
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() ) );
if( optDir.Exists )
{
foreach( var file in optDir.EnumerateFiles( "*.*", SearchOption.AllDirectories ) )
{
option.AddFile( file.FullName.Substring( baseFolder.FullName.Length ).TrimStart( '\\' ),
file.FullName.Substring( optDir.FullName.Length ).TrimStart( '\\' ).Replace( '\\', '/' ) );
option.AddFile( new RelPath( file, baseFolder ), new GamePath( file, optDir ) );
}
}

View file

@ -4,13 +4,13 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography;
using Dalamud.Plugin;
using Penumbra.Util;
namespace Penumbra.Models
{
public class Deduplicator
{
private readonly DirectoryInfo _baseDir;
private readonly int _baseDirLength;
private readonly ModMeta _mod;
private SHA256? _hasher;
@ -24,10 +24,8 @@ namespace Penumbra.Models
public Deduplicator( DirectoryInfo baseDir, ModMeta mod )
{
_baseDir = baseDir;
_baseDirLength = baseDir.FullName.Length;
_mod = mod;
_baseDir = baseDir;
_mod = mod;
BuildDict();
}
@ -89,8 +87,8 @@ namespace Penumbra.Models
private void ReplaceFile( FileInfo f1, FileInfo f2 )
{
var relName1 = f1.FullName.Substring( _baseDirLength ).TrimStart( '\\' );
var relName2 = f2.FullName.Substring( _baseDirLength ).TrimStart( '\\' );
RelPath relName1 = new( f1, _baseDir );
RelPath relName2 = new( f2, _baseDir );
var inOption = false;
foreach( var group in _mod.Groups.Select( g => g.Value.Options ) )
@ -125,15 +123,15 @@ namespace Penumbra.Models
{
OptionName = "Required",
OptionDesc = "",
OptionFiles = new Dictionary< string, HashSet< string > >()
OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >()
}
}
};
_mod.Groups.Add( duplicates, info );
}
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, relName2.Replace( '\\', '/' ) );
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, relName1.Replace( '\\', '/' ) );
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, new GamePath( relName2 ) );
_mod.Groups[ duplicates ].Options[ 0 ].AddFile( relName1, new GamePath( relName1 ) );
}
PluginLog.Information( $"File {relName1} and {relName2} are identical. Deleting the second." );

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Penumbra.Util;
namespace Penumbra.Models
{
@ -14,17 +15,17 @@ namespace Penumbra.Models
public string OptionName;
public string OptionDesc;
[JsonProperty( ItemConverterType = typeof( Util.SingleOrArrayConverter< string > ) )]
public Dictionary< string, HashSet< string > > OptionFiles;
[JsonProperty( ItemConverterType = typeof( SingleOrArrayConverter< GamePath > ) )]
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 ) )
{
return set.Add( gamePath );
}
OptionFiles[ filePath ] = new HashSet< string >() { gamePath };
OptionFiles[ filePath ] = new HashSet< GamePath >() { gamePath };
return true;
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Penumbra.Util;
namespace Penumbra.Models
{
@ -19,7 +20,7 @@ namespace Penumbra.Models
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();

View file

@ -4,52 +4,37 @@ using System.IO;
using System.Linq;
using Dalamud.Plugin;
using Penumbra.Models;
using Penumbra.Util;
namespace Penumbra.Mods
{
public class ModManager : IDisposable
{
private readonly Plugin _plugin;
public readonly Dictionary< string, FileInfo > ResolvedFiles = new();
public readonly Dictionary< string, string > SwappedFiles = new();
private readonly Plugin _plugin;
public readonly Dictionary< GamePath, FileInfo > ResolvedFiles = new();
public readonly Dictionary< GamePath, GamePath > SwappedFiles = new();
public ModCollection? Mods { get; set; }
public ModCollection? Mods { get; set; }
private DirectoryInfo? _basePath;
public ModManager( Plugin plugin )
=> _plugin = plugin;
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 )
{
return;
}
DiscoverMods( _basePath );
}
public void DiscoverMods( string basePath )
{
DiscoverMods( new DirectoryInfo( basePath ) );
}
public void DiscoverMods( DirectoryInfo basePath )
{
if( basePath == null )
{
return;
}
if( !basePath.Exists )
_basePath = basePath;
if( basePath == null || !basePath.Exists )
{
Mods = null;
return;
}
_basePath = basePath;
// FileSystemPasta();
Mods = new ModCollection( basePath );
@ -69,7 +54,7 @@ namespace Penumbra.Mods
return;
}
var registeredFiles = new Dictionary< string, string >();
var registeredFiles = new Dictionary< GamePath, string >();
foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin!.Configuration!.InvertModListOrder ) )
{
@ -82,15 +67,15 @@ namespace Penumbra.Mods
_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 )
{
// just assume people put not fucked paths in here lol
if( !SwappedFiles.ContainsKey( swap.Value ) )
{
SwappedFiles[ swap.Key.ToLowerInvariant() ] = swap.Value;
registeredFiles[ swap.Key ] = mod.Meta.Name;
SwappedFiles[ swap.Key ] = swap.Value;
registeredFiles[ swap.Key ] = mod.Meta.Name;
}
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 )
{
var relativeFilePath = file.FullName.Substring( baseDir.Length ).TrimStart( '\\' );
var doNotAdd = false;
HashSet< string > paths;
foreach( var group in mod.Meta.Groups.Select( G => G.Value ) )
RelPath relativeFilePath = new( file, mod.ModBasePath );
var doNotAdd = false;
foreach( var group in mod.Meta.Groups.Values )
{
if( !settings.Conf.TryGetValue( group.GroupName, out var setting )
|| group.SelectionType == SelectType.Single
@ -131,20 +111,18 @@ namespace Penumbra.Mods
settings.Conf[ group.GroupName ] &= ( 1 << group.Options.Count ) - 1;
}
HashSet< GamePath > paths;
switch( group.SelectionType )
{
case SelectType.Single:
if( group.Options[ setting ].OptionFiles.TryGetValue( relativeFilePath, out paths ) )
{
AddFiles( paths, out doNotAdd, file, registeredFiles, mod );
doNotAdd |= AddFiles( paths, file, registeredFiles, mod );
}
else
{
if( group.Options.Where( ( o, i ) => i != setting )
.Any( option => option.OptionFiles.ContainsKey( relativeFilePath ) ) )
{
doNotAdd = true;
}
doNotAdd |= group.Options.Where( ( o, i ) => i != setting )
.Any( option => option.OptionFiles.ContainsKey( relativeFilePath ) );
}
break;
@ -155,12 +133,12 @@ namespace Penumbra.Mods
{
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 )
{
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 )
{
doNotAdd = true;
foreach( var gamePath in gamePaths )
{
if( !ResolvedFiles.ContainsKey( gamePath ) )
{
ResolvedFiles[ gamePath.ToLowerInvariant() ] = file;
registeredFiles[ gamePath ] = mod.Meta.Name;
ResolvedFiles[ gamePath ] = file;
registeredFiles[ gamePath ] = mod.Meta.Name;
}
else if( registeredFiles.TryGetValue( gamePath, out var modName ) )
{
mod.AddConflict( modName, gamePath );
}
}
return true;
}
public void ChangeModPriority( ModInfo info, bool up = false )
@ -216,7 +194,7 @@ namespace Penumbra.Mods
DiscoverMods();
}
public FileInfo? GetCandidateForGameFile( string gameResourcePath )
public FileInfo? GetCandidateForGameFile( GamePath gameResourcePath )
{
var val = ResolvedFiles.TryGetValue( gameResourcePath, out var candidate );
if( !val )
@ -232,15 +210,11 @@ namespace Penumbra.Mods
return candidate;
}
public string? GetSwappedFilePath( string gameResourcePath )
public GamePath? GetSwappedFilePath( GamePath gameResourcePath )
=> SwappedFiles.TryGetValue( gameResourcePath, out var swappedPath ) ? swappedPath : null;
public string? ResolveSwappedOrReplacementFilePath( string gameResourcePath )
{
gameResourcePath = gameResourcePath.ToLowerInvariant();
return GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath );
}
public string? ResolveSwappedOrReplacementFilePath( GamePath gameResourcePath )
=> GetCandidateForGameFile( gameResourcePath )?.FullName ?? GetSwappedFilePath( gameResourcePath ) ?? null;
public void Dispose()

View file

@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Plugin;
using Penumbra.Models;
using Penumbra.Util;
namespace Penumbra.Mods
{
@ -20,7 +20,7 @@ namespace Penumbra.Mods
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()
{
@ -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 ) )
{
@ -45,10 +45,7 @@ namespace Penumbra.Mods
return;
}
FileConflicts[ modName ] = new List< string >
{
path
};
FileConflicts[ modName ] = new List< GamePath > { path };
}
}
}

View file

@ -1,6 +1,8 @@
using System.IO;
using System.Linq;
using ImGuiNET;
using Penumbra.Mods;
using Penumbra.Util;
namespace Penumbra.UI
{
@ -12,8 +14,7 @@ namespace Penumbra.UI
private const float TextSizePadding = 5f;
private ModManager _mods => Service< ModManager >.Get();
private (string, string)[]? _fileList;
private float _maxGamePath;
private float _maxGamePath;
public TabEffective( SettingsInterface ui )
{
@ -24,24 +25,24 @@ namespace Penumbra.UI
{
if( advanced )
{
_fileList = _mods.ResolvedFiles.Select( P => ( P.Value.FullName, P.Key ) ).ToArray();
_maxGamePath = ( _fileList.Length > 0 ? _fileList.Max( P => ImGui.CalcTextSize( P.Item2 ).X ) : 0f ) + TextSizePadding;
_maxGamePath = TextSizePadding + ( _mods.ResolvedFiles.Count > 0
? _mods.ResolvedFiles.Keys.Max( f => ImGui.CalcTextSize( f ).X )
: 0f );
}
else
{
_fileList = null;
_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.SetCursorPosX( _maxGamePath );
ImGui.TextUnformatted( " <-- " );
ImGui.SameLine();
ImGui.Selectable( file.Item1 );
ImGui.Selectable( file.FullName );
}
public void Draw()
@ -54,9 +55,9 @@ namespace Penumbra.UI
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();

View file

@ -1,12 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using System.IO;
using ImGuiNET;
using Penumbra.Models;
using Penumbra.Mods;
using Penumbra.Util;
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.
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 ColorRed = 0xFF0000C8;
private bool _editMode = false;
private int _selectedGroupIndex = 0;
private OptionGroup? _selectedGroup = null;
private int _selectedOptionIndex = 0;
private Option? _selectedOption = null;
private (string label, string name)[]? _changedItemsList = null;
private float? _fileSwapOffset = null;
private string _currentGamePaths = "";
private bool _editMode;
private int _selectedGroupIndex;
private OptionGroup? _selectedGroup;
private int _selectedOptionIndex;
private Option? _selectedOption;
private (string label, string name)[]? _changedItemsList;
private float? _fileSwapOffset;
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 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.
var numGroups = _selector.Mod()?.Mod.Meta.Groups.Count ?? 0;
_selectedGroupIndex = idx;
if( _selectedGroupIndex >= numGroups)
if( _selectedGroupIndex >= numGroups )
{
_selectedGroupIndex = 0;
}
@ -87,7 +89,8 @@ namespace Penumbra.UI
}
}
private void SelectGroup() => SelectGroup( _selectedGroupIndex );
private void SelectGroup()
=> SelectGroup( _selectedGroupIndex );
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()
{
@ -191,7 +195,8 @@ namespace Penumbra.UI
ImGui.SetNextItemWidth( -1 );
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 )
{
@ -207,13 +212,11 @@ namespace Penumbra.UI
if( _editMode )
{
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()
{
if( !Mod.Mod.FileConflicts.Any() )
{
return;
}
if( !ImGui.BeginTabItem( LabelConflictsTab ) )
if( !Mod.Mod.FileConflicts.Any() || !ImGui.BeginTabItem( LabelConflictsTab ) )
{
return;
}
@ -275,7 +273,8 @@ namespace Penumbra.UI
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 );
if( ImGui.ListBoxHeader( LabelFileSwapHeader, AutoFillSize ) )
@ -308,7 +307,8 @@ namespace Penumbra.UI
}
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 )
{
@ -317,12 +317,6 @@ namespace Penumbra.UI
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 )
{
var inAll = true;
@ -365,7 +359,7 @@ namespace Penumbra.UI
foreach( var file in _fullFilenameList! )
{
ImGui.PushStyleColor( ImGuiCol.Text, file.color );
ImGui.Selectable( file.name );
ImGui.Selectable( file.name.FullName );
ImGui.PopStyleColor();
}
@ -388,8 +382,8 @@ namespace Penumbra.UI
var option = ( Option )_selectedOption;
var gamePaths = _currentGamePaths.Split( ';' );
if( gamePaths.Length == 0 || gamePaths[ 0 ].Length == 0 )
var gamePaths = _currentGamePaths.Split( ';' ).Select( P => new GamePath( P ) ).ToArray();
if( gamePaths.Length == 0 || ( ( string )gamePaths[ 0 ] ).Length == 0 )
{
return;
}
@ -403,27 +397,28 @@ namespace Penumbra.UI
continue;
}
var fileName = _fullFilenameList[ i ].relName;
var relName = _fullFilenameList[ i ].relName;
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 )
{
changed = true;
}
if( setPaths.Count == 0 && option.OptionFiles.Remove( fileName ) )
if( setPaths.Count == 0 && option.OptionFiles.Remove( relName ) )
{
changed = true;
}
}
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.Selectable( _fullFilenameList[ idx ].name, ref _fullFilenameList[ idx ].selected );
ImGui.Selectable( _fullFilenameList[ idx ].name.FullName, ref _fullFilenameList[ idx ].selected );
ImGui.PopStyleColor();
}
@ -514,22 +509,28 @@ namespace Penumbra.UI
return;
}
var fileName = _fullFilenameList![ idx ].relName;
if( ( ( Option )_selectedOption ).OptionFiles.TryGetValue( fileName, out var gamePaths ) )
var fileName = _fullFilenameList![ idx ].relName;
var optionFiles = ( ( Option )_selectedOption ).OptionFiles;
if( optionFiles.TryGetValue( fileName, out var gamePaths ) )
{
Selectable( 0, ColorGreen );
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 )
&& tmp != gamePath )
{
gamePaths.Remove( gamePath );
if( tmp.Length > 0 )
{
gamePaths.Add( tmp );
gamePaths.Add( new GamePath( tmp ) );
}
else if( gamePaths.Count == 0 )
{
optionFiles.Remove( fileName );
}
_selector.SaveCurrentMod();
@ -547,7 +548,6 @@ namespace Penumbra.UI
private void DrawMultiSelectorCheckBox( OptionGroup group, int idx, int flag, string label )
{
var opt = group.Options[ idx ];
var enabled = ( flag & ( 1 << idx ) ) != 0;
var oldEnabled = enabled;
if( ImGui.Checkbox( label, ref enabled ) && oldEnabled != enabled )
@ -601,8 +601,6 @@ namespace Penumbra.UI
{
DrawMultiSelector( g );
}
return;
}
private void DrawConfigurationTab()

View file

@ -3,6 +3,7 @@ using System.Linq;
using System.Numerics;
using ImGuiNET;
using Penumbra.Models;
using Penumbra.Util;
namespace Penumbra.UI
{
@ -134,7 +135,7 @@ namespace Penumbra.UI
&& newOption.Length != 0 )
{
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();
}
}
@ -232,7 +233,7 @@ namespace Penumbra.UI
modChanged = true;
Mod.Conf[ group.GroupName ] = code;
group.Options.Add( new Option()
{ OptionName = newName, OptionDesc = "", OptionFiles = new Dictionary< string, HashSet< string > >() } );
{ OptionName = newName, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
}
}
else

View file

@ -110,6 +110,9 @@ namespace Penumbra.Util
public static GamePath GenerateUnchecked( string path )
=> new( path, true );
public static GamePath GenerateUncheckedLower( string path )
=> new( Lower(path), true );
public static implicit operator bool( GamePath gamePath )
=> gamePath._path.Length > 0;