mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 20:24:17 +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
|
|
@ -3,7 +3,6 @@ namespace Penumbra.GameData;
|
||||||
public static class Sigs
|
public static class Sigs
|
||||||
{
|
{
|
||||||
// ResourceLoader.Debug
|
// ResourceLoader.Debug
|
||||||
public const string ResourceHandleDestructor = "48 89 5C 24 ?? 57 48 83 EC ?? 48 8D 05 ?? ?? ?? ?? 48 8B D9 48 89 01 B8";
|
|
||||||
public const string ResourceManager = "48 8B 05 ?? ?? ?? ?? 33 ED F0";
|
public const string ResourceManager = "48 8B 05 ?? ?? ?? ?? 33 ED F0";
|
||||||
|
|
||||||
// ResourceLoader.Replacement
|
// ResourceLoader.Replacement
|
||||||
|
|
@ -19,10 +18,10 @@ public static class Sigs
|
||||||
public const string LoadTexFileExtern = "E8 ?? ?? ?? ?? 0F B6 E8 48 8B CB E8";
|
public const string LoadTexFileExtern = "E8 ?? ?? ?? ?? 0F B6 E8 48 8B CB E8";
|
||||||
public const string LoadMdlFileExtern = "E8 ?? ?? ?? ?? EB 02 B0 F1";
|
public const string LoadMdlFileExtern = "E8 ?? ?? ?? ?? EB 02 B0 F1";
|
||||||
|
|
||||||
// CutsceneCharacters
|
// GameEventManager
|
||||||
|
public const string ResourceHandleDestructor = "48 89 5C 24 ?? 57 48 83 EC ?? 48 8D 05 ?? ?? ?? ?? 48 8B D9 48 89 01 B8";
|
||||||
public const string CopyCharacter = "E8 ?? ?? ?? ?? 0F B6 9F ?? ?? ?? ?? 48 8D 8F";
|
public const string CopyCharacter = "E8 ?? ?? ?? ?? 0F B6 9F ?? ?? ?? ?? 48 8D 8F";
|
||||||
|
|
||||||
// IdentifiedCollectionCache
|
|
||||||
public const string CharacterDestructor =
|
public const string CharacterDestructor =
|
||||||
"48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 48 8D 05 ?? ?? ?? ?? 48 8B D9 48 89 01 48 8D 05 ?? ?? ?? ?? 48 89 81 ?? ?? ?? ?? 48 8D 05";
|
"48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 48 8D 05 ?? ?? ?? ?? 48 8B D9 48 89 01 48 8D 05 ?? ?? ?? ?? 48 89 81 ?? ?? ?? ?? 48 8D 05";
|
||||||
|
|
||||||
|
|
|
||||||
126
Penumbra/Interop/GameEventManager.cs
Normal file
126
Penumbra/Interop/GameEventManager.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using Dalamud.Utility.Signatures;
|
||||||
|
using Penumbra.GameData;
|
||||||
|
using System;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
|
using Penumbra.Interop.Structs;
|
||||||
|
|
||||||
|
namespace Penumbra.Interop;
|
||||||
|
|
||||||
|
public unsafe class GameEventManager : IDisposable
|
||||||
|
{
|
||||||
|
public GameEventManager()
|
||||||
|
{
|
||||||
|
SignatureHelper.Initialise( this );
|
||||||
|
_characterDtorHook.Enable();
|
||||||
|
_copyCharacterHook.Enable();
|
||||||
|
_resourceHandleDestructorHook.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_characterDtorHook.Dispose();
|
||||||
|
_copyCharacterHook.Dispose();
|
||||||
|
_resourceHandleDestructorHook.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Character Destructor
|
||||||
|
|
||||||
|
private delegate void CharacterDestructorDelegate( Character* character );
|
||||||
|
|
||||||
|
[Signature( Sigs.CharacterDestructor, DetourName = nameof( CharacterDestructorDetour ) )]
|
||||||
|
private readonly Hook< CharacterDestructorDelegate > _characterDtorHook = null!;
|
||||||
|
|
||||||
|
private void CharacterDestructorDetour( Character* character )
|
||||||
|
{
|
||||||
|
if( CharacterDestructor != null )
|
||||||
|
{
|
||||||
|
foreach( var subscriber in CharacterDestructor.GetInvocationList() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
( ( CharacterDestructorEvent )subscriber ).Invoke( character );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error( $"Error in {nameof( CharacterDestructor )} event when executing {subscriber.Method.Name}:\n{ex}" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Penumbra.Log.Verbose( $"{nameof( CharacterDestructor )} triggered with 0x{( nint )character:X}." );
|
||||||
|
_characterDtorHook.Original( character );
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void CharacterDestructorEvent( Character* character );
|
||||||
|
public event CharacterDestructorEvent? CharacterDestructor;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Copy Character
|
||||||
|
|
||||||
|
private unsafe delegate ulong CopyCharacterDelegate( GameObject* target, GameObject* source, uint unk );
|
||||||
|
|
||||||
|
[Signature( Sigs.CopyCharacter, DetourName = nameof( CopyCharacterDetour ) )]
|
||||||
|
private readonly Hook< CopyCharacterDelegate > _copyCharacterHook = null!;
|
||||||
|
|
||||||
|
private ulong CopyCharacterDetour( GameObject* target, GameObject* source, uint unk )
|
||||||
|
{
|
||||||
|
if( CopyCharacter != null )
|
||||||
|
{
|
||||||
|
foreach( var subscriber in CopyCharacter.GetInvocationList() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
( ( CopyCharacterEvent )subscriber ).Invoke( ( Character* )target, ( Character* )source );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error( $"Error in {nameof( CopyCharacter )} event when executing {subscriber.Method.Name}:\n{ex}" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Penumbra.Log.Verbose( $"{nameof( CopyCharacter )} triggered with target 0x{( nint )target:X} and source 0x{( nint )source:X}." );
|
||||||
|
return _copyCharacterHook.Original( target, source, unk );
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void CopyCharacterEvent( Character* target, Character* source );
|
||||||
|
public event CopyCharacterEvent? CopyCharacter;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ResourceHandle Destructor
|
||||||
|
|
||||||
|
private delegate IntPtr ResourceHandleDestructorDelegate( ResourceHandle* handle );
|
||||||
|
|
||||||
|
[Signature( Sigs.ResourceHandleDestructor, DetourName = nameof( ResourceHandleDestructorDetour ) )]
|
||||||
|
private readonly Hook< ResourceHandleDestructorDelegate > _resourceHandleDestructorHook = null!;
|
||||||
|
|
||||||
|
private IntPtr ResourceHandleDestructorDetour( ResourceHandle* handle )
|
||||||
|
{
|
||||||
|
if( ResourceHandleDestructor != null )
|
||||||
|
{
|
||||||
|
foreach( var subscriber in ResourceHandleDestructor.GetInvocationList() )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
( ( ResourceHandleDestructorEvent )subscriber ).Invoke( handle );
|
||||||
|
}
|
||||||
|
catch( Exception ex )
|
||||||
|
{
|
||||||
|
Penumbra.Log.Error( $"Error in {nameof( ResourceHandleDestructor )} event when executing {subscriber.Method.Name}:\n{ex}" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Penumbra.Log.Verbose( $"{nameof( ResourceHandleDestructor )} triggered with 0x{( nint )handle:X}." );
|
||||||
|
return _resourceHandleDestructorHook!.Original( handle );
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void ResourceHandleDestructorEvent( ResourceHandle* handle );
|
||||||
|
public event ResourceHandleDestructorEvent? ResourceHandleDestructor;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using Dalamud.Hooking;
|
|
||||||
using Dalamud.Utility.Signatures;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
|
||||||
using Penumbra.GameData;
|
|
||||||
|
|
||||||
namespace Penumbra.Interop.Resolver;
|
namespace Penumbra.Interop.Resolver;
|
||||||
|
|
||||||
|
|
@ -16,6 +12,7 @@ public class CutsceneCharacters : IDisposable
|
||||||
public const int CutsceneSlots = 40;
|
public const int CutsceneSlots = 40;
|
||||||
public const int CutsceneEndIdx = CutsceneStartIdx + CutsceneSlots;
|
public const int CutsceneEndIdx = CutsceneStartIdx + CutsceneSlots;
|
||||||
|
|
||||||
|
private readonly GameEventManager _events;
|
||||||
private readonly short[] _copiedCharacters = Enumerable.Repeat( ( short )-1, CutsceneSlots ).ToArray();
|
private readonly short[] _copiedCharacters = Enumerable.Repeat( ( short )-1, CutsceneSlots ).ToArray();
|
||||||
|
|
||||||
public IEnumerable< KeyValuePair< int, global::Dalamud.Game.ClientState.Objects.Types.GameObject > > Actors
|
public IEnumerable< KeyValuePair< int, global::Dalamud.Game.ClientState.Objects.Types.GameObject > > Actors
|
||||||
|
|
@ -23,10 +20,10 @@ public class CutsceneCharacters : IDisposable
|
||||||
.Where( i => Dalamud.Objects[ i ] != null )
|
.Where( i => Dalamud.Objects[ i ] != null )
|
||||||
.Select( i => KeyValuePair.Create( i, this[ i ] ?? Dalamud.Objects[ i ]! ) );
|
.Select( i => KeyValuePair.Create( i, this[ i ] ?? Dalamud.Objects[ i ]! ) );
|
||||||
|
|
||||||
public CutsceneCharacters()
|
public CutsceneCharacters(GameEventManager events)
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise( this );
|
_events = events;
|
||||||
Dalamud.Conditions.ConditionChange += Reset;
|
Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the related actor to a cutscene actor.
|
// Get the related actor to a cutscene actor.
|
||||||
|
|
@ -53,71 +50,36 @@ public class CutsceneCharacters : IDisposable
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset( ConditionFlag flag, bool value )
|
public unsafe void Enable()
|
||||||
{
|
{
|
||||||
switch( flag )
|
_events.CopyCharacter += OnCharacterCopy;
|
||||||
{
|
_events.CharacterDestructor += OnCharacterDestructor;
|
||||||
case ConditionFlag.BetweenAreas:
|
|
||||||
case ConditionFlag.BetweenAreas51:
|
|
||||||
if( !value )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
public unsafe void Disable()
|
||||||
case ConditionFlag.OccupiedInCutSceneEvent:
|
|
||||||
case ConditionFlag.WatchingCutscene:
|
|
||||||
case ConditionFlag.WatchingCutscene78:
|
|
||||||
if( value )
|
|
||||||
{
|
{
|
||||||
return;
|
_events.CopyCharacter -= OnCharacterCopy;
|
||||||
|
_events.CharacterDestructor -= OnCharacterDestructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( var i = 0; i < _copiedCharacters.Length; ++i )
|
|
||||||
{
|
|
||||||
_copiedCharacters[ i ] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enable()
|
|
||||||
=> _copyCharacterHook.Enable();
|
|
||||||
|
|
||||||
public void Disable()
|
|
||||||
=> _copyCharacterHook.Disable();
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
=> Disable();
|
||||||
|
|
||||||
|
private unsafe void OnCharacterDestructor( Character* character )
|
||||||
{
|
{
|
||||||
_copyCharacterHook.Dispose();
|
if( character->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
||||||
Dalamud.Conditions.ConditionChange -= Reset;
|
{
|
||||||
|
var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||||
|
_copiedCharacters[ idx ] = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe delegate ulong CopyCharacterDelegate( GameObject* target, GameObject* source, uint unk );
|
private unsafe void OnCharacterCopy( Character* target, Character* source )
|
||||||
|
|
||||||
[Signature( Sigs.CopyCharacter, DetourName = nameof( CopyCharacterDetour ) )]
|
|
||||||
private readonly Hook< CopyCharacterDelegate > _copyCharacterHook = null!;
|
|
||||||
|
|
||||||
private unsafe ulong CopyCharacterDetour( GameObject* target, GameObject* source, uint unk )
|
|
||||||
{
|
{
|
||||||
try
|
if( target != null && target->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
||||||
{
|
{
|
||||||
if( target != null && target->ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx )
|
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
|
||||||
{
|
_copiedCharacters[idx] = (short) (source != null ? source->GameObject.ObjectIndex : -1);
|
||||||
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}." );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
return _copyCharacterHook.Original( target, source, unk );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,25 +1,23 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Dalamud.Hooking;
|
|
||||||
using Dalamud.Utility.Signatures;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData;
|
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Resolver;
|
namespace Penumbra.Interop.Resolver;
|
||||||
|
|
||||||
public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPtr Address, ActorIdentifier Identifier, ModCollection Collection) >
|
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 readonly Dictionary< IntPtr, (ActorIdentifier, ModCollection) > _cache = new(317);
|
||||||
private bool _dirty = false;
|
private bool _dirty = false;
|
||||||
private bool _enabled = false;
|
private bool _enabled = false;
|
||||||
|
|
||||||
public IdentifiedCollectionCache()
|
public IdentifiedCollectionCache(GameEventManager events)
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise( this );
|
_events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Enable()
|
public void Enable()
|
||||||
|
|
@ -32,7 +30,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
||||||
Penumbra.CollectionManager.CollectionChanged += CollectionChangeClear;
|
Penumbra.CollectionManager.CollectionChanged += CollectionChangeClear;
|
||||||
Penumbra.TempMods.CollectionChanged += CollectionChangeClear;
|
Penumbra.TempMods.CollectionChanged += CollectionChangeClear;
|
||||||
Dalamud.ClientState.TerritoryChanged += TerritoryClear;
|
Dalamud.ClientState.TerritoryChanged += TerritoryClear;
|
||||||
_characterDtorHook.Enable();
|
_events.CharacterDestructor += OnCharacterDestruct;
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +44,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
||||||
Penumbra.CollectionManager.CollectionChanged -= CollectionChangeClear;
|
Penumbra.CollectionManager.CollectionChanged -= CollectionChangeClear;
|
||||||
Penumbra.TempMods.CollectionChanged -= CollectionChangeClear;
|
Penumbra.TempMods.CollectionChanged -= CollectionChangeClear;
|
||||||
Dalamud.ClientState.TerritoryChanged -= TerritoryClear;
|
Dalamud.ClientState.TerritoryChanged -= TerritoryClear;
|
||||||
_characterDtorHook.Disable();
|
_events.CharacterDestructor -= OnCharacterDestruct;
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +80,6 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Disable();
|
Disable();
|
||||||
_characterDtorHook.Dispose();
|
|
||||||
GC.SuppressFinalize( this );
|
GC.SuppressFinalize( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,14 +113,6 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable< (IntPt
|
||||||
private void TerritoryClear( object? _1, ushort _2 )
|
private void TerritoryClear( object? _1, ushort _2 )
|
||||||
=> _dirty = _cache.Count > 0;
|
=> _dirty = _cache.Count > 0;
|
||||||
|
|
||||||
private delegate void CharacterDestructorDelegate( Character* character );
|
private void OnCharacterDestruct( Character* character )
|
||||||
|
=> _cache.Remove( ( IntPtr )character );
|
||||||
[Signature( Sigs.CharacterDestructor, DetourName = nameof( CharacterDestructorDetour ) )]
|
|
||||||
private Hook< CharacterDestructorDelegate > _characterDtorHook = null!;
|
|
||||||
|
|
||||||
private void CharacterDestructorDetour( Character* character )
|
|
||||||
{
|
|
||||||
_cache.Remove( ( IntPtr )character );
|
|
||||||
_characterDtorHook.Original( character );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -25,17 +25,19 @@ public unsafe partial class PathResolver
|
||||||
public class SubfileHelper : IDisposable, IReadOnlyCollection< KeyValuePair< IntPtr, ResolveData > >
|
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 > _mtrlData = new(() => ResolveData.Invalid);
|
||||||
private readonly ThreadLocal< ResolveData > _avfxData = new(() => ResolveData.Invalid);
|
private readonly ThreadLocal< ResolveData > _avfxData = new(() => ResolveData.Invalid);
|
||||||
|
|
||||||
private readonly ConcurrentDictionary< IntPtr, ResolveData > _subFileCollection = new();
|
private readonly ConcurrentDictionary< IntPtr, ResolveData > _subFileCollection = new();
|
||||||
|
|
||||||
public SubfileHelper( ResourceLoader loader )
|
public SubfileHelper( ResourceLoader loader, GameEventManager events )
|
||||||
{
|
{
|
||||||
SignatureHelper.Initialise( this );
|
SignatureHelper.Initialise( this );
|
||||||
|
|
||||||
_loader = loader;
|
_loader = loader;
|
||||||
|
_events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check specifically for shpk and tex files whether we are currently in a material load.
|
// 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();
|
_apricotResourceLoadHook.Enable();
|
||||||
_loader.ResourceLoadCustomization += SubfileLoadHandler;
|
_loader.ResourceLoadCustomization += SubfileLoadHandler;
|
||||||
_loader.ResourceLoaded += SubfileContainerRequested;
|
_loader.ResourceLoaded += SubfileContainerRequested;
|
||||||
_loader.FileLoaded += SubfileContainerLoaded;
|
_events.ResourceHandleDestructor += ResourceDestroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disable()
|
public void Disable()
|
||||||
|
|
@ -95,7 +97,7 @@ public unsafe partial class PathResolver
|
||||||
_apricotResourceLoadHook.Disable();
|
_apricotResourceLoadHook.Disable();
|
||||||
_loader.ResourceLoadCustomization -= SubfileLoadHandler;
|
_loader.ResourceLoadCustomization -= SubfileLoadHandler;
|
||||||
_loader.ResourceLoaded -= SubfileContainerRequested;
|
_loader.ResourceLoaded -= SubfileContainerRequested;
|
||||||
_loader.FileLoaded -= SubfileContainerLoaded;
|
_events.ResourceHandleDestructor -= ResourceDestroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
@ -121,16 +123,8 @@ public unsafe partial class PathResolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SubfileContainerLoaded( ResourceHandle* handle, ByteString path, bool success, bool custom )
|
private void ResourceDestroyed( ResourceHandle* handle )
|
||||||
{
|
=> _subFileCollection.TryRemove( ( IntPtr )handle, out _ );
|
||||||
switch( handle->FileType )
|
|
||||||
{
|
|
||||||
case ResourceType.Mtrl:
|
|
||||||
case ResourceType.Avfx:
|
|
||||||
_subFileCollection.TryRemove( ( IntPtr )handle, out _ );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to set the correct collection for the actual material path that is loaded
|
// We need to set the correct collection for the actual material path that is loaded
|
||||||
// before actually loading the file.
|
// before actually loading the file.
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ public partial class PathResolver : IDisposable
|
||||||
public bool Enabled { get; private set; }
|
public bool Enabled { get; private set; }
|
||||||
|
|
||||||
private readonly ResourceLoader _loader;
|
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 DrawObjectState DrawObjects = new();
|
||||||
private static readonly BitArray ValidHumanModels;
|
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 AnimationState _animations;
|
||||||
private readonly PathState _paths;
|
private readonly PathState _paths;
|
||||||
private readonly MetaState _meta;
|
private readonly MetaState _meta;
|
||||||
|
|
@ -43,7 +43,7 @@ public partial class PathResolver : IDisposable
|
||||||
_animations = new AnimationState( DrawObjects );
|
_animations = new AnimationState( DrawObjects );
|
||||||
_paths = new PathState( this );
|
_paths = new PathState( this );
|
||||||
_meta = new MetaState( _paths.HumanVTable );
|
_meta = new MetaState( _paths.HumanVTable );
|
||||||
_subFiles = new SubfileHelper( _loader );
|
_subFiles = new SubfileHelper( _loader, Penumbra.GameEvents );
|
||||||
}
|
}
|
||||||
|
|
||||||
// The modified resolver that handles game path resolving.
|
// The modified resolver that handles game path resolving.
|
||||||
|
|
@ -175,6 +175,9 @@ public partial class PathResolver : IDisposable
|
||||||
internal IEnumerable< KeyValuePair< IntPtr, ResolveData > > ResourceCollections
|
internal IEnumerable< KeyValuePair< IntPtr, ResolveData > > ResourceCollections
|
||||||
=> _subFiles;
|
=> _subFiles;
|
||||||
|
|
||||||
|
internal int SubfileCount
|
||||||
|
=> _subFiles.Count;
|
||||||
|
|
||||||
internal ResolveData CurrentMtrlData
|
internal ResolveData CurrentMtrlData
|
||||||
=> _subFiles.MtrlData;
|
=> _subFiles.MtrlData;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
|
|
||||||
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
public static ResidentResourceManager ResidentResources { get; private set; } = null!;
|
||||||
public static CharacterUtility CharacterUtility { get; private set; } = null!;
|
public static CharacterUtility CharacterUtility { get; private set; } = null!;
|
||||||
|
public static GameEventManager GameEvents { get; private set; } = null!;
|
||||||
public static MetaFileManager MetaFileManager { get; private set; } = null!;
|
public static MetaFileManager MetaFileManager { get; private set; } = null!;
|
||||||
public static Mod.Manager ModManager { get; private set; } = null!;
|
public static Mod.Manager ModManager { get; private set; } = null!;
|
||||||
public static ModCollection.Manager CollectionManager { get; private set; } = null!;
|
public static ModCollection.Manager CollectionManager { get; private set; } = null!;
|
||||||
|
|
@ -93,6 +94,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
DevPenumbraExists = CheckDevPluginPenumbra();
|
DevPenumbraExists = CheckDevPluginPenumbra();
|
||||||
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
IsNotInstalledPenumbra = CheckIsNotInstalled();
|
||||||
IsValidSourceRepo = CheckSourceRepo();
|
IsValidSourceRepo = CheckSourceRepo();
|
||||||
|
GameEvents = new GameEventManager();
|
||||||
Identifier = GameData.GameData.GetIdentifier( Dalamud.PluginInterface, Dalamud.GameData );
|
Identifier = GameData.GameData.GetIdentifier( Dalamud.PluginInterface, Dalamud.GameData );
|
||||||
GamePathParser = GameData.GameData.GetGamePathParser();
|
GamePathParser = GameData.GameData.GetGamePathParser();
|
||||||
StainManager = new StainManager( Dalamud.PluginInterface, Dalamud.GameData );
|
StainManager = new StainManager( Dalamud.PluginInterface, Dalamud.GameData );
|
||||||
|
|
@ -305,6 +307,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
PathResolver?.Dispose();
|
PathResolver?.Dispose();
|
||||||
ResourceLogger?.Dispose();
|
ResourceLogger?.Dispose();
|
||||||
ResourceLoader?.Dispose();
|
ResourceLoader?.Dispose();
|
||||||
|
GameEvents?.Dispose();
|
||||||
CharacterUtility?.Dispose();
|
CharacterUtility?.Dispose();
|
||||||
Performance?.Dispose();
|
Performance?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue