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.Conditions;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
using Penumbra.Mods; using Penumbra.Mods;
namespace Penumbra.Interop namespace Penumbra.Interop;
{
public class ObjectReloader : IDisposable public unsafe class ObjectReloader : IDisposable
{ {
private delegate void ManipulateDraw( IntPtr actor ); 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 RenderModeOffset = 0x0104;
private const int UnloadAllRedrawDelay = 250; private const int UnloadAllRedrawDelay = 250;
private const uint NpcObjectId = unchecked( ( uint )-536870912 ); private const uint NpcObjectId = unchecked( ( uint )-536870912 );
@ -41,14 +31,20 @@ namespace Penumbra.Interop
private int _currentFrame; private int _currentFrame;
private bool _changedSettings; private bool _changedSettings;
private uint _currentObjectId = uint.MaxValue; private uint _currentObjectId = uint.MaxValue;
private LoadingFlags _currentObjectStartState = 0; private DrawState _currentObjectStartState = 0;
private RedrawType _currentRedrawType = RedrawType.Unload; private RedrawType _currentRedrawType = RedrawType.Unload;
private string? _currentObjectName; private string? _currentObjectName;
private bool _wasTarget; private bool _wasTarget;
private bool _inGPose; private bool _inGPose;
public static IntPtr RenderPtr( GameObject actor ) public static DrawState* ActorDrawState( GameObject actor )
=> actor.Address + RenderModeOffset; => ( 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 ) public ObjectReloader( ModManager mods, int defaultWaitFrames )
{ {
@ -73,33 +69,25 @@ namespace Penumbra.Interop
private unsafe void WriteInvisible( GameObject actor, int actorIdx ) private unsafe void WriteInvisible( GameObject actor, int actorIdx )
{ {
var renderPtr = RenderPtr( actor ); _currentObjectStartState = *ActorDrawState( actor );
if( renderPtr == IntPtr.Zero ) *ActorDrawState( actor ) |= DrawState.Invisibility;
{
return;
}
_currentObjectStartState = *( LoadingFlags* )renderPtr;
*( LoadingFlags* )renderPtr |= LoadingFlags.Invisibility;
if( _inGPose ) if( _inGPose )
{ {
var ptr = ( void*** )actor.Address; GetDisableDraw( actor )( actor.Address );
var disableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 17 ] ) );
disableDraw( actor.Address );
} }
} }
private unsafe bool StillLoading( IntPtr renderPtr ) private bool StillLoading( DrawState* renderPtr )
{ {
const LoadingFlags stillLoadingFlags = LoadingFlags.SomeNpcFlag const DrawState stillLoadingFlags = DrawState.SomeNpcFlag
| LoadingFlags.MaybeCulled | DrawState.MaybeCulled
| LoadingFlags.MaybeHiddenMinion | DrawState.MaybeHiddenMinion
| LoadingFlags.MaybeHiddenSummon; | DrawState.MaybeHiddenSummon;
if( renderPtr != IntPtr.Zero ) if( renderPtr != null )
{ {
var loadingFlags = *( LoadingFlags* )renderPtr; var loadingFlags = *( DrawState* )renderPtr;
if( loadingFlags == _currentObjectStartState ) if( loadingFlags == _currentObjectStartState )
{ {
return false; return false;
@ -111,16 +99,13 @@ namespace Penumbra.Interop
return false; return false;
} }
private unsafe void WriteVisible( GameObject actor, int actorIdx ) private void WriteVisible( GameObject actor, int actorIdx )
{ {
var renderPtr = RenderPtr( actor ); *ActorDrawState( actor ) &= ~DrawState.Invisibility;
*( LoadingFlags* )renderPtr &= ~LoadingFlags.Invisibility;
if( _inGPose ) if( _inGPose )
{ {
var ptr = ( void*** )actor.Address; GetEnableDraw( actor )( actor.Address );
var enableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 16 ] ) );
enableDraw( actor.Address );
} }
} }
@ -281,7 +266,7 @@ namespace Penumbra.Interop
var (actor, _) = FindCurrentObject(); var (actor, _) = FindCurrentObject();
if( actor != null ) if( actor != null )
{ {
if( !StillLoading( RenderPtr( actor ) ) ) if( !StillLoading( ActorDrawState( actor ) ) )
{ {
RestoreSettings(); RestoreSettings();
if( _wasTarget && Dalamud.Targets.Target == null ) 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() public void Clear()
{ {
RestoreSettings(); RestoreSettings();
@ -442,4 +393,3 @@ namespace Penumbra.Interop
Dalamud.Framework.Update -= OnUpdateEvent; 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.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Interop; using Penumbra.Interop;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Files; using Penumbra.Meta.Files;
using Penumbra.UI.Custom; using Penumbra.UI.Custom;
using CharacterUtility = Penumbra.Interop.CharacterUtility;
using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle; using ResourceHandle = Penumbra.Interop.Structs.ResourceHandle;
namespace Penumbra.UI; namespace Penumbra.UI;
@ -159,7 +161,7 @@ public partial class SettingsInterface
//PrintValue( "Resource Loader Enabled", _penumbra.ResourceLoader.IsEnabled.ToString() ); //PrintValue( "Resource Loader Enabled", _penumbra.ResourceLoader.IsEnabled.ToString() );
} }
private void DrawDebugTabRedraw() private unsafe void DrawDebugTabRedraw()
{ {
if( !ImGui.CollapsingHeader( "Redrawing##Debug" ) ) if( !ImGui.CollapsingHeader( "Redrawing##Debug" ) )
{ {
@ -187,7 +189,7 @@ public partial class SettingsInterface
.GetField( "_currentObjectName", BindingFlags.Instance | BindingFlags.NonPublic ) .GetField( "_currentObjectName", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( _penumbra.ObjectReloader ); ?.GetValue( _penumbra.ObjectReloader );
var currentObjectStartState = ( ObjectReloader.LoadingFlags? )_penumbra.ObjectReloader.GetType() var currentObjectStartState = ( DrawState? )_penumbra.ObjectReloader.GetType()
.GetField( "_currentObjectStartState", BindingFlags.Instance | BindingFlags.NonPublic ) .GetField( "_currentObjectStartState", BindingFlags.Instance | BindingFlags.NonPublic )
?.GetValue( _penumbra.ObjectReloader ); ?.GetValue( _penumbra.ObjectReloader );
@ -200,7 +202,7 @@ public partial class SettingsInterface
.Invoke( _penumbra.ObjectReloader, Array.Empty< object >() )!; .Invoke( _penumbra.ObjectReloader, Array.Empty< object >() )!;
var currentRender = currentObject != null var currentRender = currentObject != null
? ( ObjectReloader.LoadingFlags? )Marshal.ReadInt32( ObjectReloader.RenderPtr( currentObject ) ) ? ObjectReloader.ActorDrawState( currentObject )
: null; : null;
var waitFrames = ( int? )_penumbra.ObjectReloader.GetType() var waitFrames = ( int? )_penumbra.ObjectReloader.GetType()