Added temporary storage of guids of collections to be wiped on bootup when crash/reload #109

Merged
cake merged 1 commits from temporary-collections-cleanup-crash into 2.0.2 2025-12-26 20:43:03 +00:00
6 changed files with 90 additions and 4 deletions

View File

@@ -154,4 +154,5 @@ public class LightlessConfig : ILightlessConfiguration
public bool SyncshellFinderEnabled { get; set; } = false;
public string? SelectedFinderSyncshell { get; set; } = null;
public string LastSeenVersion { get; set; } = string.Empty;
public HashSet<Guid> OrphanableTempCollections { get; set; } = [];
}

View File

@@ -46,6 +46,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
private readonly TextureDownscaleService _textureDownscaleService;
private readonly PairStateCache _pairStateCache;
private readonly PairPerformanceMetricsCache _performanceMetricsCache;
private readonly PenumbraTempCollectionJanitor _tempCollectionJanitor;
private readonly PairManager _pairManager;
private CancellationTokenSource? _applicationCancellationTokenSource;
private Guid _applicationId;
@@ -181,7 +182,8 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
ServerConfigurationManager serverConfigManager,
TextureDownscaleService textureDownscaleService,
PairStateCache pairStateCache,
PairPerformanceMetricsCache performanceMetricsCache) : base(logger, mediator)
PairPerformanceMetricsCache performanceMetricsCache,
PenumbraTempCollectionJanitor tempCollectionJanitor) : base(logger, mediator)
{
_pairManager = pairManager;
Ident = ident;
@@ -199,7 +201,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
_textureDownscaleService = textureDownscaleService;
_pairStateCache = pairStateCache;
_performanceMetricsCache = performanceMetricsCache;
LastAppliedDataBytes = -1;
_tempCollectionJanitor = tempCollectionJanitor;
}
public void Initialize()
@@ -422,6 +424,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
{
_penumbraCollection = created;
_pairStateCache.StoreTemporaryCollection(Ident, created);
_tempCollectionJanitor.Register(created);
}
return _penumbraCollection;
@@ -454,6 +457,7 @@ internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPa
_needsCollectionRebuild = true;
_forceFullReapply = true;
_forceApplyMods = true;
_tempCollectionJanitor.Unregister(toRelease);
}
if (!releaseFromPenumbra || toRelease == Guid.Empty || !_ipcManager.Penumbra.APIAvailable)

View File

@@ -31,6 +31,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
private readonly TextureDownscaleService _textureDownscaleService;
private readonly PairStateCache _pairStateCache;
private readonly PairPerformanceMetricsCache _pairPerformanceMetricsCache;
private readonly PenumbraTempCollectionJanitor _tempCollectionJanitor;
public PairHandlerAdapterFactory(
ILoggerFactory loggerFactory,
@@ -48,7 +49,8 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
ServerConfigurationManager serverConfigManager,
TextureDownscaleService textureDownscaleService,
PairStateCache pairStateCache,
PairPerformanceMetricsCache pairPerformanceMetricsCache)
PairPerformanceMetricsCache pairPerformanceMetricsCache,
PenumbraTempCollectionJanitor tempCollectionJanitor)
{
_loggerFactory = loggerFactory;
_mediator = mediator;
@@ -66,6 +68,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
_textureDownscaleService = textureDownscaleService;
_pairStateCache = pairStateCache;
_pairPerformanceMetricsCache = pairPerformanceMetricsCache;
_tempCollectionJanitor = tempCollectionJanitor;
}
public IPairHandlerAdapter Create(string ident)
@@ -91,6 +94,7 @@ internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory
_serverConfigManager,
_textureDownscaleService,
_pairStateCache,
_pairPerformanceMetricsCache);
_pairPerformanceMetricsCache,
_tempCollectionJanitor);
}
}

View File

@@ -135,6 +135,7 @@ public sealed class Plugin : IDalamudPlugin
services.AddSingleton<ZoneChatService>();
services.AddSingleton<IdDisplayHandler>();
services.AddSingleton<PlayerPerformanceService>();
services.AddSingleton<PenumbraTempCollectionJanitor>();
services.AddSingleton<TextureMetadataHelper>(sp =>
new TextureMetadataHelper(sp.GetRequiredService<ILogger<TextureMetadataHelper>>(), gameData));

View File

@@ -0,0 +1,71 @@
using LightlessSync.Interop.Ipc;
using LightlessSync.LightlessConfiguration;
using LightlessSync.Services.Mediator;
using Microsoft.Extensions.Logging;
namespace LightlessSync.Services;
public sealed class PenumbraTempCollectionJanitor : DisposableMediatorSubscriberBase
{
private readonly IpcManager _ipc;
private readonly LightlessConfigService _config;
private int _ran;
public PenumbraTempCollectionJanitor(
ILogger<PenumbraTempCollectionJanitor> logger,
LightlessMediator mediator,
IpcManager ipc,
LightlessConfigService config) : base(logger, mediator)
{
_ipc = ipc;
_config = config;
Mediator.Subscribe<PenumbraInitializedMessage>(this, _ => CleanupOrphansOnBoot());
}
public void Register(Guid id)
{
if (id == Guid.Empty) return;
if (_config.Current.OrphanableTempCollections.Add(id))
_config.Save();
}
public void Unregister(Guid id)
{
if (id == Guid.Empty) return;
if (_config.Current.OrphanableTempCollections.Remove(id))
_config.Save();
}
private void CleanupOrphansOnBoot()
{
if (Interlocked.Exchange(ref _ran, 1) == 1)
return;
if (!_ipc.Penumbra.APIAvailable)
return;
var ids = _config.Current.OrphanableTempCollections.ToArray();
if (ids.Length == 0)
return;
var appId = Guid.NewGuid();
Logger.LogInformation("Cleaning up {count} orphaned Lightless temp collections found in configuration", ids.Length);
foreach (var id in ids)
{
try
{
_ipc.Penumbra.RemoveTemporaryCollectionAsync(Logger, appId, id)
.GetAwaiter().GetResult();
}
catch (Exception ex)
{
Logger.LogDebug(ex, "Failed removing orphaned temp collection {id}", id);
}
}
_config.Current.OrphanableTempCollections.Clear();
_config.Save();
}
}

View File

@@ -178,6 +178,11 @@ public class DownloadUi : WindowMediatorSubscriberBase
foreach (var transfer in transfers)
{
var transferKey = transfer.Key;
// Skip if no valid game object
if (transferKey.GetGameObject() == null)
continue;
var rawPos = _dalamudUtilService.WorldToScreen(transferKey.GetGameObject());
// If RawPos is zero, remove it from smoothed dictionary