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

This commit is contained in:
Ottermandias 2021-07-10 22:20:18 +02:00
parent cfdff30189
commit cf223c927c
15 changed files with 309 additions and 60 deletions

View file

@ -10,7 +10,7 @@ namespace Penumbra.Game
public class CharEquipment public class CharEquipment
{ {
[StructLayout( LayoutKind.Sequential, Pack = 1 )] [StructLayout( LayoutKind.Sequential, Pack = 1 )]
private readonly struct Weapon internal readonly struct Weapon
{ {
public readonly ushort _1; public readonly ushort _1;
public readonly ushort _2; public readonly ushort _2;
@ -22,7 +22,7 @@ namespace Penumbra.Game
} }
[StructLayout( LayoutKind.Sequential, Pack = 1 )] [StructLayout( LayoutKind.Sequential, Pack = 1 )]
private readonly struct Equip internal readonly struct Equip
{ {
public readonly ushort _1; public readonly ushort _1;
public readonly byte _2; public readonly byte _2;
@ -39,18 +39,18 @@ namespace Penumbra.Game
private const int WeaponSlots = 2; private const int WeaponSlots = 2;
private readonly ushort IsSet; // Also fills struct size to 56, a multiple of 8. private readonly ushort IsSet; // Also fills struct size to 56, a multiple of 8.
private readonly Weapon Mainhand; internal readonly Weapon Mainhand;
private readonly Weapon Offhand; internal readonly Weapon Offhand;
private readonly Equip Head; internal readonly Equip Head;
private readonly Equip Body; internal readonly Equip Body;
private readonly Equip Hands; internal readonly Equip Hands;
private readonly Equip Legs; internal readonly Equip Legs;
private readonly Equip Feet; internal readonly Equip Feet;
private readonly Equip Ear; internal readonly Equip Ear;
private readonly Equip Neck; internal readonly Equip Neck;
private readonly Equip Wrist; internal readonly Equip Wrist;
private readonly Equip LFinger; internal readonly Equip LFinger;
private readonly Equip RFinger; internal readonly Equip RFinger;
public CharEquipment() public CharEquipment()
=> Clear(); => Clear();

View file

@ -286,5 +286,23 @@ namespace Penumbra.Game
IdentifyParsed( set, info ); 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;
}
}
}
} }
} }

View file

@ -22,11 +22,14 @@ namespace Penumbra.Interop
public class ActorRefresher : IDisposable public class ActorRefresher : IDisposable
{ {
[Flags] [Flags]
private enum LoadingFlags : int public enum LoadingFlags : int
{ {
Invisibility = 0x00_02, Invisibility = 0x00_00_00_02,
IsLoading = 0x08_00, IsLoading = 0x00_00_08_00,
SomeNpcFlag = 0x01_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; private const int RenderModeOffset = 0x0104;
@ -43,6 +46,9 @@ namespace Penumbra.Interop
private string? _currentActorName = null; private string? _currentActorName = null;
private Redraw _currentActorRedraw = Redraw.Unload; private Redraw _currentActorRedraw = Redraw.Unload;
public static IntPtr RenderPtr( Actor actor )
=> actor.Address + RenderModeOffset;
public ActorRefresher( DalamudPluginInterface pi, ModManager mods ) public ActorRefresher( DalamudPluginInterface pi, ModManager mods )
{ {
_pi = pi; _pi = pi;
@ -74,10 +80,16 @@ namespace Penumbra.Interop
private static unsafe bool StillLoading( IntPtr renderPtr ) private static unsafe bool StillLoading( IntPtr renderPtr )
{ {
const LoadingFlags stillLoadingFlags = LoadingFlags.SomeNpcFlag
| LoadingFlags.MaybeCulled
| LoadingFlags.MaybeHiddenMinion
| LoadingFlags.MaybeHiddenSummon;
if( renderPtr != IntPtr.Zero ) if( renderPtr != IntPtr.Zero )
{ {
var loadingFlags = *( LoadingFlags* )renderPtr; var loadingFlags = *( LoadingFlags* )renderPtr;
return loadingFlags != 0 && !loadingFlags.HasFlag( LoadingFlags.SomeNpcFlag );
return !( loadingFlags == 0 || ( loadingFlags & stillLoadingFlags ) != 0 );
} }
return false; return false;
@ -140,7 +152,7 @@ namespace Penumbra.Interop
return; return;
} }
if( StillLoading( actor.Address + RenderModeOffset ) ) if( StillLoading( RenderPtr( actor ) ) )
{ {
return; return;
} }
@ -148,7 +160,7 @@ namespace Penumbra.Interop
switch( _currentActorRedraw ) switch( _currentActorRedraw )
{ {
case Redraw.Unload: case Redraw.Unload:
WriteInvisible( actor.Address + RenderModeOffset ); WriteInvisible( RenderPtr( actor ) );
_currentFrame = 0; _currentFrame = 0;
break; break;
case Redraw.RedrawWithSettings: case Redraw.RedrawWithSettings:
@ -156,16 +168,16 @@ namespace Penumbra.Interop
++_currentFrame; ++_currentFrame;
break; break;
case Redraw.RedrawWithoutSettings: case Redraw.RedrawWithoutSettings:
WriteVisible( actor.Address + RenderModeOffset ); WriteVisible( RenderPtr( actor ) );
_currentFrame = 0; _currentFrame = 0;
break; break;
case Redraw.WithoutSettings: case Redraw.WithoutSettings:
WriteInvisible( actor.Address + RenderModeOffset ); WriteInvisible( RenderPtr( actor ) );
++_currentFrame; ++_currentFrame;
break; break;
case Redraw.WithSettings: case Redraw.WithSettings:
ChangeSettings(); ChangeSettings();
WriteInvisible( actor.Address + RenderModeOffset ); WriteInvisible( RenderPtr( actor ) );
++_currentFrame; ++_currentFrame;
break; break;
case Redraw.OnlyWithSettings: case Redraw.OnlyWithSettings:
@ -175,7 +187,7 @@ namespace Penumbra.Interop
return; return;
} }
WriteInvisible( actor.Address + RenderModeOffset ); WriteInvisible( RenderPtr( actor ) );
++_currentFrame; ++_currentFrame;
break; break;
default: throw new InvalidEnumArgumentException(); default: throw new InvalidEnumArgumentException();
@ -191,7 +203,7 @@ namespace Penumbra.Interop
return; return;
} }
WriteVisible( actor.Address + RenderModeOffset ); WriteVisible( RenderPtr( actor ) );
_currentFrame = _changedSettings ? _currentFrame + 1 : 0; _currentFrame = _changedSettings ? _currentFrame + 1 : 0;
} }
@ -200,7 +212,7 @@ namespace Penumbra.Interop
var actor = FindCurrentActor(); var actor = FindCurrentActor();
if( actor != null ) if( actor != null )
{ {
if( !StillLoading( actor.Address + RenderModeOffset ) ) if( !StillLoading( RenderPtr( actor ) ) )
{ {
RestoreSettings(); RestoreSettings();
_currentFrame = 0; _currentFrame = 0;
@ -292,7 +304,7 @@ namespace Penumbra.Interop
Clear(); Clear();
foreach( var a in _pi.ClientState.Actors ) foreach( var a in _pi.ClientState.Actors )
{ {
WriteInvisible( a.Address + RenderModeOffset ); WriteInvisible( RenderPtr( a ) );
} }
} }
@ -301,7 +313,7 @@ namespace Penumbra.Interop
Clear(); Clear();
foreach( var a in _pi.ClientState.Actors ) foreach( var a in _pi.ClientState.Actors )
{ {
WriteVisible( a.Address + RenderModeOffset ); WriteVisible( RenderPtr( a ) );
} }
} }

View file

@ -21,9 +21,9 @@ namespace Penumbra.Meta
public FileInformation( object data ) public FileInformation( object data )
=> Data = 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(), EqdpFile eqdp => eqdp.WriteBytes(),
EqpFile eqp => eqp.WriteBytes(), EqpFile eqp => eqp.WriteBytes(),
@ -34,7 +34,7 @@ namespace Penumbra.Meta
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
DisposeFile( CurrentFile ); DisposeFile( CurrentFile );
CurrentFile = TempFile.WriteNew( dir, data ); CurrentFile = TempFile.WriteNew( dir, data, $"_{originalPath.Filename()}" );
Changed = false; Changed = false;
} }
} }
@ -93,22 +93,28 @@ namespace Penumbra.Meta
public void Dispose() public void Dispose()
=> Reset(); => Reset();
private void ClearDirectory() private static void ClearDirectory( DirectoryInfo modDir )
{ {
_dir.Refresh(); modDir.Refresh();
if( _dir.Exists ) if( modDir.Exists )
{ {
try try
{ {
Directory.Delete( _dir.FullName, true ); Directory.Delete( modDir.FullName, true );
} }
catch( Exception e ) 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 ) public MetaManager( string name, Dictionary< GamePath, FileInfo > resolvedFiles, DirectoryInfo modDir )
{ {
_resolvedFiles = resolvedFiles; _resolvedFiles = resolvedFiles;
@ -123,7 +129,7 @@ namespace Penumbra.Meta
Directory.CreateDirectory( _dir.FullName ); Directory.CreateDirectory( _dir.FullName );
foreach( var kvp in _currentFiles.Where( kvp => kvp.Value.Changed ) ) 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!; _resolvedFiles[ kvp.Key ] = kvp.Value.CurrentFile!;
} }
} }

View file

@ -174,8 +174,8 @@ namespace Penumbra.Mods
_plugin.Configuration.Save(); _plugin.Configuration.Save();
} }
public void SetCurrentCollection( ModCollection newCollection ) public void SetDefaultCollection( ModCollection newCollection )
=> SetCollection( newCollection, CurrentCollection, c => => SetCollection( newCollection, DefaultCollection, c =>
{ {
if( ActiveCollection == DefaultCollection ) if( ActiveCollection == DefaultCollection )
{ {
@ -184,19 +184,30 @@ namespace Penumbra.Mods
resourceManager.ReloadPlayerResources(); resourceManager.ReloadPlayerResources();
} }
CurrentCollection = c; DefaultCollection = c;
}, s => _plugin.Configuration.CurrentCollection = s ); }, s => _plugin.Configuration.DefaultCollection = s );
public void SetForcedCollection( ModCollection newCollection ) public void SetForcedCollection( ModCollection newCollection )
=> SetCollection( newCollection, ForcedCollection, c => ForcedCollection = c, s => _plugin.Configuration.ForcedCollection = s ); => SetCollection( newCollection, ForcedCollection, c => ForcedCollection = c, s => _plugin.Configuration.ForcedCollection = s );
public void SetDefaultCollection( ModCollection newCollection ) public void SetCurrentCollection( ModCollection newCollection )
=> SetCollection( newCollection, DefaultCollection, c => DefaultCollection = c, s => _plugin.Configuration.DefaultCollection = s ); => SetCollection( newCollection, CurrentCollection, c => CurrentCollection = c, s => _plugin.Configuration.CurrentCollection = s );
public void SetCharacterCollection( string characterName, ModCollection newCollection ) public void SetCharacterCollection( string characterName, ModCollection newCollection )
=> SetCollection( newCollection, => SetCollection( newCollection,
CharacterCollection.TryGetValue( characterName, out var oldCollection ) ? oldCollection : ModCollection.Empty, 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 ) public bool CreateCharacterCollection( string characterName )
{ {

View file

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Penumbra.Interop;
using Penumbra.Mod; using Penumbra.Mod;
using Penumbra.Util; using Penumbra.Util;
@ -87,7 +88,7 @@ namespace Penumbra.Mods
} }
Cache.SortMods(); Cache.SortMods();
CalculateEffectiveFileList( modDirectory, true ); CalculateEffectiveFileList( modDirectory, true, false );
} }
public void ClearCache() 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 ); Cache ??= new ModCollectionCache( Name, modDir );
UpdateSettings(); UpdateSettings();
@ -133,6 +134,10 @@ namespace Penumbra.Mods
if( withMetaManipulations ) if( withMetaManipulations )
{ {
Cache.UpdateMetaManipulations(); Cache.UpdateMetaManipulations();
if( activeCollection )
{
Service< GameResourceManagement >.Get().ReloadPlayerResources();
}
} }
} }
@ -240,6 +245,6 @@ namespace Penumbra.Mods
public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath ) public string? ResolveSwappedOrReplacementPath( GamePath gameResourcePath )
=> Cache?.ResolveSwappedOrReplacementPath( gameResourcePath ); => Cache?.ResolveSwappedOrReplacementPath( gameResourcePath );
public static readonly ModCollection Empty = new(){ Name = "" }; public static readonly ModCollection Empty = new() { Name = "" };
} }
} }

View file

@ -24,8 +24,10 @@ namespace Penumbra.Mods
public ModManager( Plugin plugin ) public ModManager( Plugin plugin )
{ {
_plugin = plugin; _plugin = plugin;
BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory ); BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory );
MetaManager.ClearBaseDirectory( BasePath );
Collections = new CollectionManager( plugin, this ); Collections = new CollectionManager( plugin, this );
} }

View file

@ -216,7 +216,8 @@ namespace Penumbra.Mods
manager.Collections.SaveCollection( collection ); manager.Collections.SaveCollection( collection );
if( collection.Cache != null && settings.Enabled ) 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 );
} }
} }
} }

View file

@ -5,6 +5,7 @@ using EmbedIO.WebApi;
using Penumbra.API; using Penumbra.API;
using Penumbra.Game; using Penumbra.Game;
using Penumbra.Interop; using Penumbra.Interop;
using Penumbra.Meta;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.UI; using Penumbra.UI;
@ -154,6 +155,11 @@ namespace Penumbra
break; break;
} }
case "debug":
{
SettingsInterface.MakeDebugTabVisible();
break;
}
} }
return; return;

View file

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

View file

@ -565,7 +565,8 @@ namespace Penumbra.UI
if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null ) if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null )
{ {
_modManager.Collections.CurrentCollection.CalculateEffectiveFileList( Mod.Data.BasePath, _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(); Save();
@ -605,7 +606,8 @@ namespace Penumbra.UI
if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null ) if( Mod.Settings.Enabled && _modManager.Collections.CurrentCollection.Cache != null )
{ {
_modManager.Collections.CurrentCollection.CalculateEffectiveFileList( Mod.Data.BasePath, _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(); Save();

View file

@ -205,7 +205,8 @@ namespace Penumbra.UI
collection.Save( _base._plugin.PluginInterface! ); collection.Save( _base._plugin.PluginInterface! );
if( collection.Cache != null ) 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! ); collection.Save( _base._plugin.PluginInterface! );
if( collection.Cache != null ) 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 );
} }
} }
} }

View file

@ -29,6 +29,9 @@ namespace Penumbra.UI
public void FlipVisibility() public void FlipVisibility()
=> _menu.Visible = !_menu.Visible; => _menu.Visible = !_menu.Visible;
public void MakeDebugTabVisible()
=> _menu.DebugTabVisible = true;
public void Draw() public void Draw()
{ {
_menuBar.Draw(); _menuBar.Draw();

View file

@ -36,7 +36,8 @@ namespace Penumbra.UI
#else #else
private const bool DefaultVisibility = false; private const bool DefaultVisibility = false;
#endif #endif
public bool Visible = DefaultVisibility; public bool Visible = DefaultVisibility;
public bool DebugTabVisible = DefaultVisibility;
public void Draw() public void Draw()
{ {
@ -73,6 +74,11 @@ namespace Penumbra.UI
} }
} }
if( DebugTabVisible )
{
_base.DrawDebugTab();
}
ImGui.EndTabBar(); ImGui.EndTabBar();
ImGui.End(); ImGui.End();
} }

View file

@ -1,16 +1,17 @@
using System.IO; using System.IO;
using System.Linq;
namespace Penumbra.Util namespace Penumbra.Util
{ {
public static class TempFile public static class TempFile
{ {
public static FileInfo TempFileName( DirectoryInfo baseDir ) public static FileInfo TempFileName( DirectoryInfo baseDir, string suffix = "")
{ {
const uint maxTries = 15; const uint maxTries = 15;
for( var i = 0; i < maxTries; ++i ) for( var i = 0; i < maxTries; ++i )
{ {
var name = Path.GetRandomFileName(); 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 ) if( !path.Exists )
{ {
return path; return path;
@ -20,9 +21,9 @@ namespace Penumbra.Util
throw new IOException(); 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 ); File.WriteAllBytes( fileName.FullName, data );
fileName.Refresh(); fileName.Refresh();
return fileName; return fileName;