mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
More fixes, some cleanup.
This commit is contained in:
parent
581b91b337
commit
e6752ade04
20 changed files with 193 additions and 361 deletions
|
|
@ -49,7 +49,7 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !Utf8String.FromString( substring, out var ascii ) || !ascii.IsAscii )
|
if( !Utf8String.FromString( substring, out var ascii, true ) || !ascii.IsAscii )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var substring = file.FullName[ baseDir.FullName.Length.. ];
|
var substring = file.FullName[ (baseDir.FullName.Length + 1).. ];
|
||||||
return FromString( substring, out path );
|
return FromString( substring, out path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var substring = file.FullName[ baseDir.FullName.Length.. ];
|
var substring = file.FullName[ (baseDir.FullName.Length + 1).. ];
|
||||||
return FromString( substring, out path );
|
return FromString( substring, out path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ public sealed unsafe partial class Utf8String : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
Marshal.FreeHGlobal( ( IntPtr )_path );
|
Marshal.FreeHGlobal( ( IntPtr )_path );
|
||||||
GC.RemoveMemoryPressure( Length );
|
GC.RemoveMemoryPressure( Length + 1 );
|
||||||
_length = AsciiCheckedFlag | AsciiFlag | AsciiLowerCheckedFlag | AsciiLowerFlag | NullTerminatedFlag;
|
_length = AsciiCheckedFlag | AsciiFlag | AsciiLowerCheckedFlag | AsciiLowerFlag | NullTerminatedFlag;
|
||||||
_path = Null.NullBytePtr;
|
_path = Null.NullBytePtr;
|
||||||
_crc32 = 0;
|
_crc32 = 0;
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,6 @@ public class Configuration : IPluginConfiguration
|
||||||
|
|
||||||
public bool DisableSoundStreaming { get; set; } = true;
|
public bool DisableSoundStreaming { get; set; } = true;
|
||||||
public bool EnableHttpApi { get; set; }
|
public bool EnableHttpApi { get; set; }
|
||||||
public bool EnablePlayerWatch { get; set; } = false;
|
|
||||||
public int WaitFrames { get; set; } = 30;
|
|
||||||
|
|
||||||
public string ModDirectory { get; set; } = string.Empty;
|
public string ModDirectory { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -16,18 +14,13 @@ public unsafe class ObjectReloader : IDisposable
|
||||||
{
|
{
|
||||||
private delegate void ManipulateDraw( IntPtr actor );
|
private delegate void ManipulateDraw( IntPtr actor );
|
||||||
|
|
||||||
private const int RenderModeOffset = 0x0104;
|
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
|
||||||
private const int UnloadAllRedrawDelay = 250;
|
public const int GPosePlayerIdx = 201;
|
||||||
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
|
public const int GPoseEndIdx = GPosePlayerIdx + 48;
|
||||||
public const int GPosePlayerIdx = 201;
|
|
||||||
public const int GPoseEndIdx = GPosePlayerIdx + 48;
|
|
||||||
|
|
||||||
private readonly ModManager _mods;
|
private readonly ModManager _mods;
|
||||||
private readonly Queue< (uint actorId, string name, RedrawType s) > _actorIds = new();
|
private readonly Queue< (uint actorId, string name, RedrawType s) > _actorIds = new();
|
||||||
|
|
||||||
internal int DefaultWaitFrames;
|
|
||||||
|
|
||||||
private int _waitFrames;
|
|
||||||
private int _currentFrame;
|
private int _currentFrame;
|
||||||
private bool _changedSettings;
|
private bool _changedSettings;
|
||||||
private uint _currentObjectId = uint.MaxValue;
|
private uint _currentObjectId = uint.MaxValue;
|
||||||
|
|
@ -46,11 +39,8 @@ public unsafe class ObjectReloader : IDisposable
|
||||||
private static delegate*< IntPtr, void > GetEnableDraw( GameObject actor )
|
private static delegate*< IntPtr, void > GetEnableDraw( GameObject actor )
|
||||||
=> ( ( delegate*< IntPtr, void >** )actor.Address )[ 0 ][ 16 ];
|
=> ( ( delegate*< IntPtr, void >** )actor.Address )[ 0 ][ 16 ];
|
||||||
|
|
||||||
public ObjectReloader( ModManager mods, int defaultWaitFrames )
|
public ObjectReloader( ModManager mods )
|
||||||
{
|
=> _mods = mods;
|
||||||
_mods = mods;
|
|
||||||
DefaultWaitFrames = defaultWaitFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChangeSettings()
|
private void ChangeSettings()
|
||||||
{
|
{
|
||||||
|
|
@ -289,13 +279,6 @@ public unsafe class ObjectReloader : IDisposable
|
||||||
|| Dalamud.Conditions[ ConditionFlag.BetweenAreas ]
|
|| Dalamud.Conditions[ ConditionFlag.BetweenAreas ]
|
||||||
|| Dalamud.Conditions[ ConditionFlag.OccupiedInCutSceneEvent ] )
|
|| Dalamud.Conditions[ ConditionFlag.OccupiedInCutSceneEvent ] )
|
||||||
{
|
{
|
||||||
_waitFrames = DefaultWaitFrames;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _waitFrames > 0 )
|
|
||||||
{
|
|
||||||
--_waitFrames;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,12 @@ public unsafe partial class PathResolver
|
||||||
CharacterBaseCreateHook?.Enable();
|
CharacterBaseCreateHook?.Enable();
|
||||||
EnableDrawHook?.Enable();
|
EnableDrawHook?.Enable();
|
||||||
CharacterBaseDestructorHook?.Enable();
|
CharacterBaseDestructorHook?.Enable();
|
||||||
|
Penumbra.ModManager.Collections.CollectionChanged += CheckCollections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisableDataHooks()
|
private void DisableDataHooks()
|
||||||
{
|
{
|
||||||
|
Penumbra.ModManager.Collections.CollectionChanged -= CheckCollections;
|
||||||
CharacterBaseCreateHook?.Disable();
|
CharacterBaseCreateHook?.Disable();
|
||||||
EnableDrawHook?.Disable();
|
EnableDrawHook?.Disable();
|
||||||
CharacterBaseDestructorHook?.Disable();
|
CharacterBaseDestructorHook?.Disable();
|
||||||
|
|
@ -178,8 +180,13 @@ public unsafe partial class PathResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update collections linked to Game/DrawObjects due to a change in collection configuration.
|
// Update collections linked to Game/DrawObjects due to a change in collection configuration.
|
||||||
private void CheckCollections()
|
private void CheckCollections( ModCollection? _1, ModCollection? _2, CollectionType type, string? name )
|
||||||
{
|
{
|
||||||
|
if( type is not (CollectionType.Character or CollectionType.Default) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach( var (key, (_, idx)) in DrawObjectToObject.ToArray() )
|
foreach( var (key, (_, idx)) in DrawObjectToObject.ToArray() )
|
||||||
{
|
{
|
||||||
if( !VerifyEntry( key, idx, out var obj ) )
|
if( !VerifyEntry( key, idx, out var obj ) )
|
||||||
|
|
@ -187,8 +194,8 @@ public unsafe partial class PathResolver
|
||||||
DrawObjectToObject.Remove( key );
|
DrawObjectToObject.Remove( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
var collection = IdentifyCollection( obj );
|
var newCollection = IdentifyCollection( obj );
|
||||||
DrawObjectToObject[ key ] = ( collection, idx );
|
DrawObjectToObject[ key ] = ( newCollection, idx );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Utility.Signatures;
|
using Dalamud.Utility.Signatures;
|
||||||
using Penumbra.GameData.ByteString;
|
using Penumbra.GameData.ByteString;
|
||||||
|
|
@ -64,6 +65,7 @@ public unsafe partial class PathResolver
|
||||||
|
|
||||||
var mtrlPath = Utf8String.FromSpanUnsafe( mtrl->Handle.FileNameSpan(), true, null, true );
|
var mtrlPath = Utf8String.FromSpanUnsafe( mtrl->Handle.FileNameSpan(), true, null, true );
|
||||||
var collection = PathCollections.TryGetValue( mtrlPath, out var c ) ? c : null;
|
var collection = PathCollections.TryGetValue( mtrlPath, out var c ) ? c : null;
|
||||||
|
var x = PathCollections.ToList();
|
||||||
for( var i = 0; i < mtrl->NumTex; ++i )
|
for( var i = 0; i < mtrl->NumTex; ++i )
|
||||||
{
|
{
|
||||||
var texString = new Utf8String( mtrl->TexString( i ) );
|
var texString = new Utf8String( mtrl->TexString( i ) );
|
||||||
|
|
|
||||||
|
|
@ -92,16 +92,17 @@ public unsafe partial class PathResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GMP
|
// GMP. This gets called every time when changing visor state, and it accesses the gmp file itself,
|
||||||
public delegate void ApplyVisorDelegate( IntPtr drawObject, IntPtr unk1, float unk2, IntPtr unk3, ushort unk4, char unk5 );
|
// but it only applies a changed gmp file after a redraw for some reason.
|
||||||
|
public delegate byte SetupVisorDelegate( IntPtr drawObject, ushort modelId, byte visorState );
|
||||||
|
|
||||||
[Signature( "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", DetourName = "ApplyVisorDetour" )]
|
[Signature( "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", DetourName = "SetupVisorDetour" )]
|
||||||
public Hook< ApplyVisorDelegate >? ApplyVisorHook;
|
public Hook< SetupVisorDelegate >? SetupVisorHook;
|
||||||
|
|
||||||
private void ApplyVisorDetour( IntPtr drawObject, IntPtr unk1, float unk2, IntPtr unk3, ushort unk4, char unk5 )
|
private byte SetupVisorDetour( IntPtr drawObject, ushort modelId, byte visorState )
|
||||||
{
|
{
|
||||||
using var gmp = MetaChanger.ChangeGmp( this, drawObject );
|
using var gmp = MetaChanger.ChangeGmp( this, drawObject );
|
||||||
ApplyVisorHook!.Original( drawObject, unk1, unk2, unk3, unk4, unk5 );
|
return SetupVisorHook!.Original( drawObject, modelId, visorState );
|
||||||
}
|
}
|
||||||
|
|
||||||
// RSP
|
// RSP
|
||||||
|
|
@ -132,7 +133,7 @@ public unsafe partial class PathResolver
|
||||||
OnModelLoadCompleteHook?.Enable();
|
OnModelLoadCompleteHook?.Enable();
|
||||||
#endif
|
#endif
|
||||||
#if USE_GMP
|
#if USE_GMP
|
||||||
ApplyVisorHook?.Enable();
|
SetupVisorHook?.Enable();
|
||||||
#endif
|
#endif
|
||||||
#if USE_CMP
|
#if USE_CMP
|
||||||
RspSetupCharacterHook?.Enable();
|
RspSetupCharacterHook?.Enable();
|
||||||
|
|
@ -144,7 +145,7 @@ public unsafe partial class PathResolver
|
||||||
GetEqpIndirectHook?.Disable();
|
GetEqpIndirectHook?.Disable();
|
||||||
UpdateModelsHook?.Disable();
|
UpdateModelsHook?.Disable();
|
||||||
OnModelLoadCompleteHook?.Disable();
|
OnModelLoadCompleteHook?.Disable();
|
||||||
ApplyVisorHook?.Disable();
|
SetupVisorHook?.Disable();
|
||||||
RspSetupCharacterHook?.Disable();
|
RspSetupCharacterHook?.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +154,7 @@ public unsafe partial class PathResolver
|
||||||
GetEqpIndirectHook?.Dispose();
|
GetEqpIndirectHook?.Dispose();
|
||||||
UpdateModelsHook?.Dispose();
|
UpdateModelsHook?.Dispose();
|
||||||
OnModelLoadCompleteHook?.Dispose();
|
OnModelLoadCompleteHook?.Dispose();
|
||||||
ApplyVisorHook?.Dispose();
|
SetupVisorHook?.Dispose();
|
||||||
RspSetupCharacterHook?.Dispose();
|
RspSetupCharacterHook?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,12 @@ public partial class PathResolver : IDisposable
|
||||||
resolved = Penumbra.ModManager.Collections.ForcedCollection.ResolveSwappedOrReplacementPath( gamePath );
|
resolved = Penumbra.ModManager.Collections.ForcedCollection.ResolveSwappedOrReplacementPath( gamePath );
|
||||||
if( resolved == null )
|
if( resolved == null )
|
||||||
{
|
{
|
||||||
|
// We also need to handle defaulted materials against a non-default collection.
|
||||||
|
if( nonDefault && gamePath.Path.EndsWith( 'm', 't', 'r', 'l' ) )
|
||||||
|
{
|
||||||
|
SetCollection( gamePath.Path, collection );
|
||||||
|
}
|
||||||
|
|
||||||
return ( null, collection );
|
return ( null, collection );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,19 +37,31 @@ public unsafe struct ResourceHandle
|
||||||
public ReadOnlySpan< byte > FileNameSpan()
|
public ReadOnlySpan< byte > FileNameSpan()
|
||||||
=> new(FileName(), FileNameLength);
|
=> new(FileName(), FileNameLength);
|
||||||
|
|
||||||
|
[FieldOffset( 0x00 )]
|
||||||
|
public void** VTable;
|
||||||
|
|
||||||
[FieldOffset( 0x48 )]
|
[FieldOffset( 0x48 )]
|
||||||
public byte* FileNameData;
|
public byte* FileNameData;
|
||||||
|
|
||||||
[FieldOffset( 0x58 )]
|
[FieldOffset( 0x58 )]
|
||||||
public int FileNameLength;
|
public int FileNameLength;
|
||||||
|
|
||||||
|
// May return null.
|
||||||
|
public static byte* GetData( ResourceHandle* handle )
|
||||||
|
=> ( ( delegate*< ResourceHandle*, byte* > )handle->VTable[ 23 ] )( handle );
|
||||||
|
|
||||||
|
public static ulong GetLength( ResourceHandle* handle )
|
||||||
|
=> ( ( delegate*< ResourceHandle*, ulong > )handle->VTable[ 17 ] )( handle );
|
||||||
|
|
||||||
|
|
||||||
|
// Only use these if you know what you are doing.
|
||||||
|
// Those are actually only sure to be accessible for DefaultResourceHandles.
|
||||||
[FieldOffset( 0xB0 )]
|
[FieldOffset( 0xB0 )]
|
||||||
public DataIndirection* Data;
|
public DataIndirection* Data;
|
||||||
|
|
||||||
[FieldOffset( 0xB8 )]
|
[FieldOffset( 0xB8 )]
|
||||||
public uint DataLength;
|
public uint DataLength;
|
||||||
|
|
||||||
|
|
||||||
public (IntPtr Data, int Length) GetData()
|
public (IntPtr Data, int Length) GetData()
|
||||||
=> Data != null
|
=> Data != null
|
||||||
? ( ( IntPtr )Data->DataPtr, ( int )Data->DataLength )
|
? ( ( IntPtr )Data->DataPtr, ( int )Data->DataLength )
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
||||||
|
|
||||||
public static EqdpEntry GetDefault( int fileIdx, int setIdx )
|
public static EqdpEntry GetDefault( int fileIdx, int setIdx )
|
||||||
{
|
{
|
||||||
var data = ( byte* )Penumbra.CharacterUtility.DefaultResources[ fileIdx ].Address;
|
var data = ( byte* )Penumbra.CharacterUtility.DefaultResource( fileIdx ).Address;
|
||||||
var blockSize = *( ushort* )( data + IdentifierSize );
|
var blockSize = *( ushort* )( data + IdentifierSize );
|
||||||
var totalBlockCount = *( ushort* )( data + IdentifierSize + 2 );
|
var totalBlockCount = *( ushort* )( data + IdentifierSize + 2 );
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
||||||
|
|
||||||
var blockData = ( ushort* )( data + IdentifierSize + PreambleSize + totalBlockCount * 2 + block * 2 );
|
var blockData = ( ushort* )( data + IdentifierSize + PreambleSize + totalBlockCount * 2 + block * 2 );
|
||||||
var x = new ReadOnlySpan< ushort >( blockData, blockSize );
|
var x = new ReadOnlySpan< ushort >( blockData, blockSize );
|
||||||
return (EqdpEntry) (*( blockData + setIdx % blockSize ));
|
return ( EqdpEntry )( *( blockData + setIdx % blockSize ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EqdpEntry GetDefault( GenderRace raceCode, bool accessory, int setIdx )
|
public static EqdpEntry GetDefault( GenderRace raceCode, bool accessory, int setIdx )
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,9 @@ public unsafe class ImcFile : MetaBaseFile
|
||||||
var file = Dalamud.GameData.GetFile( path.ToString() );
|
var file = Dalamud.GameData.GetFile( path.ToString() );
|
||||||
if( file == null )
|
if( file == null )
|
||||||
{
|
{
|
||||||
throw new Exception();
|
throw new Exception(
|
||||||
|
"Could not obtain default Imc File.\n"
|
||||||
|
+ "Either the default file does not exist (possibly for offhand files from TexTools) or the installation is corrupted." );
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed( byte* ptr = file.Data )
|
fixed( byte* ptr = file.Data )
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ public unsafe class MetaBaseFile : IDisposable
|
||||||
{
|
{
|
||||||
Length = length;
|
Length = length;
|
||||||
Data = ( byte* )MemoryHelper.GameAllocateDefault( ( ulong )length );
|
Data = ( byte* )MemoryHelper.GameAllocateDefault( ( ulong )length );
|
||||||
;
|
if( length > 0 )
|
||||||
GC.AddMemoryPressure( length );
|
{
|
||||||
|
GC.AddMemoryPressure( length );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free memory.
|
// Free memory.
|
||||||
|
|
@ -33,7 +35,11 @@ public unsafe class MetaBaseFile : IDisposable
|
||||||
{
|
{
|
||||||
var ptr = ( IntPtr )Data;
|
var ptr = ( IntPtr )Data;
|
||||||
MemoryHelper.GameFree( ref ptr, ( ulong )Length );
|
MemoryHelper.GameFree( ref ptr, ( ulong )Length );
|
||||||
GC.RemoveMemoryPressure( Length );
|
if( Length > 0 )
|
||||||
|
{
|
||||||
|
GC.RemoveMemoryPressure( Length );
|
||||||
|
}
|
||||||
|
|
||||||
Length = 0;
|
Length = 0;
|
||||||
Data = null;
|
Data = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,24 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Penumbra.Interop.Structs;
|
|
||||||
using Penumbra.Mod;
|
using Penumbra.Mod;
|
||||||
using Penumbra.Util;
|
using Penumbra.Util;
|
||||||
|
|
||||||
namespace Penumbra.Mods;
|
namespace Penumbra.Mods;
|
||||||
|
|
||||||
|
public enum CollectionType : byte
|
||||||
|
{
|
||||||
|
Inactive,
|
||||||
|
Default,
|
||||||
|
Forced,
|
||||||
|
Character,
|
||||||
|
Current,
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void CollectionChangeDelegate( ModCollection? oldCollection, ModCollection? newCollection, CollectionType type,
|
||||||
|
string? characterName = null );
|
||||||
|
|
||||||
// Contains all collections and respective functions, as well as the collection settings.
|
// Contains all collections and respective functions, as well as the collection settings.
|
||||||
public class CollectionManager
|
public class CollectionManager
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +31,10 @@ public class CollectionManager
|
||||||
public ModCollection CurrentCollection { get; private set; } = ModCollection.Empty;
|
public ModCollection CurrentCollection { get; private set; } = ModCollection.Empty;
|
||||||
public ModCollection DefaultCollection { get; private set; } = ModCollection.Empty;
|
public ModCollection DefaultCollection { get; private set; } = ModCollection.Empty;
|
||||||
public ModCollection ForcedCollection { get; private set; } = ModCollection.Empty;
|
public ModCollection ForcedCollection { get; private set; } = ModCollection.Empty;
|
||||||
public ModCollection ActiveCollection { get; private set; }
|
public ModCollection ActiveCollection { get; private set; } = ModCollection.Empty;
|
||||||
|
|
||||||
|
// Is invoked after the collections actually changed.
|
||||||
|
public event CollectionChangeDelegate? CollectionChanged;
|
||||||
|
|
||||||
public CollectionManager( ModManager manager )
|
public CollectionManager( ModManager manager )
|
||||||
{
|
{
|
||||||
|
|
@ -29,7 +42,7 @@ public class CollectionManager
|
||||||
|
|
||||||
ReadCollections();
|
ReadCollections();
|
||||||
LoadConfigCollections( Penumbra.Config );
|
LoadConfigCollections( Penumbra.Config );
|
||||||
ActiveCollection = DefaultCollection;
|
SetActiveCollection( DefaultCollection, string.Empty );
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetActiveCollection( ModCollection newActive, string name )
|
public bool SetActiveCollection( ModCollection newActive, string name )
|
||||||
|
|
@ -44,14 +57,7 @@ public class CollectionManager
|
||||||
{
|
{
|
||||||
ActiveCollection = newActive;
|
ActiveCollection = newActive;
|
||||||
Penumbra.ResidentResources.Reload();
|
Penumbra.ResidentResources.Reload();
|
||||||
if( ActiveCollection.Cache == null )
|
ActiveCollection.SetFiles();
|
||||||
{
|
|
||||||
Penumbra.CharacterUtility.ResetAll();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActiveCollection.Cache.MetaManipulations.SetFiles();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -131,8 +137,9 @@ public class CollectionManager
|
||||||
|
|
||||||
var newCollection = new ModCollection( name, settings );
|
var newCollection = new ModCollection( name, settings );
|
||||||
Collections.Add( name, newCollection );
|
Collections.Add( name, newCollection );
|
||||||
|
CollectionChanged?.Invoke( null, newCollection, CollectionType.Inactive );
|
||||||
newCollection.Save();
|
newCollection.Save();
|
||||||
SetCurrentCollection( newCollection );
|
SetCollection( newCollection, CollectionType.Current );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,26 +156,27 @@ public class CollectionManager
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollectionChanged?.Invoke( collection, null, CollectionType.Inactive );
|
||||||
if( CurrentCollection == collection )
|
if( CurrentCollection == collection )
|
||||||
{
|
{
|
||||||
SetCurrentCollection( Collections[ ModCollection.DefaultCollection ] );
|
SetCollection( Collections[ ModCollection.DefaultCollection ], CollectionType.Current );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ForcedCollection == collection )
|
if( ForcedCollection == collection )
|
||||||
{
|
{
|
||||||
SetForcedCollection( ModCollection.Empty );
|
SetCollection( ModCollection.Empty, CollectionType.Forced );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( DefaultCollection == collection )
|
if( DefaultCollection == collection )
|
||||||
{
|
{
|
||||||
SetDefaultCollection( ModCollection.Empty );
|
SetCollection( ModCollection.Empty, CollectionType.Default );
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach( var (characterName, characterCollection) in CharacterCollection.ToArray() )
|
foreach( var (characterName, characterCollection) in CharacterCollection.ToArray() )
|
||||||
{
|
{
|
||||||
if( characterCollection == collection )
|
if( characterCollection == collection )
|
||||||
{
|
{
|
||||||
SetCharacterCollection( characterName, ModCollection.Empty );
|
SetCollection( ModCollection.Empty, CollectionType.Character, characterName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,51 +204,63 @@ public class CollectionManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCollection( ModCollection newCollection, ModCollection oldCollection, Action< ModCollection > setter,
|
public void SetCollection( ModCollection newCollection, CollectionType type, string? characterName = null )
|
||||||
Action< string > configSetter )
|
|
||||||
{
|
{
|
||||||
if( newCollection.Name == oldCollection.Name )
|
var oldCollection = type switch
|
||||||
|
{
|
||||||
|
CollectionType.Default => DefaultCollection,
|
||||||
|
CollectionType.Forced => ForcedCollection,
|
||||||
|
CollectionType.Current => CurrentCollection,
|
||||||
|
CollectionType.Character => characterName?.Length > 0
|
||||||
|
? CharacterCollection.TryGetValue( characterName, out var c )
|
||||||
|
? c
|
||||||
|
: ModCollection.Empty
|
||||||
|
: null,
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if( oldCollection == null || newCollection.Name == oldCollection.Name )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddCache( newCollection );
|
AddCache( newCollection );
|
||||||
|
|
||||||
setter( newCollection );
|
|
||||||
RemoveCache( oldCollection );
|
RemoveCache( oldCollection );
|
||||||
configSetter( newCollection.Name );
|
switch( type )
|
||||||
Penumbra.Config.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDefaultCollection( ModCollection newCollection )
|
|
||||||
=> SetCollection( newCollection, DefaultCollection, c =>
|
|
||||||
{
|
{
|
||||||
if( CollectionChangedTo.Length == 0 )
|
case CollectionType.Default:
|
||||||
{
|
DefaultCollection = newCollection;
|
||||||
SetActiveCollection( c, string.Empty );
|
Penumbra.Config.DefaultCollection = newCollection.Name;
|
||||||
}
|
if( CollectionChangedTo.Length == 0 )
|
||||||
|
|
||||||
DefaultCollection = c;
|
|
||||||
}, s => Penumbra.Config.DefaultCollection = s );
|
|
||||||
|
|
||||||
public void SetForcedCollection( ModCollection newCollection )
|
|
||||||
=> SetCollection( newCollection, ForcedCollection, c => ForcedCollection = c, s => Penumbra.Config.ForcedCollection = s );
|
|
||||||
|
|
||||||
public void SetCurrentCollection( ModCollection newCollection )
|
|
||||||
=> SetCollection( newCollection, CurrentCollection, c => CurrentCollection = c, s => Penumbra.Config.CurrentCollection = s );
|
|
||||||
|
|
||||||
public void SetCharacterCollection( string characterName, ModCollection newCollection )
|
|
||||||
=> SetCollection( newCollection,
|
|
||||||
CharacterCollection.TryGetValue( characterName, out var oldCollection ) ? oldCollection : ModCollection.Empty,
|
|
||||||
c =>
|
|
||||||
{
|
|
||||||
if( CollectionChangedTo == characterName && CharacterCollection.TryGetValue( characterName, out var collection ) )
|
|
||||||
{
|
{
|
||||||
SetActiveCollection( c, CollectionChangedTo );
|
SetActiveCollection( newCollection, string.Empty );
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterCollection[ characterName ] = c;
|
break;
|
||||||
}, s => Penumbra.Config.CharacterCollections[ characterName ] = s );
|
case CollectionType.Forced:
|
||||||
|
ForcedCollection = newCollection;
|
||||||
|
Penumbra.Config.ForcedCollection = newCollection.Name;
|
||||||
|
break;
|
||||||
|
case CollectionType.Current:
|
||||||
|
CurrentCollection = newCollection;
|
||||||
|
Penumbra.Config.CurrentCollection = newCollection.Name;
|
||||||
|
break;
|
||||||
|
case CollectionType.Character:
|
||||||
|
if( CollectionChangedTo == characterName && CharacterCollection.ContainsKey( characterName ) )
|
||||||
|
{
|
||||||
|
SetActiveCollection( newCollection, CollectionChangedTo );
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterCollection[ characterName! ] = newCollection;
|
||||||
|
Penumbra.Config.CharacterCollections[ characterName! ] = newCollection.Name;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionChanged?.Invoke( oldCollection, newCollection, type, characterName );
|
||||||
|
|
||||||
|
Penumbra.Config.Save();
|
||||||
|
}
|
||||||
|
|
||||||
public bool CreateCharacterCollection( string characterName )
|
public bool CreateCharacterCollection( string characterName )
|
||||||
{
|
{
|
||||||
|
|
@ -252,7 +272,7 @@ public class CollectionManager
|
||||||
CharacterCollection[ characterName ] = ModCollection.Empty;
|
CharacterCollection[ characterName ] = ModCollection.Empty;
|
||||||
Penumbra.Config.CharacterCollections[ characterName ] = string.Empty;
|
Penumbra.Config.CharacterCollections[ characterName ] = string.Empty;
|
||||||
Penumbra.Config.Save();
|
Penumbra.Config.Save();
|
||||||
Penumbra.PlayerWatcher.AddPlayerToWatch( characterName );
|
CollectionChanged?.Invoke( null, ModCollection.Empty, CollectionType.Character, characterName );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,7 +282,7 @@ public class CollectionManager
|
||||||
{
|
{
|
||||||
RemoveCache( collection );
|
RemoveCache( collection );
|
||||||
CharacterCollection.Remove( characterName );
|
CharacterCollection.Remove( characterName );
|
||||||
Penumbra.PlayerWatcher.RemovePlayerFromWatch( characterName );
|
CollectionChanged?.Invoke( collection, null, CollectionType.Character, characterName );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Penumbra.Config.CharacterCollections.Remove( characterName ) )
|
if( Penumbra.Config.CharacterCollections.Remove( characterName ) )
|
||||||
|
|
@ -338,7 +358,6 @@ public class CollectionManager
|
||||||
var configChanged = false;
|
var configChanged = false;
|
||||||
foreach( var (player, collectionName) in config.CharacterCollections.ToArray() )
|
foreach( var (player, collectionName) in config.CharacterCollections.ToArray() )
|
||||||
{
|
{
|
||||||
Penumbra.PlayerWatcher.AddPlayerToWatch( player );
|
|
||||||
if( collectionName.Length == 0 )
|
if( collectionName.Length == 0 )
|
||||||
{
|
{
|
||||||
CharacterCollection.Add( player, ModCollection.Empty );
|
CharacterCollection.Add( player, ModCollection.Empty );
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ public class ModManager
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.RecreateCaches();
|
Collections.RecreateCaches();
|
||||||
|
Collections.DefaultCollection.SetFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteMod( DirectoryInfo modFolder )
|
public void DeleteMod( DirectoryInfo modFolder )
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
private const string CommandName = "/penumbra";
|
private const string CommandName = "/penumbra";
|
||||||
|
|
||||||
public static Configuration Config { get; private set; } = null!;
|
public static Configuration Config { get; private set; } = null!;
|
||||||
public static IPlayerWatcher PlayerWatcher { get; private set; } = null!;
|
|
||||||
|
|
||||||
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
||||||
public static CharacterUtility CharacterUtility { get; private set; } = null!;
|
public static CharacterUtility CharacterUtility { get; private set; } = null!;
|
||||||
|
|
@ -72,10 +71,9 @@ public class Penumbra : IDalamudPlugin
|
||||||
MetaDefaults = new MetaDefaults();
|
MetaDefaults = new MetaDefaults();
|
||||||
ResourceLoader = new ResourceLoader( this );
|
ResourceLoader = new ResourceLoader( this );
|
||||||
ResourceLogger = new ResourceLogger( ResourceLoader );
|
ResourceLogger = new ResourceLogger( ResourceLoader );
|
||||||
PlayerWatcher = PlayerWatchFactory.Create( Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects );
|
|
||||||
ModManager = new ModManager();
|
ModManager = new ModManager();
|
||||||
ModManager.DiscoverMods();
|
ModManager.DiscoverMods();
|
||||||
ObjectReloader = new ObjectReloader( ModManager, Config.WaitFrames );
|
ObjectReloader = new ObjectReloader( ModManager );
|
||||||
PathResolver = new PathResolver( ResourceLoader );
|
PathResolver = new PathResolver( ResourceLoader );
|
||||||
|
|
||||||
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
||||||
|
|
@ -101,17 +99,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
CreateWebServer();
|
CreateWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !Config.EnablePlayerWatch || !Config.EnableMods )
|
|
||||||
{
|
|
||||||
PlayerWatcher.Disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerWatcher.PlayerChanged += p =>
|
|
||||||
{
|
|
||||||
PluginLog.Debug( "Triggered Redraw of {Player}.", p.Name );
|
|
||||||
ObjectReloader.RedrawObject( p, RedrawType.OnlyWithSettings );
|
|
||||||
};
|
|
||||||
|
|
||||||
ResourceLoader.EnableHooks();
|
ResourceLoader.EnableHooks();
|
||||||
if( Config.EnableMods )
|
if( Config.EnableMods )
|
||||||
{
|
{
|
||||||
|
|
@ -127,17 +114,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
ResourceLoader.EnableFullLogging();
|
ResourceLoader.EnableFullLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
PluginLog.Information( $"MetaManipulation: {sizeof( MetaManipulation )}" );
|
|
||||||
PluginLog.Information( $"EqpManipulation: {sizeof( EqpManipulation )}" );
|
|
||||||
PluginLog.Information( $"GmpManipulation: {sizeof( GmpManipulation )}" );
|
|
||||||
PluginLog.Information( $"EqdpManipulation: {sizeof( EqdpManipulation )}" );
|
|
||||||
PluginLog.Information( $"EstManipulation: {sizeof( EstManipulation )}" );
|
|
||||||
PluginLog.Information( $"RspManipulation: {sizeof( RspManipulation )}" );
|
|
||||||
PluginLog.Information( $"ImcManipulation: {sizeof( ImcManipulation )}" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enable()
|
public bool Enable()
|
||||||
|
|
@ -150,10 +126,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
Config.EnableMods = true;
|
Config.EnableMods = true;
|
||||||
ResourceLoader.EnableReplacements();
|
ResourceLoader.EnableReplacements();
|
||||||
ResidentResources.Reload();
|
ResidentResources.Reload();
|
||||||
if( Config.EnablePlayerWatch )
|
|
||||||
{
|
|
||||||
PlayerWatcher.SetStatus( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.Save();
|
Config.Save();
|
||||||
ObjectReloader.RedrawAll( RedrawType.WithSettings );
|
ObjectReloader.RedrawAll( RedrawType.WithSettings );
|
||||||
|
|
@ -170,10 +142,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
Config.EnableMods = false;
|
Config.EnableMods = false;
|
||||||
ResourceLoader.DisableReplacements();
|
ResourceLoader.DisableReplacements();
|
||||||
ResidentResources.Reload();
|
ResidentResources.Reload();
|
||||||
if( Config.EnablePlayerWatch )
|
|
||||||
{
|
|
||||||
PlayerWatcher.SetStatus( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.Save();
|
Config.Save();
|
||||||
ObjectReloader.RedrawAll( RedrawType.WithoutSettings );
|
ObjectReloader.RedrawAll( RedrawType.WithoutSettings );
|
||||||
|
|
@ -232,7 +200,6 @@ public class Penumbra : IDalamudPlugin
|
||||||
Api.Dispose();
|
Api.Dispose();
|
||||||
SettingsInterface.Dispose();
|
SettingsInterface.Dispose();
|
||||||
ObjectReloader.Dispose();
|
ObjectReloader.Dispose();
|
||||||
PlayerWatcher.Dispose();
|
|
||||||
|
|
||||||
Dalamud.Commands.RemoveHandler( CommandName );
|
Dalamud.Commands.RemoveHandler( CommandName );
|
||||||
|
|
||||||
|
|
@ -268,7 +235,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModManager.Collections.SetDefaultCollection( collection );
|
ModManager.Collections.SetCollection( collection, CollectionType.Default );
|
||||||
Dalamud.Chat.Print( $"Set {collection.Name} as default collection." );
|
Dalamud.Chat.Print( $"Set {collection.Name} as default collection." );
|
||||||
SettingsInterface.ResetDefaultCollection();
|
SettingsInterface.ResetDefaultCollection();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -279,7 +246,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModManager.Collections.SetForcedCollection( collection );
|
ModManager.Collections.SetCollection( collection, CollectionType.Forced );
|
||||||
Dalamud.Chat.Print( $"Set {collection.Name} as forced collection." );
|
Dalamud.Chat.Print( $"Set {collection.Name} as forced collection." );
|
||||||
SettingsInterface.ResetForcedCollection();
|
SettingsInterface.ResetForcedCollection();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ public partial class SettingsInterface
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Penumbra.ModManager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
|
Penumbra.ModManager.Collections.SetCollection( _collections[ idx + 1 ], CollectionType.Current );
|
||||||
_currentCollectionIndex = idx;
|
_currentCollectionIndex = idx;
|
||||||
_selector.Cache.TriggerListReset();
|
_selector.Cache.TriggerListReset();
|
||||||
if( _selector.Mod != null )
|
if( _selector.Mod != null )
|
||||||
|
|
@ -208,7 +208,7 @@ public partial class SettingsInterface
|
||||||
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
||||||
if( ImGui.Combo( "##Default Collection", ref index, _collectionNamesWithNone ) && index != _currentDefaultIndex )
|
if( ImGui.Combo( "##Default Collection", ref index, _collectionNamesWithNone ) && index != _currentDefaultIndex )
|
||||||
{
|
{
|
||||||
Penumbra.ModManager.Collections.SetDefaultCollection( _collections[ index ] );
|
Penumbra.ModManager.Collections.SetCollection( _collections[ index ], CollectionType.Default );
|
||||||
_currentDefaultIndex = index;
|
_currentDefaultIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@ public partial class SettingsInterface
|
||||||
&& index != _currentForcedIndex
|
&& index != _currentForcedIndex
|
||||||
&& manager.Collections.CharacterCollection.Count > 0 )
|
&& manager.Collections.CharacterCollection.Count > 0 )
|
||||||
{
|
{
|
||||||
manager.Collections.SetForcedCollection( _collections[ index ] );
|
manager.Collections.SetCollection( _collections[ index ], CollectionType.Forced );
|
||||||
_currentForcedIndex = index;
|
_currentForcedIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -352,7 +352,7 @@ public partial class SettingsInterface
|
||||||
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
||||||
if( ImGui.Combo( $"##{name}collection", ref tmp, _collectionNamesWithNone ) && idx != tmp )
|
if( ImGui.Combo( $"##{name}collection", ref tmp, _collectionNamesWithNone ) && idx != tmp )
|
||||||
{
|
{
|
||||||
manager.Collections.SetCharacterCollection( name, _collections[ tmp ] );
|
manager.Collections.SetCollection( _collections[ tmp ], CollectionType.Character, name );
|
||||||
_currentCharacterIndices[ name ] = tmp;
|
_currentCharacterIndices[ name ] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,104 +22,6 @@ namespace Penumbra.UI;
|
||||||
|
|
||||||
public partial class SettingsInterface
|
public partial class SettingsInterface
|
||||||
{
|
{
|
||||||
private static void DrawDebugTabPlayers()
|
|
||||||
{
|
|
||||||
if( !ImGui.CollapsingHeader( "Players##Debug" ) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var players = Penumbra.PlayerWatcher.WatchedPlayers().ToArray();
|
|
||||||
var count = players.Sum( s => Math.Max( 1, s.Item2.Length ) );
|
|
||||||
if( count == 0 )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !ImGui.BeginTable( "##ObjectTable", 13, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX,
|
|
||||||
new Vector2( -1, ImGui.GetTextLineHeightWithSpacing() * 4 * count ) ) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTable );
|
|
||||||
|
|
||||||
var identifier = GameData.GameData.GetIdentifier();
|
|
||||||
|
|
||||||
foreach( var (actor, equip) in players.SelectMany( kvp => kvp.Item2.Any()
|
|
||||||
? kvp.Item2
|
|
||||||
.Select( x => ( $"{kvp.Item1} ({x.Item1})", x.Item2 ) )
|
|
||||||
: new[] { ( kvp.Item1, new CharacterEquipment() ) } ) )
|
|
||||||
{
|
|
||||||
// @formatter:off
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( actor );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.MainHand}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Head}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Body}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Hands}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Legs}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Feet}" );
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
if (equip.IsSet == 0)
|
|
||||||
{
|
|
||||||
ImGui.Text( "(not set)" );
|
|
||||||
}
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.MainHand.Set, equip.MainHand.Type, equip.MainHand.Variant, EquipSlot.MainHand )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Head.Set, 0, equip.Head.Variant, EquipSlot.Head )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Body.Set, 0, equip.Body.Variant, EquipSlot.Body )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Hands.Set, 0, equip.Hands.Variant, EquipSlot.Hands )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Legs.Set, 0, equip.Legs.Variant, EquipSlot.Legs )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Feet.Set, 0, equip.Feet.Variant, EquipSlot.Feet )?.Name.ToString() ?? "Unknown" );
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.OffHand}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Ears}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Neck}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.Wrists}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.LFinger}" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( $"{equip.RFinger}" );
|
|
||||||
|
|
||||||
ImGui.TableNextRow();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.OffHand.Set, equip.OffHand.Type, equip.OffHand.Variant, EquipSlot.OffHand )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Ears.Set, 0, equip.Ears.Variant, EquipSlot.Ears )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Neck.Set, 0, equip.Neck.Variant, EquipSlot.Neck )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.Wrists.Set, 0, equip.Wrists.Variant, EquipSlot.Wrists )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.LFinger.Set, 0, equip.LFinger.Variant, EquipSlot.LFinger )?.Name.ToString() ?? "Unknown" );
|
|
||||||
ImGui.TableNextColumn();
|
|
||||||
ImGui.Text( identifier.Identify( equip.RFinger.Set, 0, equip.RFinger.Variant, EquipSlot.LFinger )?.Name.ToString() ?? "Unknown" );
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PrintValue( string name, string value )
|
private static void PrintValue( string name, string value )
|
||||||
{
|
{
|
||||||
ImGui.TableNextRow();
|
ImGui.TableNextRow();
|
||||||
|
|
@ -431,8 +333,8 @@ public partial class SettingsInterface
|
||||||
{
|
{
|
||||||
var def = ExpandedGmpFile.GetDefault( gmp );
|
var def = ExpandedGmpFile.GetDefault( gmp );
|
||||||
var val = Penumbra.ModManager.Collections.ActiveCollection.Cache?.MetaManipulations.Gmp.File?[ gmp ] ?? def;
|
var val = Penumbra.ModManager.Collections.ActiveCollection.Cache?.MetaManipulations.Gmp.File?[ gmp ] ?? def;
|
||||||
ImGui.Text( def.Value.ToString("X") );
|
ImGui.Text( def.Value.ToString( "X" ) );
|
||||||
ImGui.Text( val.Value.ToString("X") );
|
ImGui.Text( val.Value.ToString( "X" ) );
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -557,8 +459,6 @@ public partial class SettingsInterface
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
DrawDebugTabRedraw();
|
DrawDebugTabRedraw();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
DrawDebugTabPlayers();
|
|
||||||
ImGui.NewLine();
|
|
||||||
DrawDebugTabIpc();
|
DrawDebugTabIpc();
|
||||||
ImGui.NewLine();
|
ImGui.NewLine();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing.Text;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.Meta.Files;
|
using Penumbra.Meta.Files;
|
||||||
|
|
@ -77,22 +75,12 @@ public partial class SettingsInterface
|
||||||
( Gender.FemaleNpc.ToName(), Gender.FemaleNpc ),
|
( Gender.FemaleNpc.ToName(), Gender.FemaleNpc ),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly (string, ObjectType)[] ObjectTypes =
|
private static readonly (string, EstManipulation.EstType)[] EstTypes =
|
||||||
{
|
{
|
||||||
( "Equipment", ObjectType.Equipment ),
|
( "Hair", EstManipulation.EstType.Hair ),
|
||||||
( "Customization", ObjectType.Character ),
|
( "Face", EstManipulation.EstType.Face ),
|
||||||
};
|
( "Body", EstManipulation.EstType.Body ),
|
||||||
|
( "Head", EstManipulation.EstType.Head ),
|
||||||
private static readonly (string, EquipSlot)[] EstEquipSlots =
|
|
||||||
{
|
|
||||||
EqpEquipSlots[ 0 ],
|
|
||||||
EqpEquipSlots[ 1 ],
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly (string, BodySlot)[] EstBodySlots =
|
|
||||||
{
|
|
||||||
( "Hair", BodySlot.Hair ),
|
|
||||||
( "Face", BodySlot.Face ),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly (string, SubRace)[] Subraces =
|
private static readonly (string, SubRace)[] Subraces =
|
||||||
|
|
@ -133,9 +121,11 @@ public partial class SettingsInterface
|
||||||
( RspAttribute.FemaleMaxTail.ToFullString(), RspAttribute.FemaleMaxTail ),
|
( RspAttribute.FemaleMaxTail.ToFullString(), RspAttribute.FemaleMaxTail ),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private static readonly (string, ObjectType)[] ImcObjectType =
|
private static readonly (string, ObjectType)[] ImcObjectType =
|
||||||
{
|
{
|
||||||
ObjectTypes[ 0 ],
|
( "Equipment", ObjectType.Equipment ),
|
||||||
|
( "Customization", ObjectType.Character ),
|
||||||
( "Weapon", ObjectType.Weapon ),
|
( "Weapon", ObjectType.Weapon ),
|
||||||
( "Demihuman", ObjectType.DemiHuman ),
|
( "Demihuman", ObjectType.DemiHuman ),
|
||||||
( "Monster", ObjectType.Monster ),
|
( "Monster", ObjectType.Monster ),
|
||||||
|
|
@ -143,8 +133,8 @@ public partial class SettingsInterface
|
||||||
|
|
||||||
private static readonly (string, BodySlot)[] ImcBodySlots =
|
private static readonly (string, BodySlot)[] ImcBodySlots =
|
||||||
{
|
{
|
||||||
EstBodySlots[ 0 ],
|
( "Hair", BodySlot.Hair ),
|
||||||
EstBodySlots[ 1 ],
|
( "Face", BodySlot.Face ),
|
||||||
( "Body", BodySlot.Body ),
|
( "Body", BodySlot.Body ),
|
||||||
( "Tail", BodySlot.Tail ),
|
( "Tail", BodySlot.Tail ),
|
||||||
( "Ears", BodySlot.Zear ),
|
( "Ears", BodySlot.Zear ),
|
||||||
|
|
@ -646,24 +636,26 @@ public partial class SettingsInterface
|
||||||
RestrictedInputInt( "Set Id##newManipImc", ref _newManipSetId, 0, ushort.MaxValue );
|
RestrictedInputInt( "Set Id##newManipImc", ref _newManipSetId, 0, ushort.MaxValue );
|
||||||
RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue );
|
RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue );
|
||||||
CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType );
|
CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType );
|
||||||
EquipSlot equipSlot = default;
|
ImcManipulation imc = new();
|
||||||
switch( objectType )
|
switch( objectType )
|
||||||
{
|
{
|
||||||
case ObjectType.Equipment:
|
case ObjectType.Equipment:
|
||||||
CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot );
|
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
||||||
//newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant,
|
imc = new ImcManipulation( equipSlot, _newManipVariant, _newManipSetId, new ImcEntry() );
|
||||||
// new ImcFile.ImageChangeData() );
|
|
||||||
break;
|
break;
|
||||||
case ObjectType.DemiHuman:
|
case ObjectType.DemiHuman:
|
||||||
case ObjectType.Weapon:
|
case ObjectType.Weapon:
|
||||||
case ObjectType.Monster:
|
case ObjectType.Monster:
|
||||||
RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
|
RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
|
||||||
CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
|
CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
|
||||||
//newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
|
imc = new ImcManipulation( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
|
||||||
// _newManipVariant, new ImcFile.ImageChangeData() );
|
_newManipVariant, new ImcEntry() );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newManip = new MetaManipulation( new ImcManipulation( imc.ObjectType, imc.BodySlot, imc.PrimaryId, imc.SecondaryId,
|
||||||
|
imc.Variant, imc.EquipSlot, ImcFile.GetDefault( imc.GamePath(), imc.EquipSlot, imc.Variant ) ) );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaManipulation.Type.Eqdp:
|
case MetaManipulation.Type.Eqdp:
|
||||||
|
|
@ -672,76 +664,50 @@ public partial class SettingsInterface
|
||||||
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
||||||
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
||||||
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
||||||
//newManip = MetaManipulation.Eqdp( equipSlot, Names.CombinedRace( gender, race ), ( ushort )_newManipSetId,
|
var eqdp = new EqdpManipulation( new EqdpEntry(), equipSlot, gender, race, _newManipSetId );
|
||||||
// new EqdpEntry() );
|
newManip = new MetaManipulation( new EqdpManipulation( ExpandedEqdpFile.GetDefault( eqdp.FileIndex(), eqdp.SetId ),
|
||||||
|
equipSlot, gender, race, _newManipSetId ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaManipulation.Type.Eqp:
|
case MetaManipulation.Type.Eqp:
|
||||||
{
|
{
|
||||||
RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue );
|
RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue );
|
||||||
CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
CustomCombo( "Equipment Slot", EqpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
||||||
//newManip = MetaManipulation.Eqp( equipSlot, ( ushort )_newManipSetId, 0 );
|
newManip = new MetaManipulation( new EqpManipulation( ExpandedEqpFile.GetDefault( _newManipSetId ) & Eqp.Mask( equipSlot ),
|
||||||
|
equipSlot, _newManipSetId ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaManipulation.Type.Est:
|
case MetaManipulation.Type.Est:
|
||||||
{
|
{
|
||||||
RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue );
|
RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue );
|
||||||
CustomCombo( "Object Type", ObjectTypes, out var objectType, ref _newManipObjectType );
|
CustomCombo( "Est Type", EstTypes, out var estType, ref _newManipObjectType );
|
||||||
EquipSlot equipSlot = default;
|
|
||||||
BodySlot bodySlot = default;
|
|
||||||
switch( ( ObjectType )_newManipObjectType )
|
|
||||||
{
|
|
||||||
case ObjectType.Equipment:
|
|
||||||
CustomCombo( "Equipment Slot", EstEquipSlots, out equipSlot, ref _newManipEquipSlot );
|
|
||||||
break;
|
|
||||||
case ObjectType.Character:
|
|
||||||
CustomCombo( "Body Slot", EstBodySlots, out bodySlot, ref _newManipBodySlot );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
||||||
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
||||||
//newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot,
|
newManip = new MetaManipulation( new EstManipulation( gender, race, estType, _newManipSetId,
|
||||||
// ( ushort )_newManipSetId, 0 );
|
EstFile.GetDefault( estType, Names.CombinedRace( gender, race ), _newManipSetId ) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaManipulation.Type.Gmp:
|
case MetaManipulation.Type.Gmp:
|
||||||
RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue );
|
RestrictedInputInt( "Set Id##newManipGmp", ref _newManipSetId, 0, ushort.MaxValue );
|
||||||
//newManip = MetaManipulation.Gmp( ( ushort )_newManipSetId, new GmpEntry() );
|
newManip = new MetaManipulation( new GmpManipulation( ExpandedGmpFile.GetDefault( _newManipSetId ), _newManipSetId ) );
|
||||||
break;
|
break;
|
||||||
case MetaManipulation.Type.Rsp:
|
case MetaManipulation.Type.Rsp:
|
||||||
CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
|
CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
|
||||||
CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute );
|
CustomCombo( "Attribute", RspAttributes, out var rspAttribute, ref _newManipAttribute );
|
||||||
//newManip = MetaManipulation.Rsp( subRace, rspAttribute, 1f );
|
newManip = new MetaManipulation( new RspManipulation( subRace, rspAttribute,
|
||||||
|
CmpFile.GetDefault( subRace, rspAttribute ) ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
|
if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
|
||||||
// && newManip != null
|
&& newManip != null
|
||||||
// && list.All( m => m.Identifier != newManip.Value.Identifier ) )
|
&& list.All( m => !m.Equals( newManip ) ) )
|
||||||
//{
|
{
|
||||||
// var def = Penumbra.MetaDefaults.GetDefaultValue( newManip.Value );
|
list.Add( newManip.Value );
|
||||||
// if( def != null )
|
change = true;
|
||||||
// {
|
++count;
|
||||||
// var manip = newManip.Value.Type switch
|
ImGui.CloseCurrentPopup();
|
||||||
// {
|
}
|
||||||
// MetaType.Est => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
|
|
||||||
// MetaType.Eqp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
|
|
||||||
// MetaType.Eqdp => new MetaManipulation( newManip.Value.Identifier, (ushort) def ),
|
|
||||||
// MetaType.Gmp => new MetaManipulation( newManip.Value.Identifier, ( ulong )def ),
|
|
||||||
// MetaType.Imc => new MetaManipulation( newManip.Value.Identifier,
|
|
||||||
// ( ( ImcFile.ImageChangeData )def ).ToInteger() ),
|
|
||||||
// MetaType.Rsp => MetaManipulation.Rsp( newManip.Value.RspIdentifier.SubRace,
|
|
||||||
// newManip.Value.RspIdentifier.Attribute, ( float )def ),
|
|
||||||
// _ => throw new InvalidEnumArgumentException(),
|
|
||||||
// };
|
|
||||||
// list.Add( manip );
|
|
||||||
// change = true;
|
|
||||||
// ++count;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ImGui.CloseCurrentPopup();
|
|
||||||
//}
|
|
||||||
|
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,10 @@ public partial class SettingsInterface
|
||||||
|
|
||||||
if( ImGui.IsItemClicked() )
|
if( ImGui.IsItemClicked() )
|
||||||
{
|
{
|
||||||
var data = ( ( Interop.Structs.ResourceHandle* )r )->GetData();
|
var data = Interop.Structs.ResourceHandle.GetData( ( Interop.Structs.ResourceHandle* )r );
|
||||||
|
var length = ( int )Interop.Structs.ResourceHandle.GetLength( ( Interop.Structs.ResourceHandle* )r );
|
||||||
ImGui.SetClipboardText( string.Join( " ",
|
ImGui.SetClipboardText( string.Join( " ",
|
||||||
new ReadOnlySpan< byte >( ( byte* )data.Data, data.Length ).ToArray().Select( b => b.ToString( "X2" ) ) ) );
|
new ReadOnlySpan< byte >( data, length ).ToArray().Select( b => b.ToString( "X2" ) ) ) );
|
||||||
//ImGuiNative.igSetClipboardText( ( byte* )Structs.ResourceHandle.GetData( ( IntPtr )r ) );
|
//ImGuiNative.igSetClipboardText( ( byte* )Structs.ResourceHandle.GetData( ( IntPtr )r ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ public partial class SettingsInterface
|
||||||
|
|
||||||
public TabSettings( SettingsInterface ui )
|
public TabSettings( SettingsInterface ui )
|
||||||
{
|
{
|
||||||
_base = ui;
|
_base = ui;
|
||||||
_config = Penumbra.Config;
|
_config = Penumbra.Config;
|
||||||
_configChanged = false;
|
_configChanged = false;
|
||||||
_newModDirectory = _config.ModDirectory;
|
_newModDirectory = _config.ModDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DrawPressEnterWarning( string old )
|
private static bool DrawPressEnterWarning( string old )
|
||||||
|
|
@ -239,44 +239,6 @@ public partial class SettingsInterface
|
||||||
ImGuiComponents.HelpMarker( "Enables other applications, e.g. Anamnesis, to use some Penumbra functions, like requesting redraws." );
|
ImGuiComponents.HelpMarker( "Enables other applications, e.g. Anamnesis, to use some Penumbra functions, like requesting redraws." );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawEnabledPlayerWatcher()
|
|
||||||
{
|
|
||||||
var enabled = _config.EnablePlayerWatch;
|
|
||||||
if( ImGui.Checkbox( "Enable Automatic Character Redraws", ref enabled ) )
|
|
||||||
{
|
|
||||||
_config.EnablePlayerWatch = enabled;
|
|
||||||
_configChanged = true;
|
|
||||||
Penumbra.PlayerWatcher.SetStatus( enabled );
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImGuiComponents.HelpMarker(
|
|
||||||
"If this setting is enabled, Penumbra will keep tabs on characters that have a corresponding character collection setup in the Collections tab.\n"
|
|
||||||
+ "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip.\n" );
|
|
||||||
|
|
||||||
if( !_config.EnablePlayerWatch || !_config.ShowAdvanced )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var waitFrames = _config.WaitFrames;
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImGui.SetNextItemWidth( 50 * ImGuiHelpers.GlobalScale );
|
|
||||||
if( ImGui.InputInt( "Wait Frames", ref waitFrames, 0, 0 )
|
|
||||||
&& waitFrames != _config.WaitFrames
|
|
||||||
&& waitFrames is > 0 and < 3000 )
|
|
||||||
{
|
|
||||||
_base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames;
|
|
||||||
_config.WaitFrames = waitFrames;
|
|
||||||
_configChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
ImGuiComponents.HelpMarker(
|
|
||||||
"The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n"
|
|
||||||
+ "Keep this as low as possible while producing stable results." );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DrawReloadResourceButton()
|
private static void DrawReloadResourceButton()
|
||||||
{
|
{
|
||||||
if( ImGui.Button( "Reload Resident Resources" ) )
|
if( ImGui.Button( "Reload Resident Resources" ) )
|
||||||
|
|
@ -388,7 +350,6 @@ public partial class SettingsInterface
|
||||||
|
|
||||||
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
||||||
DrawEnabledBox();
|
DrawEnabledBox();
|
||||||
DrawEnabledPlayerWatcher();
|
|
||||||
|
|
||||||
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
||||||
DrawScaleModSelectorBox();
|
DrawScaleModSelectorBox();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue