mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
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:
parent
cfdff30189
commit
cf223c927c
15 changed files with 309 additions and 60 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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!;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 = "" };
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,8 @@ namespace Penumbra.Mods
|
|||
{
|
||||
_plugin = plugin;
|
||||
BasePath = new DirectoryInfo( plugin.Configuration.ModDirectory );
|
||||
MetaManager.ClearBaseDirectory( BasePath );
|
||||
|
||||
Collections = new CollectionManager( plugin, this );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
174
Penumbra/UI/MenuTabs/TabDebug.cs
Normal file
174
Penumbra/UI/MenuTabs/TabDebug.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ namespace Penumbra.UI
|
|||
private const bool DefaultVisibility = false;
|
||||
#endif
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue