diff --git a/Penumbra/Interop/Loader/CharacterResolver.cs b/Penumbra/Interop/Loader/CharacterResolver.cs
index 68b83b41..640cc0d9 100644
--- a/Penumbra/Interop/Loader/CharacterResolver.cs
+++ b/Penumbra/Interop/Loader/CharacterResolver.cs
@@ -76,7 +76,7 @@ public class CharacterResolver : IDisposable
_loader.FileLoaded -= ImcLoadResource;
}
- // Use the default method of path replacement.
+ /// Use the default method of path replacement.
private (FullPath?, ResolveData) DefaultResolver(Utf8GamePath path)
{
var resolved = _collectionManager.Default.ResolvePath(path);
diff --git a/Penumbra/Interop/Resolver/CutsceneCharacters.cs b/Penumbra/Interop/Resolver/CutsceneService.cs
similarity index 78%
rename from Penumbra/Interop/Resolver/CutsceneCharacters.cs
rename to Penumbra/Interop/Resolver/CutsceneService.cs
index 06b4f228..4bb8799c 100644
--- a/Penumbra/Interop/Resolver/CutsceneCharacters.cs
+++ b/Penumbra/Interop/Resolver/CutsceneService.cs
@@ -8,7 +8,7 @@ using Penumbra.Interop.Services;
namespace Penumbra.Interop.Resolver;
-public class CutsceneCharacters : IDisposable
+public class CutsceneService : IDisposable
{
public const int CutsceneStartIdx = 200;
public const int CutsceneSlots = 40;
@@ -23,7 +23,7 @@ public class CutsceneCharacters : IDisposable
.Where(i => _objects[i] != null)
.Select(i => KeyValuePair.Create(i, this[i] ?? _objects[i]!));
- public CutsceneCharacters(ObjectTable objects, GameEventManager events)
+ public CutsceneService(ObjectTable objects, GameEventManager events)
{
_objects = objects;
_events = events;
@@ -69,19 +69,19 @@ public class CutsceneCharacters : IDisposable
private unsafe void OnCharacterDestructor(Character* character)
{
- if (character->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx)
- {
- var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
- _copiedCharacters[idx] = -1;
- }
+ if (character->GameObject.ObjectIndex is < CutsceneStartIdx or >= CutsceneEndIdx)
+ return;
+
+ var idx = character->GameObject.ObjectIndex - CutsceneStartIdx;
+ _copiedCharacters[idx] = -1;
}
private unsafe void OnCharacterCopy(Character* target, Character* source)
{
- if (target != null && target->GameObject.ObjectIndex is >= CutsceneStartIdx and < CutsceneEndIdx)
- {
- var idx = target->GameObject.ObjectIndex - CutsceneStartIdx;
- _copiedCharacters[idx] = (short)(source != null ? source->GameObject.ObjectIndex : -1);
- }
+ 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);
}
}
diff --git a/Penumbra/Interop/Resolver/IdentifiedCollectionCache.cs b/Penumbra/Interop/Resolver/IdentifiedCollectionCache.cs
index fa09f64d..83739dca 100644
--- a/Penumbra/Interop/Resolver/IdentifiedCollectionCache.cs
+++ b/Penumbra/Interop/Resolver/IdentifiedCollectionCache.cs
@@ -1,27 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using Dalamud.Game.ClientState;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Penumbra.Collections;
using Penumbra.GameData.Actors;
-using Penumbra.Interop.Services;
+using Penumbra.Interop.Services;
using Penumbra.Services;
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 GameEventManager _events;
- private readonly Dictionary _cache = new(317);
- private bool _dirty = false;
- private bool _enabled = false;
+ private readonly ClientState _clientState;
+ private readonly Dictionary _cache = new(317);
+ private bool _dirty;
+ private bool _enabled;
- public IdentifiedCollectionCache(CommunicatorService communicator, GameEventManager events)
+ public IdentifiedCollectionCache(ClientState clientState, CommunicatorService communicator, GameEventManager events)
{
+ _clientState = clientState;
_communicator = communicator;
_events = events;
+ Enable();
}
public void Enable()
@@ -29,10 +33,10 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
if (_enabled)
return;
- _communicator.CollectionChange.Event += CollectionChangeClear;
- DalamudServices.SClientState.TerritoryChanged += TerritoryClear;
- _events.CharacterDestructor += OnCharacterDestruct;
- _enabled = true;
+ _communicator.CollectionChange.Event += CollectionChangeClear;
+ _clientState.TerritoryChanged += TerritoryClear;
+ _events.CharacterDestructor += OnCharacterDestruct;
+ _enabled = true;
}
public void Disable()
@@ -40,10 +44,10 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
if (!_enabled)
return;
- _communicator.CollectionChange.Event -= CollectionChangeClear;
- DalamudServices.SClientState.TerritoryChanged -= TerritoryClear;
- _events.CharacterDestructor -= OnCharacterDestruct;
- _enabled = false;
+ _communicator.CollectionChange.Event -= CollectionChangeClear;
+ _clientState.TerritoryChanged -= TerritoryClear;
+ _events.CharacterDestructor -= OnCharacterDestruct;
+ _enabled = false;
}
public ResolveData Set(ModCollection collection, ActorIdentifier identifier, GameObject* data)
@@ -54,7 +58,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
_cache.Clear();
}
- _cache[(IntPtr)data] = (identifier, collection);
+ _cache[(nint)data] = (identifier, collection);
return collection.ToResolveData(data);
}
@@ -65,7 +69,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
_dirty = false;
_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);
return true;
@@ -81,7 +85,7 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
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)
{
@@ -108,5 +112,5 @@ public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(IntPtr
=> _dirty = _cache.Count > 0;
private void OnCharacterDestruct(Character* character)
- => _cache.Remove((IntPtr)character);
+ => _cache.Remove((nint)character);
}
diff --git a/Penumbra/Interop/Resolver/PathResolver.PathState.cs b/Penumbra/Interop/Resolver/PathResolver.PathState.cs
index 2b4aceca..1cf2b206 100644
--- a/Penumbra/Interop/Resolver/PathResolver.PathState.cs
+++ b/Penumbra/Interop/Resolver/PathResolver.PathState.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Threading;
using Dalamud.Utility.Signatures;
using Penumbra.Collections;
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.
private readonly ConcurrentDictionary< ByteString, ResolveData > _pathCollections = new();
+ private readonly ThreadLocal _resolveData = new ThreadLocal(() => ResolveData.Invalid, true);
+
public PathState( PathResolver parent )
{
SignatureHelper.Initialise( this );
@@ -60,6 +63,7 @@ public unsafe partial class PathResolver
public void Dispose()
{
+ _resolveData.Dispose();
_human.Dispose();
_weapon.Dispose();
_demiHuman.Dispose();
@@ -76,7 +80,10 @@ public unsafe partial class PathResolver
=> _pathCollections.TryGetValue( path, out 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.
[MethodImpl( MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization )]
@@ -89,6 +96,7 @@ public unsafe partial class PathResolver
var gamePath = new ByteString( ( byte* )path );
SetCollection( gameObject, gamePath, collection );
+ _resolveData.Value = collection.ToResolveData(gameObject);
return path;
}
diff --git a/Penumbra/Interop/Resolver/PathResolver.cs b/Penumbra/Interop/Resolver/PathResolver.cs
index 059a0550..3b805acd 100644
--- a/Penumbra/Interop/Resolver/PathResolver.cs
+++ b/Penumbra/Interop/Resolver/PathResolver.cs
@@ -1,16 +1,14 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using Dalamud.Game.ClientState;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
-using FFXIVClientStructs.FFXIV.Client.System.Resource;
-using OtterGui.Classes;
using Penumbra.Collections;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Loader;
using Penumbra.Interop.Services;
-using Penumbra.Interop.Structs;
using Penumbra.Services;
using Penumbra.String;
using Penumbra.String.Classes;
@@ -18,6 +16,20 @@ using Penumbra.Util;
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.
// It will hook any path resolving functions for humans,
// as well as DrawObject creation.
@@ -29,7 +41,7 @@ public partial class PathResolver : IDisposable
private readonly CommunicatorService _communicator;
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 readonly BitArray ValidHumanModels;
internal static IdentifiedCollectionCache IdentifiedCache = null!; // TODO
@@ -41,11 +53,11 @@ public partial class PathResolver : IDisposable
static PathResolver()
=> 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);
_communicator = communicator;
- IdentifiedCache = new IdentifiedCollectionCache(communicator, events);
+ IdentifiedCache = cache;
SignatureHelper.Initialise(this);
_drawObjects = new DrawObjectState(_communicator);
_loader = loader;
diff --git a/Penumbra/PenumbraNew.cs b/Penumbra/PenumbraNew.cs
index 3d52c6be..c74af610 100644
--- a/Penumbra/PenumbraNew.cs
+++ b/Penumbra/PenumbraNew.cs
@@ -15,7 +15,6 @@ using Penumbra.Interop.Services;
using Penumbra.Mods;
using Penumbra.Services;
using Penumbra.UI;
-using Penumbra.UI.Classes;
using Penumbra.UI.AdvancedWindow;
using Penumbra.UI.ModsTab;
using Penumbra.UI.Tabs;
@@ -60,12 +59,12 @@ public class PenumbraNew
.AddSingleton()
.AddSingleton()
.AddSingleton();
-
+
// Add Game Services
services.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton()
+ .AddSingleton()
.AddSingleton()
.AddSingleton()
.AddSingleton()
@@ -74,7 +73,11 @@ public class PenumbraNew
.AddSingleton()
.AddSingleton()
.AddSingleton()
- .AddSingleton();
+ .AddSingleton();
+
+ // Add PathResolver
+ services.AddSingleton()
+ .AddSingleton();
// Add Configuration
services.AddTransient()
diff --git a/Penumbra/Services/Wrappers.cs b/Penumbra/Services/Wrappers.cs
index e0ab8aae..131507cc 100644
--- a/Penumbra/Services/Wrappers.cs
+++ b/Penumbra/Services/Wrappers.cs
@@ -29,7 +29,7 @@ public sealed class ItemService : AsyncServiceWrapper
public sealed class ActorService : AsyncServiceWrapper
{
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,
() => new ActorManager(pi, objects, clientState, framework, gameData, gui, idx => (short)cutscene.GetParentIndex(idx)))
{ }