Tmp for Mod2

This commit is contained in:
Ottermandias 2022-04-09 16:29:20 +02:00
parent 069ae772a5
commit 48e442a9fd
30 changed files with 697 additions and 252 deletions

View file

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using Dalamud.Logging;
using Newtonsoft.Json;
using Penumbra.Util;
namespace Penumbra.Mods;
public interface IModGroup : IEnumerable< ISubMod >
{
public string Name { get; }
public string Description { get; }
public SelectType Type { get; }
public int Priority { get; }
public int OptionPriority( Index optionIdx );
public ISubMod this[ Index idx ] { get; }
public int Count { get; }
public bool IsOption
=> Type switch
{
SelectType.Single => Count > 1,
SelectType.Multi => Count > 0,
_ => false,
};
public string FileName( DirectoryInfo basePath )
=> Path.Combine( basePath.FullName, $"group_{Name.RemoveInvalidPathSymbols().ToLowerInvariant()}.json" );
public void DeleteFile( DirectoryInfo basePath )
{
var file = FileName( basePath );
if( !File.Exists( file ) )
{
return;
}
try
{
File.Delete( file );
}
catch( Exception e )
{
PluginLog.Error( $"Could not delete file {file}:\n{e}" );
throw;
}
}
public static void SaveModGroup( IModGroup group, DirectoryInfo basePath )
{
var file = group.FileName( basePath );
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 };
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
j.WriteStartObject();
j.WritePropertyName( nameof( group.Name ) );
j.WriteValue( group.Name );
j.WritePropertyName( nameof( group.Description ) );
j.WriteValue( group.Description );
j.WritePropertyName( nameof( group.Priority ) );
j.WriteValue( group.Priority );
j.WritePropertyName( nameof( Type ) );
j.WriteValue( group.Type.ToString() );
j.WritePropertyName( "Options" );
j.WriteStartArray();
for( var idx = 0; idx < group.Count; ++idx )
{
ISubMod.WriteSubMod( j, serializer, group[ idx ], basePath, group.Type == SelectType.Multi ? group.OptionPriority( idx ) : null );
}
j.WriteEndArray();
j.WriteEndObject();
}
}

View file

@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
namespace Penumbra.Mods;
public interface ISubMod
{
public string Name { get; }
public IReadOnlyDictionary< Utf8GamePath, FullPath > Files { get; }
public IReadOnlyDictionary< Utf8GamePath, FullPath > FileSwaps { get; }
public IReadOnlySet< MetaManipulation > Manipulations { get; }
public static void WriteSubMod( JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, int? priority )
{
j.WriteStartObject();
j.WritePropertyName( nameof( Name ) );
j.WriteValue( mod.Name );
if( priority != null )
{
j.WritePropertyName( nameof( IModGroup.Priority ) );
j.WriteValue( priority.Value );
}
j.WritePropertyName( nameof( mod.Files ) );
j.WriteStartObject();
foreach( var (gamePath, file) in mod.Files )
{
if( file.ToRelPath( basePath, out var relPath ) )
{
j.WritePropertyName( gamePath.ToString() );
j.WriteValue( relPath.ToString() );
}
}
j.WriteEndObject();
j.WritePropertyName( nameof( mod.FileSwaps ) );
j.WriteStartObject();
foreach( var (gamePath, file) in mod.FileSwaps )
{
j.WritePropertyName( gamePath.ToString() );
j.WriteValue( file.ToString() );
}
j.WriteEndObject();
j.WritePropertyName( nameof( mod.Manipulations ) );
serializer.Serialize( j, mod.Manipulations );
j.WriteEndObject();
}
}

View file

@ -0,0 +1,67 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Penumbra.Mods;
public partial class Mod2
{
private sealed class MultiModGroup : IModGroup
{
public SelectType Type
=> SelectType.Multi;
public string Name { get; set; } = "Group";
public string Description { get; set; } = "A non-exclusive group of settings.";
public int Priority { get; set; }
public int OptionPriority( Index idx )
=> PrioritizedOptions[ idx ].Priority;
public ISubMod this[ Index idx ]
=> PrioritizedOptions[ idx ].Mod;
[JsonIgnore]
public int Count
=> PrioritizedOptions.Count;
public readonly List< (SubMod Mod, int Priority) > PrioritizedOptions = new();
public IEnumerator< ISubMod > GetEnumerator()
=> PrioritizedOptions.Select( o => o.Mod ).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public static MultiModGroup? Load( JObject json, DirectoryInfo basePath )
{
var options = json[ "Options" ];
var ret = new MultiModGroup()
{
Name = json[ nameof( Name ) ]?.ToObject< string >() ?? string.Empty,
Description = json[ nameof( Description ) ]?.ToObject< string >() ?? string.Empty,
Priority = json[ nameof( Priority ) ]?.ToObject< int >() ?? 0,
};
if( ret.Name.Length == 0 )
{
return null;
}
if( options != null )
{
foreach( var child in options.Children() )
{
var subMod = new SubMod();
subMod.Load( basePath, child, out var priority );
ret.PrioritizedOptions.Add( ( subMod, priority ) );
}
}
return ret;
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Penumbra.Mods;
public partial class Mod2
{
private sealed class SingleModGroup : IModGroup
{
public SelectType Type
=> SelectType.Single;
public string Name { get; set; } = "Option";
public string Description { get; set; } = "A mutually exclusive group of settings.";
public int Priority { get; set; }
public readonly List< SubMod > OptionData = new();
public int OptionPriority( Index _ )
=> Priority;
public ISubMod this[ Index idx ]
=> OptionData[ idx ];
[JsonIgnore]
public int Count
=> OptionData.Count;
public IEnumerator< ISubMod > GetEnumerator()
=> OptionData.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public static SingleModGroup? Load( JObject json, DirectoryInfo basePath )
{
var options = json[ "Options" ];
var ret = new SingleModGroup
{
Name = json[ nameof( Name ) ]?.ToObject< string >() ?? string.Empty,
Description = json[ nameof( Description ) ]?.ToObject< string >() ?? string.Empty,
Priority = json[ nameof( Priority ) ]?.ToObject< int >() ?? 0,
};
if( ret.Name.Length == 0 )
{
return null;
}
if( options != null )
{
foreach( var child in options.Children() )
{
var subMod = new SubMod();
subMod.Load( basePath, child, out _ );
ret.OptionData.Add( subMod );
}
}
return ret;
}
}
}

View file

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
namespace Penumbra.Mods;
public partial class Mod2
{
private string DefaultFile
=> Path.Combine( BasePath.FullName, "default_mod.json" );
private void SaveDefaultMod()
{
var defaultFile = DefaultFile;
using var stream = File.Exists( defaultFile )
? File.Open( defaultFile, FileMode.Truncate )
: File.Open( defaultFile, FileMode.CreateNew );
using var w = new StreamWriter( stream );
using var j = new JsonTextWriter( w );
j.Formatting = Formatting.Indented;
var serializer = new JsonSerializer
{
Formatting = Formatting.Indented,
};
ISubMod.WriteSubMod( j, serializer, _default, BasePath, 0 );
}
private void LoadDefaultOption()
{
var defaultFile = DefaultFile;
try
{
if( !File.Exists( defaultFile ) )
{
_default.Load( BasePath, new JObject(), out _ );
}
else
{
_default.Load( BasePath, JObject.Parse( File.ReadAllText( defaultFile ) ), out _ );
}
}
catch( Exception e )
{
PluginLog.Error( $"Could not parse default file for {Name}:\n{e}" );
}
}
private sealed class SubMod : ISubMod
{
public string Name { get; set; } = "Default";
public readonly Dictionary< Utf8GamePath, FullPath > FileData = new();
public readonly Dictionary< Utf8GamePath, FullPath > FileSwapData = new();
public readonly HashSet< MetaManipulation > ManipulationData = new();
public IReadOnlyDictionary< Utf8GamePath, FullPath > Files
=> FileData;
public IReadOnlyDictionary< Utf8GamePath, FullPath > FileSwaps
=> FileSwapData;
public IReadOnlySet< MetaManipulation > Manipulations
=> ManipulationData;
public void Load( DirectoryInfo basePath, JToken json, out int priority )
{
FileData.Clear();
FileSwapData.Clear();
ManipulationData.Clear();
Name = json[ nameof( ISubMod.Name ) ]?.ToObject< string >() ?? string.Empty;
priority = json[ nameof( IModGroup.Priority ) ]?.ToObject< int >() ?? 0;
var files = ( JObject? )json[ nameof( Files ) ];
if( files != null )
{
foreach( var property in files.Properties() )
{
if( Utf8GamePath.FromString( property.Name, out var p, true ) )
{
FileData.TryAdd( p, new FullPath( basePath, property.Value.ToObject< Utf8RelPath >() ) );
}
}
}
var swaps = ( JObject? )json[ nameof( FileSwaps ) ];
if( swaps != null )
{
foreach( var property in swaps.Properties() )
{
if( Utf8GamePath.FromString( property.Name, out var p, true ) )
{
FileSwapData.TryAdd( p, new FullPath( property.Value.ToObject< string >()! ) );
}
}
}
var manips = json[ nameof( Manipulations ) ];
if( manips != null )
{
foreach( var s in manips.Children().Select( c => c.ToObject< MetaManipulation >() ) )
{
ManipulationData.Add( s );
}
}
}
}
}

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Penumbra.Mods;
// Contains the settings for a given mod.
public class ModSettings
{
public static readonly ModSettings Empty = new();
public bool Enabled { get; set; }
public int Priority { get; set; }
public Dictionary< string, int > Settings { get; set; } = new();
// For backwards compatibility
private Dictionary< string, int > Conf
{
set => Settings = value;
}
public ModSettings DeepCopy()
{
var settings = new ModSettings
{
Enabled = Enabled,
Priority = Priority,
Settings = Settings.ToDictionary( kvp => kvp.Key, kvp => kvp.Value ),
};
return settings;
}
public static ModSettings DefaultSettings( ModMeta meta )
{
return new ModSettings
{
Enabled = false,
Priority = 0,
Settings = meta.Groups.ToDictionary( kvp => kvp.Key, _ => 0 ),
};
}
public bool FixSpecificSetting( string name, ModMeta meta )
{
if( !meta.Groups.TryGetValue( name, out var group ) )
{
return Settings.Remove( name );
}
if( Settings.TryGetValue( name, out var oldSetting ) )
{
Settings[ name ] = group.SelectionType switch
{
SelectType.Single => Math.Min( Math.Max( oldSetting, 0 ), group.Options.Count - 1 ),
SelectType.Multi => Math.Min( Math.Max( oldSetting, 0 ), ( 1 << group.Options.Count ) - 1 ),
_ => Settings[ group.GroupName ],
};
return oldSetting != Settings[ group.GroupName ];
}
Settings[ name ] = 0;
return true;
}
public bool FixInvalidSettings( ModMeta meta )
{
if( meta.Groups.Count == 0 )
{
return false;
}
return Settings.Keys.ToArray().Union( meta.Groups.Keys )
.Aggregate( false, ( current, name ) => current | FixSpecificSetting( name, meta ) );
}
}