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;
|
||||
}
|
||||
|
||||
if( !Utf8String.FromString( substring, out var ascii ) || !ascii.IsAscii )
|
||||
if( !Utf8String.FromString( substring, out var ascii, true ) || !ascii.IsAscii )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
|||
return false;
|
||||
}
|
||||
|
||||
var substring = file.FullName[ baseDir.FullName.Length.. ];
|
||||
var substring = file.FullName[ (baseDir.FullName.Length + 1).. ];
|
||||
return FromString( substring, out path );
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ public readonly struct Utf8RelPath : IEquatable< Utf8RelPath >, IComparable< Utf
|
|||
return false;
|
||||
}
|
||||
|
||||
var substring = file.FullName[ baseDir.FullName.Length.. ];
|
||||
var substring = file.FullName[ (baseDir.FullName.Length + 1).. ];
|
||||
return FromString( substring, out path );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ public sealed unsafe partial class Utf8String : IDisposable
|
|||
}
|
||||
|
||||
Marshal.FreeHGlobal( ( IntPtr )_path );
|
||||
GC.RemoveMemoryPressure( Length );
|
||||
GC.RemoveMemoryPressure( Length + 1 );
|
||||
_length = AsciiCheckedFlag | AsciiFlag | AsciiLowerCheckedFlag | AsciiLowerFlag | NullTerminatedFlag;
|
||||
_path = Null.NullBytePtr;
|
||||
_crc32 = 0;
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ public class Configuration : IPluginConfiguration
|
|||
|
||||
public bool DisableSoundStreaming { get; set; } = true;
|
||||
public bool EnableHttpApi { get; set; }
|
||||
public bool EnablePlayerWatch { get; set; } = false;
|
||||
public int WaitFrames { get; set; } = 30;
|
||||
|
||||
public string ModDirectory { get; set; } = string.Empty;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -16,8 +14,6 @@ public unsafe class ObjectReloader : IDisposable
|
|||
{
|
||||
private delegate void ManipulateDraw( IntPtr actor );
|
||||
|
||||
private const int RenderModeOffset = 0x0104;
|
||||
private const int UnloadAllRedrawDelay = 250;
|
||||
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
|
||||
public const int GPosePlayerIdx = 201;
|
||||
public const int GPoseEndIdx = GPosePlayerIdx + 48;
|
||||
|
|
@ -25,9 +21,6 @@ public unsafe class ObjectReloader : IDisposable
|
|||
private readonly ModManager _mods;
|
||||
private readonly Queue< (uint actorId, string name, RedrawType s) > _actorIds = new();
|
||||
|
||||
internal int DefaultWaitFrames;
|
||||
|
||||
private int _waitFrames;
|
||||
private int _currentFrame;
|
||||
private bool _changedSettings;
|
||||
private uint _currentObjectId = uint.MaxValue;
|
||||
|
|
@ -46,11 +39,8 @@ public unsafe class ObjectReloader : IDisposable
|
|||
private static delegate*< IntPtr, void > GetEnableDraw( GameObject actor )
|
||||
=> ( ( delegate*< IntPtr, void >** )actor.Address )[ 0 ][ 16 ];
|
||||
|
||||
public ObjectReloader( ModManager mods, int defaultWaitFrames )
|
||||
{
|
||||
_mods = mods;
|
||||
DefaultWaitFrames = defaultWaitFrames;
|
||||
}
|
||||
public ObjectReloader( ModManager mods )
|
||||
=> _mods = mods;
|
||||
|
||||
private void ChangeSettings()
|
||||
{
|
||||
|
|
@ -289,13 +279,6 @@ public unsafe class ObjectReloader : IDisposable
|
|||
|| Dalamud.Conditions[ ConditionFlag.BetweenAreas ]
|
||||
|| Dalamud.Conditions[ ConditionFlag.OccupiedInCutSceneEvent ] )
|
||||
{
|
||||
_waitFrames = DefaultWaitFrames;
|
||||
return;
|
||||
}
|
||||
|
||||
if( _waitFrames > 0 )
|
||||
{
|
||||
--_waitFrames;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,10 +68,12 @@ public unsafe partial class PathResolver
|
|||
CharacterBaseCreateHook?.Enable();
|
||||
EnableDrawHook?.Enable();
|
||||
CharacterBaseDestructorHook?.Enable();
|
||||
Penumbra.ModManager.Collections.CollectionChanged += CheckCollections;
|
||||
}
|
||||
|
||||
private void DisableDataHooks()
|
||||
{
|
||||
Penumbra.ModManager.Collections.CollectionChanged -= CheckCollections;
|
||||
CharacterBaseCreateHook?.Disable();
|
||||
EnableDrawHook?.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.
|
||||
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() )
|
||||
{
|
||||
if( !VerifyEntry( key, idx, out var obj ) )
|
||||
|
|
@ -187,8 +194,8 @@ public unsafe partial class PathResolver
|
|||
DrawObjectToObject.Remove( key );
|
||||
}
|
||||
|
||||
var collection = IdentifyCollection( obj );
|
||||
DrawObjectToObject[ key ] = ( collection, idx );
|
||||
var newCollection = IdentifyCollection( obj );
|
||||
DrawObjectToObject[ key ] = ( newCollection, idx );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using Penumbra.GameData.ByteString;
|
||||
|
|
@ -64,6 +65,7 @@ public unsafe partial class PathResolver
|
|||
|
||||
var mtrlPath = Utf8String.FromSpanUnsafe( mtrl->Handle.FileNameSpan(), true, null, true );
|
||||
var collection = PathCollections.TryGetValue( mtrlPath, out var c ) ? c : null;
|
||||
var x = PathCollections.ToList();
|
||||
for( var i = 0; i < mtrl->NumTex; ++i )
|
||||
{
|
||||
var texString = new Utf8String( mtrl->TexString( i ) );
|
||||
|
|
|
|||
|
|
@ -92,16 +92,17 @@ public unsafe partial class PathResolver
|
|||
}
|
||||
}
|
||||
|
||||
// GMP
|
||||
public delegate void ApplyVisorDelegate( IntPtr drawObject, IntPtr unk1, float unk2, IntPtr unk3, ushort unk4, char unk5 );
|
||||
// GMP. This gets called every time when changing visor state, and it accesses the gmp file itself,
|
||||
// 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" )]
|
||||
public Hook< ApplyVisorDelegate >? ApplyVisorHook;
|
||||
[Signature( "48 8B ?? 53 55 57 48 83 ?? ?? 48 8B", DetourName = "SetupVisorDetour" )]
|
||||
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 );
|
||||
ApplyVisorHook!.Original( drawObject, unk1, unk2, unk3, unk4, unk5 );
|
||||
return SetupVisorHook!.Original( drawObject, modelId, visorState );
|
||||
}
|
||||
|
||||
// RSP
|
||||
|
|
@ -132,7 +133,7 @@ public unsafe partial class PathResolver
|
|||
OnModelLoadCompleteHook?.Enable();
|
||||
#endif
|
||||
#if USE_GMP
|
||||
ApplyVisorHook?.Enable();
|
||||
SetupVisorHook?.Enable();
|
||||
#endif
|
||||
#if USE_CMP
|
||||
RspSetupCharacterHook?.Enable();
|
||||
|
|
@ -144,7 +145,7 @@ public unsafe partial class PathResolver
|
|||
GetEqpIndirectHook?.Disable();
|
||||
UpdateModelsHook?.Disable();
|
||||
OnModelLoadCompleteHook?.Disable();
|
||||
ApplyVisorHook?.Disable();
|
||||
SetupVisorHook?.Disable();
|
||||
RspSetupCharacterHook?.Disable();
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +154,7 @@ public unsafe partial class PathResolver
|
|||
GetEqpIndirectHook?.Dispose();
|
||||
UpdateModelsHook?.Dispose();
|
||||
OnModelLoadCompleteHook?.Dispose();
|
||||
ApplyVisorHook?.Dispose();
|
||||
SetupVisorHook?.Dispose();
|
||||
RspSetupCharacterHook?.Dispose();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ public partial class PathResolver : IDisposable
|
|||
resolved = Penumbra.ModManager.Collections.ForcedCollection.ResolveSwappedOrReplacementPath( gamePath );
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,19 +37,31 @@ public unsafe struct ResourceHandle
|
|||
public ReadOnlySpan< byte > FileNameSpan()
|
||||
=> new(FileName(), FileNameLength);
|
||||
|
||||
[FieldOffset( 0x00 )]
|
||||
public void** VTable;
|
||||
|
||||
[FieldOffset( 0x48 )]
|
||||
public byte* FileNameData;
|
||||
|
||||
[FieldOffset( 0x58 )]
|
||||
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 )]
|
||||
public DataIndirection* Data;
|
||||
|
||||
[FieldOffset( 0xB8 )]
|
||||
public uint DataLength;
|
||||
|
||||
|
||||
public (IntPtr Data, int Length) GetData()
|
||||
=> Data != null
|
||||
? ( ( IntPtr )Data->DataPtr, ( int )Data->DataLength )
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile
|
|||
|
||||
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 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 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 )
|
||||
|
|
|
|||
|
|
@ -201,7 +201,9 @@ public unsafe class ImcFile : MetaBaseFile
|
|||
var file = Dalamud.GameData.GetFile( path.ToString() );
|
||||
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 )
|
||||
|
|
|
|||
|
|
@ -24,16 +24,22 @@ public unsafe class MetaBaseFile : IDisposable
|
|||
{
|
||||
Length = length;
|
||||
Data = ( byte* )MemoryHelper.GameAllocateDefault( ( ulong )length );
|
||||
;
|
||||
if( length > 0 )
|
||||
{
|
||||
GC.AddMemoryPressure( length );
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory.
|
||||
protected void ReleaseUnmanagedResources()
|
||||
{
|
||||
var ptr = ( IntPtr )Data;
|
||||
MemoryHelper.GameFree( ref ptr, ( ulong )Length );
|
||||
if( Length > 0 )
|
||||
{
|
||||
GC.RemoveMemoryPressure( Length );
|
||||
}
|
||||
|
||||
Length = 0;
|
||||
Data = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Logging;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Mod;
|
||||
using Penumbra.Util;
|
||||
|
||||
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.
|
||||
public class CollectionManager
|
||||
{
|
||||
|
|
@ -21,7 +31,10 @@ public class CollectionManager
|
|||
public ModCollection CurrentCollection { get; private set; } = ModCollection.Empty;
|
||||
public ModCollection DefaultCollection { 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 )
|
||||
{
|
||||
|
|
@ -29,7 +42,7 @@ public class CollectionManager
|
|||
|
||||
ReadCollections();
|
||||
LoadConfigCollections( Penumbra.Config );
|
||||
ActiveCollection = DefaultCollection;
|
||||
SetActiveCollection( DefaultCollection, string.Empty );
|
||||
}
|
||||
|
||||
public bool SetActiveCollection( ModCollection newActive, string name )
|
||||
|
|
@ -44,14 +57,7 @@ public class CollectionManager
|
|||
{
|
||||
ActiveCollection = newActive;
|
||||
Penumbra.ResidentResources.Reload();
|
||||
if( ActiveCollection.Cache == null )
|
||||
{
|
||||
Penumbra.CharacterUtility.ResetAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveCollection.Cache.MetaManipulations.SetFiles();
|
||||
}
|
||||
ActiveCollection.SetFiles();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -131,8 +137,9 @@ public class CollectionManager
|
|||
|
||||
var newCollection = new ModCollection( name, settings );
|
||||
Collections.Add( name, newCollection );
|
||||
CollectionChanged?.Invoke( null, newCollection, CollectionType.Inactive );
|
||||
newCollection.Save();
|
||||
SetCurrentCollection( newCollection );
|
||||
SetCollection( newCollection, CollectionType.Current );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -149,26 +156,27 @@ public class CollectionManager
|
|||
return false;
|
||||
}
|
||||
|
||||
CollectionChanged?.Invoke( collection, null, CollectionType.Inactive );
|
||||
if( CurrentCollection == collection )
|
||||
{
|
||||
SetCurrentCollection( Collections[ ModCollection.DefaultCollection ] );
|
||||
SetCollection( Collections[ ModCollection.DefaultCollection ], CollectionType.Current );
|
||||
}
|
||||
|
||||
if( ForcedCollection == collection )
|
||||
{
|
||||
SetForcedCollection( ModCollection.Empty );
|
||||
SetCollection( ModCollection.Empty, CollectionType.Forced );
|
||||
}
|
||||
|
||||
if( DefaultCollection == collection )
|
||||
{
|
||||
SetDefaultCollection( ModCollection.Empty );
|
||||
SetCollection( ModCollection.Empty, CollectionType.Default );
|
||||
}
|
||||
|
||||
foreach( var (characterName, characterCollection) in CharacterCollection.ToArray() )
|
||||
{
|
||||
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,
|
||||
Action< string > configSetter )
|
||||
public void SetCollection( ModCollection newCollection, CollectionType type, string? characterName = null )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
AddCache( newCollection );
|
||||
|
||||
setter( newCollection );
|
||||
RemoveCache( oldCollection );
|
||||
configSetter( newCollection.Name );
|
||||
Penumbra.Config.Save();
|
||||
}
|
||||
|
||||
public void SetDefaultCollection( ModCollection newCollection )
|
||||
=> SetCollection( newCollection, DefaultCollection, c =>
|
||||
switch( type )
|
||||
{
|
||||
case CollectionType.Default:
|
||||
DefaultCollection = newCollection;
|
||||
Penumbra.Config.DefaultCollection = newCollection.Name;
|
||||
if( CollectionChangedTo.Length == 0 )
|
||||
{
|
||||
SetActiveCollection( c, string.Empty );
|
||||
SetActiveCollection( newCollection, string.Empty );
|
||||
}
|
||||
|
||||
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 =>
|
||||
break;
|
||||
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 ) )
|
||||
{
|
||||
if( CollectionChangedTo == characterName && CharacterCollection.TryGetValue( characterName, out var collection ) )
|
||||
{
|
||||
SetActiveCollection( c, CollectionChangedTo );
|
||||
SetActiveCollection( newCollection, CollectionChangedTo );
|
||||
}
|
||||
|
||||
CharacterCollection[ characterName ] = c;
|
||||
}, s => Penumbra.Config.CharacterCollections[ characterName ] = s );
|
||||
CharacterCollection[ characterName! ] = newCollection;
|
||||
Penumbra.Config.CharacterCollections[ characterName! ] = newCollection.Name;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
CollectionChanged?.Invoke( oldCollection, newCollection, type, characterName );
|
||||
|
||||
Penumbra.Config.Save();
|
||||
}
|
||||
|
||||
public bool CreateCharacterCollection( string characterName )
|
||||
{
|
||||
|
|
@ -252,7 +272,7 @@ public class CollectionManager
|
|||
CharacterCollection[ characterName ] = ModCollection.Empty;
|
||||
Penumbra.Config.CharacterCollections[ characterName ] = string.Empty;
|
||||
Penumbra.Config.Save();
|
||||
Penumbra.PlayerWatcher.AddPlayerToWatch( characterName );
|
||||
CollectionChanged?.Invoke( null, ModCollection.Empty, CollectionType.Character, characterName );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +282,7 @@ public class CollectionManager
|
|||
{
|
||||
RemoveCache( collection );
|
||||
CharacterCollection.Remove( characterName );
|
||||
Penumbra.PlayerWatcher.RemovePlayerFromWatch( characterName );
|
||||
CollectionChanged?.Invoke( collection, null, CollectionType.Character, characterName );
|
||||
}
|
||||
|
||||
if( Penumbra.Config.CharacterCollections.Remove( characterName ) )
|
||||
|
|
@ -338,7 +358,6 @@ public class CollectionManager
|
|||
var configChanged = false;
|
||||
foreach( var (player, collectionName) in config.CharacterCollections.ToArray() )
|
||||
{
|
||||
Penumbra.PlayerWatcher.AddPlayerToWatch( player );
|
||||
if( collectionName.Length == 0 )
|
||||
{
|
||||
CharacterCollection.Add( player, ModCollection.Empty );
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ public class ModManager
|
|||
}
|
||||
|
||||
Collections.RecreateCaches();
|
||||
Collections.DefaultCollection.SetFiles();
|
||||
}
|
||||
|
||||
public void DeleteMod( DirectoryInfo modFolder )
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ public class Penumbra : IDalamudPlugin
|
|||
private const string CommandName = "/penumbra";
|
||||
|
||||
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 CharacterUtility CharacterUtility { get; private set; } = null!;
|
||||
|
|
@ -72,10 +71,9 @@ public class Penumbra : IDalamudPlugin
|
|||
MetaDefaults = new MetaDefaults();
|
||||
ResourceLoader = new ResourceLoader( this );
|
||||
ResourceLogger = new ResourceLogger( ResourceLoader );
|
||||
PlayerWatcher = PlayerWatchFactory.Create( Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects );
|
||||
ModManager = new ModManager();
|
||||
ModManager.DiscoverMods();
|
||||
ObjectReloader = new ObjectReloader( ModManager, Config.WaitFrames );
|
||||
ObjectReloader = new ObjectReloader( ModManager );
|
||||
PathResolver = new PathResolver( ResourceLoader );
|
||||
|
||||
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
|
||||
|
|
@ -101,17 +99,6 @@ public class Penumbra : IDalamudPlugin
|
|||
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();
|
||||
if( Config.EnableMods )
|
||||
{
|
||||
|
|
@ -127,17 +114,6 @@ public class Penumbra : IDalamudPlugin
|
|||
{
|
||||
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()
|
||||
|
|
@ -150,10 +126,6 @@ public class Penumbra : IDalamudPlugin
|
|||
Config.EnableMods = true;
|
||||
ResourceLoader.EnableReplacements();
|
||||
ResidentResources.Reload();
|
||||
if( Config.EnablePlayerWatch )
|
||||
{
|
||||
PlayerWatcher.SetStatus( true );
|
||||
}
|
||||
|
||||
Config.Save();
|
||||
ObjectReloader.RedrawAll( RedrawType.WithSettings );
|
||||
|
|
@ -170,10 +142,6 @@ public class Penumbra : IDalamudPlugin
|
|||
Config.EnableMods = false;
|
||||
ResourceLoader.DisableReplacements();
|
||||
ResidentResources.Reload();
|
||||
if( Config.EnablePlayerWatch )
|
||||
{
|
||||
PlayerWatcher.SetStatus( false );
|
||||
}
|
||||
|
||||
Config.Save();
|
||||
ObjectReloader.RedrawAll( RedrawType.WithoutSettings );
|
||||
|
|
@ -232,7 +200,6 @@ public class Penumbra : IDalamudPlugin
|
|||
Api.Dispose();
|
||||
SettingsInterface.Dispose();
|
||||
ObjectReloader.Dispose();
|
||||
PlayerWatcher.Dispose();
|
||||
|
||||
Dalamud.Commands.RemoveHandler( CommandName );
|
||||
|
||||
|
|
@ -268,7 +235,7 @@ public class Penumbra : IDalamudPlugin
|
|||
return false;
|
||||
}
|
||||
|
||||
ModManager.Collections.SetDefaultCollection( collection );
|
||||
ModManager.Collections.SetCollection( collection, CollectionType.Default );
|
||||
Dalamud.Chat.Print( $"Set {collection.Name} as default collection." );
|
||||
SettingsInterface.ResetDefaultCollection();
|
||||
return true;
|
||||
|
|
@ -279,7 +246,7 @@ public class Penumbra : IDalamudPlugin
|
|||
return false;
|
||||
}
|
||||
|
||||
ModManager.Collections.SetForcedCollection( collection );
|
||||
ModManager.Collections.SetCollection( collection, CollectionType.Forced );
|
||||
Dalamud.Chat.Print( $"Set {collection.Name} as forced collection." );
|
||||
SettingsInterface.ResetForcedCollection();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ public partial class SettingsInterface
|
|||
return;
|
||||
}
|
||||
|
||||
Penumbra.ModManager.Collections.SetCurrentCollection( _collections[ idx + 1 ] );
|
||||
Penumbra.ModManager.Collections.SetCollection( _collections[ idx + 1 ], CollectionType.Current );
|
||||
_currentCollectionIndex = idx;
|
||||
_selector.Cache.TriggerListReset();
|
||||
if( _selector.Mod != null )
|
||||
|
|
@ -208,7 +208,7 @@ public partial class SettingsInterface
|
|||
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ public partial class SettingsInterface
|
|||
&& index != _currentForcedIndex
|
||||
&& manager.Collections.CharacterCollection.Count > 0 )
|
||||
{
|
||||
manager.Collections.SetForcedCollection( _collections[ index ] );
|
||||
manager.Collections.SetCollection( _collections[ index ], CollectionType.Forced );
|
||||
_currentForcedIndex = index;
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +352,7 @@ public partial class SettingsInterface
|
|||
ImGui.SetNextItemWidth( SettingsMenu.InputTextWidth );
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,104 +22,6 @@ namespace Penumbra.UI;
|
|||
|
||||
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 )
|
||||
{
|
||||
ImGui.TableNextRow();
|
||||
|
|
@ -431,8 +333,8 @@ public partial class SettingsInterface
|
|||
{
|
||||
var def = ExpandedGmpFile.GetDefault( gmp );
|
||||
var val = Penumbra.ModManager.Collections.ActiveCollection.Cache?.MetaManipulations.Gmp.File?[ gmp ] ?? def;
|
||||
ImGui.Text( def.Value.ToString("X") );
|
||||
ImGui.Text( val.Value.ToString("X") );
|
||||
ImGui.Text( def.Value.ToString( "X" ) );
|
||||
ImGui.Text( val.Value.ToString( "X" ) );
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
|
|
@ -557,8 +459,6 @@ public partial class SettingsInterface
|
|||
ImGui.NewLine();
|
||||
DrawDebugTabRedraw();
|
||||
ImGui.NewLine();
|
||||
DrawDebugTabPlayers();
|
||||
ImGui.NewLine();
|
||||
DrawDebugTabIpc();
|
||||
ImGui.NewLine();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Interface;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
|
|
@ -77,22 +75,12 @@ public partial class SettingsInterface
|
|||
( Gender.FemaleNpc.ToName(), Gender.FemaleNpc ),
|
||||
};
|
||||
|
||||
private static readonly (string, ObjectType)[] ObjectTypes =
|
||||
private static readonly (string, EstManipulation.EstType)[] EstTypes =
|
||||
{
|
||||
( "Equipment", ObjectType.Equipment ),
|
||||
( "Customization", ObjectType.Character ),
|
||||
};
|
||||
|
||||
private static readonly (string, EquipSlot)[] EstEquipSlots =
|
||||
{
|
||||
EqpEquipSlots[ 0 ],
|
||||
EqpEquipSlots[ 1 ],
|
||||
};
|
||||
|
||||
private static readonly (string, BodySlot)[] EstBodySlots =
|
||||
{
|
||||
( "Hair", BodySlot.Hair ),
|
||||
( "Face", BodySlot.Face ),
|
||||
( "Hair", EstManipulation.EstType.Hair ),
|
||||
( "Face", EstManipulation.EstType.Face ),
|
||||
( "Body", EstManipulation.EstType.Body ),
|
||||
( "Head", EstManipulation.EstType.Head ),
|
||||
};
|
||||
|
||||
private static readonly (string, SubRace)[] Subraces =
|
||||
|
|
@ -133,9 +121,11 @@ public partial class SettingsInterface
|
|||
( RspAttribute.FemaleMaxTail.ToFullString(), RspAttribute.FemaleMaxTail ),
|
||||
};
|
||||
|
||||
|
||||
private static readonly (string, ObjectType)[] ImcObjectType =
|
||||
{
|
||||
ObjectTypes[ 0 ],
|
||||
( "Equipment", ObjectType.Equipment ),
|
||||
( "Customization", ObjectType.Character ),
|
||||
( "Weapon", ObjectType.Weapon ),
|
||||
( "Demihuman", ObjectType.DemiHuman ),
|
||||
( "Monster", ObjectType.Monster ),
|
||||
|
|
@ -143,8 +133,8 @@ public partial class SettingsInterface
|
|||
|
||||
private static readonly (string, BodySlot)[] ImcBodySlots =
|
||||
{
|
||||
EstBodySlots[ 0 ],
|
||||
EstBodySlots[ 1 ],
|
||||
( "Hair", BodySlot.Hair ),
|
||||
( "Face", BodySlot.Face ),
|
||||
( "Body", BodySlot.Body ),
|
||||
( "Tail", BodySlot.Tail ),
|
||||
( "Ears", BodySlot.Zear ),
|
||||
|
|
@ -646,24 +636,26 @@ public partial class SettingsInterface
|
|||
RestrictedInputInt( "Set Id##newManipImc", ref _newManipSetId, 0, ushort.MaxValue );
|
||||
RestrictedInputInt( "Variant##newManipImc", ref _newManipVariant, 0, byte.MaxValue );
|
||||
CustomCombo( "Object Type", ImcObjectType, out var objectType, ref _newManipObjectType );
|
||||
EquipSlot equipSlot = default;
|
||||
ImcManipulation imc = new();
|
||||
switch( objectType )
|
||||
{
|
||||
case ObjectType.Equipment:
|
||||
CustomCombo( "Equipment Slot", EqdpEquipSlots, out equipSlot, ref _newManipEquipSlot );
|
||||
//newManip = MetaManipulation.Imc( equipSlot, _newManipSetId, _newManipVariant,
|
||||
// new ImcFile.ImageChangeData() );
|
||||
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
||||
imc = new ImcManipulation( equipSlot, _newManipVariant, _newManipSetId, new ImcEntry() );
|
||||
break;
|
||||
case ObjectType.DemiHuman:
|
||||
case ObjectType.Weapon:
|
||||
case ObjectType.Monster:
|
||||
RestrictedInputInt( "Secondary Id##newManipImc", ref _newManipSecondaryId, 0, ushort.MaxValue );
|
||||
CustomCombo( "Body Slot", ImcBodySlots, out var bodySlot, ref _newManipBodySlot );
|
||||
//newManip = MetaManipulation.Imc( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
|
||||
// _newManipVariant, new ImcFile.ImageChangeData() );
|
||||
imc = new ImcManipulation( objectType, bodySlot, _newManipSetId, _newManipSecondaryId,
|
||||
_newManipVariant, new ImcEntry() );
|
||||
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;
|
||||
}
|
||||
case MetaManipulation.Type.Eqdp:
|
||||
|
|
@ -672,76 +664,50 @@ public partial class SettingsInterface
|
|||
CustomCombo( "Equipment Slot", EqdpEquipSlots, out var equipSlot, ref _newManipEquipSlot );
|
||||
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
||||
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
||||
//newManip = MetaManipulation.Eqdp( equipSlot, Names.CombinedRace( gender, race ), ( ushort )_newManipSetId,
|
||||
// new EqdpEntry() );
|
||||
var eqdp = new EqdpManipulation( new EqdpEntry(), equipSlot, gender, race, _newManipSetId );
|
||||
newManip = new MetaManipulation( new EqdpManipulation( ExpandedEqdpFile.GetDefault( eqdp.FileIndex(), eqdp.SetId ),
|
||||
equipSlot, gender, race, _newManipSetId ) );
|
||||
break;
|
||||
}
|
||||
case MetaManipulation.Type.Eqp:
|
||||
{
|
||||
RestrictedInputInt( "Set Id##newManipEqp", ref _newManipSetId, 0, ushort.MaxValue );
|
||||
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;
|
||||
}
|
||||
case MetaManipulation.Type.Est:
|
||||
{
|
||||
RestrictedInputInt( "Set Id##newManipEst", ref _newManipSetId, 0, ushort.MaxValue );
|
||||
CustomCombo( "Object Type", ObjectTypes, out var objectType, 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( "Est Type", EstTypes, out var estType, ref _newManipObjectType );
|
||||
CustomCombo( "Race", Races, out var race, ref _newManipRace );
|
||||
CustomCombo( "Gender", Genders, out var gender, ref _newManipGender );
|
||||
//newManip = MetaManipulation.Est( objectType, equipSlot, Names.CombinedRace( gender, race ), bodySlot,
|
||||
// ( ushort )_newManipSetId, 0 );
|
||||
newManip = new MetaManipulation( new EstManipulation( gender, race, estType, _newManipSetId,
|
||||
EstFile.GetDefault( estType, Names.CombinedRace( gender, race ), _newManipSetId ) ) );
|
||||
break;
|
||||
}
|
||||
case MetaManipulation.Type.Gmp:
|
||||
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;
|
||||
case MetaManipulation.Type.Rsp:
|
||||
CustomCombo( "Subrace", Subraces, out var subRace, ref _newManipSubrace );
|
||||
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;
|
||||
}
|
||||
|
||||
//if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
|
||||
// && newManip != null
|
||||
// && list.All( m => m.Identifier != newManip.Value.Identifier ) )
|
||||
//{
|
||||
// var def = Penumbra.MetaDefaults.GetDefaultValue( newManip.Value );
|
||||
// if( def != null )
|
||||
// {
|
||||
// var manip = newManip.Value.Type switch
|
||||
// {
|
||||
// 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();
|
||||
//}
|
||||
if( ImGui.Button( "Create Manipulation##newManip", Vector2.UnitX * -1 )
|
||||
&& newManip != null
|
||||
&& list.All( m => !m.Equals( newManip ) ) )
|
||||
{
|
||||
list.Add( newManip.Value );
|
||||
change = true;
|
||||
++count;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,9 +87,10 @@ public partial class SettingsInterface
|
|||
|
||||
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( " ",
|
||||
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 ) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -239,44 +239,6 @@ public partial class SettingsInterface
|
|||
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()
|
||||
{
|
||||
if( ImGui.Button( "Reload Resident Resources" ) )
|
||||
|
|
@ -388,7 +350,6 @@ public partial class SettingsInterface
|
|||
|
||||
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
||||
DrawEnabledBox();
|
||||
DrawEnabledPlayerWatcher();
|
||||
|
||||
ImGuiCustom.VerticalDistance( DefaultVerticalSpace );
|
||||
DrawScaleModSelectorBox();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue