mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Fixed GamePath Serialization for FileSwaps, added FileSwap Edit menu, some formatting.
This commit is contained in:
parent
7c56de8c81
commit
67415db7c0
4 changed files with 135 additions and 25 deletions
|
|
@ -20,6 +20,8 @@ namespace Penumbra.Models
|
||||||
|
|
||||||
public List< string > ChangedItems { get; set; } = new();
|
public List< string > ChangedItems { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty( ItemConverterType = typeof( GamePathConverter ))]
|
||||||
public Dictionary< GamePath, GamePath > 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();
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,12 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
private void DrawFileSwapTab()
|
private void DrawFileSwapTab()
|
||||||
{
|
{
|
||||||
|
if( _editMode )
|
||||||
|
{
|
||||||
|
DrawFileSwapTabEdit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( !Meta.FileSwaps.Any() )
|
if( !Meta.FileSwaps.Any() )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ namespace Penumbra.UI
|
||||||
private const char GamePathsSeparator = ';';
|
private const char GamePathsSeparator = ';';
|
||||||
|
|
||||||
private static readonly string TooltipFilesTabEdit =
|
private static readonly string TooltipFilesTabEdit =
|
||||||
$"{TooltipFilesTab}\n" +
|
$"{TooltipFilesTab}\n"
|
||||||
$"Red Files are replaced in another group or a different option in this group, but not contained in the current option.";
|
+ $"Red Files are replaced in another group or a different option in this group, but not contained in the current option.";
|
||||||
|
|
||||||
private static readonly string TooltipGamePathsEdit =
|
private static readonly string TooltipGamePathsEdit =
|
||||||
$"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\n" +
|
$"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\n"
|
||||||
$"Use '{TextDefaultGamePath}' to add the original file path." +
|
+ $"Use '{TextDefaultGamePath}' to add the original file path."
|
||||||
$"Use '{TextDefaultGamePath}-#' to skip the first # relative directories.";
|
+ $"Use '{TextDefaultGamePath}-#' to skip the first # relative directories.";
|
||||||
|
|
||||||
private const float MultiEditBoxWidth = 300f;
|
private const float MultiEditBoxWidth = 300f;
|
||||||
|
|
||||||
|
|
@ -109,7 +109,8 @@ 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!.Settings[ group.GroupName ];
|
var oldConf = Mod!.Settings[ group.GroupName ];
|
||||||
Meta.Groups.Remove( group.GroupName );
|
Meta.Groups.Remove( group.GroupName );
|
||||||
|
|
@ -120,7 +121,7 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
GroupName = groupName,
|
GroupName = groupName,
|
||||||
SelectionType = SelectType.Multi,
|
SelectionType = SelectType.Multi,
|
||||||
Options = group.Options
|
Options = group.Options,
|
||||||
};
|
};
|
||||||
Mod.Settings[ groupName ] = oldConf;
|
Mod.Settings[ groupName ] = oldConf;
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +138,7 @@ namespace Penumbra.UI
|
||||||
ImGui.SetCursorPosX( nameBoxStart );
|
ImGui.SetCursorPosX( nameBoxStart );
|
||||||
ImGui.SetNextItemWidth( MultiEditBoxWidth );
|
ImGui.SetNextItemWidth( MultiEditBoxWidth );
|
||||||
if( ImGui.InputText( $"##new_{group.GroupName}_l", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue )
|
if( ImGui.InputText( $"##new_{group.GroupName}_l", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue )
|
||||||
&& newOption.Length != 0 )
|
&& newOption.Length != 0 )
|
||||||
{
|
{
|
||||||
group.Options.Add( new Option()
|
group.Options.Add( new Option()
|
||||||
{ OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
|
{ OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
|
||||||
|
|
@ -200,7 +201,7 @@ 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!.Settings[ group.GroupName ];
|
var oldConf = Mod!.Settings[ group.GroupName ];
|
||||||
if( groupName != group.GroupName )
|
if( groupName != group.GroupName )
|
||||||
|
|
@ -215,7 +216,7 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
GroupName = groupName,
|
GroupName = groupName,
|
||||||
Options = group.Options,
|
Options = group.Options,
|
||||||
SelectionType = SelectType.Single
|
SelectionType = SelectType.Single,
|
||||||
} );
|
} );
|
||||||
Mod.Settings[ groupName ] = oldConf;
|
Mod.Settings[ groupName ] = oldConf;
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +246,7 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
OptionName = newName,
|
OptionName = newName,
|
||||||
OptionDesc = "",
|
OptionDesc = "",
|
||||||
OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >()
|
OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >(),
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,7 +265,7 @@ namespace Penumbra.UI
|
||||||
group.Options[ code ] = new Option()
|
group.Options[ code ] = new Option()
|
||||||
{
|
{
|
||||||
OptionName = newName, OptionDesc = group.Options[ code ].OptionDesc,
|
OptionName = newName, OptionDesc = group.Options[ code ].OptionDesc,
|
||||||
OptionFiles = group.Options[ code ].OptionFiles
|
OptionFiles = group.Options[ code ].OptionFiles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -304,7 +305,7 @@ namespace Penumbra.UI
|
||||||
{
|
{
|
||||||
GroupName = newGroup,
|
GroupName = newGroup,
|
||||||
SelectionType = selectType,
|
SelectionType = selectType,
|
||||||
Options = new List< Option >()
|
Options = new List< Option >(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Mod.Settings[ newGroup ] = 0;
|
Mod.Settings[ newGroup ] = 0;
|
||||||
|
|
@ -362,6 +363,87 @@ namespace Penumbra.UI
|
||||||
|
|
||||||
DrawAddMultiGroupField();
|
DrawAddMultiGroupField();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawFileSwapTabEdit()
|
||||||
|
{
|
||||||
|
const string arrow = " -> ";
|
||||||
|
|
||||||
|
if( ImGui.BeginTabItem( LabelFileSwapTab ) )
|
||||||
|
{
|
||||||
|
ImGui.SetNextItemWidth( -1 );
|
||||||
|
if( ImGui.BeginListBox( LabelFileSwapHeader, AutoFillSize ) )
|
||||||
|
{
|
||||||
|
var swaps = Meta.FileSwaps.Keys.ToArray();
|
||||||
|
|
||||||
|
var arrowWidth = ImGui.CalcTextSize( arrow ).X;
|
||||||
|
var width = ( ImGui.GetWindowWidth() - arrowWidth - 4 * ImGui.GetStyle().ItemSpacing.X ) / 2;
|
||||||
|
for( var idx = 0; idx < swaps.Length + 1; ++idx )
|
||||||
|
{
|
||||||
|
var key = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : swaps[ idx ];
|
||||||
|
var value = idx == swaps.Length ? GamePath.GenerateUnchecked( "" ) : Meta.FileSwaps[ key ];
|
||||||
|
string keyString = key;
|
||||||
|
string valueString = value;
|
||||||
|
|
||||||
|
ImGui.SetNextItemWidth( width );
|
||||||
|
if( ImGui.InputTextWithHint( $"##swapLhs_{idx}", "Enter new file to be replaced...", ref keyString,
|
||||||
|
GamePath.MaxGamePathLength, ImGuiInputTextFlags.EnterReturnsTrue ) )
|
||||||
|
{
|
||||||
|
var newKey = new GamePath( keyString );
|
||||||
|
if( newKey.CompareTo( key ) != 0 )
|
||||||
|
{
|
||||||
|
if( idx < swaps.Length )
|
||||||
|
{
|
||||||
|
Meta.FileSwaps.Remove( key );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( newKey != string.Empty )
|
||||||
|
{
|
||||||
|
Meta.FileSwaps[ newKey ] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_selector.SaveCurrentMod();
|
||||||
|
if( Mod.Enabled )
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( idx < swaps.Length )
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted( arrow );
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
ImGui.SetNextItemWidth( width );
|
||||||
|
if( ImGui.InputTextWithHint( $"##swapRhs_{idx}", "Enter new replacement path...", ref valueString,
|
||||||
|
GamePath.MaxGamePathLength,
|
||||||
|
ImGuiInputTextFlags.EnterReturnsTrue ) )
|
||||||
|
{
|
||||||
|
var newValue = new GamePath( valueString );
|
||||||
|
if( newValue.CompareTo( value ) != 0 )
|
||||||
|
{
|
||||||
|
Meta.FileSwaps[ key ] = newValue;
|
||||||
|
_selector.SaveCurrentMod();
|
||||||
|
if( Mod.Enabled )
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_fileSwapOffset = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Penumbra.Util
|
namespace Penumbra.Util
|
||||||
{
|
{
|
||||||
|
|
@ -29,7 +31,7 @@ namespace Penumbra.Util
|
||||||
=> _path = CheckPre( file, baseDir ) ? Trim( Substring( file, baseDir ) ) : "";
|
=> _path = CheckPre( file, baseDir ) ? Trim( Substring( file, baseDir ) ) : "";
|
||||||
|
|
||||||
public RelPath( GamePath gamePath )
|
public RelPath( GamePath gamePath )
|
||||||
=> _path = gamePath ? ReplaceSlash( gamePath ) : "";
|
=> _path = ReplaceSlash( gamePath );
|
||||||
|
|
||||||
private static bool CheckPre( FileInfo file, DirectoryInfo baseDir )
|
private static bool CheckPre( FileInfo file, DirectoryInfo baseDir )
|
||||||
=> file.FullName.StartsWith( baseDir.FullName ) && file.FullName.Length < MaxRelPathLength;
|
=> file.FullName.StartsWith( baseDir.FullName ) && file.FullName.Length < MaxRelPathLength;
|
||||||
|
|
@ -43,9 +45,6 @@ namespace Penumbra.Util
|
||||||
private static string Trim( string path )
|
private static string Trim( string path )
|
||||||
=> path.TrimStart( '\\' );
|
=> path.TrimStart( '\\' );
|
||||||
|
|
||||||
public static implicit operator bool( RelPath relPath )
|
|
||||||
=> relPath._path.Length > 0;
|
|
||||||
|
|
||||||
public static implicit operator string( RelPath relPath )
|
public static implicit operator string( RelPath relPath )
|
||||||
=> relPath._path;
|
=> relPath._path;
|
||||||
|
|
||||||
|
|
@ -56,9 +55,9 @@ namespace Penumbra.Util
|
||||||
{
|
{
|
||||||
return rhs switch
|
return rhs switch
|
||||||
{
|
{
|
||||||
string => string.Compare( _path, _path, StringComparison.InvariantCulture ),
|
string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
|
||||||
RelPath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
|
RelPath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
|
||||||
_ => -1
|
_ => -1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,10 +119,7 @@ namespace Penumbra.Util
|
||||||
=> new( path, true );
|
=> new( path, true );
|
||||||
|
|
||||||
public static GamePath GenerateUncheckedLower( string path )
|
public static GamePath GenerateUncheckedLower( string path )
|
||||||
=> new( Lower(path), true );
|
=> new( Lower( path ), true );
|
||||||
|
|
||||||
public static implicit operator bool( GamePath gamePath )
|
|
||||||
=> gamePath._path.Length > 0;
|
|
||||||
|
|
||||||
public static implicit operator string( GamePath gamePath )
|
public static implicit operator string( GamePath gamePath )
|
||||||
=> gamePath._path;
|
=> gamePath._path;
|
||||||
|
|
@ -143,11 +139,35 @@ namespace Penumbra.Util
|
||||||
{
|
{
|
||||||
string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
|
string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
|
||||||
GamePath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
|
GamePath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
|
||||||
_ => -1
|
_ => -1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
=> _path;
|
=> _path;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public class GamePathConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert( Type objectType )
|
||||||
|
=> objectType == typeof( GamePath );
|
||||||
|
|
||||||
|
public override object ReadJson( JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer )
|
||||||
|
{
|
||||||
|
var token = JToken.Load( reader );
|
||||||
|
return token.ToObject< GamePath >();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
=> true;
|
||||||
|
|
||||||
|
public override void WriteJson( JsonWriter writer, object? value, JsonSerializer serializer )
|
||||||
|
{
|
||||||
|
if( value != null )
|
||||||
|
{
|
||||||
|
var v = ( GamePath) value;
|
||||||
|
serializer.Serialize( writer, v.ToString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue