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;
}
// Use the default method of path replacement.
/// <summary> Use the default method of path replacement. </summary>
private (FullPath?, ResolveData) DefaultResolver(Utf8GamePath path)
{
var resolved = _collectionManager.Default.ResolvePath(path);

View file

@ -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);
}
}

View file

@ -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<IntPtr, (ActorIdentifier, ModCollection)> _cache = new(317);
private bool _dirty = false;
private bool _enabled = false;
private readonly ClientState _clientState;
private readonly Dictionary<IntPtr, (ActorIdentifier, ModCollection)> _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);
}

View file

@ -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> _resolveData = new ThreadLocal<ResolveData>(() => 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;
}

View file

@ -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;

View file

@ -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<StainService>()
.AddSingleton<ItemService>()
.AddSingleton<ActorService>();
// Add Game Services
services.AddSingleton<GameEventManager>()
.AddSingleton<FrameworkManager>()
.AddSingleton<MetaFileManager>()
.AddSingleton<CutsceneCharacters>()
.AddSingleton<CutsceneService>()
.AddSingleton<CharacterUtility>()
.AddSingleton<ResourceManagerService>()
.AddSingleton<ResourceService>()
@ -74,7 +73,11 @@ public class PenumbraNew
.AddSingleton<CreateFileWHook>()
.AddSingleton<ResidentResourceManager>()
.AddSingleton<FontReloader>()
.AddSingleton<RedrawService>();
.AddSingleton<RedrawService>();
// Add PathResolver
services.AddSingleton<CutsceneService>()
.AddSingleton<IdentifiedCollectionCache>();
// Add Configuration
services.AddTransient<ConfigMigrationService>()

View file

@ -29,7 +29,7 @@ public sealed class ItemService : AsyncServiceWrapper<ItemData>
public sealed class ActorService : AsyncServiceWrapper<ActorManager>
{
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)))
{ }