mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Some object reloading changes.
This commit is contained in:
parent
e7282384f5
commit
8d2e84eecf
3 changed files with 353 additions and 387 deletions
|
|
@ -7,439 +7,389 @@ 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 unsafe class ObjectReloader : IDisposable
|
||||||
{
|
{
|
||||||
public class ObjectReloader : IDisposable
|
private delegate void ManipulateDraw( IntPtr actor );
|
||||||
|
|
||||||
|
private const int RenderModeOffset = 0x0104;
|
||||||
|
private const int UnloadAllRedrawDelay = 250;
|
||||||
|
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
|
||||||
|
public const int GPosePlayerIdx = 201;
|
||||||
|
public const int GPoseEndIdx = GPosePlayerIdx + 48;
|
||||||
|
|
||||||
|
private readonly ModManager _mods;
|
||||||
|
private readonly Queue< (uint actorId, string name, RedrawType s) > _actorIds = new();
|
||||||
|
|
||||||
|
internal int DefaultWaitFrames;
|
||||||
|
|
||||||
|
private int _waitFrames;
|
||||||
|
private int _currentFrame;
|
||||||
|
private bool _changedSettings;
|
||||||
|
private uint _currentObjectId = uint.MaxValue;
|
||||||
|
private DrawState _currentObjectStartState = 0;
|
||||||
|
private RedrawType _currentRedrawType = RedrawType.Unload;
|
||||||
|
private string? _currentObjectName;
|
||||||
|
private bool _wasTarget;
|
||||||
|
private bool _inGPose;
|
||||||
|
|
||||||
|
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 )
|
||||||
{
|
{
|
||||||
private delegate void ManipulateDraw( IntPtr actor );
|
_mods = mods;
|
||||||
|
DefaultWaitFrames = defaultWaitFrames;
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
private void ChangeSettings()
|
||||||
public enum LoadingFlags : int
|
{
|
||||||
|
if( _currentObjectName != null && _mods.Collections.CharacterCollection.TryGetValue( _currentObjectName, out var collection ) )
|
||||||
{
|
{
|
||||||
Invisibility = 0x00_00_00_02,
|
_changedSettings = true;
|
||||||
IsLoading = 0x00_00_08_00,
|
_mods.Collections.SetActiveCollection( collection, _currentObjectName );
|
||||||
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 void RestoreSettings()
|
||||||
private const int UnloadAllRedrawDelay = 250;
|
{
|
||||||
private const uint NpcObjectId = unchecked( ( uint )-536870912 );
|
_mods.Collections.ResetActiveCollection();
|
||||||
public const int GPosePlayerIdx = 201;
|
_changedSettings = false;
|
||||||
public const int GPoseEndIdx = GPosePlayerIdx + 48;
|
}
|
||||||
|
|
||||||
private readonly ModManager _mods;
|
private unsafe void WriteInvisible( GameObject actor, int actorIdx )
|
||||||
private readonly Queue< (uint actorId, string name, RedrawType s) > _actorIds = new();
|
{
|
||||||
|
_currentObjectStartState = *ActorDrawState( actor );
|
||||||
|
*ActorDrawState( actor ) |= DrawState.Invisibility;
|
||||||
|
|
||||||
internal int DefaultWaitFrames;
|
if( _inGPose )
|
||||||
|
|
||||||
private int _waitFrames;
|
|
||||||
private int _currentFrame;
|
|
||||||
private bool _changedSettings;
|
|
||||||
private uint _currentObjectId = uint.MaxValue;
|
|
||||||
private LoadingFlags _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 ObjectReloader( ModManager mods, int defaultWaitFrames )
|
|
||||||
{
|
{
|
||||||
_mods = mods;
|
GetDisableDraw( actor )( actor.Address );
|
||||||
DefaultWaitFrames = defaultWaitFrames;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ChangeSettings()
|
private bool StillLoading( DrawState* renderPtr )
|
||||||
|
{
|
||||||
|
const DrawState stillLoadingFlags = DrawState.SomeNpcFlag
|
||||||
|
| DrawState.MaybeCulled
|
||||||
|
| DrawState.MaybeHiddenMinion
|
||||||
|
| DrawState.MaybeHiddenSummon;
|
||||||
|
|
||||||
|
if( renderPtr != null )
|
||||||
{
|
{
|
||||||
if( _currentObjectName != null && _mods.Collections.CharacterCollection.TryGetValue( _currentObjectName, out var collection ) )
|
var loadingFlags = *( DrawState* )renderPtr;
|
||||||
{
|
if( loadingFlags == _currentObjectStartState )
|
||||||
_changedSettings = true;
|
|
||||||
_mods.Collections.SetActiveCollection( collection, _currentObjectName );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RestoreSettings()
|
|
||||||
{
|
|
||||||
_mods.Collections.ResetActiveCollection();
|
|
||||||
_changedSettings = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void WriteInvisible( GameObject actor, int actorIdx )
|
|
||||||
{
|
|
||||||
var renderPtr = RenderPtr( actor );
|
|
||||||
if( renderPtr == IntPtr.Zero )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentObjectStartState = *( LoadingFlags* )renderPtr;
|
|
||||||
*( LoadingFlags* )renderPtr |= LoadingFlags.Invisibility;
|
|
||||||
|
|
||||||
if( _inGPose )
|
|
||||||
{
|
|
||||||
var ptr = ( void*** )actor.Address;
|
|
||||||
var disableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 17 ] ) );
|
|
||||||
disableDraw( actor.Address );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe bool StillLoading( IntPtr renderPtr )
|
|
||||||
{
|
|
||||||
const LoadingFlags stillLoadingFlags = LoadingFlags.SomeNpcFlag
|
|
||||||
| LoadingFlags.MaybeCulled
|
|
||||||
| LoadingFlags.MaybeHiddenMinion
|
|
||||||
| LoadingFlags.MaybeHiddenSummon;
|
|
||||||
|
|
||||||
if( renderPtr != IntPtr.Zero )
|
|
||||||
{
|
|
||||||
var loadingFlags = *( LoadingFlags* )renderPtr;
|
|
||||||
if( loadingFlags == _currentObjectStartState )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !( loadingFlags == 0 || ( loadingFlags & stillLoadingFlags ) != 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private unsafe void WriteVisible( GameObject actor, int actorIdx )
|
|
||||||
{
|
|
||||||
var renderPtr = RenderPtr( actor );
|
|
||||||
*( LoadingFlags* )renderPtr &= ~LoadingFlags.Invisibility;
|
|
||||||
|
|
||||||
if( _inGPose )
|
|
||||||
{
|
|
||||||
var ptr = ( void*** )actor.Address;
|
|
||||||
var enableDraw = Marshal.GetDelegateForFunctionPointer< ManipulateDraw >( new IntPtr( ptr[ 0 ][ 16 ] ) );
|
|
||||||
enableDraw( actor.Address );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckObject( GameObject actor )
|
|
||||||
{
|
|
||||||
if( _currentObjectId != actor.ObjectId )
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _currentObjectId != NpcObjectId )
|
return !( loadingFlags == 0 || ( loadingFlags & stillLoadingFlags ) != 0 );
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _currentObjectName == actor.Name.ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckObjectGPose( GameObject actor )
|
return false;
|
||||||
=> actor.ObjectId == NpcObjectId && _currentObjectName == actor.Name.ToString();
|
}
|
||||||
|
|
||||||
private (GameObject?, int) FindCurrentObject()
|
private void WriteVisible( GameObject actor, int actorIdx )
|
||||||
|
{
|
||||||
|
*ActorDrawState( actor ) &= ~DrawState.Invisibility;
|
||||||
|
|
||||||
|
if( _inGPose )
|
||||||
{
|
{
|
||||||
if( _inGPose )
|
GetEnableDraw( actor )( actor.Address );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckObject( GameObject actor )
|
||||||
|
{
|
||||||
|
if( _currentObjectId != actor.ObjectId )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _currentObjectId != NpcObjectId )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _currentObjectName == actor.Name.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckObjectGPose( GameObject actor )
|
||||||
|
=> actor.ObjectId == NpcObjectId && _currentObjectName == actor.Name.ToString();
|
||||||
|
|
||||||
|
private (GameObject?, int) FindCurrentObject()
|
||||||
|
{
|
||||||
|
if( _inGPose )
|
||||||
|
{
|
||||||
|
for( var i = GPosePlayerIdx; i < GPoseEndIdx; ++i )
|
||||||
{
|
{
|
||||||
for( var i = GPosePlayerIdx; i < GPoseEndIdx; ++i )
|
|
||||||
{
|
|
||||||
var actor = Dalamud.Objects[ i ];
|
|
||||||
if( actor == null )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( CheckObjectGPose( actor ) )
|
|
||||||
{
|
|
||||||
return ( actor, i );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for( var i = 0; i < Dalamud.Objects.Length; ++i )
|
|
||||||
{
|
|
||||||
if( i == GPosePlayerIdx )
|
|
||||||
{
|
|
||||||
i = GPoseEndIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
var actor = Dalamud.Objects[ i ];
|
var actor = Dalamud.Objects[ i ];
|
||||||
if( actor != null && CheckObject( actor ) )
|
if( actor == null )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CheckObjectGPose( actor ) )
|
||||||
{
|
{
|
||||||
return ( actor, i );
|
return ( actor, i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ( null, -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopObject()
|
for( var i = 0; i < Dalamud.Objects.Length; ++i )
|
||||||
{
|
{
|
||||||
if( _actorIds.Count > 0 )
|
if( i == GPosePlayerIdx )
|
||||||
{
|
{
|
||||||
var (id, name, s) = _actorIds.Dequeue();
|
i = GPoseEndIdx;
|
||||||
_currentObjectName = name;
|
}
|
||||||
_currentObjectId = id;
|
|
||||||
_currentRedrawType = s;
|
var actor = Dalamud.Objects[ i ];
|
||||||
var (actor, _) = FindCurrentObject();
|
if( actor != null && CheckObject( actor ) )
|
||||||
if( actor == null )
|
{
|
||||||
|
return ( actor, i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( null, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopObject()
|
||||||
|
{
|
||||||
|
if( _actorIds.Count > 0 )
|
||||||
|
{
|
||||||
|
var (id, name, s) = _actorIds.Dequeue();
|
||||||
|
_currentObjectName = name;
|
||||||
|
_currentObjectId = id;
|
||||||
|
_currentRedrawType = s;
|
||||||
|
var (actor, _) = FindCurrentObject();
|
||||||
|
if( actor == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_wasTarget = actor.Address == Dalamud.Targets.Target?.Address;
|
||||||
|
|
||||||
|
++_currentFrame;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dalamud.Framework.Update -= OnUpdateEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySettingsOrRedraw()
|
||||||
|
{
|
||||||
|
var (actor, idx) = FindCurrentObject();
|
||||||
|
if( actor == null )
|
||||||
|
{
|
||||||
|
_currentFrame = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( _currentRedrawType )
|
||||||
|
{
|
||||||
|
case RedrawType.Unload:
|
||||||
|
WriteInvisible( actor, idx );
|
||||||
|
_currentFrame = 0;
|
||||||
|
break;
|
||||||
|
case RedrawType.RedrawWithSettings:
|
||||||
|
ChangeSettings();
|
||||||
|
++_currentFrame;
|
||||||
|
break;
|
||||||
|
case RedrawType.RedrawWithoutSettings:
|
||||||
|
WriteVisible( actor, idx );
|
||||||
|
_currentFrame = 0;
|
||||||
|
break;
|
||||||
|
case RedrawType.WithoutSettings:
|
||||||
|
WriteInvisible( actor, idx );
|
||||||
|
++_currentFrame;
|
||||||
|
break;
|
||||||
|
case RedrawType.WithSettings:
|
||||||
|
ChangeSettings();
|
||||||
|
WriteInvisible( actor, idx );
|
||||||
|
++_currentFrame;
|
||||||
|
break;
|
||||||
|
case RedrawType.OnlyWithSettings:
|
||||||
|
ChangeSettings();
|
||||||
|
if( !_changedSettings )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_wasTarget = actor.Address == Dalamud.Targets.Target?.Address;
|
WriteInvisible( actor, idx );
|
||||||
|
|
||||||
++_currentFrame;
|
++_currentFrame;
|
||||||
}
|
break;
|
||||||
else
|
case RedrawType.AfterGPoseWithSettings:
|
||||||
{
|
case RedrawType.AfterGPoseWithoutSettings:
|
||||||
Dalamud.Framework.Update -= OnUpdateEvent;
|
if( _inGPose )
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplySettingsOrRedraw()
|
|
||||||
{
|
|
||||||
var (actor, idx) = FindCurrentObject();
|
|
||||||
if( actor == null )
|
|
||||||
{
|
|
||||||
_currentFrame = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( _currentRedrawType )
|
|
||||||
{
|
|
||||||
case RedrawType.Unload:
|
|
||||||
WriteInvisible( actor, idx );
|
|
||||||
_currentFrame = 0;
|
|
||||||
break;
|
|
||||||
case RedrawType.RedrawWithSettings:
|
|
||||||
ChangeSettings();
|
|
||||||
++_currentFrame;
|
|
||||||
break;
|
|
||||||
case RedrawType.RedrawWithoutSettings:
|
|
||||||
WriteVisible( actor, idx );
|
|
||||||
_currentFrame = 0;
|
|
||||||
break;
|
|
||||||
case RedrawType.WithoutSettings:
|
|
||||||
WriteInvisible( actor, idx );
|
|
||||||
++_currentFrame;
|
|
||||||
break;
|
|
||||||
case RedrawType.WithSettings:
|
|
||||||
ChangeSettings();
|
|
||||||
WriteInvisible( actor, idx );
|
|
||||||
++_currentFrame;
|
|
||||||
break;
|
|
||||||
case RedrawType.OnlyWithSettings:
|
|
||||||
ChangeSettings();
|
|
||||||
if( !_changedSettings )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteInvisible( actor, idx );
|
|
||||||
++_currentFrame;
|
|
||||||
break;
|
|
||||||
case RedrawType.AfterGPoseWithSettings:
|
|
||||||
case RedrawType.AfterGPoseWithoutSettings:
|
|
||||||
if( _inGPose )
|
|
||||||
{
|
|
||||||
_actorIds.Enqueue( ( _currentObjectId, _currentObjectName!, _currentRedrawType ) );
|
|
||||||
_currentFrame = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_currentRedrawType = _currentRedrawType == RedrawType.AfterGPoseWithSettings
|
|
||||||
? RedrawType.WithSettings
|
|
||||||
: RedrawType.WithoutSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default: throw new InvalidEnumArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartRedrawAndWait()
|
|
||||||
{
|
|
||||||
var (actor, idx) = FindCurrentObject();
|
|
||||||
if( actor == null )
|
|
||||||
{
|
|
||||||
RevertSettings();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteVisible( actor, idx );
|
|
||||||
_currentFrame = _changedSettings || _wasTarget ? _currentFrame + 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertSettings()
|
|
||||||
{
|
|
||||||
var (actor, _) = FindCurrentObject();
|
|
||||||
if( actor != null )
|
|
||||||
{
|
|
||||||
if( !StillLoading( RenderPtr( actor ) ) )
|
|
||||||
{
|
{
|
||||||
RestoreSettings();
|
_actorIds.Enqueue( ( _currentObjectId, _currentObjectName!, _currentRedrawType ) );
|
||||||
if( _wasTarget && Dalamud.Targets.Target == null )
|
|
||||||
{
|
|
||||||
Dalamud.Targets.SetTarget( actor );
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
|
_currentRedrawType = _currentRedrawType == RedrawType.AfterGPoseWithSettings
|
||||||
|
? RedrawType.WithSettings
|
||||||
|
: RedrawType.WithoutSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default: throw new InvalidEnumArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartRedrawAndWait()
|
||||||
|
{
|
||||||
|
var (actor, idx) = FindCurrentObject();
|
||||||
|
if( actor == null )
|
||||||
|
{
|
||||||
|
RevertSettings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteVisible( actor, idx );
|
||||||
|
_currentFrame = _changedSettings || _wasTarget ? _currentFrame + 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevertSettings()
|
||||||
|
{
|
||||||
|
var (actor, _) = FindCurrentObject();
|
||||||
|
if( actor != null )
|
||||||
|
{
|
||||||
|
if( !StillLoading( ActorDrawState( actor ) ) )
|
||||||
{
|
{
|
||||||
|
RestoreSettings();
|
||||||
|
if( _wasTarget && Dalamud.Targets.Target == null )
|
||||||
|
{
|
||||||
|
Dalamud.Targets.SetTarget( actor );
|
||||||
|
}
|
||||||
|
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
private void OnUpdateEvent( object framework )
|
|
||||||
{
|
{
|
||||||
if( Dalamud.Conditions[ ConditionFlag.BetweenAreas51 ]
|
|
||||||
|| Dalamud.Conditions[ ConditionFlag.BetweenAreas ]
|
|
||||||
|| Dalamud.Conditions[ ConditionFlag.OccupiedInCutSceneEvent ] )
|
|
||||||
{
|
|
||||||
_waitFrames = DefaultWaitFrames;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _waitFrames > 0 )
|
|
||||||
{
|
|
||||||
--_waitFrames;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_inGPose = Dalamud.Objects[ GPosePlayerIdx ] != null;
|
|
||||||
|
|
||||||
switch( _currentFrame )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
PopObject();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ApplySettingsOrRedraw();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
StartRedrawAndWait();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
RevertSettings();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_currentFrame = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RedrawObjectIntern( uint objectId, string actorName, RedrawType settings )
|
|
||||||
{
|
|
||||||
if( _actorIds.Contains( ( objectId, actorName, settings ) ) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_actorIds.Enqueue( ( objectId, actorName, settings ) );
|
|
||||||
if( _actorIds.Count == 1 )
|
|
||||||
{
|
|
||||||
Dalamud.Framework.Update += OnUpdateEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RedrawObject( GameObject? actor, RedrawType settings = RedrawType.WithSettings )
|
|
||||||
{
|
|
||||||
if( actor != null )
|
|
||||||
{
|
|
||||||
RedrawObjectIntern( actor.ObjectId, actor.Name.ToString(), RedrawType.WithoutSettings ); // TODO settings );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GameObject? GetLocalPlayer()
|
|
||||||
{
|
|
||||||
var gPosePlayer = Dalamud.Objects[ GPosePlayerIdx ];
|
|
||||||
return gPosePlayer ?? Dalamud.Objects[ 0 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
private GameObject? GetName( string name )
|
|
||||||
{
|
|
||||||
var lowerName = name.ToLowerInvariant();
|
|
||||||
return lowerName switch
|
|
||||||
{
|
|
||||||
"" => null,
|
|
||||||
"<me>" => GetLocalPlayer(),
|
|
||||||
"self" => GetLocalPlayer(),
|
|
||||||
"<t>" => Dalamud.Targets.Target,
|
|
||||||
"target" => Dalamud.Targets.Target,
|
|
||||||
"<f>" => Dalamud.Targets.FocusTarget,
|
|
||||||
"focus" => Dalamud.Targets.FocusTarget,
|
|
||||||
"<mo>" => Dalamud.Targets.MouseOverTarget,
|
|
||||||
"mouseover" => Dalamud.Targets.MouseOverTarget,
|
|
||||||
_ => Dalamud.Objects.FirstOrDefault(
|
|
||||||
a => string.Equals( a.Name.ToString(), lowerName, StringComparison.InvariantCultureIgnoreCase ) ),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RedrawObject( string name, RedrawType settings = RedrawType.WithSettings )
|
|
||||||
=> RedrawObject( GetName( name ), settings );
|
|
||||||
|
|
||||||
public void RedrawAll( RedrawType settings = RedrawType.WithSettings )
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
foreach( var actor in Dalamud.Objects )
|
|
||||||
{
|
|
||||||
RedrawObject( actor, settings );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
private void OnUpdateEvent( object framework )
|
||||||
|
{
|
||||||
|
if( Dalamud.Conditions[ ConditionFlag.BetweenAreas51 ]
|
||||||
|
|| Dalamud.Conditions[ ConditionFlag.BetweenAreas ]
|
||||||
|
|| Dalamud.Conditions[ ConditionFlag.OccupiedInCutSceneEvent ] )
|
||||||
{
|
{
|
||||||
RevertSettings();
|
_waitFrames = DefaultWaitFrames;
|
||||||
_actorIds.Clear();
|
return;
|
||||||
Dalamud.Framework.Update -= OnUpdateEvent;
|
}
|
||||||
|
|
||||||
|
if( _waitFrames > 0 )
|
||||||
|
{
|
||||||
|
--_waitFrames;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inGPose = Dalamud.Objects[ GPosePlayerIdx ] != null;
|
||||||
|
|
||||||
|
switch( _currentFrame )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
PopObject();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ApplySettingsOrRedraw();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
StartRedrawAndWait();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
RevertSettings();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_currentFrame = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RedrawObjectIntern( uint objectId, string actorName, RedrawType settings )
|
||||||
|
{
|
||||||
|
if( _actorIds.Contains( ( objectId, actorName, settings ) ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actorIds.Enqueue( ( objectId, actorName, settings ) );
|
||||||
|
if( _actorIds.Count == 1 )
|
||||||
|
{
|
||||||
|
Dalamud.Framework.Update += OnUpdateEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RedrawObject( GameObject? actor, RedrawType settings = RedrawType.WithSettings )
|
||||||
|
{
|
||||||
|
if( actor != null )
|
||||||
|
{
|
||||||
|
RedrawObjectIntern( actor.ObjectId, actor.Name.ToString(), RedrawType.WithoutSettings ); // TODO settings );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameObject? GetLocalPlayer()
|
||||||
|
{
|
||||||
|
var gPosePlayer = Dalamud.Objects[ GPosePlayerIdx ];
|
||||||
|
return gPosePlayer ?? Dalamud.Objects[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameObject? GetName( string name )
|
||||||
|
{
|
||||||
|
var lowerName = name.ToLowerInvariant();
|
||||||
|
return lowerName switch
|
||||||
|
{
|
||||||
|
"" => null,
|
||||||
|
"<me>" => GetLocalPlayer(),
|
||||||
|
"self" => GetLocalPlayer(),
|
||||||
|
"<t>" => Dalamud.Targets.Target,
|
||||||
|
"target" => Dalamud.Targets.Target,
|
||||||
|
"<f>" => Dalamud.Targets.FocusTarget,
|
||||||
|
"focus" => Dalamud.Targets.FocusTarget,
|
||||||
|
"<mo>" => Dalamud.Targets.MouseOverTarget,
|
||||||
|
"mouseover" => Dalamud.Targets.MouseOverTarget,
|
||||||
|
_ => Dalamud.Objects.FirstOrDefault(
|
||||||
|
a => string.Equals( a.Name.ToString(), lowerName, StringComparison.InvariantCultureIgnoreCase ) ),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RedrawObject( string name, RedrawType settings = RedrawType.WithSettings )
|
||||||
|
=> RedrawObject( GetName( name ), settings );
|
||||||
|
|
||||||
|
public void RedrawAll( RedrawType settings = RedrawType.WithSettings )
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
foreach( var actor in Dalamud.Objects )
|
||||||
|
{
|
||||||
|
RedrawObject( actor, settings );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
RestoreSettings();
|
||||||
|
_currentFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
RevertSettings();
|
||||||
|
_actorIds.Clear();
|
||||||
|
Dalamud.Framework.Update -= OnUpdateEvent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
14
Penumbra/Interop/Structs/DrawState.cs
Normal file
14
Penumbra/Interop/Structs/DrawState.cs
Normal 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,
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue