Fixed GamePath Serialization for FileSwaps, added FileSwap Edit menu, some formatting.

This commit is contained in:
Ottermandias 2021-04-19 00:41:18 +02:00
parent 7c56de8c81
commit 67415db7c0
4 changed files with 135 additions and 25 deletions

View file

@ -20,6 +20,8 @@ namespace Penumbra.Models
public List< string > ChangedItems { get; set; } = new();
[JsonProperty( ItemConverterType = typeof( GamePathConverter ))]
public Dictionary< GamePath, GamePath > FileSwaps { get; } = new();
public Dictionary< string, OptionGroup > Groups { get; set; } = new();

View file

@ -269,6 +269,12 @@ namespace Penumbra.UI
private void DrawFileSwapTab()
{
if( _editMode )
{
DrawFileSwapTabEdit();
return;
}
if( !Meta.FileSwaps.Any() )
{
return;

View file

@ -25,13 +25,13 @@ namespace Penumbra.UI
private const char GamePathsSeparator = ';';
private static readonly string TooltipFilesTabEdit =
$"{TooltipFilesTab}\n" +
$"Red Files are replaced in another group or a different option in this group, but not contained in the current option.";
$"{TooltipFilesTab}\n"
+ $"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 =
$"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\n" +
$"Use '{TextDefaultGamePath}' to add the original file path." +
$"Use '{TextDefaultGamePath}-#' to skip the first # relative directories.";
$"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\n"
+ $"Use '{TextDefaultGamePath}' to add the original file path."
+ $"Use '{TextDefaultGamePath}-#' to skip the first # relative directories.";
private const float MultiEditBoxWidth = 300f;
@ -109,7 +109,8 @@ namespace Penumbra.UI
{
var groupName = group.GroupName;
if( ImGuiCustom.BeginFramedGroupEdit( ref groupName )
&& groupName != group.GroupName && !Meta!.Groups.ContainsKey( groupName ) )
&& groupName != group.GroupName
&& !Meta!.Groups.ContainsKey( groupName ) )
{
var oldConf = Mod!.Settings[ group.GroupName ];
Meta.Groups.Remove( group.GroupName );
@ -120,7 +121,7 @@ namespace Penumbra.UI
{
GroupName = groupName,
SelectionType = SelectType.Multi,
Options = group.Options
Options = group.Options,
};
Mod.Settings[ groupName ] = oldConf;
}
@ -137,7 +138,7 @@ namespace Penumbra.UI
ImGui.SetCursorPosX( nameBoxStart );
ImGui.SetNextItemWidth( MultiEditBoxWidth );
if( ImGui.InputText( $"##new_{group.GroupName}_l", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue )
&& newOption.Length != 0 )
&& newOption.Length != 0 )
{
group.Options.Add( new Option()
{ OptionName = newOption, OptionDesc = "", OptionFiles = new Dictionary< RelPath, HashSet< GamePath > >() } );
@ -200,7 +201,7 @@ namespace Penumbra.UI
{
var groupName = group.GroupName;
if( ImGui.InputText( $"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue )
&& !Meta!.Groups.ContainsKey( groupName ) )
&& !Meta!.Groups.ContainsKey( groupName ) )
{
var oldConf = Mod!.Settings[ group.GroupName ];
if( groupName != group.GroupName )
@ -215,7 +216,7 @@ namespace Penumbra.UI
{
GroupName = groupName,
Options = group.Options,
SelectionType = SelectType.Single
SelectionType = SelectType.Single,
} );
Mod.Settings[ groupName ] = oldConf;
}
@ -245,7 +246,7 @@ namespace Penumbra.UI
{
OptionName = newName,
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()
{
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,
SelectionType = selectType,
Options = new List< Option >()
Options = new List< Option >(),
};
Mod.Settings[ newGroup ] = 0;
@ -362,6 +363,87 @@ namespace Penumbra.UI
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;
}
}
}
}
}

View file

@ -1,6 +1,8 @@
using System;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Penumbra.Util
{
@ -29,7 +31,7 @@ namespace Penumbra.Util
=> _path = CheckPre( file, baseDir ) ? Trim( Substring( file, baseDir ) ) : "";
public RelPath( GamePath gamePath )
=> _path = gamePath ? ReplaceSlash( gamePath ) : "";
=> _path = ReplaceSlash( gamePath );
private static bool CheckPre( FileInfo file, DirectoryInfo baseDir )
=> file.FullName.StartsWith( baseDir.FullName ) && file.FullName.Length < MaxRelPathLength;
@ -43,9 +45,6 @@ namespace Penumbra.Util
private static string Trim( string path )
=> path.TrimStart( '\\' );
public static implicit operator bool( RelPath relPath )
=> relPath._path.Length > 0;
public static implicit operator string( RelPath relPath )
=> relPath._path;
@ -56,9 +55,9 @@ namespace Penumbra.Util
{
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 ),
_ => -1
_ => -1,
};
}
@ -120,10 +119,7 @@ namespace Penumbra.Util
=> new( path, true );
public static GamePath GenerateUncheckedLower( string path )
=> new( Lower(path), true );
public static implicit operator bool( GamePath gamePath )
=> gamePath._path.Length > 0;
=> new( Lower( path ), true );
public static implicit operator string( GamePath gamePath )
=> gamePath._path;
@ -143,11 +139,35 @@ namespace Penumbra.Util
{
string path => string.Compare( _path, path, StringComparison.InvariantCulture ),
GamePath path => string.Compare( _path, path._path, StringComparison.InvariantCulture ),
_ => -1
_ => -1,
};
}
public override string ToString()
=> _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() );
}
}
}
}