mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-31 21:03:48 +01:00
Add GameEventManager, change cutscene character and subfile container resets.
This commit is contained in:
parent
7ab1426a2c
commit
24fda725a2
7 changed files with 183 additions and 107 deletions
|
|
@ -2,11 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
|
||||
namespace Penumbra.Interop.Resolver;
|
||||
|
||||
|
|
@ -16,17 +12,18 @@ public class CutsceneCharacters : IDisposable
|
|||
public const int CutsceneSlots = 40;
|
||||
public const int CutsceneEndIdx = CutsceneStartIdx + CutsceneSlots;
|
||||
|
||||
private readonly short[] _copiedCharacters = Enumerable.Repeat( ( short )-1, CutsceneSlots ).ToArray();
|
||||
private readonly GameEventManager _events;
|
||||
private readonly short[] _copiedCharacters = Enumerable.Repeat( ( short )-1, CutsceneSlots ).ToArray();
|
||||
|
||||
public IEnumerable< KeyValuePair< int, global::Dalamud.Game.ClientState.Objects.Types.GameObject > > Actors
|
||||
=> Enumerable.Range( CutsceneStartIdx, CutsceneSlots )
|
||||
.Where( i => Dalamud.Objects[ i ] != null )
|
||||
.Select( i => KeyValuePair.Create( i, this[ i ] ?? Dalamud.Objects[ i ]! ) );
|
||||
|
||||
public CutsceneCharacters()
|
||||
public CutsceneCharacters(GameEventManager events)
|
||||
{
|
||||
SignatureHelper.Initialise( this );
|
||||
Dalamud.Conditions.ConditionChange += Reset;
|
||||
_events = events;
|
||||
Enable();
|
||||
}
|
||||
|
||||
// Get the related actor to a cutscene actor.
|
||||
|
|
@ -53,71 +50,36 @@ public class CutsceneCharacters : IDisposable
|
|||
return -1;
|
||||
}
|
||||
|
||||
public void Reset( ConditionFlag flag, bool value )
|
||||
public unsafe void Enable()
|
||||
{
|
||||
switch( flag )
|
||||
{
|
||||
case ConditionFlag.BetweenAreas:
|
||||
case ConditionFlag.BetweenAreas51:
|
||||
if( !value )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case ConditionFlag.OccupiedInCutSceneEvent:
|
||||
case ConditionFlag.WatchingCutscene:
|
||||
case ConditionFlag.WatchingCutscene78:
|
||||
if( value )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
for( var i = 0; i < _copiedCharacters.Length; ++i )
|
||||
{
|
||||
_copiedCharacters[ i ] = -1;
|
||||
}
|
||||
_events.CopyCharacter += OnCharacterCopy;
|
||||
_events.CharacterDestructor += OnCharacterDestructor;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
=> _copyCharacterHook.Enable();
|
||||
|
||||
public void Disable()
|
||||
=> _copyCharacterHook.Disable();
|
||||
public unsafe void Disable()
|
||||
{
|
||||
_events.CopyCharacter -= OnCharacterCopy;
|
||||
_events.CharacterDestructor -= OnCharacterDestructor;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> Disable();
|
||||
|
||||
private unsafe void OnCharacterDestructor( Character* character )
|
||||
{
|
||||
_copyCharacterHook.Dispose();
|
||||
Dalamud.Conditions.ConditionChange -= Reset;
|
||||
if( character->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
||||
{
|
||||
var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||
_copiedCharacters[ idx ] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe delegate ulong CopyCharacterDelegate( GameObject* target, GameObject* source, uint unk );
|
||||
|
||||
[Signature( Sigs.CopyCharacter, DetourName = nameof( CopyCharacterDetour ) )]
|
||||
private readonly Hook< CopyCharacterDelegate > _copyCharacterHook = null!;
|
||||
|
||||
private unsafe ulong CopyCharacterDetour( GameObject* target, GameObject* source, uint unk )
|
||||
private unsafe void OnCharacterCopy( Character* target, Character* source )
|
||||
{
|
||||
try
|
||||
if( target != null && target->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
||||
{
|
||||
if( target != null && target->ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
||||
{
|
||||
var parent = source == null || source->ObjectIndex is < 0 or >= CutsceneStartIdx
|
||||
? -1
|
||||
: source->ObjectIndex;
|
||||
_copiedCharacters[ target->ObjectIndex - CutsceneStartIdx ] = ( short )parent;
|
||||
Penumbra.Log.Debug( $"Set cutscene character {target->ObjectIndex} to {parent}." );
|
||||
}
|
||||
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||
_copiedCharacters[idx] = (short) (source != null ? source->GameObject.ObjectIndex : -1);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
return _copyCharacterHook.Original( target, source, unk );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,23 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
namespace Penumbra.Interop.Resolver;
|
||||
|
||||
public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPtr Address, ActorIdentifier Identifier, ModCollection Collection) >
|
||||
{
|
||||
private readonly GameEventManager _events;
|
||||
private readonly Dictionary< IntPtr, (ActorIdentifier, ModCollection) > _cache = new(317);
|
||||
private bool _dirty = false;
|
||||
private bool _enabled = false;
|
||||
|
||||
public IdentifiedCollectionCache()
|
||||
public IdentifiedCollectionCache(GameEventManager events)
|
||||
{
|
||||
SignatureHelper.Initialise( this );
|
||||
_events = events;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
|
|
@ -32,8 +30,8 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
|||
Penumbra.CollectionManager.CollectionChanged += CollectionChangeClear;
|
||||
Penumbra.TempMods.CollectionChanged += CollectionChangeClear;
|
||||
Dalamud.ClientState.TerritoryChanged += TerritoryClear;
|
||||
_characterDtorHook.Enable();
|
||||
_enabled = true;
|
||||
_events.CharacterDestructor += OnCharacterDestruct;
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
|
@ -46,8 +44,8 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
|||
Penumbra.CollectionManager.CollectionChanged -= CollectionChangeClear;
|
||||
Penumbra.TempMods.CollectionChanged -= CollectionChangeClear;
|
||||
Dalamud.ClientState.TerritoryChanged -= TerritoryClear;
|
||||
_characterDtorHook.Disable();
|
||||
_enabled = false;
|
||||
_events.CharacterDestructor -= OnCharacterDestruct;
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
public ResolveData Set( ModCollection collection, ActorIdentifier identifier, GameObject* data )
|
||||
|
|
@ -82,7 +80,6 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
|||
public void Dispose()
|
||||
{
|
||||
Disable();
|
||||
_characterDtorHook.Dispose();
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
|
|
@ -116,14 +113,6 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
|||
private void TerritoryClear( object? _1, ushort _2 )
|
||||
=> _dirty = _cache.Count > 0;
|
||||
|
||||
private delegate void CharacterDestructorDelegate( Character* character );
|
||||
|
||||
[Signature( Sigs.CharacterDestructor, DetourName = nameof( CharacterDestructorDetour ) )]
|
||||
private Hook< CharacterDestructorDelegate > _characterDtorHook = null!;
|
||||
|
||||
private void CharacterDestructorDetour( Character* character )
|
||||
{
|
||||
_cache.Remove( ( IntPtr )character );
|
||||
_characterDtorHook.Original( character );
|
||||
}
|
||||
private void OnCharacterDestruct( Character* character )
|
||||
=> _cache.Remove( ( IntPtr )character );
|
||||
}
|
||||
|
|
@ -24,18 +24,20 @@ public unsafe partial class PathResolver
|
|||
// Thus, we need to ensure the correct files are loaded when a material is loaded.
|
||||
public class SubfileHelper : IDisposable, IReadOnlyCollection< KeyValuePair< IntPtr, ResolveData > >
|
||||
{
|
||||
private readonly ResourceLoader _loader;
|
||||
private readonly ResourceLoader _loader;
|
||||
private readonly GameEventManager _events;
|
||||
|
||||
private readonly ThreadLocal< ResolveData > _mtrlData = new(() => ResolveData.Invalid);
|
||||
private readonly ThreadLocal< ResolveData > _avfxData = new(() => ResolveData.Invalid);
|
||||
|
||||
private readonly ConcurrentDictionary< IntPtr, ResolveData > _subFileCollection = new();
|
||||
|
||||
public SubfileHelper( ResourceLoader loader )
|
||||
public SubfileHelper( ResourceLoader loader, GameEventManager events )
|
||||
{
|
||||
SignatureHelper.Initialise( this );
|
||||
|
||||
_loader = loader;
|
||||
_events = events;
|
||||
}
|
||||
|
||||
// Check specifically for shpk and tex files whether we are currently in a material load.
|
||||
|
|
@ -85,7 +87,7 @@ public unsafe partial class PathResolver
|
|||
_apricotResourceLoadHook.Enable();
|
||||
_loader.ResourceLoadCustomization += SubfileLoadHandler;
|
||||
_loader.ResourceLoaded += SubfileContainerRequested;
|
||||
_loader.FileLoaded += SubfileContainerLoaded;
|
||||
_events.ResourceHandleDestructor += ResourceDestroyed;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
|
@ -95,7 +97,7 @@ public unsafe partial class PathResolver
|
|||
_apricotResourceLoadHook.Disable();
|
||||
_loader.ResourceLoadCustomization -= SubfileLoadHandler;
|
||||
_loader.ResourceLoaded -= SubfileContainerRequested;
|
||||
_loader.FileLoaded -= SubfileContainerLoaded;
|
||||
_events.ResourceHandleDestructor -= ResourceDestroyed;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -121,16 +123,8 @@ public unsafe partial class PathResolver
|
|||
}
|
||||
}
|
||||
|
||||
private void SubfileContainerLoaded( ResourceHandle* handle, ByteString path, bool success, bool custom )
|
||||
{
|
||||
switch( handle->FileType )
|
||||
{
|
||||
case ResourceType.Mtrl:
|
||||
case ResourceType.Avfx:
|
||||
_subFileCollection.TryRemove( ( IntPtr )handle, out _ );
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void ResourceDestroyed( ResourceHandle* handle )
|
||||
=> _subFileCollection.TryRemove( ( IntPtr )handle, out _ );
|
||||
|
||||
// We need to set the correct collection for the actual material path that is loaded
|
||||
// before actually loading the file.
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ public partial class PathResolver : IDisposable
|
|||
public bool Enabled { get; private set; }
|
||||
|
||||
private readonly ResourceLoader _loader;
|
||||
private static readonly CutsceneCharacters Cutscenes = new();
|
||||
private static readonly CutsceneCharacters Cutscenes = new(Penumbra.GameEvents);
|
||||
private static readonly DrawObjectState DrawObjects = new();
|
||||
private static readonly BitArray ValidHumanModels;
|
||||
internal static readonly IdentifiedCollectionCache IdentifiedCache = new();
|
||||
internal static readonly IdentifiedCollectionCache IdentifiedCache = new(Penumbra.GameEvents);
|
||||
private readonly AnimationState _animations;
|
||||
private readonly PathState _paths;
|
||||
private readonly MetaState _meta;
|
||||
|
|
@ -43,7 +43,7 @@ public partial class PathResolver : IDisposable
|
|||
_animations = new AnimationState( DrawObjects );
|
||||
_paths = new PathState( this );
|
||||
_meta = new MetaState( _paths.HumanVTable );
|
||||
_subFiles = new SubfileHelper( _loader );
|
||||
_subFiles = new SubfileHelper( _loader, Penumbra.GameEvents );
|
||||
}
|
||||
|
||||
// The modified resolver that handles game path resolving.
|
||||
|
|
@ -175,6 +175,9 @@ public partial class PathResolver : IDisposable
|
|||
internal IEnumerable< KeyValuePair< IntPtr, ResolveData > > ResourceCollections
|
||||
=> _subFiles;
|
||||
|
||||
internal int SubfileCount
|
||||
=> _subFiles.Count;
|
||||
|
||||
internal ResolveData CurrentMtrlData
|
||||
=> _subFiles.MtrlData;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue