mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
96 lines
3.3 KiB
C#
96 lines
3.3 KiB
C#
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.Collections.Manager;
|
|
using Penumbra.Communication;
|
|
using Penumbra.GameData.Actors;
|
|
using Penumbra.Interop.Services;
|
|
using Penumbra.Services;
|
|
|
|
namespace Penumbra.Interop.PathResolving;
|
|
|
|
public unsafe class IdentifiedCollectionCache : IDisposable, IEnumerable<(nint Address, ActorIdentifier Identifier, ModCollection Collection)>
|
|
{
|
|
private readonly CommunicatorService _communicator;
|
|
private readonly GameEventManager _events;
|
|
private readonly ClientState _clientState;
|
|
private readonly Dictionary<nint, (ActorIdentifier, ModCollection)> _cache = new(317);
|
|
private bool _dirty;
|
|
|
|
public IdentifiedCollectionCache(ClientState clientState, CommunicatorService communicator, GameEventManager events)
|
|
{
|
|
_clientState = clientState;
|
|
_communicator = communicator;
|
|
_events = events;
|
|
|
|
_communicator.CollectionChange.Subscribe(CollectionChangeClear, CollectionChange.Priority.IdentifiedCollectionCache);
|
|
_clientState.TerritoryChanged += TerritoryClear;
|
|
_events.CharacterDestructor += OnCharacterDestruct;
|
|
}
|
|
|
|
public ResolveData Set(ModCollection collection, ActorIdentifier identifier, GameObject* data)
|
|
{
|
|
if (_dirty)
|
|
{
|
|
_dirty = false;
|
|
_cache.Clear();
|
|
}
|
|
|
|
_cache[(nint)data] = (identifier, collection);
|
|
return collection.ToResolveData(data);
|
|
}
|
|
|
|
public bool TryGetValue(GameObject* gameObject, out ResolveData resolve)
|
|
{
|
|
if (_dirty)
|
|
{
|
|
_dirty = false;
|
|
_cache.Clear();
|
|
}
|
|
else if (_cache.TryGetValue((nint)gameObject, out var p))
|
|
{
|
|
resolve = p.Item2.ToResolveData(gameObject);
|
|
return true;
|
|
}
|
|
|
|
resolve = default;
|
|
return false;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_communicator.CollectionChange.Unsubscribe(CollectionChangeClear);
|
|
_clientState.TerritoryChanged -= TerritoryClear;
|
|
_events.CharacterDestructor -= OnCharacterDestruct;
|
|
}
|
|
|
|
public IEnumerator<(nint Address, ActorIdentifier Identifier, ModCollection Collection)> GetEnumerator()
|
|
{
|
|
foreach (var (address, (identifier, collection)) in _cache)
|
|
{
|
|
if (_dirty)
|
|
yield break;
|
|
|
|
yield return (address, identifier, collection);
|
|
}
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
=> GetEnumerator();
|
|
|
|
private void CollectionChangeClear(CollectionType type, ModCollection? _1, ModCollection? _2, string _3)
|
|
{
|
|
if (type is not (CollectionType.Current or CollectionType.Interface or CollectionType.Inactive))
|
|
_dirty = _cache.Count > 0;
|
|
}
|
|
|
|
private void TerritoryClear(object? _1, ushort _2)
|
|
=> _dirty = _cache.Count > 0;
|
|
|
|
private void OnCharacterDestruct(Character* character)
|
|
=> _cache.Remove((nint)character);
|
|
}
|