mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-01 05:13:43 +01:00
Make penumbra initialization before game code has run possible.
This commit is contained in:
parent
f13893cf77
commit
9ae843731d
19 changed files with 610 additions and 672 deletions
|
|
@ -1,73 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public struct MetaManagerCmp : IDisposable
|
||||
private CmpFile? _cmpFile = null;
|
||||
private readonly List< RspManipulation > _cmpManipulations = new();
|
||||
|
||||
public void SetCmpFiles()
|
||||
=> SetFile( _cmpFile, CharacterUtility.HumanCmpIdx );
|
||||
|
||||
public static void ResetCmpFiles()
|
||||
=> SetFile( null, CharacterUtility.HumanCmpIdx );
|
||||
|
||||
public void ResetCmp()
|
||||
{
|
||||
public CmpFile? File = null;
|
||||
public readonly Dictionary< RspManipulation, IMod > Manipulations = new();
|
||||
|
||||
public MetaManagerCmp()
|
||||
{ }
|
||||
|
||||
[Conditional( "USE_CMP" )]
|
||||
public void SetFiles()
|
||||
=> SetFile( File, CharacterUtility.HumanCmpIdx );
|
||||
|
||||
[Conditional( "USE_CMP" )]
|
||||
public static void ResetFiles()
|
||||
=> SetFile( null, CharacterUtility.HumanCmpIdx );
|
||||
|
||||
[Conditional( "USE_CMP" )]
|
||||
public void Reset()
|
||||
if( _cmpFile == null )
|
||||
{
|
||||
if( File == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
File.Reset( Manipulations.Keys.Select( m => ( m.SubRace, m.Attribute ) ) );
|
||||
Manipulations.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
public bool ApplyMod( RspManipulation m, IMod mod )
|
||||
_cmpFile.Reset( _cmpManipulations.Select( m => ( m.SubRace, m.Attribute ) ) );
|
||||
_cmpManipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( RspManipulation manip )
|
||||
{
|
||||
_cmpManipulations.AddOrReplace( manip );
|
||||
_cmpFile ??= new CmpFile();
|
||||
return manip.Apply( _cmpFile );
|
||||
}
|
||||
|
||||
public bool RevertMod( RspManipulation manip )
|
||||
{
|
||||
if( _cmpManipulations.Remove( manip ) )
|
||||
{
|
||||
#if USE_CMP
|
||||
Manipulations[ m ] = mod;
|
||||
File ??= new CmpFile();
|
||||
return m.Apply( File );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
var def = CmpFile.GetDefault( manip.SubRace, manip.Attribute );
|
||||
manip = new RspManipulation( manip.SubRace, manip.Attribute, def );
|
||||
return manip.Apply( _cmpFile! );
|
||||
}
|
||||
|
||||
public bool RevertMod( RspManipulation m )
|
||||
{
|
||||
#if USE_CMP
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var def = CmpFile.GetDefault( m.SubRace, m.Attribute );
|
||||
var manip = new RspManipulation( m.SubRace, m.Attribute, def );
|
||||
return manip.Apply( File! );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
File?.Dispose();
|
||||
File = null;
|
||||
Manipulations.Clear();
|
||||
}
|
||||
public void DisposeCmp()
|
||||
{
|
||||
_cmpFile?.Dispose();
|
||||
_cmpFile = null;
|
||||
_cmpManipulations.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public struct MetaManagerEqdp : IDisposable
|
||||
private readonly ExpandedEqdpFile?[] _eqdpFiles = new ExpandedEqdpFile?[CharacterUtility.NumEqdpFiles - 2]; // TODO: female Hrothgar
|
||||
|
||||
private readonly List< EqdpManipulation > _eqdpManipulations = new();
|
||||
|
||||
public void SetEqdpFiles()
|
||||
{
|
||||
public readonly ExpandedEqdpFile?[] Files = new ExpandedEqdpFile?[CharacterUtility.NumEqdpFiles - 2]; // TODO: female Hrothgar
|
||||
|
||||
public readonly Dictionary< EqdpManipulation, IMod > Manipulations = new();
|
||||
|
||||
public MetaManagerEqdp()
|
||||
{ }
|
||||
|
||||
[Conditional( "USE_EQDP" )]
|
||||
public void SetFiles()
|
||||
for( var i = 0; i < CharacterUtility.EqdpIndices.Length; ++i )
|
||||
{
|
||||
for( var i = 0; i < CharacterUtility.EqdpIndices.Length; ++i )
|
||||
{
|
||||
SetFile( Files[ i ], CharacterUtility.EqdpIndices[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional( "USE_EQDP" )]
|
||||
public static void ResetFiles()
|
||||
{
|
||||
foreach( var idx in CharacterUtility.EqdpIndices )
|
||||
{
|
||||
SetFile( null, idx );
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional( "USE_EQDP" )]
|
||||
public void Reset()
|
||||
{
|
||||
foreach( var file in Files )
|
||||
{
|
||||
file?.Reset( Manipulations.Keys.Where( m => m.FileIndex() == file.Index ).Select( m => ( int )m.SetId ) );
|
||||
}
|
||||
|
||||
Manipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( EqdpManipulation m, IMod mod )
|
||||
{
|
||||
#if USE_EQDP
|
||||
Manipulations[ m ] = mod;
|
||||
var file = Files[ Array.IndexOf( CharacterUtility.EqdpIndices, m.FileIndex() ) ] ??=
|
||||
new ExpandedEqdpFile( Names.CombinedRace( m.Gender, m.Race ), m.Slot.IsAccessory() ); // TODO: female Hrothgar
|
||||
return m.Apply( file );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool RevertMod( EqdpManipulation m )
|
||||
{
|
||||
#if USE_EQDP
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var def = ExpandedEqdpFile.GetDefault( Names.CombinedRace( m.Gender, m.Race ), m.Slot.IsAccessory(), m.SetId );
|
||||
var file = Files[ Array.IndexOf( CharacterUtility.EqdpIndices, m.FileIndex() ) ]!;
|
||||
var manip = new EqdpManipulation( def, m.Slot, m.Gender, m.Race, m.SetId );
|
||||
return manip.Apply( file );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public ExpandedEqdpFile? File( GenderRace race, bool accessory )
|
||||
=> Files[ Array.IndexOf( CharacterUtility.EqdpIndices, CharacterUtility.EqdpIdx( race, accessory ) ) ]; // TODO: female Hrothgar
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
for( var i = 0; i < Files.Length; ++i )
|
||||
{
|
||||
Files[ i ]?.Dispose();
|
||||
Files[ i ] = null;
|
||||
}
|
||||
|
||||
Manipulations.Clear();
|
||||
SetFile( _eqdpFiles[ i ], CharacterUtility.EqdpIndices[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetEqdpFiles()
|
||||
{
|
||||
foreach( var idx in CharacterUtility.EqdpIndices )
|
||||
{
|
||||
SetFile( null, idx );
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetEqdp()
|
||||
{
|
||||
foreach( var file in _eqdpFiles )
|
||||
{
|
||||
file?.Reset( _eqdpManipulations.Where( m => m.FileIndex() == file.Index ).Select( m => ( int )m.SetId ) );
|
||||
}
|
||||
|
||||
_eqdpManipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( EqdpManipulation manip )
|
||||
{
|
||||
_eqdpManipulations.AddOrReplace( manip );
|
||||
var file = _eqdpFiles[ Array.IndexOf( CharacterUtility.EqdpIndices, manip.FileIndex() ) ] ??=
|
||||
new ExpandedEqdpFile( Names.CombinedRace( manip.Gender, manip.Race ), manip.Slot.IsAccessory() ); // TODO: female Hrothgar
|
||||
return manip.Apply( file );
|
||||
}
|
||||
|
||||
public bool RevertMod( EqdpManipulation manip )
|
||||
{
|
||||
if( _eqdpManipulations.Remove( manip ) )
|
||||
{
|
||||
var def = ExpandedEqdpFile.GetDefault( Names.CombinedRace( manip.Gender, manip.Race ), manip.Slot.IsAccessory(), manip.SetId );
|
||||
var file = _eqdpFiles[ Array.IndexOf( CharacterUtility.EqdpIndices, manip.FileIndex() ) ]!;
|
||||
manip = new EqdpManipulation( def, manip.Slot, manip.Gender, manip.Race, manip.SetId );
|
||||
return manip.Apply( file );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ExpandedEqdpFile? EqdpFile( GenderRace race, bool accessory )
|
||||
=> _eqdpFiles
|
||||
[ Array.IndexOf( CharacterUtility.EqdpIndices, CharacterUtility.EqdpIdx( race, accessory ) ) ]; // TODO: female Hrothgar
|
||||
|
||||
public void DisposeEqdp()
|
||||
{
|
||||
for( var i = 0; i < _eqdpFiles.Length; ++i )
|
||||
{
|
||||
_eqdpFiles[ i ]?.Dispose();
|
||||
_eqdpFiles[ i ] = null;
|
||||
}
|
||||
|
||||
_eqdpManipulations.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public struct MetaManagerEqp : IDisposable
|
||||
private ExpandedEqpFile? _eqpFile = null;
|
||||
private readonly List< EqpManipulation > _eqpManipulations = new();
|
||||
|
||||
public void SetEqpFiles()
|
||||
=> SetFile( _eqpFile, CharacterUtility.EqpIdx );
|
||||
|
||||
public static void ResetEqpFiles()
|
||||
=> SetFile( null, CharacterUtility.EqpIdx );
|
||||
|
||||
public void ResetEqp()
|
||||
{
|
||||
public ExpandedEqpFile? File = null;
|
||||
public readonly Dictionary< EqpManipulation, IMod > Manipulations = new();
|
||||
|
||||
public MetaManagerEqp()
|
||||
{ }
|
||||
|
||||
[Conditional( "USE_EQP" )]
|
||||
public void SetFiles()
|
||||
=> SetFile( File, CharacterUtility.EqpIdx );
|
||||
|
||||
[Conditional( "USE_EQP" )]
|
||||
public static void ResetFiles()
|
||||
=> SetFile( null, CharacterUtility.EqpIdx );
|
||||
|
||||
[Conditional( "USE_EQP" )]
|
||||
public void Reset()
|
||||
if( _eqpFile == null )
|
||||
{
|
||||
if( File == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
File.Reset( Manipulations.Keys.Select( m => ( int )m.SetId ) );
|
||||
Manipulations.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
public bool ApplyMod( EqpManipulation m, IMod mod )
|
||||
_eqpFile.Reset( _eqpManipulations.Select( m => ( int )m.SetId ) );
|
||||
_eqpManipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( EqpManipulation manip )
|
||||
{
|
||||
_eqpManipulations.AddOrReplace( manip );
|
||||
_eqpFile ??= new ExpandedEqpFile();
|
||||
return manip.Apply( _eqpFile );
|
||||
}
|
||||
|
||||
public bool RevertMod( EqpManipulation manip )
|
||||
{
|
||||
var idx = _eqpManipulations.FindIndex( manip.Equals );
|
||||
if( idx >= 0 )
|
||||
{
|
||||
#if USE_EQP
|
||||
Manipulations[ m ] = mod;
|
||||
File ??= new ExpandedEqpFile();
|
||||
return m.Apply( File );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
var def = ExpandedEqpFile.GetDefault( manip.SetId );
|
||||
manip = new EqpManipulation( def, manip.Slot, manip.SetId );
|
||||
return manip.Apply( _eqpFile! );
|
||||
}
|
||||
|
||||
public bool RevertMod( EqpManipulation m )
|
||||
{
|
||||
#if USE_EQP
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var def = ExpandedEqpFile.GetDefault( m.SetId );
|
||||
var manip = new EqpManipulation( def, m.Slot, m.SetId );
|
||||
return manip.Apply( File! );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
File?.Dispose();
|
||||
File = null;
|
||||
Manipulations.Clear();
|
||||
}
|
||||
public void DisposeEqp()
|
||||
{
|
||||
_eqpFile?.Dispose();
|
||||
_eqpFile = null;
|
||||
_eqpManipulations.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,106 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public struct MetaManagerEst : IDisposable
|
||||
private EstFile? _estFaceFile = null;
|
||||
private EstFile? _estHairFile = null;
|
||||
private EstFile? _estBodyFile = null;
|
||||
private EstFile? _estHeadFile = null;
|
||||
|
||||
private readonly List< EstManipulation > _estManipulations = new();
|
||||
|
||||
public void SetEstFiles()
|
||||
{
|
||||
public EstFile? FaceFile = null;
|
||||
public EstFile? HairFile = null;
|
||||
public EstFile? BodyFile = null;
|
||||
public EstFile? HeadFile = null;
|
||||
SetFile( _estFaceFile, CharacterUtility.FaceEstIdx );
|
||||
SetFile( _estHairFile, CharacterUtility.HairEstIdx );
|
||||
SetFile( _estBodyFile, CharacterUtility.BodyEstIdx );
|
||||
SetFile( _estHeadFile, CharacterUtility.HeadEstIdx );
|
||||
}
|
||||
|
||||
public readonly Dictionary< EstManipulation, IMod > Manipulations = new();
|
||||
public static void ResetEstFiles()
|
||||
{
|
||||
SetFile( null, CharacterUtility.FaceEstIdx );
|
||||
SetFile( null, CharacterUtility.HairEstIdx );
|
||||
SetFile( null, CharacterUtility.BodyEstIdx );
|
||||
SetFile( null, CharacterUtility.HeadEstIdx );
|
||||
}
|
||||
|
||||
public MetaManagerEst()
|
||||
{ }
|
||||
public void ResetEst()
|
||||
{
|
||||
_estFaceFile?.Reset();
|
||||
_estHairFile?.Reset();
|
||||
_estBodyFile?.Reset();
|
||||
_estHeadFile?.Reset();
|
||||
_estManipulations.Clear();
|
||||
}
|
||||
|
||||
[Conditional( "USE_EST" )]
|
||||
public void SetFiles()
|
||||
public bool ApplyMod( EstManipulation m )
|
||||
{
|
||||
_estManipulations.AddOrReplace( m );
|
||||
var file = m.Slot switch
|
||||
{
|
||||
SetFile( FaceFile, CharacterUtility.FaceEstIdx );
|
||||
SetFile( HairFile, CharacterUtility.HairEstIdx );
|
||||
SetFile( BodyFile, CharacterUtility.BodyEstIdx );
|
||||
SetFile( HeadFile, CharacterUtility.HeadEstIdx );
|
||||
}
|
||||
EstManipulation.EstType.Hair => _estHairFile ??= new EstFile( EstManipulation.EstType.Hair ),
|
||||
EstManipulation.EstType.Face => _estFaceFile ??= new EstFile( EstManipulation.EstType.Face ),
|
||||
EstManipulation.EstType.Body => _estBodyFile ??= new EstFile( EstManipulation.EstType.Body ),
|
||||
EstManipulation.EstType.Head => _estHeadFile ??= new EstFile( EstManipulation.EstType.Head ),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
return m.Apply( file );
|
||||
}
|
||||
|
||||
[Conditional( "USE_EST" )]
|
||||
public static void ResetFiles()
|
||||
public bool RevertMod( EstManipulation m )
|
||||
{
|
||||
if( _estManipulations.Remove( m ) )
|
||||
{
|
||||
SetFile( null, CharacterUtility.FaceEstIdx );
|
||||
SetFile( null, CharacterUtility.HairEstIdx );
|
||||
SetFile( null, CharacterUtility.BodyEstIdx );
|
||||
SetFile( null, CharacterUtility.HeadEstIdx );
|
||||
}
|
||||
|
||||
[Conditional( "USE_EST" )]
|
||||
public void Reset()
|
||||
{
|
||||
FaceFile?.Reset();
|
||||
HairFile?.Reset();
|
||||
BodyFile?.Reset();
|
||||
HeadFile?.Reset();
|
||||
Manipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( EstManipulation m, IMod mod )
|
||||
{
|
||||
#if USE_EST
|
||||
Manipulations[ m ] = mod;
|
||||
var def = EstFile.GetDefault( m.Slot, Names.CombinedRace( m.Gender, m.Race ), m.SetId );
|
||||
var manip = new EstManipulation( m.Gender, m.Race, m.Slot, m.SetId, def );
|
||||
var file = m.Slot switch
|
||||
{
|
||||
EstManipulation.EstType.Hair => HairFile ??= new EstFile( EstManipulation.EstType.Hair ),
|
||||
EstManipulation.EstType.Face => FaceFile ??= new EstFile( EstManipulation.EstType.Face ),
|
||||
EstManipulation.EstType.Body => BodyFile ??= new EstFile( EstManipulation.EstType.Body ),
|
||||
EstManipulation.EstType.Head => HeadFile ??= new EstFile( EstManipulation.EstType.Head ),
|
||||
EstManipulation.EstType.Hair => _estHairFile!,
|
||||
EstManipulation.EstType.Face => _estFaceFile!,
|
||||
EstManipulation.EstType.Body => _estBodyFile!,
|
||||
EstManipulation.EstType.Head => _estHeadFile!,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
return m.Apply( file );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return manip.Apply( file );
|
||||
}
|
||||
|
||||
public bool RevertMod( EstManipulation m )
|
||||
{
|
||||
#if USE_EST
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var def = EstFile.GetDefault( m.Slot, Names.CombinedRace( m.Gender, m.Race ), m.SetId );
|
||||
var manip = new EstManipulation( m.Gender, m.Race, m.Slot, m.SetId, def );
|
||||
var file = m.Slot switch
|
||||
{
|
||||
EstManipulation.EstType.Hair => HairFile!,
|
||||
EstManipulation.EstType.Face => FaceFile!,
|
||||
EstManipulation.EstType.Body => BodyFile!,
|
||||
EstManipulation.EstType.Head => HeadFile!,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
return manip.Apply( file );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
FaceFile?.Dispose();
|
||||
HairFile?.Dispose();
|
||||
BodyFile?.Dispose();
|
||||
HeadFile?.Dispose();
|
||||
FaceFile = null;
|
||||
HairFile = null;
|
||||
BodyFile = null;
|
||||
HeadFile = null;
|
||||
Manipulations.Clear();
|
||||
}
|
||||
public void DisposeEst()
|
||||
{
|
||||
_estFaceFile?.Dispose();
|
||||
_estHairFile?.Dispose();
|
||||
_estBodyFile?.Dispose();
|
||||
_estHeadFile?.Dispose();
|
||||
_estFaceFile = null;
|
||||
_estHairFile = null;
|
||||
_estBodyFile = null;
|
||||
_estHeadFile = null;
|
||||
_estManipulations.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
|
|
@ -11,62 +12,49 @@ namespace Penumbra.Meta.Manager;
|
|||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public struct MetaManagerGmp : IDisposable
|
||||
private ExpandedGmpFile? _gmpFile = null;
|
||||
private readonly List< GmpManipulation > _gmpManipulations = new();
|
||||
|
||||
public void SetGmpFiles()
|
||||
=> SetFile( _gmpFile, CharacterUtility.GmpIdx );
|
||||
|
||||
public static void ResetGmpFiles()
|
||||
=> SetFile( null, CharacterUtility.GmpIdx );
|
||||
|
||||
public void ResetGmp()
|
||||
{
|
||||
public ExpandedGmpFile? File = null;
|
||||
public readonly Dictionary< GmpManipulation, IMod > Manipulations = new();
|
||||
|
||||
public MetaManagerGmp()
|
||||
{ }
|
||||
|
||||
|
||||
[Conditional( "USE_GMP" )]
|
||||
public void SetFiles()
|
||||
=> SetFile( File, CharacterUtility.GmpIdx );
|
||||
|
||||
[Conditional( "USE_GMP" )]
|
||||
public static void ResetFiles()
|
||||
=> SetFile( null, CharacterUtility.GmpIdx );
|
||||
|
||||
[Conditional( "USE_GMP" )]
|
||||
public void Reset()
|
||||
if( _gmpFile == null )
|
||||
{
|
||||
if( File != null )
|
||||
{
|
||||
File.Reset( Manipulations.Keys.Select( m => ( int )m.SetId ) );
|
||||
Manipulations.Clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public bool ApplyMod( GmpManipulation m, IMod mod )
|
||||
_gmpFile.Reset( _gmpManipulations.Select( m => ( int )m.SetId ) );
|
||||
_gmpManipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( GmpManipulation manip )
|
||||
{
|
||||
_gmpManipulations.AddOrReplace( manip );
|
||||
_gmpFile ??= new ExpandedGmpFile();
|
||||
return manip.Apply( _gmpFile );
|
||||
}
|
||||
|
||||
public bool RevertMod( GmpManipulation manip )
|
||||
{
|
||||
if( _gmpManipulations.Remove( manip ) )
|
||||
{
|
||||
#if USE_GMP
|
||||
Manipulations[ m ] = mod;
|
||||
File ??= new ExpandedGmpFile();
|
||||
return m.Apply( File );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
var def = ExpandedGmpFile.GetDefault( manip.SetId );
|
||||
manip = new GmpManipulation( def, manip.SetId );
|
||||
return manip.Apply( _gmpFile! );
|
||||
}
|
||||
|
||||
public bool RevertMod( GmpManipulation m )
|
||||
{
|
||||
#if USE_GMP
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var def = ExpandedGmpFile.GetDefault( m.SetId );
|
||||
var manip = new GmpManipulation( def, m.SetId );
|
||||
return manip.Apply( File! );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
File?.Dispose();
|
||||
File = null;
|
||||
Manipulations.Clear();
|
||||
}
|
||||
public void DisposeGmp()
|
||||
{
|
||||
_gmpFile?.Dispose();
|
||||
_gmpFile = null;
|
||||
_gmpManipulations.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,215 +1,195 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Dalamud.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.ByteString;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Meta.Manipulations;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager
|
||||
{
|
||||
public readonly struct MetaManagerImc : IDisposable
|
||||
private readonly Dictionary< Utf8GamePath, ImcFile > _imcFiles = new();
|
||||
private readonly List< ImcManipulation > _imcManipulations = new();
|
||||
private static int _imcManagerCount;
|
||||
|
||||
public void SetImcFiles()
|
||||
{
|
||||
public readonly Dictionary< Utf8GamePath, ImcFile > Files = new();
|
||||
public readonly Dictionary< ImcManipulation, IMod > Manipulations = new();
|
||||
|
||||
private readonly ModCollection _collection;
|
||||
private static int _imcManagerCount;
|
||||
|
||||
public MetaManagerImc( ModCollection collection )
|
||||
if( !_collection.HasCache )
|
||||
{
|
||||
_collection = collection;
|
||||
SetupDelegate();
|
||||
return;
|
||||
}
|
||||
|
||||
[Conditional( "USE_IMC" )]
|
||||
public void SetFiles()
|
||||
foreach( var path in _imcFiles.Keys )
|
||||
{
|
||||
if( !_collection.HasCache )
|
||||
{
|
||||
return;
|
||||
}
|
||||
_collection.ForceFile( path, CreateImcPath( path ) );
|
||||
}
|
||||
}
|
||||
|
||||
foreach( var path in Files.Keys )
|
||||
public void ResetImc()
|
||||
{
|
||||
if( _collection.HasCache )
|
||||
{
|
||||
foreach( var (path, file) in _imcFiles )
|
||||
{
|
||||
_collection.ForceFile( path, CreateImcPath( path ) );
|
||||
_collection.RemoveFile( path );
|
||||
file.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var (_, file) in _imcFiles )
|
||||
{
|
||||
file.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional( "USE_IMC" )]
|
||||
public void Reset()
|
||||
_imcManipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( ImcManipulation manip )
|
||||
{
|
||||
_imcManipulations.AddOrReplace( manip );
|
||||
var path = manip.GamePath();
|
||||
try
|
||||
{
|
||||
if( !_imcFiles.TryGetValue( path, out var file ) )
|
||||
{
|
||||
file = new ImcFile( path );
|
||||
}
|
||||
|
||||
if( !manip.Apply( file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_imcFiles[ path ] = file;
|
||||
var fullPath = CreateImcPath( path );
|
||||
if( _collection.HasCache )
|
||||
{
|
||||
foreach( var (path, file) in Files )
|
||||
{
|
||||
_collection.RemoveFile( path );
|
||||
file.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var (_, file) in Files )
|
||||
{
|
||||
file.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
Manipulations.Clear();
|
||||
}
|
||||
|
||||
public bool ApplyMod( ImcManipulation m, IMod mod )
|
||||
{
|
||||
#if USE_IMC
|
||||
Manipulations[ m ] = mod;
|
||||
var path = m.GamePath();
|
||||
try
|
||||
{
|
||||
if( !Files.TryGetValue( path, out var file ) )
|
||||
{
|
||||
file = new ImcFile( path );
|
||||
}
|
||||
|
||||
if( !m.Apply( file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Files[ path ] = file;
|
||||
var fullPath = CreateImcPath( path );
|
||||
if( _collection.HasCache )
|
||||
{
|
||||
_collection.ForceFile( path, fullPath );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
++Penumbra.ImcExceptions;
|
||||
PluginLog.Error( $"Could not apply IMC Manipulation:\n{e}" );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool RevertMod( ImcManipulation m )
|
||||
{
|
||||
#if USE_IMC
|
||||
if( Manipulations.Remove( m ) )
|
||||
{
|
||||
var path = m.GamePath();
|
||||
if( !Files.TryGetValue( path, out var file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var def = ImcFile.GetDefault( path, m.EquipSlot, m.Variant, out _ );
|
||||
var manip = m with { Entry = def };
|
||||
if( !manip.Apply( file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fullPath = CreateImcPath( path );
|
||||
if( _collection.HasCache )
|
||||
{
|
||||
_collection.ForceFile( path, fullPath );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach( var file in Files.Values )
|
||||
{
|
||||
file.Dispose();
|
||||
}
|
||||
|
||||
Files.Clear();
|
||||
Manipulations.Clear();
|
||||
RestoreDelegate();
|
||||
}
|
||||
|
||||
[Conditional( "USE_IMC" )]
|
||||
private static unsafe void SetupDelegate()
|
||||
{
|
||||
if( _imcManagerCount++ == 0 )
|
||||
{
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization += ImcLoadHandler;
|
||||
Penumbra.ResourceLoader.ResourceLoaded += ImcResourceHandler;
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional( "USE_IMC" )]
|
||||
private static unsafe void RestoreDelegate()
|
||||
{
|
||||
if( --_imcManagerCount == 0 )
|
||||
{
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization -= ImcLoadHandler;
|
||||
Penumbra.ResourceLoader.ResourceLoaded -= ImcResourceHandler;
|
||||
}
|
||||
}
|
||||
|
||||
private FullPath CreateImcPath( Utf8GamePath path )
|
||||
=> new($"|{_collection.Name}_{_collection.RecomputeCounter}|{path}");
|
||||
|
||||
private static unsafe bool ImcLoadHandler( Utf8String split, Utf8String path, ResourceManager* resourceManager,
|
||||
SeFileDescriptor* fileDescriptor, int priority, bool isSync, out byte ret )
|
||||
{
|
||||
ret = 0;
|
||||
if( fileDescriptor->ResourceHandle->FileType != ResourceType.Imc )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginLog.Verbose( "Using ImcLoadHandler for path {$Path:l}.", path );
|
||||
ret = Penumbra.ResourceLoader.ReadSqPackHook.Original( resourceManager, fileDescriptor, priority, isSync );
|
||||
|
||||
var lastUnderscore = split.LastIndexOf( ( byte )'_' );
|
||||
var name = lastUnderscore == -1 ? split.ToString() : split.Substring( 0, lastUnderscore ).ToString();
|
||||
if( Penumbra.CollectionManager.ByName( name, out var collection )
|
||||
&& collection.HasCache
|
||||
&& collection.MetaCache!.Imc.Files.TryGetValue(
|
||||
Utf8GamePath.FromSpan( path.Span, out var p ) ? p : Utf8GamePath.Empty, out var file ) )
|
||||
{
|
||||
PluginLog.Debug( "Loaded {GamePath:l} from file and replaced with IMC from collection {Collection:l}.", path,
|
||||
collection.Name );
|
||||
file.Replace( fileDescriptor->ResourceHandle, true );
|
||||
file.ChangesSinceLoad = false;
|
||||
_collection.ForceFile( path, fullPath );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static unsafe void ImcResourceHandler( ResourceHandle* resource, Utf8GamePath gamePath, FullPath? _2, object? resolveData )
|
||||
catch( Exception e )
|
||||
{
|
||||
// Only check imcs.
|
||||
if( resource->FileType != ResourceType.Imc
|
||||
|| resolveData is not ModCollection { HasCache: true } collection
|
||||
|| !collection.MetaCache!.Imc.Files.TryGetValue( gamePath, out var file )
|
||||
|| !file.ChangesSinceLoad )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PluginLog.Debug( "File {GamePath:l} was already loaded but IMC in collection {Collection:l} was changed, so reloaded.", gamePath,
|
||||
collection.Name );
|
||||
file.Replace( resource, false );
|
||||
file.ChangesSinceLoad = false;
|
||||
++Penumbra.ImcExceptions;
|
||||
PluginLog.Error( $"Could not apply IMC Manipulation:\n{e}" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RevertMod( ImcManipulation m )
|
||||
{
|
||||
#if USE_IMC
|
||||
if( _imcManipulations.Remove( m ) )
|
||||
{
|
||||
var path = m.GamePath();
|
||||
if( !_imcFiles.TryGetValue( path, out var file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var def = ImcFile.GetDefault( path, m.EquipSlot, m.Variant, out _ );
|
||||
var manip = m with { Entry = def };
|
||||
if( !manip.Apply( file ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fullPath = CreateImcPath( path );
|
||||
if( _collection.HasCache )
|
||||
{
|
||||
_collection.ForceFile( path, fullPath );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public void DisposeImc()
|
||||
{
|
||||
foreach( var file in _imcFiles.Values )
|
||||
{
|
||||
file.Dispose();
|
||||
}
|
||||
|
||||
_imcFiles.Clear();
|
||||
_imcManipulations.Clear();
|
||||
RestoreImcDelegate();
|
||||
}
|
||||
|
||||
private static unsafe void SetupImcDelegate()
|
||||
{
|
||||
if( _imcManagerCount++ == 0 )
|
||||
{
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization += ImcLoadHandler;
|
||||
Penumbra.ResourceLoader.ResourceLoaded += ImcResourceHandler;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void RestoreImcDelegate()
|
||||
{
|
||||
if( --_imcManagerCount == 0 )
|
||||
{
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization -= ImcLoadHandler;
|
||||
Penumbra.ResourceLoader.ResourceLoaded -= ImcResourceHandler;
|
||||
}
|
||||
}
|
||||
|
||||
private FullPath CreateImcPath( Utf8GamePath path )
|
||||
=> new($"|{_collection.Name}_{_collection.RecomputeCounter}|{path}");
|
||||
|
||||
|
||||
private static unsafe bool ImcLoadHandler( Utf8String split, Utf8String path, ResourceManager* resourceManager,
|
||||
SeFileDescriptor* fileDescriptor, int priority, bool isSync, out byte ret )
|
||||
{
|
||||
ret = 0;
|
||||
if( fileDescriptor->ResourceHandle->FileType != ResourceType.Imc )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginLog.Verbose( "Using ImcLoadHandler for path {$Path:l}.", path );
|
||||
ret = Penumbra.ResourceLoader.ReadSqPackHook.Original( resourceManager, fileDescriptor, priority, isSync );
|
||||
|
||||
var lastUnderscore = split.LastIndexOf( ( byte )'_' );
|
||||
var name = lastUnderscore == -1 ? split.ToString() : split.Substring( 0, lastUnderscore ).ToString();
|
||||
if( Penumbra.CollectionManager.ByName( name, out var collection )
|
||||
&& collection.HasCache
|
||||
&& collection.MetaCache!._imcFiles.TryGetValue( Utf8GamePath.FromSpan( path.Span, out var p ) ? p : Utf8GamePath.Empty, out var file ) )
|
||||
{
|
||||
PluginLog.Debug( "Loaded {GamePath:l} from file and replaced with IMC from collection {Collection:l}.", path,
|
||||
collection.Name );
|
||||
file.Replace( fileDescriptor->ResourceHandle, true );
|
||||
file.ChangesSinceLoad = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static unsafe void ImcResourceHandler( ResourceHandle* resource, Utf8GamePath gamePath, FullPath? _2, object? resolveData )
|
||||
{
|
||||
// Only check imcs.
|
||||
if( resource->FileType != ResourceType.Imc
|
||||
|| resolveData is not ModCollection { HasCache: true } collection
|
||||
|| !collection.MetaCache!._imcFiles.TryGetValue( gamePath, out var file )
|
||||
|| !file.ChangesSinceLoad )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PluginLog.Debug( "File {GamePath:l} was already loaded but IMC in collection {Collection:l} was changed, so reloaded.", gamePath,
|
||||
collection.Name );
|
||||
file.Replace( resource, false );
|
||||
file.ChangesSinceLoad = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Meta.Files;
|
||||
|
|
@ -9,17 +10,135 @@ using Penumbra.Mods;
|
|||
|
||||
namespace Penumbra.Meta.Manager;
|
||||
|
||||
public partial class MetaManager : IDisposable
|
||||
public partial class MetaManager : IDisposable, IEnumerable<KeyValuePair<MetaManipulation, IMod>>
|
||||
{
|
||||
public MetaManagerEqp Eqp = new();
|
||||
public MetaManagerEqdp Eqdp = new();
|
||||
public MetaManagerGmp Gmp = new();
|
||||
public MetaManagerEst Est = new();
|
||||
public MetaManagerCmp Cmp = new();
|
||||
public MetaManagerImc Imc;
|
||||
private readonly Dictionary< MetaManipulation, IMod > _manipulations = new();
|
||||
private readonly ModCollection _collection;
|
||||
|
||||
public bool TryGetValue( MetaManipulation manip, [NotNullWhen( true )] out IMod? mod )
|
||||
=> _manipulations.TryGetValue( manip, out mod );
|
||||
|
||||
public int Count
|
||||
=> _manipulations.Count;
|
||||
|
||||
public IReadOnlyCollection< MetaManipulation > Manipulations
|
||||
=> _manipulations.Keys;
|
||||
|
||||
|
||||
public IEnumerator<KeyValuePair<MetaManipulation, IMod>> GetEnumerator()
|
||||
=> _manipulations.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public MetaManager( ModCollection collection )
|
||||
{
|
||||
_collection = collection;
|
||||
SetupImcDelegate();
|
||||
Penumbra.CharacterUtility.LoadingFinished += ApplyStoredManipulations;
|
||||
}
|
||||
|
||||
public void SetFiles()
|
||||
{
|
||||
SetEqpFiles();
|
||||
SetEqdpFiles();
|
||||
SetGmpFiles();
|
||||
SetEstFiles();
|
||||
SetCmpFiles();
|
||||
SetImcFiles();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ResetEqp();
|
||||
ResetEqdp();
|
||||
ResetGmp();
|
||||
ResetEst();
|
||||
ResetCmp();
|
||||
ResetImc();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Penumbra.CharacterUtility.LoadingFinished -= ApplyStoredManipulations;
|
||||
DisposeEqp();
|
||||
DisposeEqdp();
|
||||
DisposeCmp();
|
||||
DisposeGmp();
|
||||
DisposeEst();
|
||||
DisposeImc();
|
||||
}
|
||||
|
||||
public bool ApplyMod( MetaManipulation manip, IMod mod )
|
||||
{
|
||||
_manipulations[ manip ] = mod;
|
||||
if( !Penumbra.CharacterUtility.Ready )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return manip.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ),
|
||||
MetaManipulation.Type.Gmp => ApplyMod( manip.Gmp ),
|
||||
MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ),
|
||||
MetaManipulation.Type.Est => ApplyMod( manip.Est ),
|
||||
MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ),
|
||||
MetaManipulation.Type.Imc => ApplyMod( manip.Imc ),
|
||||
MetaManipulation.Type.Unknown => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public bool RevertMod( MetaManipulation manip )
|
||||
{
|
||||
var ret = _manipulations.Remove( manip );
|
||||
if( !Penumbra.CharacterUtility.Ready )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return manip.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => RevertMod( manip.Eqp ),
|
||||
MetaManipulation.Type.Gmp => RevertMod( manip.Gmp ),
|
||||
MetaManipulation.Type.Eqdp => RevertMod( manip.Eqdp ),
|
||||
MetaManipulation.Type.Est => RevertMod( manip.Est ),
|
||||
MetaManipulation.Type.Rsp => RevertMod( manip.Rsp ),
|
||||
MetaManipulation.Type.Imc => RevertMod( manip.Imc ),
|
||||
MetaManipulation.Type.Unknown => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
// Use this when CharacterUtility becomes ready.
|
||||
private void ApplyStoredManipulations()
|
||||
{
|
||||
if( !Penumbra.CharacterUtility.Ready )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach( var manip in Manipulations )
|
||||
{
|
||||
var _ = manip.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => ApplyMod( manip.Eqp ),
|
||||
MetaManipulation.Type.Gmp => ApplyMod( manip.Gmp ),
|
||||
MetaManipulation.Type.Eqdp => ApplyMod( manip.Eqdp ),
|
||||
MetaManipulation.Type.Est => ApplyMod( manip.Est ),
|
||||
MetaManipulation.Type.Rsp => ApplyMod( manip.Rsp ),
|
||||
MetaManipulation.Type.Imc => ApplyMod( manip.Imc ),
|
||||
MetaManipulation.Type.Unknown => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
Penumbra.CharacterUtility.LoadingFinished -= ApplyStoredManipulations;
|
||||
}
|
||||
|
||||
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
|
||||
public static unsafe void SetFile( MetaBaseFile? file, int index )
|
||||
private static unsafe void SetFile( MetaBaseFile? file, int index )
|
||||
{
|
||||
if( file == null )
|
||||
{
|
||||
|
|
@ -30,99 +149,4 @@ public partial class MetaManager : IDisposable
|
|||
Penumbra.CharacterUtility.SetResource( index, ( IntPtr )file.Data, file.Length );
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue( MetaManipulation manip, [NotNullWhen( true )] out IMod? mod )
|
||||
{
|
||||
mod = manip.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => Eqp.Manipulations.TryGetValue( manip.Eqp, out var m ) ? m : null,
|
||||
MetaManipulation.Type.Gmp => Gmp.Manipulations.TryGetValue( manip.Gmp, out var m ) ? m : null,
|
||||
MetaManipulation.Type.Eqdp => Eqdp.Manipulations.TryGetValue( manip.Eqdp, out var m ) ? m : null,
|
||||
MetaManipulation.Type.Est => Est.Manipulations.TryGetValue( manip.Est, out var m ) ? m : null,
|
||||
MetaManipulation.Type.Rsp => Cmp.Manipulations.TryGetValue( manip.Rsp, out var m ) ? m : null,
|
||||
MetaManipulation.Type.Imc => Imc.Manipulations.TryGetValue( manip.Imc, out var m ) ? m : null,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
return mod != null;
|
||||
}
|
||||
|
||||
public int Count
|
||||
=> Imc.Manipulations.Count
|
||||
+ Eqdp.Manipulations.Count
|
||||
+ Cmp.Manipulations.Count
|
||||
+ Gmp.Manipulations.Count
|
||||
+ Est.Manipulations.Count
|
||||
+ Eqp.Manipulations.Count;
|
||||
|
||||
public MetaManipulation[] Manipulations
|
||||
=> Imc.Manipulations.Keys.Select( m => ( MetaManipulation )m )
|
||||
.Concat( Eqdp.Manipulations.Keys.Select( m => ( MetaManipulation )m ) )
|
||||
.Concat( Cmp.Manipulations.Keys.Select( m => ( MetaManipulation )m ) )
|
||||
.Concat( Gmp.Manipulations.Keys.Select( m => ( MetaManipulation )m ) )
|
||||
.Concat( Est.Manipulations.Keys.Select( m => ( MetaManipulation )m ) )
|
||||
.Concat( Eqp.Manipulations.Keys.Select( m => ( MetaManipulation )m ) )
|
||||
.ToArray();
|
||||
|
||||
public MetaManager( ModCollection collection )
|
||||
=> Imc = new MetaManagerImc( collection );
|
||||
|
||||
public void SetFiles()
|
||||
{
|
||||
Eqp.SetFiles();
|
||||
Eqdp.SetFiles();
|
||||
Gmp.SetFiles();
|
||||
Est.SetFiles();
|
||||
Cmp.SetFiles();
|
||||
Imc.SetFiles();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Eqp.Reset();
|
||||
Eqdp.Reset();
|
||||
Gmp.Reset();
|
||||
Est.Reset();
|
||||
Cmp.Reset();
|
||||
Imc.Reset();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Eqp.Dispose();
|
||||
Eqdp.Dispose();
|
||||
Gmp.Dispose();
|
||||
Est.Dispose();
|
||||
Cmp.Dispose();
|
||||
Imc.Dispose();
|
||||
}
|
||||
|
||||
public bool ApplyMod( MetaManipulation m, IMod mod )
|
||||
{
|
||||
return m.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => Eqp.ApplyMod( m.Eqp, mod ),
|
||||
MetaManipulation.Type.Gmp => Gmp.ApplyMod( m.Gmp, mod ),
|
||||
MetaManipulation.Type.Eqdp => Eqdp.ApplyMod( m.Eqdp, mod ),
|
||||
MetaManipulation.Type.Est => Est.ApplyMod( m.Est, mod ),
|
||||
MetaManipulation.Type.Rsp => Cmp.ApplyMod( m.Rsp, mod ),
|
||||
MetaManipulation.Type.Imc => Imc.ApplyMod( m.Imc, mod ),
|
||||
MetaManipulation.Type.Unknown => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public bool RevertMod( MetaManipulation m )
|
||||
{
|
||||
return m.ManipulationType switch
|
||||
{
|
||||
MetaManipulation.Type.Eqp => Eqp.RevertMod( m.Eqp ),
|
||||
MetaManipulation.Type.Gmp => Gmp.RevertMod( m.Gmp ),
|
||||
MetaManipulation.Type.Eqdp => Eqdp.RevertMod( m.Eqdp ),
|
||||
MetaManipulation.Type.Est => Est.RevertMod( m.Est ),
|
||||
MetaManipulation.Type.Rsp => Cmp.RevertMod( m.Rsp ),
|
||||
MetaManipulation.Type.Imc => Imc.RevertMod( m.Imc ),
|
||||
MetaManipulation.Type.Unknown => false,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
|
@ -220,4 +219,16 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
return Functions.MemCmpUnchecked( lhs, &other, sizeof( MetaManipulation ) );
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.ToString(),
|
||||
Type.Gmp => Gmp.ToString(),
|
||||
Type.Eqdp => Eqdp.ToString(),
|
||||
Type.Est => Est.ToString(),
|
||||
Type.Rsp => Rsp.ToString(),
|
||||
Type.Imc => Imc.ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue