From 61b6365542f5f561319d33d9d126a577ff60116d Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Mon, 10 Feb 2025 21:43:34 +0100 Subject: [PATCH] dunno what's wrong with pets (fuck pets, not literally) --- .../FileCache/TransientResourceManager.cs | 93 ++++++++++--------- .../Interop/Ipc/IpcCallerHonorific.cs | 4 +- .../PlayerData/Factories/PlayerDataFactory.cs | 63 ++++++------- 3 files changed, 85 insertions(+), 75 deletions(-) diff --git a/MareSynchronos/FileCache/TransientResourceManager.cs b/MareSynchronos/FileCache/TransientResourceManager.cs index bc0df71..2b2de94 100644 --- a/MareSynchronos/FileCache/TransientResourceManager.cs +++ b/MareSynchronos/FileCache/TransientResourceManager.cs @@ -80,27 +80,28 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase public void CleanUpSemiTransientResources(ObjectKind objectKind, List? fileReplacement = null) { - if (SemiTransientResources.TryGetValue(objectKind, out HashSet? value)) + if (!SemiTransientResources.TryGetValue(objectKind, out HashSet? value)) + return; + + if (fileReplacement == null) { - if (fileReplacement == null) - { - value.Clear(); - return; - } + value.Clear(); + return; + } - bool removedPaths = false; - foreach (var replacement in fileReplacement.Where(p => !p.HasFileReplacement).SelectMany(p => p.GamePaths).ToList()) - { - removedPaths = true; - PlayerConfig.RemovePath(replacement); - } + int removedPaths = 0; + foreach (var replacement in fileReplacement.Where(p => !p.HasFileReplacement).SelectMany(p => p.GamePaths).ToList()) + { + removedPaths++; + PlayerConfig.RemovePath(replacement); + value.Remove(replacement); + } - if (removedPaths) - { - // force reload semi transient resources - _semiTransientResources = null; - _configurationService.Save(); - } + if (removedPaths > 0) + { + Logger.LogTrace("Removed {amount} of SemiTransient paths during CleanUp, Saving from {name}", removedPaths, nameof(CleanUpSemiTransientResources)); + // force reload semi transient resources + _configurationService.Save(); } } @@ -131,27 +132,33 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase semiTransientResources.Add(gamePath); } - if (objectKind == ObjectKind.Player && newlyAddedGamePaths.Any()) + bool saveConfig = false; + if (objectKind == ObjectKind.Player && newlyAddedGamePaths.Count != 0) { + saveConfig = true; foreach (var item in newlyAddedGamePaths.Where(f => !string.IsNullOrEmpty(f))) { PlayerConfig.AddOrElevate(_dalamudUtil.ClassJobId, item); } - - _configurationService.Save(); } - else if (objectKind == ObjectKind.Pet && newlyAddedGamePaths.Any()) + else if (objectKind == ObjectKind.Pet && newlyAddedGamePaths.Count != 0) { - foreach (var item in newlyAddedGamePaths.Where(f => !string.IsNullOrEmpty(f))) - { - if (!PlayerConfig.JobSpecificPetCache.TryGetValue(_dalamudUtil.ClassJobId, out var petPerma)) - { - PlayerConfig.JobSpecificPetCache[_dalamudUtil.ClassJobId] = petPerma = []; - } + saveConfig = true; - petPerma.Add(item); + if (!PlayerConfig.JobSpecificPetCache.TryGetValue(_dalamudUtil.ClassJobId, out var petPerma)) + { + PlayerConfig.JobSpecificPetCache[_dalamudUtil.ClassJobId] = petPerma = []; } + foreach (var item in newlyAddedGamePaths.Where(f => !string.IsNullOrEmpty(f))) + { + petPerma.Add(item); + } + } + + if (saveConfig) + { + Logger.LogTrace("Saving transient.json from {method}", nameof(PersistTransientResources)); _configurationService.Save(); } @@ -166,6 +173,7 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase if (objectKind == ObjectKind.Player) { PlayerConfig.RemovePath(path); + Logger.LogTrace("Saving transient.json from {method}", nameof(RemoveTransientResource)); _configurationService.Save(); } } @@ -176,14 +184,13 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase if (SemiTransientResources.TryGetValue(objectKind, out var semiTransient) && semiTransient != null && semiTransient.Contains(item)) return false; - if (!TransientResources.TryGetValue(objectKind, out HashSet? value)) + if (!TransientResources.TryGetValue(objectKind, out HashSet? transientResource)) { - value = new HashSet(StringComparer.Ordinal); - TransientResources[objectKind] = value; + transientResource = new HashSet(StringComparer.Ordinal); + TransientResources[objectKind] = transientResource; } - value.Add(item.ToLowerInvariant()); - return true; + return transientResource.Add(item.ToLowerInvariant()); } internal void ClearTransientPaths(ObjectKind objectKind, List list) @@ -220,6 +227,7 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase if (removed > 0) { reloadSemiTransient = true; + Logger.LogTrace("Saving transient.json from {method}", nameof(ClearTransientPaths)); _configurationService.Save(); } } @@ -337,28 +345,29 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase // ^ all of the code above is just to sanitize the data - if (!TransientResources.TryGetValue(objectKind, out HashSet? value)) + if (!TransientResources.TryGetValue(objectKind, out HashSet? transientResources)) { - value = new(StringComparer.OrdinalIgnoreCase); - TransientResources[objectKind] = value; + transientResources = new(StringComparer.OrdinalIgnoreCase); + TransientResources[objectKind] = transientResources; } var owner = _playerRelatedPointers.FirstOrDefault(f => f.Address == gameObjectAddress); bool alreadyTransient = false; - if (value.Contains(replacedGamePath) - || SemiTransientResources.SelectMany(k => k.Value).Any(f => string.Equals(f, gamePath, StringComparison.OrdinalIgnoreCase))) + bool transientContains = transientResources.Contains(replacedGamePath); + bool semiTransientContains = SemiTransientResources.SelectMany(k => k.Value).Any(f => string.Equals(f, gamePath, StringComparison.OrdinalIgnoreCase)); + if (transientContains || semiTransientContains) { if (!IsTransientRecording) - Logger.LogTrace("Not adding {replacedPath} : {filePath}, Reason: Transient: {contains}, SemiTransient: {contains2}", replacedGamePath, filePath, - value.Contains(replacedGamePath), SemiTransientResources.SelectMany(k => k.Value).Any(f => string.Equals(f, gamePath, StringComparison.OrdinalIgnoreCase))); + Logger.LogTrace("Not adding {replacedPath} => {filePath}, Reason: Transient: {contains}, SemiTransient: {contains2}", replacedGamePath, filePath, + transientContains, semiTransientContains); alreadyTransient = true; } else { if (!IsTransientRecording) { - bool isAdded = value.Add(replacedGamePath); + bool isAdded = transientResources.Add(replacedGamePath); if (isAdded) { Logger.LogDebug("Adding {replacedGamePath} for {gameObject} ({filePath})", replacedGamePath, owner?.ToString() ?? gameObjectAddress.ToString("X"), filePath); diff --git a/MareSynchronos/Interop/Ipc/IpcCallerHonorific.cs b/MareSynchronos/Interop/Ipc/IpcCallerHonorific.cs index 15afb0a..91c2f1c 100644 --- a/MareSynchronos/Interop/Ipc/IpcCallerHonorific.cs +++ b/MareSynchronos/Interop/Ipc/IpcCallerHonorific.cs @@ -77,10 +77,10 @@ public sealed class IpcCallerHonorific : IIpcCaller }).ConfigureAwait(false); } - public string GetTitle() + public async Task GetTitle() { if (!APIAvailable) return string.Empty; - string title = _honorificGetLocalCharacterTitle.InvokeFunc(); + string title = await _dalamudUtil.RunOnFrameworkThread(() => _honorificGetLocalCharacterTitle.InvokeFunc()).ConfigureAwait(false); return string.IsNullOrEmpty(title) ? string.Empty : Convert.ToBase64String(Encoding.UTF8.GetBytes(title)); } diff --git a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs index fedd7db..75cb452 100644 --- a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs +++ b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs @@ -112,22 +112,22 @@ public class PlayerDataFactory return ((Character*)playerPointer)->GameObject.DrawObject == null; } - private async Task CreateCharacterData(CharacterData previousData, GameObjectHandler playerRelatedObject, CancellationToken token) + private async Task CreateCharacterData(CharacterData data, GameObjectHandler playerRelatedObject, CancellationToken token) { var objectKind = playerRelatedObject.ObjectKind; _logger.LogDebug("Building character data for {obj}", playerRelatedObject); - if (!previousData.FileReplacements.TryGetValue(objectKind, out HashSet? value)) + if (!data.FileReplacements.TryGetValue(objectKind, out HashSet? value)) { - previousData.FileReplacements[objectKind] = new(FileReplacementComparer.Instance); + data.FileReplacements[objectKind] = new(FileReplacementComparer.Instance); } else { value.Clear(); } - previousData.CustomizePlusScale.Remove(objectKind); + data.CustomizePlusScale.Remove(objectKind); // wait until chara is not drawing and present so nothing spontaneously explodes await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: token).ConfigureAwait(false); @@ -151,13 +151,13 @@ public class PlayerDataFactory resolvedPaths = (await _ipcManager.Penumbra.GetCharacterData(_logger, playerRelatedObject).ConfigureAwait(false)); if (resolvedPaths == null) throw new InvalidOperationException("Penumbra returned null data"); - previousData.FileReplacements[objectKind] = + data.FileReplacements[objectKind] = new HashSet(resolvedPaths.Select(c => new FileReplacement([.. c.Value], c.Key)), FileReplacementComparer.Instance) .Where(p => p.HasFileReplacement).ToHashSet(); - previousData.FileReplacements[objectKind].RemoveWhere(c => c.GamePaths.Any(g => !CacheMonitor.AllowedFileExtensions.Any(e => g.EndsWith(e, StringComparison.OrdinalIgnoreCase)))); + data.FileReplacements[objectKind].RemoveWhere(c => c.GamePaths.Any(g => !CacheMonitor.AllowedFileExtensions.Any(e => g.EndsWith(e, StringComparison.OrdinalIgnoreCase)))); _logger.LogDebug("== Static Replacements =="); - foreach (var replacement in previousData.FileReplacements[objectKind].Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase)) + foreach (var replacement in data.FileReplacements[objectKind].Where(i => i.HasFileReplacement).OrderBy(i => i.GamePaths.First(), StringComparer.OrdinalIgnoreCase)) { _logger.LogDebug("=> {repl}", replacement); } @@ -168,7 +168,7 @@ public class PlayerDataFactory // or we get into redraw city for every change and nothing works properly if (objectKind == ObjectKind.Pet) { - foreach (var item in previousData.FileReplacements[ObjectKind.Pet].Where(i => i.HasFileReplacement).SelectMany(p => p.GamePaths)) + foreach (var item in data.FileReplacements[ObjectKind.Pet].Where(i => i.HasFileReplacement).SelectMany(p => p.GamePaths)) { if (_transientResourceManager.AddTransientResource(objectKind, item)) { @@ -176,14 +176,14 @@ public class PlayerDataFactory } } - _logger.LogTrace("Clearing {count} Static Replacements for Pet", previousData.FileReplacements[ObjectKind.Pet].Count); - previousData.FileReplacements[ObjectKind.Pet].Clear(); + _logger.LogTrace("Clearing {count} Static Replacements for Pet", data.FileReplacements[ObjectKind.Pet].Count); + data.FileReplacements[ObjectKind.Pet].Clear(); } _logger.LogDebug("Handling transient update for {obj}", playerRelatedObject); // remove all potentially gathered paths from the transient resource manager that are resolved through static resolving - _transientResourceManager.ClearTransientPaths(objectKind, previousData.FileReplacements[objectKind].SelectMany(c => c.GamePaths).ToList()); + _transientResourceManager.ClearTransientPaths(objectKind, data.FileReplacements[objectKind].SelectMany(c => c.GamePaths).ToList()); // get all remaining paths and resolve them var transientPaths = ManageSemiTransientData(objectKind); @@ -193,42 +193,43 @@ public class PlayerDataFactory foreach (var replacement in resolvedTransientPaths.Select(c => new FileReplacement([.. c.Value], c.Key)).OrderBy(f => f.ResolvedPath, StringComparer.Ordinal)) { _logger.LogDebug("=> {repl}", replacement); - previousData.FileReplacements[objectKind].Add(replacement); + data.FileReplacements[objectKind].Add(replacement); } // clean up all semi transient resources that don't have any file replacement (aka null resolve) - _transientResourceManager.CleanUpSemiTransientResources(objectKind, [.. previousData.FileReplacements[objectKind]]); + _transientResourceManager.CleanUpSemiTransientResources(objectKind, [.. data.FileReplacements[objectKind]]); // make sure we only return data that actually has file replacements - foreach (var item in previousData.FileReplacements) + foreach (var item in data.FileReplacements) { - previousData.FileReplacements[item.Key] = new HashSet(item.Value.Where(v => v.HasFileReplacement).OrderBy(v => v.ResolvedPath, StringComparer.Ordinal), FileReplacementComparer.Instance); + data.FileReplacements[item.Key] = new HashSet(item.Value.Where(v => v.HasFileReplacement).OrderBy(v => v.ResolvedPath, StringComparer.Ordinal), FileReplacementComparer.Instance); } // gather up data from ipc - previousData.ManipulationString = _ipcManager.Penumbra.GetMetaManipulations(); + data.ManipulationString = _ipcManager.Penumbra.GetMetaManipulations(); Task getHeelsOffset = _ipcManager.Heels.GetOffsetAsync(); Task getGlamourerData = _ipcManager.Glamourer.GetCharacterCustomizationAsync(playerRelatedObject.Address); Task getCustomizeData = _ipcManager.CustomizePlus.GetScaleAsync(playerRelatedObject.Address); - previousData.GlamourerString[playerRelatedObject.ObjectKind] = await getGlamourerData.ConfigureAwait(false); - _logger.LogDebug("Glamourer is now: {data}", previousData.GlamourerString[playerRelatedObject.ObjectKind]); + Task getHonorificTitle = _ipcManager.Honorific.GetTitle(); + data.GlamourerString[playerRelatedObject.ObjectKind] = await getGlamourerData.ConfigureAwait(false); + _logger.LogDebug("Glamourer is now: {data}", data.GlamourerString[playerRelatedObject.ObjectKind]); var customizeScale = await getCustomizeData.ConfigureAwait(false); - previousData.CustomizePlusScale[playerRelatedObject.ObjectKind] = customizeScale ?? string.Empty; - _logger.LogDebug("Customize is now: {data}", previousData.CustomizePlusScale[playerRelatedObject.ObjectKind]); - previousData.HonorificData = _ipcManager.Honorific.GetTitle(); - _logger.LogDebug("Honorific is now: {data}", previousData.HonorificData); - previousData.HeelsData = await getHeelsOffset.ConfigureAwait(false); - _logger.LogDebug("Heels is now: {heels}", previousData.HeelsData); + data.CustomizePlusScale[playerRelatedObject.ObjectKind] = customizeScale ?? string.Empty; + _logger.LogDebug("Customize is now: {data}", data.CustomizePlusScale[playerRelatedObject.ObjectKind]); + data.HonorificData = await getHonorificTitle.ConfigureAwait(false); + _logger.LogDebug("Honorific is now: {data}", data.HonorificData); + data.HeelsData = await getHeelsOffset.ConfigureAwait(false); + _logger.LogDebug("Heels is now: {heels}", data.HeelsData); if (objectKind == ObjectKind.Player) { - previousData.MoodlesData = await _ipcManager.Moodles.GetStatusAsync(playerRelatedObject.Address).ConfigureAwait(false) ?? string.Empty; - _logger.LogDebug("Moodles is now: {moodles}", previousData.MoodlesData); + data.MoodlesData = await _ipcManager.Moodles.GetStatusAsync(playerRelatedObject.Address).ConfigureAwait(false) ?? string.Empty; + _logger.LogDebug("Moodles is now: {moodles}", data.MoodlesData); - previousData.PetNamesData = _ipcManager.PetNames.GetLocalNames(); - _logger.LogDebug("Pet Nicknames is now: {petnames}", previousData.PetNamesData); + data.PetNamesData = _ipcManager.PetNames.GetLocalNames(); + _logger.LogDebug("Pet Nicknames is now: {petnames}", data.PetNamesData); } - if (previousData.FileReplacements.TryGetValue(objectKind, out HashSet? fileReplacements)) + if (data.FileReplacements.TryGetValue(objectKind, out HashSet? fileReplacements)) { var toCompute = fileReplacements.Where(f => !f.IsFileSwap).ToArray(); _logger.LogDebug("Getting Hashes for {amount} Files", toCompute.Length); @@ -248,7 +249,7 @@ public class PlayerDataFactory { try { - await VerifyPlayerAnimationBones(boneIndices, previousData, objectKind).ConfigureAwait(false); + await VerifyPlayerAnimationBones(boneIndices, data, objectKind).ConfigureAwait(false); } catch (Exception e) { @@ -258,7 +259,7 @@ public class PlayerDataFactory _logger.LogInformation("Building character data for {obj} took {time}ms", objectKind, TimeSpan.FromTicks(DateTime.UtcNow.Ticks - start.Ticks).TotalMilliseconds); - return previousData; + return data; } private async Task VerifyPlayerAnimationBones(Dictionary>? boneIndices, CharacterData previousData, ObjectKind objectKind)