Maybe?
This commit is contained in:
@@ -297,7 +297,7 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
private void DalamudUtil_FrameworkUpdate()
|
private void DalamudUtil_FrameworkUpdate()
|
||||||
{
|
{
|
||||||
RefreshPlayerRelatedAddressMap();
|
_ = Task.Run(() => RefreshPlayerRelatedAddressMap());
|
||||||
|
|
||||||
lock (_cacheAdditionLock)
|
lock (_cacheAdditionLock)
|
||||||
{
|
{
|
||||||
@@ -305,6 +305,45 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_lastClassJobId != _dalamudUtil.ClassJobId)
|
if (_lastClassJobId != _dalamudUtil.ClassJobId)
|
||||||
|
{
|
||||||
|
UpdateClassJobCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanupAbsentObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshPlayerRelatedAddressMap()
|
||||||
|
{
|
||||||
|
var tempMap = new ConcurrentDictionary<nint, GameObjectHandler>();
|
||||||
|
var updatedFrameAddresses = new ConcurrentDictionary<nint, ObjectKind>();
|
||||||
|
|
||||||
|
lock (_playerRelatedLock)
|
||||||
|
{
|
||||||
|
foreach (var handler in _playerRelatedPointers)
|
||||||
|
{
|
||||||
|
var address = (nint)handler.Address;
|
||||||
|
if (address != nint.Zero)
|
||||||
|
{
|
||||||
|
tempMap[address] = handler;
|
||||||
|
updatedFrameAddresses[address] = handler.ObjectKind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_playerRelatedByAddress.Clear();
|
||||||
|
foreach (var kvp in tempMap)
|
||||||
|
{
|
||||||
|
_playerRelatedByAddress[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedFrameAddresses.Clear();
|
||||||
|
foreach (var kvp in updatedFrameAddresses)
|
||||||
|
{
|
||||||
|
_cachedFrameAddresses[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateClassJobCache()
|
||||||
{
|
{
|
||||||
_lastClassJobId = _dalamudUtil.ClassJobId;
|
_lastClassJobId = _dalamudUtil.ClassJobId;
|
||||||
if (SemiTransientResources.TryGetValue(ObjectKind.Pet, out HashSet<string>? value))
|
if (SemiTransientResources.TryGetValue(ObjectKind.Pet, out HashSet<string>? value))
|
||||||
@@ -313,13 +352,18 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerConfig.JobSpecificCache.TryGetValue(_dalamudUtil.ClassJobId, out var jobSpecificData);
|
PlayerConfig.JobSpecificCache.TryGetValue(_dalamudUtil.ClassJobId, out var jobSpecificData);
|
||||||
SemiTransientResources[ObjectKind.Player] = PlayerConfig.GlobalPersistentCache.Concat(jobSpecificData ?? []).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
SemiTransientResources[ObjectKind.Player] = PlayerConfig.GlobalPersistentCache
|
||||||
|
.Concat(jobSpecificData ?? [])
|
||||||
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
PlayerConfig.JobSpecificPetCache.TryGetValue(_dalamudUtil.ClassJobId, out var petSpecificData);
|
PlayerConfig.JobSpecificPetCache.TryGetValue(_dalamudUtil.ClassJobId, out var petSpecificData);
|
||||||
SemiTransientResources[ObjectKind.Pet] = new HashSet<string>(
|
SemiTransientResources[ObjectKind.Pet] = new HashSet<string>(
|
||||||
petSpecificData ?? [],
|
petSpecificData ?? [],
|
||||||
StringComparer.OrdinalIgnoreCase);
|
StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CleanupAbsentObjects()
|
||||||
|
{
|
||||||
foreach (var kind in Enum.GetValues(typeof(ObjectKind)).Cast<ObjectKind>())
|
foreach (var kind in Enum.GetValues(typeof(ObjectKind)).Cast<ObjectKind>())
|
||||||
{
|
{
|
||||||
if (!_cachedFrameAddresses.Any(k => k.Value == kind) && TransientResources.Remove(kind, out _))
|
if (!_cachedFrameAddresses.Any(k => k.Value == kind) && TransientResources.Remove(kind, out _))
|
||||||
@@ -349,26 +393,6 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
|
|||||||
_semiTransientResources = null;
|
_semiTransientResources = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshPlayerRelatedAddressMap()
|
|
||||||
{
|
|
||||||
_playerRelatedByAddress.Clear();
|
|
||||||
var updatedFrameAddresses = new ConcurrentDictionary<nint, ObjectKind>();
|
|
||||||
lock (_playerRelatedLock)
|
|
||||||
{
|
|
||||||
foreach (var handler in _playerRelatedPointers)
|
|
||||||
{
|
|
||||||
var address = (nint)handler.Address;
|
|
||||||
if (address != nint.Zero)
|
|
||||||
{
|
|
||||||
_playerRelatedByAddress[address] = handler;
|
|
||||||
updatedFrameAddresses[address] = handler.ObjectKind;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_cachedFrameAddresses = updatedFrameAddresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleActorTracked(ActorObjectService.ActorDescriptor descriptor)
|
private void HandleActorTracked(ActorObjectService.ActorDescriptor descriptor)
|
||||||
{
|
{
|
||||||
if (descriptor.IsInGpose)
|
if (descriptor.IsInGpose)
|
||||||
|
|||||||
@@ -142,29 +142,23 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
fragment.FileReplacements =
|
var fileReplacementsTask = Task.Run(() =>
|
||||||
[.. new HashSet<FileReplacement>(resolvedPaths.Select(c => new FileReplacement([.. c.Value], c.Key)), FileReplacementComparer.Instance).Where(p => p.HasFileReplacement)];
|
{
|
||||||
fragment.FileReplacements.RemoveWhere(c => c.GamePaths.Any(g => !CacheMonitor.AllowedFileExtensions.Any(e => g.EndsWith(e, StringComparison.OrdinalIgnoreCase))));
|
var replacements = new HashSet<FileReplacement>(
|
||||||
|
resolvedPaths.Select(c => new FileReplacement([.. c.Value], c.Key)),
|
||||||
|
FileReplacementComparer.Instance)
|
||||||
|
.Where(p => p.HasFileReplacement)
|
||||||
|
.ToHashSet();
|
||||||
|
|
||||||
|
replacements.RemoveWhere(c => c.GamePaths.Any(g =>
|
||||||
|
!CacheMonitor.AllowedFileExtensions.Any(e =>
|
||||||
|
g.EndsWith(e, StringComparison.OrdinalIgnoreCase))));
|
||||||
|
|
||||||
|
return replacements;
|
||||||
|
}, ct);
|
||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
if (logDebug)
|
|
||||||
{
|
|
||||||
_logger.LogDebug("== Static Replacements ==");
|
|
||||||
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("=> {repl}", replacement);
|
|
||||||
ct.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement))
|
|
||||||
{
|
|
||||||
ct.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Task<string>? getHeelsOffset = null;
|
Task<string>? getHeelsOffset = null;
|
||||||
Task<string>? getGlamourerData = null;
|
Task<string>? getGlamourerData = null;
|
||||||
Task<string?>? getCustomizeData = null;
|
Task<string?>? getCustomizeData = null;
|
||||||
@@ -185,38 +179,32 @@ public class PlayerDataFactory
|
|||||||
getCustomizeData = _ipcManager.CustomizePlus.GetScaleAsync(playerRelatedObject.Address);
|
getCustomizeData = _ipcManager.CustomizePlus.GetScaleAsync(playerRelatedObject.Address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment.FileReplacements = await fileReplacementsTask.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (logDebug)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("== Static Replacements ==");
|
||||||
|
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("=> {repl}", replacement);
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var replacement in fragment.FileReplacements.Where(i => i.HasFileReplacement))
|
||||||
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var staticReplacements = fragment.FileReplacements.ToHashSet();
|
var staticReplacements = fragment.FileReplacements.ToHashSet();
|
||||||
|
|
||||||
Task<(IReadOnlyDictionary<string, string[]> ResolvedPaths, HashSet<FileReplacement>? ClearedReplacements)> transientTask = Task.Run(async () =>
|
Task<(IReadOnlyDictionary<string, string[]> ResolvedPaths, HashSet<FileReplacement>? ClearedReplacements)> transientTask = ProcessTransientDataAsync(
|
||||||
{
|
objectKind,
|
||||||
await _transientResourceManager.WaitForRecording(ct).ConfigureAwait(false);
|
playerRelatedObject,
|
||||||
|
staticReplacements,
|
||||||
HashSet<FileReplacement>? clearedReplacements = null;
|
ct);
|
||||||
|
|
||||||
if (objectKind == ObjectKind.Pet)
|
|
||||||
{
|
|
||||||
foreach (var item in staticReplacements.Where(i => i.HasFileReplacement).SelectMany(p => p.GamePaths))
|
|
||||||
{
|
|
||||||
if (_transientResourceManager.AddTransientResource(objectKind, item))
|
|
||||||
{
|
|
||||||
_logger.LogDebug("Marking static {item} for Pet as transient", item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogTrace("Clearing {count} Static Replacements for Pet", staticReplacements.Count);
|
|
||||||
clearedReplacements = staticReplacements;
|
|
||||||
}
|
|
||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
_logger.LogDebug("Handling transient update for {obj}", playerRelatedObject);
|
|
||||||
|
|
||||||
_transientResourceManager.ClearTransientPaths(objectKind, [.. staticReplacements.SelectMany(c => c.GamePaths)]);
|
|
||||||
|
|
||||||
var transientPaths = ManageSemiTransientData(objectKind);
|
|
||||||
IReadOnlyDictionary<string, string[]> resolved = await GetFileReplacementsFromPaths(playerRelatedObject, transientPaths, new HashSet<string>(StringComparer.Ordinal)).ConfigureAwait(false);
|
|
||||||
return (resolved, clearedReplacements);
|
|
||||||
}, ct);
|
|
||||||
|
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
@@ -278,12 +266,17 @@ public class PlayerDataFactory
|
|||||||
|
|
||||||
var toCompute = fragment.FileReplacements.Where(f => !f.IsFileSwap).ToArray();
|
var toCompute = fragment.FileReplacements.Where(f => !f.IsFileSwap).ToArray();
|
||||||
_logger.LogDebug("Getting Hashes for {amount} Files", toCompute.Length);
|
_logger.LogDebug("Getting Hashes for {amount} Files", toCompute.Length);
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
var computedPaths = _fileCacheManager.GetFileCachesByPaths(toCompute.Select(c => c.ResolvedPath).ToArray());
|
var computedPaths = _fileCacheManager.GetFileCachesByPaths(toCompute.Select(c => c.ResolvedPath).ToArray());
|
||||||
foreach (var file in toCompute)
|
foreach (var file in toCompute)
|
||||||
{
|
{
|
||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
file.Hash = computedPaths[file.ResolvedPath]?.Hash ?? string.Empty;
|
file.Hash = computedPaths[file.ResolvedPath]?.Hash ?? string.Empty;
|
||||||
}
|
}
|
||||||
|
}, ct).ConfigureAwait(false);
|
||||||
|
|
||||||
var removed = fragment.FileReplacements.RemoveWhere(f => !f.IsFileSwap && string.IsNullOrEmpty(f.Hash));
|
var removed = fragment.FileReplacements.RemoveWhere(f => !f.IsFileSwap && string.IsNullOrEmpty(f.Hash));
|
||||||
if (removed > 0)
|
if (removed > 0)
|
||||||
{
|
{
|
||||||
@@ -507,6 +500,48 @@ public class PlayerDataFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<(IReadOnlyDictionary<string, string[]> ResolvedPaths, HashSet<FileReplacement>? ClearedReplacements)> ProcessTransientDataAsync(
|
||||||
|
ObjectKind objectKind,
|
||||||
|
GameObjectHandler playerRelatedObject,
|
||||||
|
HashSet<FileReplacement> staticReplacements,
|
||||||
|
CancellationToken ct)
|
||||||
|
{
|
||||||
|
await _transientResourceManager.WaitForRecording(ct).ConfigureAwait(false);
|
||||||
|
|
||||||
|
HashSet<FileReplacement>? clearedReplacements = null;
|
||||||
|
|
||||||
|
var gamePaths = staticReplacements
|
||||||
|
.Where(i => i.HasFileReplacement)
|
||||||
|
.SelectMany(p => p.GamePaths)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (objectKind == ObjectKind.Pet)
|
||||||
|
{
|
||||||
|
foreach (var item in gamePaths)
|
||||||
|
{
|
||||||
|
if (_transientResourceManager.AddTransientResource(objectKind, item))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Marking static {item} for Pet as transient", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogTrace("Clearing {count} Static Replacements for Pet", staticReplacements.Count);
|
||||||
|
clearedReplacements = staticReplacements;
|
||||||
|
}
|
||||||
|
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
_transientResourceManager.ClearTransientPaths(objectKind, gamePaths);
|
||||||
|
|
||||||
|
var transientPaths = ManageSemiTransientData(objectKind);
|
||||||
|
IReadOnlyDictionary<string, string[]> resolved = await GetFileReplacementsFromPaths(
|
||||||
|
playerRelatedObject,
|
||||||
|
transientPaths,
|
||||||
|
new HashSet<string>(StringComparer.Ordinal)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return (resolved, clearedReplacements);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<IReadOnlyDictionary<string, string[]>> GetFileReplacementsFromPaths(GameObjectHandler handler, HashSet<string> forwardResolve, HashSet<string> reverseResolve)
|
private async Task<IReadOnlyDictionary<string, string[]>> GetFileReplacementsFromPaths(GameObjectHandler handler, HashSet<string> forwardResolve, HashSet<string> reverseResolve)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user