mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Allow /penumbra redraw self and redrawing all, as well as the actor watcher, to redraw the GPose character.
This commit is contained in:
parent
3a7716717c
commit
3a7209109a
4 changed files with 82 additions and 30 deletions
|
|
@ -2,6 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Game.ClientState.Actors.Types;
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
|
@ -21,6 +22,8 @@ namespace Penumbra.Interop
|
||||||
|
|
||||||
public class ActorRefresher : IDisposable
|
public class ActorRefresher : IDisposable
|
||||||
{
|
{
|
||||||
|
private delegate void ManipulateDraw( IntPtr actor );
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum LoadingFlags : int
|
public enum LoadingFlags : int
|
||||||
{
|
{
|
||||||
|
|
@ -35,6 +38,7 @@ namespace Penumbra.Interop
|
||||||
private const int RenderModeOffset = 0x0104;
|
private const int RenderModeOffset = 0x0104;
|
||||||
private const int UnloadAllRedrawDelay = 250;
|
private const int UnloadAllRedrawDelay = 250;
|
||||||
private const int NpcActorId = -536870912;
|
private const int NpcActorId = -536870912;
|
||||||
|
public const int GPosePlayerActorIdx = 201;
|
||||||
|
|
||||||
private readonly DalamudPluginInterface _pi;
|
private readonly DalamudPluginInterface _pi;
|
||||||
private readonly ModManager _mods;
|
private readonly ModManager _mods;
|
||||||
|
|
@ -71,12 +75,22 @@ namespace Penumbra.Interop
|
||||||
_changedSettings = false;
|
_changedSettings = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void WriteInvisible( IntPtr renderPtr )
|
private unsafe void WriteInvisible( Actor actor, int actorIdx )
|
||||||
{
|
{
|
||||||
if( renderPtr != IntPtr.Zero )
|
var renderPtr = RenderPtr( actor );
|
||||||
|
if( renderPtr == IntPtr.Zero )
|
||||||
{
|
{
|
||||||
_currentActorStartState = *( LoadingFlags* )renderPtr;
|
return;
|
||||||
*( LoadingFlags* )renderPtr |= LoadingFlags.Invisibility;
|
}
|
||||||
|
|
||||||
|
_currentActorStartState = *( LoadingFlags* )renderPtr;
|
||||||
|
*( LoadingFlags* )renderPtr |= LoadingFlags.Invisibility;
|
||||||
|
|
||||||
|
if( actorIdx == GPosePlayerActorIdx )
|
||||||
|
{
|
||||||
|
var ptr = ( void*** )actor.Address;
|
||||||
|
var disableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 17 ] ) );
|
||||||
|
disableDraw( actor.Address );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,11 +115,16 @@ namespace Penumbra.Interop
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe void WriteVisible( IntPtr renderPtr )
|
private static unsafe void WriteVisible( Actor actor, int actorIdx )
|
||||||
{
|
{
|
||||||
if( renderPtr != IntPtr.Zero )
|
var renderPtr = RenderPtr( actor );
|
||||||
|
*( LoadingFlags* )renderPtr &= ~LoadingFlags.Invisibility;
|
||||||
|
|
||||||
|
if( actorIdx == GPosePlayerActorIdx )
|
||||||
{
|
{
|
||||||
*( LoadingFlags* )renderPtr &= ~LoadingFlags.Invisibility;
|
var ptr = ( void*** )actor.Address;
|
||||||
|
var enableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 16 ] ) );
|
||||||
|
enableDraw( actor.Address );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,8 +143,19 @@ namespace Penumbra.Interop
|
||||||
return _currentActorName == actor.Name;
|
return _currentActorName == actor.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Actor? FindCurrentActor()
|
private (Actor?, int) FindCurrentActor()
|
||||||
=> _pi.ClientState.Actors.FirstOrDefault( CheckActor );
|
{
|
||||||
|
for( var i = 0; i < _pi.ClientState.Actors.Length; ++i )
|
||||||
|
{
|
||||||
|
var actor = _pi.ClientState.Actors[ i ];
|
||||||
|
if( actor != null && CheckActor( actor ) )
|
||||||
|
{
|
||||||
|
return ( actor, i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( null, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
private void PopActor()
|
private void PopActor()
|
||||||
{
|
{
|
||||||
|
|
@ -135,7 +165,7 @@ namespace Penumbra.Interop
|
||||||
_currentActorName = name;
|
_currentActorName = name;
|
||||||
_currentActorId = id;
|
_currentActorId = id;
|
||||||
_currentActorRedraw = s;
|
_currentActorRedraw = s;
|
||||||
var actor = FindCurrentActor();
|
var (actor, idx) = FindCurrentActor();
|
||||||
if( actor == null )
|
if( actor == null )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -151,7 +181,7 @@ namespace Penumbra.Interop
|
||||||
|
|
||||||
private void ApplySettingsOrRedraw()
|
private void ApplySettingsOrRedraw()
|
||||||
{
|
{
|
||||||
var actor = FindCurrentActor();
|
var (actor, idx) = FindCurrentActor();
|
||||||
if( actor == null )
|
if( actor == null )
|
||||||
{
|
{
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
|
|
@ -161,7 +191,8 @@ namespace Penumbra.Interop
|
||||||
switch( _currentActorRedraw )
|
switch( _currentActorRedraw )
|
||||||
{
|
{
|
||||||
case Redraw.Unload:
|
case Redraw.Unload:
|
||||||
WriteInvisible( RenderPtr( actor ) );
|
WriteInvisible( actor, idx );
|
||||||
|
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
break;
|
break;
|
||||||
case Redraw.RedrawWithSettings:
|
case Redraw.RedrawWithSettings:
|
||||||
|
|
@ -169,16 +200,16 @@ namespace Penumbra.Interop
|
||||||
++_currentFrame;
|
++_currentFrame;
|
||||||
break;
|
break;
|
||||||
case Redraw.RedrawWithoutSettings:
|
case Redraw.RedrawWithoutSettings:
|
||||||
WriteVisible( RenderPtr( actor ) );
|
WriteVisible( actor, idx );
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
break;
|
break;
|
||||||
case Redraw.WithoutSettings:
|
case Redraw.WithoutSettings:
|
||||||
WriteInvisible( RenderPtr( actor ) );
|
WriteInvisible( actor, idx );
|
||||||
++_currentFrame;
|
++_currentFrame;
|
||||||
break;
|
break;
|
||||||
case Redraw.WithSettings:
|
case Redraw.WithSettings:
|
||||||
ChangeSettings();
|
ChangeSettings();
|
||||||
WriteInvisible( RenderPtr( actor ) );
|
WriteInvisible( actor, idx );
|
||||||
++_currentFrame;
|
++_currentFrame;
|
||||||
break;
|
break;
|
||||||
case Redraw.OnlyWithSettings:
|
case Redraw.OnlyWithSettings:
|
||||||
|
|
@ -188,7 +219,7 @@ namespace Penumbra.Interop
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteInvisible( RenderPtr( actor ) );
|
WriteInvisible( actor, idx );
|
||||||
++_currentFrame;
|
++_currentFrame;
|
||||||
break;
|
break;
|
||||||
default: throw new InvalidEnumArgumentException();
|
default: throw new InvalidEnumArgumentException();
|
||||||
|
|
@ -197,20 +228,20 @@ namespace Penumbra.Interop
|
||||||
|
|
||||||
private void StartRedrawAndWait()
|
private void StartRedrawAndWait()
|
||||||
{
|
{
|
||||||
var actor = FindCurrentActor();
|
var (actor, idx) = FindCurrentActor();
|
||||||
if( actor == null )
|
if( actor == null )
|
||||||
{
|
{
|
||||||
RevertSettings();
|
RevertSettings();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteVisible( RenderPtr( actor ) );
|
WriteVisible( actor, idx );
|
||||||
_currentFrame = _changedSettings ? _currentFrame + 1 : 0;
|
_currentFrame = _changedSettings ? _currentFrame + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RevertSettings()
|
private void RevertSettings()
|
||||||
{
|
{
|
||||||
var actor = FindCurrentActor();
|
var (actor, idx) = FindCurrentActor();
|
||||||
if( actor != null )
|
if( actor != null )
|
||||||
{
|
{
|
||||||
if( !StillLoading( RenderPtr( actor ) ) )
|
if( !StillLoading( RenderPtr( actor ) ) )
|
||||||
|
|
@ -269,14 +300,20 @@ namespace Penumbra.Interop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Actor? GetLocalPlayer()
|
||||||
|
{
|
||||||
|
var gPoseActor = _pi.ClientState.Actors[ GPosePlayerActorIdx ];
|
||||||
|
return gPoseActor ?? _pi.ClientState.Actors[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
private Actor? GetName( string name )
|
private Actor? GetName( string name )
|
||||||
{
|
{
|
||||||
var lowerName = name.ToLowerInvariant();
|
var lowerName = name.ToLowerInvariant();
|
||||||
return lowerName switch
|
return lowerName switch
|
||||||
{
|
{
|
||||||
"" => null,
|
"" => null,
|
||||||
"<me>" => _pi.ClientState.Actors[ 0 ],
|
"<me>" => GetLocalPlayer(),
|
||||||
"self" => _pi.ClientState.Actors[ 0 ],
|
"self" => GetLocalPlayer(),
|
||||||
"<t>" => _pi.ClientState.Targets.CurrentTarget,
|
"<t>" => _pi.ClientState.Targets.CurrentTarget,
|
||||||
"target" => _pi.ClientState.Targets.CurrentTarget,
|
"target" => _pi.ClientState.Targets.CurrentTarget,
|
||||||
"<f>" => _pi.ClientState.Targets.FocusTarget,
|
"<f>" => _pi.ClientState.Targets.FocusTarget,
|
||||||
|
|
@ -303,18 +340,18 @@ namespace Penumbra.Interop
|
||||||
private void UnloadAll()
|
private void UnloadAll()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
foreach( var a in _pi.ClientState.Actors )
|
foreach( var (actor, index) in _pi.ClientState.Actors.Select( ( a, i ) => ( a, i ) ) )
|
||||||
{
|
{
|
||||||
WriteInvisible( RenderPtr( a ) );
|
WriteInvisible( actor, index );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RedrawAllWithoutSettings()
|
private void RedrawAllWithoutSettings()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
foreach( var a in _pi.ClientState.Actors )
|
foreach( var (actor, index) in _pi.ClientState.Actors.Select( ( a, i ) => ( a, i ) ) )
|
||||||
{
|
{
|
||||||
WriteVisible( RenderPtr( a ) );
|
WriteVisible( actor, index );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace Penumbra.Interop
|
||||||
private readonly DalamudPluginInterface _pi;
|
private readonly DalamudPluginInterface _pi;
|
||||||
private readonly Dictionary< string, CharEquipment > _equip = new();
|
private readonly Dictionary< string, CharEquipment > _equip = new();
|
||||||
private int _frameTicker;
|
private int _frameTicker;
|
||||||
|
private IntPtr _lastGPoseAddress = IntPtr.Zero;
|
||||||
|
|
||||||
public PlayerWatcher( DalamudPluginInterface pi )
|
public PlayerWatcher( DalamudPluginInterface pi )
|
||||||
=> _pi = pi;
|
=> _pi = pi;
|
||||||
|
|
@ -81,7 +82,18 @@ namespace Penumbra.Interop
|
||||||
|
|
||||||
private void OnFrameworkUpdate( object framework )
|
private void OnFrameworkUpdate( object framework )
|
||||||
{
|
{
|
||||||
var actors = _pi.ClientState.Actors;
|
var actors = _pi.ClientState.Actors;
|
||||||
|
var gPoseActor = actors[ ActorRefresher.GPosePlayerActorIdx ];
|
||||||
|
if( gPoseActor == null )
|
||||||
|
{
|
||||||
|
_lastGPoseAddress = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
else if( gPoseActor.Address != _lastGPoseAddress )
|
||||||
|
{
|
||||||
|
_lastGPoseAddress = gPoseActor.Address;
|
||||||
|
ActorChanged?.Invoke( gPoseActor );
|
||||||
|
}
|
||||||
|
|
||||||
for( var i = 0; i < ActorsPerFrame; ++i )
|
for( var i = 0; i < ActorsPerFrame; ++i )
|
||||||
{
|
{
|
||||||
_frameTicker = _frameTicker < actors.Length - 2
|
_frameTicker = _frameTicker < actors.Length - 2
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using EmbedIO;
|
using EmbedIO;
|
||||||
|
|
@ -70,7 +71,8 @@ namespace Penumbra
|
||||||
|
|
||||||
SettingsInterface = new SettingsInterface( this );
|
SettingsInterface = new SettingsInterface( this );
|
||||||
|
|
||||||
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
|
PluginInterface.UiBuilder.DisableGposeUiHide = true;
|
||||||
|
PluginInterface.UiBuilder.OnBuildUi += SettingsInterface.Draw;
|
||||||
|
|
||||||
if( Configuration.EnableHttpApi )
|
if( Configuration.EnableHttpApi )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -181,9 +181,9 @@ namespace Penumbra.UI
|
||||||
.GetField( "_currentActorRedraw", BindingFlags.Instance | BindingFlags.NonPublic )
|
.GetField( "_currentActorRedraw", BindingFlags.Instance | BindingFlags.NonPublic )
|
||||||
?.GetValue( _plugin.ActorRefresher );
|
?.GetValue( _plugin.ActorRefresher );
|
||||||
|
|
||||||
var currentActor = ( Actor? )_plugin.ActorRefresher.GetType()
|
var (currentActor, currentActorIdx) = ( (Actor?, int) )_plugin.ActorRefresher.GetType()
|
||||||
.GetMethod( "FindCurrentActor", BindingFlags.NonPublic | BindingFlags.Instance )?
|
.GetMethod( "FindCurrentActor", BindingFlags.NonPublic | BindingFlags.Instance )?
|
||||||
.Invoke( _plugin.ActorRefresher, Array.Empty< object >() );
|
.Invoke( _plugin.ActorRefresher, Array.Empty< object >() )!;
|
||||||
|
|
||||||
var currentRender = currentActor != null
|
var currentRender = currentActor != null
|
||||||
? ( ActorRefresher.LoadingFlags? )Marshal.ReadInt32( ActorRefresher.RenderPtr( currentActor ) )
|
? ( ActorRefresher.LoadingFlags? )Marshal.ReadInt32( ActorRefresher.RenderPtr( currentActor ) )
|
||||||
|
|
@ -199,7 +199,8 @@ namespace Penumbra.UI
|
||||||
PrintValue( "Current Actor Start State", ( ( int? )currentActorStartState )?.ToString( "X8" ) ?? "null" );
|
PrintValue( "Current Actor Start State", ( ( int? )currentActorStartState )?.ToString( "X8" ) ?? "null" );
|
||||||
PrintValue( "Current Actor Redraw", currentActorRedraw?.ToString() ?? "null" );
|
PrintValue( "Current Actor Redraw", currentActorRedraw?.ToString() ?? "null" );
|
||||||
PrintValue( "Current Actor Address", currentActor?.Address.ToString( "X16" ) ?? "null" );
|
PrintValue( "Current Actor Address", currentActor?.Address.ToString( "X16" ) ?? "null" );
|
||||||
PrintValue( "Current Actor Render Flags", ( ( int? )currentRender )?.ToString( "X8" ) ?? "null" );
|
PrintValue( "Current Actor Index", currentActorIdx >= 0 ? currentActorIdx.ToString() : "null" );
|
||||||
|
PrintValue( "Current Actor Render Flags", ( ( int? )currentRender )?.ToString( "X8" ) ?? "null" );
|
||||||
ImGui.EndTable();
|
ImGui.EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue