This commit is contained in:
Ottermandias 2023-03-21 17:25:18 +01:00
parent c5ac9f6f08
commit b6d6993c9f
7 changed files with 70 additions and 43 deletions

View file

@ -76,7 +76,7 @@ public class CharacterResolver : IDisposable
_loader.FileLoaded -= ImcLoadResource; _loader.FileLoaded -= ImcLoadResource;
} }
// Use the default method of path replacement. /// <summary> Use the default method of path replacement. </summary>
private (FullPath?, ResolveData) DefaultResolver(Utf8GamePath path) private (FullPath?, ResolveData) DefaultResolver(Utf8GamePath path)
{ {
var resolved = _collectionManager.Default.ResolvePath(path); var resolved = _collectionManager.Default.ResolvePath(path);

View file

@ -8,7 +8,7 @@ using Penumbra.Interop.Services;
namespace Penumbra.Interop.Resolver; namespace Penumbra.Interop.Resolver;
public class CutsceneCharacters : IDisposable public class CutsceneService : IDisposable
{ {
public const int CutsceneStartIdx = 200; public const int CutsceneStartIdx = 200;
public const int CutsceneSlots = 40; public const int CutsceneSlots = 40;
@ -23,7 +23,7 @@ public class CutsceneCharacters : IDisposable
.Where(i => _objects[i] != null) .Where(i => _objects[i] != null)
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!)); .Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!));
public CutsceneCharacters(ObjectTable objects, GameEventManager events) public CutsceneService(ObjectTable objects, GameEventManager events)
{ {
_objects = objects; _objects = objects;
_events = events; _events = events;
@ -69,19 +69,19 @@ public class CutsceneCharacters : IDisposable
private unsafe void OnCharacterDestructor(Character* character) private unsafe void OnCharacterDestructor(Character* character)
{ {
if (character->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx) if (character->GameObject.ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
{ return;
var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
_copiedCharacters[idx] = -1; var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
} _copiedCharacters[idx] = -1;
} }
private unsafe void OnCharacterCopy(Character* target, Character* source) private unsafe void OnCharacterCopy(Character* target, Character* source)
{ {
if (target != null && target->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx) if (target == null || target->GameObject.ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
{ return;
var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
_copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1); var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
} _copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1);
} }
} }

View file

