Let options keep visual ordering.

This commit is contained in:
Ottermandias 2022-04-30 23:04:39 +02:00
parent f24ec8ebe2
commit 81e93e0664
9 changed files with 105 additions and 28 deletions

View file

@ -12,6 +12,7 @@
<OutputPath>bin\$(Configuration)\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -43,6 +44,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3"/>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3">
<Private>false</Private>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -173,7 +173,8 @@ public partial class TexToolsImporter
++_currentOptionIdx;
}
Mod.CreateOptionGroup( _currentModDirectory, group, groupPriority++, description.ToString(), options );
Mod.CreateOptionGroup( _currentModDirectory, group, groupPriority, groupPriority, description.ToString(), options );
++groupPriority;
}
}

View file

@ -55,7 +55,7 @@ public sealed partial class Mod
return;
}
group.DeleteFile( mod.BasePath );
group.DeleteFile( mod.BasePath, groupIdx );
var _ = group switch
{
@ -86,7 +86,7 @@ public sealed partial class Mod
{
var group = mod._groups[ groupIdx ];
mod._groups.RemoveAt( groupIdx );
group.DeleteFile( mod.BasePath );
group.DeleteFile( mod.BasePath, groupIdx );
ModOptionChanged.Invoke( ModOptionChangeType.GroupDeleted, mod, groupIdx, -1, -1 );
}
@ -400,19 +400,32 @@ public sealed partial class Mod
private static void OnModOptionChange( ModOptionChangeType type, Mod mod, int groupIdx, int _, int _2 )
{
// File deletion is handled in the actual function.
if( type != ModOptionChangeType.GroupDeleted )
if( type is ModOptionChangeType.GroupDeleted or ModOptionChangeType.GroupMoved )
{
IModGroup.SaveModGroup( mod._groups[ groupIdx ], mod.BasePath );
mod.SaveAllGroups();
}
else
{
IModGroup.SaveModGroup( mod._groups[ groupIdx ], mod.BasePath, groupIdx );
}
// State can not change on adding groups, as they have no immediate options.
mod.HasOptions = type switch
var unused = type switch
{
ModOptionChangeType.GroupDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.GroupTypeChanged => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.OptionAdded => mod.HasOptions |= mod._groups[ groupIdx ].IsOption,
ModOptionChangeType.OptionDeleted => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
_ => mod.HasOptions,
ModOptionChangeType.GroupAdded => mod.SetCounts(),
ModOptionChangeType.GroupDeleted => mod.SetCounts(),
ModOptionChangeType.GroupMoved => false,
ModOptionChangeType.GroupTypeChanged => mod.HasOptions = mod.Groups.Any( o => o.IsOption ),
ModOptionChangeType.PriorityChanged => false,
ModOptionChangeType.OptionAdded => mod.SetCounts(),
ModOptionChangeType.OptionDeleted => mod.SetCounts(),
ModOptionChangeType.OptionMoved => false,
ModOptionChangeType.OptionFilesChanged => 0 < ( mod.TotalFileCount = mod.AllSubMods.Sum( s => s.Files.Count ) ),
ModOptionChangeType.OptionSwapsChanged => 0 < ( mod.TotalSwapCount = mod.AllSubMods.Sum( s => s.FileSwaps.Count ) ),
ModOptionChangeType.OptionMetaChanged => 0 < ( mod.TotalManipulations = mod.AllSubMods.Sum( s => s.Manipulations.Count ) ),
ModOptionChangeType.OptionUpdated => mod.SetCounts(),
ModOptionChangeType.DisplayChange => false,
_ => false,
};
}
}

View file

@ -59,7 +59,7 @@ public partial class Mod
// Create a file for an option group from given data.
internal static void CreateOptionGroup( DirectoryInfo baseFolder, ModGroup groupData,
int priority, string desc, IEnumerable< ISubMod > subMods )
int priority, int index, string desc, IEnumerable< ISubMod > subMods )
{
switch( groupData.SelectionType )
{
@ -72,7 +72,7 @@ public partial class Mod
Priority = priority,
};
group.PrioritizedOptions.AddRange( subMods.OfType< SubMod >().Select( ( s, idx ) => ( s, idx ) ) );
IModGroup.SaveModGroup( group, baseFolder );
IModGroup.SaveModGroup( group, baseFolder, index );
break;
}
case SelectType.Single:
@ -84,7 +84,7 @@ public partial class Mod
Priority = priority,
};
group.OptionData.AddRange( subMods.OfType< SubMod >() );
IModGroup.SaveModGroup( group, baseFolder );
IModGroup.SaveModGroup( group, baseFolder, index );
break;
}
}

View file

@ -2,10 +2,12 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Logging;
using Newtonsoft.Json.Linq;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
using Penumbra.Util;
namespace Penumbra.Mods;
@ -25,7 +27,7 @@ public partial class Mod
public int TotalManipulations { get; private set; }
public bool HasOptions { get; private set; }
private void SetCounts()
private bool SetCounts()
{
TotalFileCount = 0;
TotalSwapCount = 0;
@ -40,6 +42,7 @@ public partial class Mod
HasOptions = _groups.Any( o
=> o is MultiModGroup m && m.PrioritizedOptions.Count > 0
|| o is SingleModGroup s && s.OptionData.Count > 1 );
return true;
}
public IEnumerable< ISubMod > AllSubMods
@ -114,4 +117,29 @@ public partial class Mod
}
}
}
// Delete all existing group files and save them anew.
// Used when indices change in complex ways.
private void SaveAllGroups()
{
foreach( var file in GroupFiles )
{
try
{
if( file.Exists )
{
file.Delete();
}
}
catch( Exception e )
{
PluginLog.Error( $"Could not delete outdated group file {file}:\n{e}" );
}
}
foreach( var (group, index) in _groups.WithIndex() )
{
IModGroup.SaveModGroup( group, BasePath, index );
}
}
}

View file

@ -2,10 +2,12 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Dalamud.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.GameData.ByteString;
using Penumbra.Util;
namespace Penumbra.Mods;
@ -14,7 +16,36 @@ public sealed partial class Mod
private static class Migration
{
public static bool Migrate( Mod mod, JObject json )
=> MigrateV0ToV1( mod, json );
=> MigrateV0ToV1( mod, json ) || MigrateV1ToV2( mod );
private static bool MigrateV1ToV2( Mod mod )
{
if( mod.FileVersion > 1 )
{
return false;
}
foreach( var (group, index) in mod.GroupFiles.WithIndex().ToArray() )
{
var newName = Regex.Replace( group.Name, "^group_", $"group_{index + 1:D3}_", RegexOptions.Compiled );
try
{
if( newName != group.Name )
{
group.MoveTo( Path.Combine( group.DirectoryName ?? string.Empty, newName ), false );
}
}
catch( Exception e )
{
PluginLog.Error( $"Could not rename group file {group.Name} to {newName} during migration:\n{e}" );
}
}
mod.FileVersion = 2;
mod.SaveMeta();
return true;
}
private static bool MigrateV0ToV1( Mod mod, JObject json )
{
@ -50,9 +81,9 @@ public sealed partial class Mod
}
mod._default.IncorporateMetaChanges( mod.BasePath, true );
foreach( var group in mod.Groups )
foreach( var (group, index) in mod.Groups.WithIndex() )
{
IModGroup.SaveModGroup( group, mod.BasePath );
IModGroup.SaveModGroup( group, mod.BasePath, index );
}
// Delete meta files.

View file

@ -34,12 +34,12 @@ public interface IModGroup : IEnumerable< ISubMod >
_ => false,
};
public string FileName( DirectoryInfo basePath )
=> Path.Combine( basePath.FullName, $"group_{Name.RemoveInvalidPathSymbols().ToLowerInvariant()}.json" );
public string FileName( DirectoryInfo basePath, int groupIdx )
=> Path.Combine( basePath.FullName, $"group_{groupIdx + 1:D3}_{Name.RemoveInvalidPathSymbols().ToLowerInvariant()}.json" );
public void DeleteFile( DirectoryInfo basePath )
public void DeleteFile( DirectoryInfo basePath, int groupIdx )
{
var file = FileName( basePath );
var file = FileName( basePath, groupIdx );
if( !File.Exists( file ) )
{
return;
@ -48,7 +48,7 @@ public interface IModGroup : IEnumerable< ISubMod >
try
{
File.Delete( file );
PluginLog.Debug( "Deleted group file {File:l} for {GroupName:l}.", file, Name );
PluginLog.Debug( "Deleted group file {File:l} for group {GroupIdx}: {GroupName:l}.", file, groupIdx + 1, Name );
}
catch( Exception e )
{
@ -57,9 +57,9 @@ public interface IModGroup : IEnumerable< ISubMod >
}
}
public static void SaveModGroup( IModGroup group, DirectoryInfo basePath )
public static void SaveModGroup( IModGroup group, DirectoryInfo basePath, int groupIdx )
{
var file = group.FileName( basePath );
var file = group.FileName( basePath, groupIdx );
using var s = File.Exists( file ) ? File.Open( file, FileMode.Truncate ) : File.Open( file, FileMode.CreateNew );
using var writer = new StreamWriter( s );
using var j = new JsonTextWriter( writer ) { Formatting = Formatting.Indented };
@ -82,7 +82,7 @@ public interface IModGroup : IEnumerable< ISubMod >
j.WriteEndArray();
j.WriteEndObject();
PluginLog.Debug( "Saved group file {File:l} for {GroupName:l}.", file, group.Name );
PluginLog.Debug( "Saved group file {File:l} for group {GroupIdx}: {GroupName:l}.", file, groupIdx + 1, group.Name );
}
public IModGroup Convert( SelectType type );

View file

@ -259,7 +259,7 @@ public partial class ConfigWindow
}
ImGui.SameLine();
var fileName = group.FileName( _mod.BasePath );
var fileName = group.FileName( _mod.BasePath, groupIdx );
var fileExists = File.Exists( fileName );
tt = fileExists
? $"Open the {group.Name} json file in the text editor of your choice."

View file

@ -59,6 +59,7 @@ public partial class ConfigWindow
DrawSingleGroup( _mod.Groups[ idx ], idx );
}
ImGui.Dummy( _window._defaultSpace );
for( var idx = 0; idx < _mod.Groups.Count; ++idx )
{
DrawMultiGroup( _mod.Groups[ idx ], idx );