More fixes, some cleanup.

This commit is contained in:
Ottermandias 2022-03-17 14:03:57 +01:00
parent 581b91b337
commit e6752ade04
20 changed files with 193 additions and 361 deletions

View file

@ -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 );
} }

View file

@ -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;

View file

@ -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;

View file

@ -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;
} }

View file

@ -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 );
} }
} }

View file

@ -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 ) );

View file

@ -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();
} }

View file

@ -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 );
} }

View file

@ -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 )

View file

@ -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 )

View file

@ -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 )

View file

@ -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;
} }

View file

@ -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 );

View file

@ -146,6 +146,7 @@ public class ModManager
} }
Collections.RecreateCaches(); Collections.RecreateCaches();
Collections.DefaultCollection.SetFiles();
} }
public void DeleteMod( DirectoryInfo modFolder ) public void DeleteMod( DirectoryInfo modFolder )

View file

@ -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;

View file

@ -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;
} }

View file

@ -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();
} }

View file

@ -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;
} }

View file

@ -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 ) );
} }

View file

@ -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();