@ -1,27 +1,31 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Dalamud.Game.ClientState;
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.Actors; using Penumbra.GameData.Actors;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.Services; using Penumbra.Services;
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<(nint Address, ActorIdentifier Identifier, ModCollection Collection)>
{ {
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly GameEventManager _events; private readonly GameEventManager _events;
private readonly Dictionary<IntPtr, (ActorIdentifier, ModCollection)> _cache = new(317); private readonly ClientState _clientState;
private bool _dirty = false; private readonly Dictionary<IntPtr, (ActorIdentifier, ModCollection)> _cache = new(317);
private bool _enabled = false; private bool _dirty;
private bool _enabled;
public IdentifiedCollectionCache(CommunicatorService communicator, GameEventManager events) public IdentifiedCollectionCache(ClientState clientState, CommunicatorService communicator, GameEventManager events)
{ {
_clientState = clientState;
_communicator = communicator; _communicator = communicator;
_events = events; _events = events;
Enable();
} }
public void Enable() public void Enable()
@ -29,10 +33,10 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
if (_enabled) if (_enabled)
return; return;
_communicator.CollectionChange.Event += CollectionChangeClear; _communicator.CollectionChange.Event += CollectionChangeClear;
DalamudServices.SClientState.TerritoryChanged += TerritoryClear; _clientState.TerritoryChanged += TerritoryClear;
_events.CharacterDestructor += OnCharacterDestruct; _events.CharacterDestructor += OnCharacterDestruct;
_enabled = true; _enabled = true;
} }
public void Disable() public void Disable()
@ -40,10 +44,10 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
if (!_enabled) if (!_enabled)
return; return;
_communicator.CollectionChange.Event -= CollectionChangeClear; _communicator.CollectionChange.Event -= CollectionChangeClear;
DalamudServices.SClientState.TerritoryChanged -= TerritoryClear; _clientState.TerritoryChanged -= TerritoryClear;
_events.CharacterDestructor -= OnCharacterDestruct; _events.CharacterDestructor -= OnCharacterDestruct;
_enabled = false; _enabled = false;
} }
public ResolveData Set(ModCollection collection, ActorIdentifier identifier, GameObject* data) public ResolveData Set(ModCollection collection, ActorIdentifier identifier, GameObject* data)
@ -54,7 +58,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
_cache.Clear(); _cache.Clear();
} }
_cache[(IntPtr)data] = (identifier, collection); _cache[(nint)data] = (identifier, collection);
return collection.ToResolveData(data); return collection.ToResolveData(data);
} }
@ -65,7 +69,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
_dirty = false; _dirty = false;
_cache.Clear(); _cache.Clear();
} }
else if (_cache.TryGetValue((IntPtr)gameObject, out var p)) else if (_cache.TryGetValue((nint)gameObject, out var p))
{ {
resolve = p.Item2.ToResolveData(gameObject); resolve = p.Item2.ToResolveData(gameObject);
return true; return true;
@ -81,7 +85,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public IEnumerator<(IntPtr Address, ActorIdentifier Identifier, ModCollection Collection)> GetEnumerator() public IEnumerator<(nint Address, ActorIdentifier Identifier, ModCollection Collection)> GetEnumerator()
{ {
foreach (var (address, (identifier, collection)) in _cache) foreach (var (address, (identifier, collection)) in _cache)
{ {
@ -108,5 +112,5 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
=> _dirty = _cache.Count > 0; => _dirty = _cache.Count > 0;
private void OnCharacterDestruct(Character* character) private void OnCharacterDestruct(Character* character)
=> _cache.Remove((IntPtr)character); => _cache.Remove((nint)character);
} }

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData; using Penumbra.GameData;
@ -33,6 +34,8 @@ public unsafe partial class PathResolver
// This map links files to their corresponding collection, if it is non-default. // This map links files to their corresponding collection, if it is non-default.
private readonly ConcurrentDictionary< ByteString, ResolveData > _pathCollections = new(); private readonly ConcurrentDictionary< ByteString, ResolveData > _pathCollections = new();
private readonly ThreadLocal<ResolveData> _resolveData = new ThreadLocal<ResolveData>(() => ResolveData.Invalid, true);
public PathState( PathResolver parent ) public PathState( PathResolver parent )
{ {
SignatureHelper.Initialise( this ); SignatureHelper.Initialise( this );
@ -60,6 +63,7 @@ public unsafe partial class PathResolver
public void Dispose() public void Dispose()
{ {
_resolveData.Dispose();
_human.Dispose(); _human.Dispose();
_weapon.Dispose(); _weapon.Dispose();
_demiHuman.Dispose(); _demiHuman.Dispose();
@ -76,7 +80,10 @@ public unsafe partial class PathResolver
=> _pathCollections.TryGetValue( path, out collection ); => _pathCollections.TryGetValue( path, out collection );
public bool Consume( ByteString path, out ResolveData collection ) public bool Consume( ByteString path, out ResolveData collection )
=> _pathCollections.TryRemove( path, out collection ); {
collection = _resolveData.IsValueCreated && _resolveData.Value.Valid ? _resolveData.Value : ResolveData.Invalid;
return _pathCollections.TryRemove(path, out collection);
}
// Just add or remove the resolved path. // Just add or remove the resolved path.
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )] [MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
@ -89,6 +96,7 @@ public unsafe partial class PathResolver
var gamePath = new ByteString( ( byte* )path ); var gamePath = new ByteString( ( byte* )path );
SetCollection( gameObject, gamePath, collection ); SetCollection( gameObject, gamePath, collection );
_resolveData.Value = collection.ToResolveData(gameObject);
return path; return path;
} }

View file

@ -1,16 +1,14 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Dalamud.Game.ClientState;
using Dalamud.Utility.Signatures; using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using OtterGui.Classes;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.Interop.Loader; using Penumbra.Interop.Loader;
using Penumbra.Interop.Services; using Penumbra.Interop.Services;
using Penumbra.Interop.Structs;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.String; using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;
@ -18,6 +16,20 @@ using Penumbra.Util;
namespace Penumbra.Interop.Resolver; namespace Penumbra.Interop.Resolver;
//public class PathResolver2 : IDisposable
//{
// public readonly CutsceneService Cutscenes;
// public readonly IdentifiedCollectionCache Identified;
//
// public PathResolver(StartTracker timer, CutsceneService cutscenes, IdentifiedCollectionCache identified)
// {
// using var t = timer.Measure(StartTimeType.PathResolver);
// Cutscenes = cutscenes;
// Identified = identified;
// }
//}
// The Path Resolver handles character collections. // The Path Resolver handles character collections.
// It will hook any path resolving functions for humans, // It will hook any path resolving functions for humans,
// as well as DrawObject creation. // as well as DrawObject creation.
@ -29,7 +41,7 @@ public partial class PathResolver : IDisposable
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly ResourceLoader _loader; private readonly ResourceLoader _loader;
private static readonly CutsceneCharacters Cutscenes = new(DalamudServices.SObjects, Penumbra.GameEvents); // TODO private static readonly CutsceneService Cutscenes = new(DalamudServices.SObjects, Penumbra.GameEvents); // TODO
private static DrawObjectState _drawObjects = null!; // TODO private static DrawObjectState _drawObjects = null!; // TODO
private static readonly BitArray ValidHumanModels; private static readonly BitArray ValidHumanModels;
internal static IdentifiedCollectionCache IdentifiedCache = null!; // TODO internal static IdentifiedCollectionCache IdentifiedCache = null!; // TODO
@ -41,11 +53,11 @@ public partial class PathResolver : IDisposable
static PathResolver() static PathResolver()
=> ValidHumanModels = GetValidHumanModels(DalamudServices.SGameData); => ValidHumanModels = GetValidHumanModels(DalamudServices.SGameData);
public unsafe PathResolver(StartTracker timer, CommunicatorService communicator, GameEventManager events, ResourceLoader loader) public unsafe PathResolver(IdentifiedCollectionCache cache, StartTracker timer, ClientState clientState, CommunicatorService communicator, GameEventManager events, ResourceLoader loader)
{ {
using var tApi = timer.Measure(StartTimeType.PathResolver); using var tApi = timer.Measure(StartTimeType.PathResolver);
_communicator = communicator; _communicator = communicator;
IdentifiedCache = new IdentifiedCollectionCache(communicator, events); IdentifiedCache = cache;
SignatureHelper.Initialise(this); SignatureHelper.Initialise(this);
_drawObjects = new DrawObjectState(_communicator); _drawObjects = new DrawObjectState(_communicator);
_loader = loader; _loader = loader;

View file

@ -15,7 +15,6 @@ using Penumbra.Interop.Services;
using Penumbra.Mods; using Penumbra.Mods;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.UI; using Penumbra.UI;
using Penumbra.UI.Classes;
using Penumbra.UI.AdvancedWindow; using Penumbra.UI.AdvancedWindow;
using Penumbra.UI.ModsTab; using Penumbra.UI.ModsTab;
using Penumbra.UI.Tabs; using Penumbra.UI.Tabs;
@ -60,12 +59,12 @@ public class PenumbraNew
.AddSingleton<StainService>() .AddSingleton<StainService>()
.AddSingleton<ItemService>() .AddSingleton<ItemService>()
.AddSingleton<ActorService>(); .AddSingleton<ActorService>();
// Add Game Services // Add Game Services
services.AddSingleton<GameEventManager>() services.AddSingleton<GameEventManager>()
.AddSingleton<FrameworkManager>() .AddSingleton<FrameworkManager>()
.AddSingleton<MetaFileManager>() .AddSingleton<MetaFileManager>()
.AddSingleton<CutsceneCharacters>() .AddSingleton<CutsceneService>()
.AddSingleton<CharacterUtility>() .AddSingleton<CharacterUtility>()
.AddSingleton<ResourceManagerService>() .AddSingleton<ResourceManagerService>()
.AddSingleton<ResourceService>() .AddSingleton<ResourceService>()
@ -74,7 +73,11 @@ public class PenumbraNew
.AddSingleton<CreateFileWHook>() .AddSingleton<CreateFileWHook>()
.AddSingleton<ResidentResourceManager>() .AddSingleton<ResidentResourceManager>()
.AddSingleton<FontReloader>() .AddSingleton<FontReloader>()
.AddSingleton<RedrawService>(); .AddSingleton<RedrawService>();
// Add PathResolver
services.AddSingleton<CutsceneService>()
.AddSingleton<IdentifiedCollectionCache>();
// Add Configuration // Add Configuration
services.AddTransient<ConfigMigrationService>() services.AddTransient<ConfigMigrationService>()

View file

@ -29,7 +29,7 @@ public sealed class ItemService : AsyncServiceWrapper<ItemData>
public sealed class ActorService : AsyncServiceWrapper<ActorManager> public sealed class ActorService : AsyncServiceWrapper<ActorManager>
{ {
public ActorService(StartTracker tracker, DalamudPluginInterface pi, ObjectTable objects, ClientState clientState, public ActorService(StartTracker tracker, DalamudPluginInterface pi, ObjectTable objects, ClientState clientState,
Framework framework, DataManager gameData, GameGui gui, CutsceneCharacters cutscene) Framework framework, DataManager gameData, GameGui gui, CutsceneService cutscene)
: base(nameof(ActorService), tracker, StartTimeType.Actors, : base(nameof(ActorService), tracker, StartTimeType.Actors,
() => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)cutscene.GetParentIndex(idx))) () => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)cutscene.GetParentIndex(idx)))
{ } { }