From cf223c927cceca673852f19c45f56a8831819a25 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 10 Jul 2021 22:20:18 +0200 Subject: [PATCH] Try to fix actor redrawing stalling again, some fixes for collections not correctly reloading metadata or changing wrong collection. Added hidden debug tab that can be activated by /penumbra debug (and is active when compiled in debug mode by default). --- Penumbra/Game/CharEquipment.cs | 28 +-- Penumbra/Game/ObjectIdentification.cs | 18 ++ Penumbra/Interop/ActorRefresher.cs | 42 +++-- Penumbra/Meta/MetaManager.cs | 24 ++- Penumbra/Mods/CollectionManager.cs | 25 ++- Penumbra/Mods/ModCollection.cs | 11 +- Penumbra/Mods/ModManager.cs | 6 +- Penumbra/Mods/ModManagerEditExtensions.cs | 3 +- Penumbra/Plugin.cs | 6 + Penumbra/UI/MenuTabs/TabDebug.cs | 174 ++++++++++++++++++ .../TabInstalled/TabInstalledDetails.cs | 6 +- .../TabInstalled/TabInstalledModPanel.cs | 6 +- Penumbra/UI/SettingsInterface.cs | 3 + Penumbra/UI/SettingsMenu.cs | 8 +- Penumbra/Util/TempFile.cs | 9 +- 15 files changed, 309 insertions(+), 60 deletions(-) create mode 100644 Penumbra/UI/MenuTabs/TabDebug.cs diff --git a/Penumbra/Game/CharEquipment.cs b/Penumbra/Game/CharEquipment.cs index 2b1e3ede..5ebc7ee7 100644 --- a/Penumbra/Game/CharEquipment.cs +++ b/Penumbra/Game/CharEquipment.cs @@ -10,7 +10,7 @@ namespace Penumbra.Game public class CharEquipment { [StructLayout( LayoutKind.Sequential, Pack = 1 )] - private readonly struct Weapon + internal readonly struct Weapon { public readonly ushort _1; public readonly ushort _2; @@ -22,7 +22,7 @@ namespace Penumbra.Game } [StructLayout( LayoutKind.Sequential, Pack = 1 )] - private readonly struct Equip + internal readonly struct Equip { public readonly ushort _1; public readonly byte _2; @@ -39,18 +39,18 @@ namespace Penumbra.Game private const int WeaponSlots = 2; private readonly ushort IsSet; // Also fills struct size to 56, a multiple of 8. - private readonly Weapon Mainhand; - private readonly Weapon Offhand; - private readonly Equip Head; - private readonly Equip Body; - private readonly Equip Hands; - private readonly Equip Legs; - private readonly Equip Feet; - private readonly Equip Ear; - private readonly Equip Neck; - private readonly Equip Wrist; - private readonly Equip LFinger; - private readonly Equip RFinger; + internal readonly Weapon Mainhand; + internal readonly Weapon Offhand; + internal readonly Equip Head; + internal readonly Equip Body; + internal readonly Equip Hands; + internal readonly Equip Legs; + internal readonly Equip Feet; + internal readonly Equip Ear; + internal readonly Equip Neck; + internal readonly Equip Wrist; + internal readonly Equip LFinger; + internal readonly Equip RFinger; public CharEquipment() => Clear(); diff --git a/Penumbra/Game/ObjectIdentification.cs b/Penumbra/Game/ObjectIdentification.cs index c84917c6..2a426fdc 100644 --- a/Penumbra/Game/ObjectIdentification.cs +++ b/Penumbra/Game/ObjectIdentification.cs @@ -286,5 +286,23 @@ namespace Penumbra.Game IdentifyParsed( set, info ); } } + + public Item? Identify( ushort a, ushort b, ushort c, EquipSlot slot ) + { + switch( slot ) + { + case EquipSlot.MainHand: + case EquipSlot.Offhand: + { + var (begin, _) = FindIndexRange( _weapons, ( ( ulong )a << 32 ) | ( ( ulong )b << 16 ) | c, 0xFFFFFFFFFFFF ); + return begin >= 0 ? _weapons[ begin ].Item2.FirstOrDefault() : null; + } + default: + { + var (begin, _) = FindIndexRange( _equipment, ( ( ulong )a << 32 ) | ( ( ulong )slot.ToSlot() << 16 ) | b, 0xFFFFFFFFFFFF ); + return begin >= 0 ? _equipment[ begin ].Item2.FirstOrDefault() : null; + } + } + } } } \ No newline at end of file diff --git a/Penumbra/Interop/ActorRefresher.cs b/Penumbra/Interop/ActorRefresher.cs index 94c09563..365d96a9 100644 --- a/Penumbra/Interop/ActorRefresher.cs +++ b/Penumbra/Interop/ActorRefresher.cs @@ -22,11 +22,14 @@ namespace Penumbra.Interop public class ActorRefresher : IDisposable { [Flags] - private enum LoadingFlags : int + public enum LoadingFlags : int { - Invisibility = 0x00_02, - IsLoading = 0x08_00, - SomeNpcFlag = 0x01_00, + Invisibility = 0x00_00_00_02, + IsLoading = 0x00_00_08_00, + SomeNpcFlag = 0x00_00_01_00, + MaybeCulled = 0x00_00_04_00, + MaybeHiddenMinion = 0x00_00_80_00, + MaybeHiddenSummon = 0x00_80_00_00, } private const int RenderModeOffset = 0x0104; @@ -43,6 +46,9 @@ namespace Penumbra.Interop private string? _currentActorName = null; private Redraw _currentActorRedraw = Redraw.Unload; + public static IntPtr RenderPtr( Actor actor ) + => actor.Address + RenderModeOffset; + public ActorRefresher( DalamudPluginInterface pi, ModManager mods ) { _pi = pi; @@ -74,10 +80,16 @@ namespace Penumbra.Interop private static unsafe bool StillLoading( IntPtr renderPtr ) { + const LoadingFlags stillLoadingFlags = LoadingFlags.SomeNpcFlag + | LoadingFlags.MaybeCulled + | LoadingFlags.MaybeHiddenMinion + | LoadingFlags.MaybeHiddenSummon; + if( renderPtr != IntPtr.Zero ) { var loadingFlags = *( LoadingFlags* )renderPtr; - return loadingFlags != 0 && !loadingFlags.HasFlag( LoadingFlags.SomeNpcFlag ); + + return !( loadingFlags == 0 || ( loadingFlags & stillLoadingFlags ) != 0 ); } return false; @@ -140,7 +152,7 @@ namespace Penumbra.Interop return; } - if( StillLoading( actor.Address + RenderModeOffset ) ) + if( StillLoading( RenderPtr( actor ) ) ) { return; } @@ -148,7 +160,7 @@ namespace Penumbra.Interop switch( _currentActorRedraw ) { case Redraw.Unload: - WriteInvisible( actor.Address + RenderModeOffset ); + WriteInvisible( RenderPtr( actor ) ); _currentFrame = 0; break; case Redraw.RedrawWithSettings: @@ -156,16 +168,16 @@ namespace Penumbra.Interop ++_currentFrame; break; case Redraw.RedrawWithoutSettings: - WriteVisible( actor.Address + RenderModeOffset ); + WriteVisible( RenderPtr( actor ) ); _currentFrame = 0; break; case Redraw.WithoutSettings: - WriteInvisible( actor.Address + RenderModeOffset ); + WriteInvisible( RenderPtr( actor ) ); ++_currentFrame; break; case Redraw.WithSettings: ChangeSettings(); - WriteInvisible( actor.Address + RenderModeOffset ); + WriteInvisible( RenderPtr( actor ) ); ++_currentFrame; break; case Redraw.OnlyWithSettings: @@ -175,7 +187,7 @@ namespace Penumbra.Interop return; } - WriteInvisible( actor.Address + RenderModeOffset ); + WriteInvisible( RenderPtr( actor ) ); ++_currentFrame; break; default: throw new InvalidEnumArgumentException(); @@ -191,7 +203,7 @@ namespace Penumbra.Interop return; } - WriteVisible( actor.Address + RenderModeOffset ); + WriteVisible( RenderPtr( actor ) ); _currentFrame = _changedSettings ? _currentFrame + 1 : 0; } @@ -200,7 +212,7 @@ namespace Penumbra.Interop var actor = FindCurrentActor(); if( actor != null ) { - if( !StillLoading( actor.Address + RenderModeOffset ) ) + if( !StillLoading( RenderPtr( actor ) ) ) { RestoreSettings(); _currentFrame = 0; @@ -292,7 +304,7 @@ namespace Penumbra.Interop Clear(); foreach( var a in _pi.ClientState.Actors ) { - WriteInvisible( a.Address + RenderModeOffset ); + WriteInvisible( RenderPtr( a ) ); } } @@ -301,7 +313,7 @@ namespace Penumbra.Interop Clear(); foreach( var a in _pi.ClientState.Actors ) { - WriteVisible( a.Address + RenderModeOffset ); + WriteVisible( RenderPtr( a ) ); } } diff --git a/Penumbra/Meta/MetaManager.cs b/Penumbra/Meta/MetaManager.cs index dee114b2..21e15303 100644 --- a/Penumbra/Meta/MetaManager.cs +++ b/Penumbra/Meta/MetaManager.cs @@ -21,9 +21,9 @@ namespace Penumbra.Meta public FileInformation( object data ) => Data = data; - public void Write( DirectoryInfo dir ) + public void Write( DirectoryInfo dir, GamePath originalPath ) { - byte[] data = Data switch + var data = Data switch { EqdpFile eqdp => eqdp.WriteBytes(), EqpFile eqp => eqp.WriteBytes(), @@ -34,7 +34,7 @@ namespace Penumbra.Meta _ => throw new NotImplementedException(), }; DisposeFile( CurrentFile ); - CurrentFile = TempFile.WriteNew( dir, data ); + CurrentFile = TempFile.WriteNew( dir, data, $"_{originalPath.Filename()}" ); Changed = false; } } @@ -93,22 +93,28 @@ namespace Penumbra.Meta public void Dispose() => Reset(); - private void ClearDirectory() + private static void ClearDirectory( DirectoryInfo modDir ) { - _dir.Refresh(); - if( _dir.Exists ) + modDir.Refresh(); + if( modDir.Exists ) { try { - Directory.Delete( _dir.FullName, true ); + Directory.Delete( modDir.FullName, true ); } catch( Exception e ) { - PluginLog.Error( $"Could not clear temporary metafile directory \"{_dir.FullName}\":\n{e}" ); + PluginLog.Error( $"Could not clear temporary metafile directory \"{modDir.FullName}\":\n{e}" ); } } } + private void ClearDirectory() + => ClearDirectory( _dir ); + + public static void ClearBaseDirectory( DirectoryInfo modDir ) + => ClearDirectory( new DirectoryInfo( Path.Combine( modDir.FullName, TmpDirectory ) ) ); + public MetaManager( string name, Dictionary< GamePath, FileInfo > resolvedFiles, DirectoryInfo modDir ) { _resolvedFiles = resolvedFiles; @@ -123,7 +129,7 @@ namespace Penumbra.Meta Directory.CreateDirectory( _dir.FullName ); foreach( var kvp in _currentFiles.Where( kvp => kvp.Value.Changed ) ) { - kvp.Value.Write( _dir ); + kvp.Value.Write( _dir, kvp.Key ); _resolvedFiles[ kvp.Key ] = kvp.Value.CurrentFile!; } } diff --git a/Penumbra/Mods/CollectionManager.cs b/Penumbra/Mods/CollectionManager.cs index 9cb522df..f350c5f6 100644 --- a/Penumbra/Mods/CollectionManager.cs +++ b/Penumbra/Mods/CollectionManager.cs @@ -174,8 +174,8 @@ namespace Penumbra.Mods _plugin.Configuration.Save(); } - public void SetCurrentCollection( ModCollection newCollection ) - => SetCollection( newCollection, CurrentCollection, c => + public void SetDefaultCollection( ModCollection newCollection ) + => SetCollection( newCollection, DefaultCollection, c => { if( ActiveCollection == DefaultCollection ) { @@ -184,19 +184,30 @@ namespace Penumbra.Mods resourceManager.ReloadPlayerResources(); } - CurrentCollection = c; - }, s => _plugin.Configuration.CurrentCollection = s ); + DefaultCollection = c; + }, s => _plugin.Configuration.DefaultCollection = s ); public void SetForcedCollection( ModCollection newCollection ) => SetCollection( newCollection, ForcedCollection, c => ForcedCollection = c, s => _plugin.Configuration.ForcedCollection = s ); - public void SetDefaultCollection( ModCollection newCollection ) - => SetCollection( newCollection, DefaultCollection, c => DefaultCollection = c, s => _plugin.Configuration.DefaultCollection = s ); + public void SetCurrentCollection( ModCollection newCollection ) + => SetCollection( newCollection, CurrentCollection, c => CurrentCollection = c, s => _plugin.Configuration.CurrentCollection = s ); public void SetCharacterCollection( string characterName, ModCollection newCollection ) => SetCollection( newCollection, CharacterCollection.TryGetValue( characterName, out var oldCollection ) ? oldCollection : ModCollection.Empty, - c => CharacterCollection[ characterName ] = c, s => _plugin.Configuration.CharacterCollections[ characterName ] = s ); + c => + { + if( CharacterCollection.TryGetValue( characterName, out var collection ) + && ActiveCollection == collection ) + { + ActiveCollection = c; + var resourceManager = Service< GameResourceManagement >.Get(); + resourceManager.ReloadPlayerResources(); + } + + CharacterCollection[ characterName ] = c; + }, s => _plugin.Configuration.CharacterCollections[ characterName ] = s ); public bool CreateCharacterCollection( string characterName ) { diff --git a/Penumbra/Mods/ModCollection.cs b/Penumbra/Mods/ModCollection.cs index c828f377..aa6f0b26 100644 --- a/Penumbra/Mods/ModCollection.cs +++ b/Penumbra/Mods/ModCollection.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Penumbra.Interop; using Penumbra.Mod; using Penumbra.Util; @@ -87,7 +88,7 @@ namespace Penumbra.Mods } Cache.SortMods(); - CalculateEffectiveFileList( modDirectory, true ); + CalculateEffectiveFileList( modDirectory, true, false ); } public void ClearCache() @@ -125,7 +126,7 @@ namespace Penumbra.Mods } } - public void CalculateEffectiveFileList( DirectoryInfo modDir, bool withMetaManipulations ) + public void CalculateEffectiveFileList( DirectoryInfo modDir, bool withMetaManipulations, bool activeCollection ) { Cache ??= new ModCollectionCache( Name, modDir ); UpdateSettings(); @@ -133,6 +134,10 @@ namespace Penumbra.Mods if( withMetaManipulations ) { Cache.UpdateMetaManipulations(); + if( activeCollection ) + { + Service< GameResourceManagement >.Get().ReloadPlayerResources(); + } } } @@ -240,6 +245,6 @@ namespace Penumbra.Mods public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath ) => Cache?.ResolveSwappedOrReplacementPath( gameResourcePath ); - public static readonly ModCollection Empty = new(){ Name = "" }; + public static readonly ModCollection Empty = new() { Name = "" }; } } \ No newline at end of file diff --git a/Penumbra/Mods/ModManager.cs b/Penumbra/Mods/ModManager.cs index b3294087..0075968f 100644 --- a/Penumbra/Mods/ModManager.cs +++ b/Penumbra/Mods/ModManager.cs @@ -24,8 +24,10 @@ namespace Penumbra.Mods public ModManager( Plugin plugin ) { - _plugin = plugin; - BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory ); + _plugin = plugin; + BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory ); + MetaManager.ClearBaseDirectory( BasePath ); + Collections = new CollectionManager( plugin, this ); } diff --git a/Penumbra/Mods/ModManagerEditExtensions.cs b/Penumbra/Mods/ModManagerEditExtensions.cs index ce121444..a1b97345 100644 --- a/Penumbra/Mods/ModManagerEditExtensions.cs +++ b/Penumbra/Mods/ModManagerEditExtensions.cs @@ -216,7 +216,8 @@ namespace Penumbra.Mods manager.Collections.SaveCollection( collection ); if( collection.Cache != null && settings.Enabled ) { - collection.CalculateEffectiveFileList( manager.BasePath, mod.Resources.MetaManipulations.Count > 0 ); + collection.CalculateEffectiveFileList( manager.BasePath, mod.Resources.MetaManipulations.Count > 0, + collection == manager.Collections.ActiveCollection ); } } } diff --git a/Penumbra/Plugin.cs b/Penumbra/Plugin.cs index 750fb445..b9ac9f7f 100644 --- a/Penumbra/Plugin.cs +++ b/Penumbra/Plugin.cs @@ -5,6 +5,7 @@ using EmbedIO.WebApi; using Penumbra.API; using Penumbra.Game; using Penumbra.Interop; +using Penumbra.Meta; using Penumbra.Meta.Files; using Penumbra.Mods; using Penumbra.UI; @@ -154,6 +155,11 @@ namespace Penumbra break; } + case "debug": + { + SettingsInterface.MakeDebugTabVisible(); + break; + } } return; diff --git a/Penumbra/UI/MenuTabs/TabDebug.cs b/Penumbra/UI/MenuTabs/TabDebug.cs new file mode 100644 index 00000000..85287f35 --- /dev/null +++ b/Penumbra/UI/MenuTabs/TabDebug.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Numerics; +using System.Reflection; +using System.Runtime.InteropServices; +using Dalamud.Game.ClientState.Actors.Types; +using ImGuiNET; +using Penumbra.Game; +using Penumbra.Game.Enums; +using Penumbra.Interop; +using Penumbra.Mods; +using Penumbra.Util; + +namespace Penumbra.UI +{ + public partial class SettingsInterface + { + private void DrawDebugTabActors() + { + if( !ImGui.CollapsingHeader( "Actors##Debug" ) ) + { + return; + } + + var actors = ( Dictionary< string, CharEquipment >? )_plugin.PlayerWatcher.GetType() + .GetField( "_equip", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.PlayerWatcher ) + ?? new Dictionary< string, CharEquipment >(); + + if( actors.Any() && ImGui.BeginTable( "##ActorTable", 13, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX ) ) + { + var identifier = Service< ObjectIdentification >.Get(); + ImGui.TableNextRow(); + foreach( var actor in actors ) + { + ImGui.TableNextColumn(); + ImGui.Text( actor.Key ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Mainhand} {identifier.Identify( actor.Value.Mainhand._1, actor.Value.Mainhand._2, actor.Value.Mainhand._3, EquipSlot.MainHand )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Offhand} {identifier.Identify( actor.Value.Offhand._1, actor.Value.Offhand._2, actor.Value.Offhand._3, EquipSlot.Offhand )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Head} {identifier.Identify( actor.Value.Head._1, actor.Value.Head._2, 0, EquipSlot.Head )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Body} {identifier.Identify( actor.Value.Body._1, actor.Value.Body._2, 0, EquipSlot.Body )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Hands} {identifier.Identify( actor.Value.Hands._1, actor.Value.Hands._2, 0, EquipSlot.Hands )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Legs} {identifier.Identify( actor.Value.Legs._1, actor.Value.Legs._2, 0, EquipSlot.Legs )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Feet} {identifier.Identify( actor.Value.Feet._1, actor.Value.Feet._2, 0, EquipSlot.Feet )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Ear} {identifier.Identify( actor.Value.Ear._1, actor.Value.Ear._2, 0, EquipSlot.Ears )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Neck} {identifier.Identify( actor.Value.Neck._1, actor.Value.Neck._2, 0, EquipSlot.Neck )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.Wrist} {identifier.Identify( actor.Value.Wrist._1, actor.Value.Wrist._2, 0, EquipSlot.Wrists )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.LFinger} {identifier.Identify( actor.Value.LFinger._1, actor.Value.LFinger._2, 0, EquipSlot.RingL )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextColumn(); + ImGui.Text( + $"{actor.Value.RFinger} {identifier.Identify( actor.Value.RFinger._1, actor.Value.RFinger._2, 0, EquipSlot.RingL )?.Name.ToString() ?? "Unknown"}" ); + ImGui.TableNextRow(); + } + + ImGui.EndTable(); + } + } + + private void DrawDebugTabGeneral() + { + if( !ImGui.CollapsingHeader( "General##Debug" ) ) + { + return; + } + + ImGui.Text( $"Active Collection: {Service< ModManager >.Get().Collections.ActiveCollection.Name}" ); + } + + + private void DrawDebugTabRedraw() + { + if( !ImGui.CollapsingHeader( "Redrawing##Debug" ) ) + { + return; + } + + var queue = ( Queue< (int, string, Redraw) >? )_plugin.ActorRefresher.GetType() + .GetField( "_actorIds", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ) + ?? new Queue< (int, string, Redraw) >(); + + var currentFrame = ( int? )_plugin.ActorRefresher.GetType() + .GetField( "_currentFrame", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ); + + var changedSettings = ( bool? )_plugin.ActorRefresher.GetType() + .GetField( "_changedSettings", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ); + + var currentActorId = ( int? )_plugin.ActorRefresher.GetType() + .GetField( "_currentActorId", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ); + + var currentActorName = ( string? )_plugin.ActorRefresher.GetType() + .GetField( "_currentActorName", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ); + + var currentActorRedraw = ( Redraw? )_plugin.ActorRefresher.GetType() + .GetField( "_currentActorRedraw", BindingFlags.Instance | BindingFlags.NonPublic ) + ?.GetValue( _plugin.ActorRefresher ); + + var currentActor = ( Actor? )_plugin.ActorRefresher.GetType() + .GetMethod( "FindCurrentActor", BindingFlags.NonPublic | BindingFlags.Instance )? + .Invoke( _plugin.ActorRefresher, Array.Empty< object >() ); + + var currentRender = currentActor != null + ? ( ActorRefresher.LoadingFlags? )Marshal.ReadInt32( ActorRefresher.RenderPtr( currentActor ) ) + : null; + + ImGui.Text( $"Current Frame: {currentFrame?.ToString() ?? "null"}" ); + ImGui.Text( $"Current Changed Settings: {changedSettings?.ToString() ?? "null"}" ); + ImGui.Text( $"Current Actor Id: {currentActorId?.ToString( "X8" ) ?? "null"}" ); + ImGui.Text( $"Current Actor Name: {currentActorName ?? "null"}" ); + ImGui.Text( $"Current Actor Redraw: {currentActorRedraw.ToString() ?? "null"}" ); + ImGui.Text( $"Current Actor Address: {currentActor?.Address.ToString( "X16" ) ?? "null"}" ); + ImGui.Text( $"Current Actor Render Flags: {( ( int? )currentRender )?.ToString( "X8" ) ?? "null"}" ); + + if( queue.Any() && ImGui.BeginTable( "##RedrawTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollX ) ) + { + ImGui.TableNextRow(); + foreach( var (actorId, actorName, redraw) in queue ) + { + ImGui.TableNextColumn(); + ImGui.Text( actorName ); + ImGui.TableNextColumn(); + ImGui.Text( $"0x{actorId:X8}" ); + ImGui.TableNextColumn(); + ImGui.Text( redraw.ToString() ); + ImGui.TableNextRow(); + } + + ImGui.EndTable(); + } + } + + private void DrawDebugTab() + { + if( !ImGui.BeginTabItem( "Debug Tab" ) ) + { + return; + } + + DrawDebugTabGeneral(); + DrawDebugTabRedraw(); + DrawDebugTabActors(); + + ImGui.EndTabItem(); + } + } +} \ No newline at end of file diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs index 62bac749..4d784be7 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledDetails.cs @@ -565,7 +565,8 @@ namespace Penumbra.UI if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null ) { _modManager.Collections.CurrentCollection.CalculateEffectiveFileList( Mod.Data.BasePath, - Mod.Data.Resources.MetaManipulations.Count > 0 ); + Mod.Data.Resources.MetaManipulations.Count > 0, + _modManager.Collections.CurrentCollection == _modManager.Collections.ActiveCollection ); } Save(); @@ -605,7 +606,8 @@ namespace Penumbra.UI if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null ) { _modManager.Collections.CurrentCollection.CalculateEffectiveFileList( Mod.Data.BasePath, - Mod.Data.Resources.MetaManipulations.Count > 0 ); + Mod.Data.Resources.MetaManipulations.Count > 0, + _modManager.Collections.CurrentCollection == _modManager.Collections.ActiveCollection ); } Save(); diff --git a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs index 9b099cf0..4c659b51 100644 --- a/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs +++ b/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledModPanel.cs @@ -205,7 +205,8 @@ namespace Penumbra.UI collection.Save( _base._plugin.PluginInterface! ); if( collection.Cache != null ) { - collection.CalculateEffectiveFileList( _modManager.BasePath, Mod.Data.Resources.MetaManipulations.Count > 0 ); + collection.CalculateEffectiveFileList( _modManager.BasePath, Mod.Data.Resources.MetaManipulations.Count > 0, + collection == _modManager.Collections.ActiveCollection ); } } @@ -226,7 +227,8 @@ namespace Penumbra.UI collection.Save( _base._plugin.PluginInterface! ); if( collection.Cache != null ) { - collection.CalculateEffectiveFileList( _modManager.BasePath, Mod.Data.Resources.MetaManipulations.Count > 0 ); + collection.CalculateEffectiveFileList( _modManager.BasePath, Mod.Data.Resources.MetaManipulations.Count > 0, + collection == _modManager.Collections.ActiveCollection ); } } } diff --git a/Penumbra/UI/SettingsInterface.cs b/Penumbra/UI/SettingsInterface.cs index aed3c1f7..62756046 100644 --- a/Penumbra/UI/SettingsInterface.cs +++ b/Penumbra/UI/SettingsInterface.cs @@ -29,6 +29,9 @@ namespace Penumbra.UI public void FlipVisibility() => _menu.Visible = !_menu.Visible; + public void MakeDebugTabVisible() + => _menu.DebugTabVisible = true; + public void Draw() { _menuBar.Draw(); diff --git a/Penumbra/UI/SettingsMenu.cs b/Penumbra/UI/SettingsMenu.cs index 21b7c747..7779e2d2 100644 --- a/Penumbra/UI/SettingsMenu.cs +++ b/Penumbra/UI/SettingsMenu.cs @@ -36,7 +36,8 @@ namespace Penumbra.UI #else private const bool DefaultVisibility = false; #endif - public bool Visible = DefaultVisibility; + public bool Visible = DefaultVisibility; + public bool DebugTabVisible = DefaultVisibility; public void Draw() { @@ -73,6 +74,11 @@ namespace Penumbra.UI } } + if( DebugTabVisible ) + { + _base.DrawDebugTab(); + } + ImGui.EndTabBar(); ImGui.End(); } diff --git a/Penumbra/Util/TempFile.cs b/Penumbra/Util/TempFile.cs index 0b6b8e79..5a819d25 100644 --- a/Penumbra/Util/TempFile.cs +++ b/Penumbra/Util/TempFile.cs @@ -1,16 +1,17 @@ using System.IO; +using System.Linq; namespace Penumbra.Util { public static class TempFile { - public static FileInfo TempFileName( DirectoryInfo baseDir ) + public static FileInfo TempFileName( DirectoryInfo baseDir, string suffix = "") { const uint maxTries = 15; for( var i = 0; i < maxTries; ++i ) { var name = Path.GetRandomFileName(); - var path = new FileInfo( Path.Combine( baseDir.FullName, name ) ); + var path = new FileInfo( Path.Combine( baseDir.FullName, suffix.Any() ? name.Substring( 0, name.LastIndexOf( '.' ) ) + suffix : name ) ); if( !path.Exists ) { return path; @@ -20,9 +21,9 @@ namespace Penumbra.Util throw new IOException(); } - public static FileInfo WriteNew( DirectoryInfo baseDir, byte[] data ) + public static FileInfo WriteNew( DirectoryInfo baseDir, byte[] data, string suffix = "" ) { - var fileName = TempFileName( baseDir ); + var fileName = TempFileName( baseDir, suffix ); File.WriteAllBytes( fileName.FullName, data ); fileName.Refresh(); return fileName;