Some object reloading changes.

This commit is contained in:
Ottermandias 2022-03-16 15:17:55 +01:00
parent e7282384f5
commit 8d2e84eecf
3 changed files with 353 additions and 387 deletions

View file

@ -7,25 +7,15 @@ using System.Threading.Tasks;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
using Penumbra.Mods;
namespace Penumbra.Interop
{
public class ObjectReloader : IDisposable
namespace Penumbra.Interop;
public unsafe class ObjectReloader : IDisposable
{
private delegate void ManipulateDraw( IntPtr actor );
[Flags]
public enum LoadingFlags : int
{
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;
private const int UnloadAllRedrawDelay = 250;
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
@ -41,14 +31,20 @@ namespace Penumbra.Interop
private int _currentFrame;
private bool _changedSettings;
private uint _currentObjectId = uint.MaxValue;
private LoadingFlags _currentObjectStartState = 0;
private DrawState _currentObjectStartState = 0;
private RedrawType _currentRedrawType = RedrawType.Unload;
private string? _currentObjectName;
private bool _wasTarget;
private bool _inGPose;
public static IntPtr RenderPtr( GameObject actor )
=> actor.Address + RenderModeOffset;
public static DrawState* ActorDrawState( GameObject actor )
=> ( DrawState* )( actor.Address + 0x0104 );
private static delegate*< IntPtr, void > GetDisableDraw( GameObject actor )
=> ( ( delegate*< IntPtr, void >** )actor.Address )[ 0 ][ 17 ];
private static delegate*< IntPtr, void > GetEnableDraw( GameObject actor )
=> ( ( delegate*< IntPtr, void >** )actor.Address )[ 0 ][ 16 ];
public ObjectReloader( ModManager mods, int defaultWaitFrames )
{
@ -73,33 +69,25 @@ namespace Penumbra.Interop
private unsafe void WriteInvisible( GameObject actor, int actorIdx )
{
var renderPtr = RenderPtr( actor );
if( renderPtr == IntPtr.Zero )
{
return;
}
_currentObjectStartState = *( LoadingFlags* )renderPtr;
*( LoadingFlags* )renderPtr |= LoadingFlags.Invisibility;
_currentObjectStartState = *ActorDrawState( actor );
*ActorDrawState( actor ) |= DrawState.Invisibility;
if( _inGPose )
{
var ptr = ( void*** )actor.Address;
var disableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 17 ] ) );
disableDraw( actor.Address );
GetDisableDraw( actor )( actor.Address );
}
}
private unsafe bool StillLoading( IntPtr renderPtr )
private bool StillLoading( DrawState* renderPtr )
{
const LoadingFlags stillLoadingFlags = LoadingFlags.SomeNpcFlag
| LoadingFlags.MaybeCulled
| LoadingFlags.MaybeHiddenMinion
| LoadingFlags.MaybeHiddenSummon;
const DrawState stillLoadingFlags = DrawState.SomeNpcFlag
| DrawState.MaybeCulled
| DrawState.MaybeHiddenMinion
| DrawState.MaybeHiddenSummon;
if( renderPtr != IntPtr.Zero )
if( renderPtr != null )
{
var loadingFlags = *( LoadingFlags* )renderPtr;
var loadingFlags = *( DrawState* )renderPtr;
if( loadingFlags == _currentObjectStartState )
{
return false;
@ -111,16 +99,13 @@ namespace Penumbra.Interop
return false;
}
private unsafe void WriteVisible( GameObject actor, int actorIdx )
private void WriteVisible( GameObject actor, int actorIdx )
{
var renderPtr = RenderPtr( actor );
*( LoadingFlags* )renderPtr &= ~LoadingFlags.Invisibility;
*ActorDrawState( actor ) &= ~DrawState.Invisibility;
if( _inGPose )
{
var ptr = ( void*** )actor.Address;
var enableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 16 ] ) );
enableDraw( actor.Address );
GetEnableDraw( actor )( actor.Address );
}
}
@ -281,7 +266,7 @@ namespace Penumbra.Interop
var (actor, _) = FindCurrentObject();
if( actor != null )
{
if( !StillLoading( RenderPtr( actor ) ) )
if( !StillLoading( ActorDrawState( actor ) ) )
{
RestoreSettings();
if( _wasTarget && Dalamud.Targets.Target == null )
@ -395,40 +380,6 @@ namespace Penumbra.Interop
}
}
private void UnloadAll()
{
Clear();
foreach( var (actor, index) in Dalamud.Objects.Select( ( a, i ) => ( a, i ) ) )
{
WriteInvisible( actor, index );
}
}
private void RedrawAllWithoutSettings()
{
Clear();
foreach( var (actor, index) in Dalamud.Objects.Select( ( a, i ) => ( a, i ) ) )
{
WriteVisible( actor, index );
}
}
public async void UnloadAtOnceRedrawWithSettings()
{
Clear();
UnloadAll();
await Task.Delay( UnloadAllRedrawDelay );
RedrawAll( RedrawType.RedrawWithSettings );
}
public async void UnloadAtOnceRedrawWithoutSettings()
{
Clear();
UnloadAll();
await Task.Delay( UnloadAllRedrawDelay );
RedrawAllWithoutSettings();
}
public void Clear()
{
RestoreSettings();
@ -442,4 +393,3 @@ namespace Penumbra.Interop
Dalamud.Framework.Update -= OnUpdateEvent;
}
}
}

View file

@ -0,0 +1,14 @@
using System;
namespace Penumbra.Interop.Structs;
[Flags]
public enum DrawState : uint
{
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,
}

View file

@ -11,8 +11,10 @@ using Penumbra.Api;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Files;
using Penumbra.UI.Custom;
using CharacterUtility = Penumbra.Interop.CharacterUtility;
using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle;
namespace Penumbra.UI;
@ -159,7 +161,7 @@ public partial class SettingsInterface
//PrintValue( "Resource Loader Enabled", _penumbra.ResourceLoader.IsEnabled.ToString() );
}
private void DrawDebugTabRedraw()
private unsafe void DrawDebugTabRedraw()
{
if( !ImGui.CollapsingHeader( "Redrawing##Debug" ) )
{
@ -187,7 +189,7 @@ public partial class SettingsInterface
.GetField( "_currentObjectName", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( _penumbra.ObjectReloader );
var currentObjectStartState = ( ObjectReloader.LoadingFlags? )_penumbra.ObjectReloader.GetType()
var currentObjectStartState = ( DrawState? )_penumbra.ObjectReloader.GetType()
.GetField( "_currentObjectStartState", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( _penumbra.ObjectReloader );
@ -200,7 +202,7 @@ public partial class SettingsInterface
.Invoke( _penumbra.ObjectReloader, Array.Empty< object >() )!;
var currentRender = currentObject != null
? ( ObjectReloader.LoadingFlags? )Marshal.ReadInt32( ObjectReloader.RenderPtr( currentObject ) )
? ObjectReloader.ActorDrawState( currentObject )
: null;
var waitFrames = ( int? )_penumbra.ObjectReloader.GetType()