mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
refactor: made _collections thread-safe
This commit is contained in:
parent
101df501c5
commit
723eaa0076
1 changed files with 44 additions and 17 deletions
|
|
@ -72,6 +72,8 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
ModCollection.Empty,
|
ModCollection.Empty,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private readonly Lock _collectionsLock = new();
|
||||||
|
|
||||||
/// <remarks> A list of all collections ever created still existing by their local id. </remarks>
|
/// <remarks> A list of all collections ever created still existing by their local id. </remarks>
|
||||||
private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
|
private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
|
||||||
_collectionsByLocal = new() { [LocalCollectionId.Zero] = ModCollection.Empty };
|
_collectionsByLocal = new() { [LocalCollectionId.Zero] = ModCollection.Empty };
|
||||||
|
|
@ -79,8 +81,11 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
|
|
||||||
public readonly ModCollection DefaultNamed;
|
public readonly ModCollection DefaultNamed;
|
||||||
|
|
||||||
/// <remarks> Incremented by 1 because the empty collection gets Zero. </remarks>
|
/// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
|
||||||
public LocalCollectionId CurrentCollectionId { get; private set; } = LocalCollectionId.Zero + 1;
|
private int _currentCollectionIdValue = 1;
|
||||||
|
|
||||||
|
/// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
|
||||||
|
public LocalCollectionId CurrentCollectionId => new(_currentCollectionIdValue);
|
||||||
|
|
||||||
/// <summary> Default enumeration skips the empty collection. </summary>
|
/// <summary> Default enumeration skips the empty collection. </summary>
|
||||||
public IEnumerator<ModCollection> GetEnumerator()
|
public IEnumerator<ModCollection> GetEnumerator()
|
||||||
|
|
@ -162,8 +167,12 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
if (name.Length == 0)
|
if (name.Length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var newCollection = Create(name, _collections.Count, duplicate);
|
ModCollection newCollection;
|
||||||
_collections.Add(newCollection);
|
lock (_collectionsLock)
|
||||||
|
{
|
||||||
|
newCollection = Create(name, _collections.Count, duplicate);
|
||||||
|
_collections.Add(newCollection);
|
||||||
|
}
|
||||||
_saveService.ImmediateSave(new ModCollectionSave(_modStorage, newCollection));
|
_saveService.ImmediateSave(new ModCollectionSave(_modStorage, newCollection));
|
||||||
Penumbra.Messager.NotificationMessage($"Created new collection {newCollection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
Penumbra.Messager.NotificationMessage($"Created new collection {newCollection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
||||||
_communicator.CollectionChange.Invoke(CollectionType.Inactive, null, newCollection, string.Empty);
|
_communicator.CollectionChange.Invoke(CollectionType.Inactive, null, newCollection, string.Empty);
|
||||||
|
|
@ -189,10 +198,13 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
|
|
||||||
Delete(collection);
|
Delete(collection);
|
||||||
_saveService.ImmediateDelete(new ModCollectionSave(_modStorage, collection));
|
_saveService.ImmediateDelete(new ModCollectionSave(_modStorage, collection));
|
||||||
_collections.RemoveAt(collection.Identity.Index);
|
lock (_collectionsLock)
|
||||||
// Update indices.
|
{
|
||||||
for (var i = collection.Identity.Index; i < Count; ++i)
|
_collections.RemoveAt(collection.Identity.Index);
|
||||||
_collections[i].Identity.Index = i;
|
// Update indices.
|
||||||
|
for (var i = collection.Identity.Index; i < Count; ++i)
|
||||||
|
_collections[i].Identity.Index = i;
|
||||||
|
}
|
||||||
|
|
||||||
Penumbra.Messager.NotificationMessage($"Deleted collection {collection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
Penumbra.Messager.NotificationMessage($"Deleted collection {collection.Identity.AnonymizedName}.", NotificationType.Success, false);
|
||||||
_communicator.CollectionChange.Invoke(CollectionType.Inactive, collection, null, string.Empty);
|
_communicator.CollectionChange.Invoke(CollectionType.Inactive, collection, null, string.Empty);
|
||||||
|
|
@ -316,15 +328,17 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
/// <summary> Move all settings in all collections to unused settings. </summary>
|
/// <summary> Move all settings in all collections to unused settings. </summary>
|
||||||
private void OnModDiscoveryStarted()
|
private void OnModDiscoveryStarted()
|
||||||
{
|
{
|
||||||
foreach (var collection in this)
|
var snapshot = GetModSnapShot();
|
||||||
|
foreach (var collection in snapshot)
|
||||||
collection.Settings.PrepareModDiscovery(_modStorage);
|
collection.Settings.PrepareModDiscovery(_modStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Restore all settings in all collections to mods. </summary>
|
/// <summary> Restore all settings in all collections to mods. </summary>
|
||||||
private void OnModDiscoveryFinished()
|
private void OnModDiscoveryFinished()
|
||||||
{
|
{
|
||||||
|
var snapshot = GetModSnapShot();
|
||||||
// Re-apply all mod settings.
|
// Re-apply all mod settings.
|
||||||
foreach (var collection in this)
|
foreach (var collection in snapshot)
|
||||||
collection.Settings.ApplyModSettings(collection, _saveService, _modStorage);
|
collection.Settings.ApplyModSettings(collection, _saveService, _modStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,22 +346,23 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
private void OnModPathChange(ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory,
|
||||||
DirectoryInfo? newDirectory)
|
DirectoryInfo? newDirectory)
|
||||||
{
|
{
|
||||||
|
var snapshot = GetModSnapShot();
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ModPathChangeType.Added:
|
case ModPathChangeType.Added:
|
||||||
foreach (var collection in this)
|
foreach (var collection in snapshot)
|
||||||
collection.Settings.AddMod(mod);
|
collection.Settings.AddMod(mod);
|
||||||
break;
|
break;
|
||||||
case ModPathChangeType.Deleted:
|
case ModPathChangeType.Deleted:
|
||||||
foreach (var collection in this)
|
foreach (var collection in snapshot)
|
||||||
collection.Settings.RemoveMod(mod);
|
collection.Settings.RemoveMod(mod);
|
||||||
break;
|
break;
|
||||||
case ModPathChangeType.Moved:
|
case ModPathChangeType.Moved:
|
||||||
foreach (var collection in this.Where(collection => collection.GetOwnSettings(mod.Index) != null))
|
foreach (var collection in snapshot.Where(collection => collection.GetOwnSettings(mod.Index) != null))
|
||||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||||
break;
|
break;
|
||||||
case ModPathChangeType.Reloaded:
|
case ModPathChangeType.Reloaded:
|
||||||
foreach (var collection in this)
|
foreach (var collection in snapshot)
|
||||||
{
|
{
|
||||||
if (collection.GetOwnSettings(mod.Index)?.Settings.FixAll(mod) ?? false)
|
if (collection.GetOwnSettings(mod.Index)?.Settings.FixAll(mod) ?? false)
|
||||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||||
|
|
@ -366,7 +381,8 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
if (!requiresSaving)
|
if (!requiresSaving)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var collection in this)
|
var snapshot = GetModSnapShot();
|
||||||
|
foreach (var collection in snapshot)
|
||||||
{
|
{
|
||||||
if (collection.GetOwnSettings(mod.Index)?.HandleChanges(type, mod, group, option, movedToIdx) ?? false)
|
if (collection.GetOwnSettings(mod.Index)?.HandleChanges(type, mod, group, option, movedToIdx) ?? false)
|
||||||
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
_saveService.QueueSave(new ModCollectionSave(_modStorage, collection));
|
||||||
|
|
@ -380,11 +396,22 @@ public class CollectionStorage : IReadOnlyList<ModCollection>, IDisposable, ISer
|
||||||
if (file.CurrentUsage == 0)
|
if (file.CurrentUsage == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var collection in this)
|
var snapshot = GetModSnapShot();
|
||||||
|
foreach (var collection in snapshot)
|
||||||
{
|
{
|
||||||
var (settings, _) = collection.GetActualSettings(mod.Index);
|
var (settings, _) = collection.GetActualSettings(mod.Index);
|
||||||
if (settings is { Enabled: true })
|
if (settings is { Enabled: true })
|
||||||
collection.Counters.IncrementChange();
|
collection.Counters.IncrementChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ModCollection[] GetModSnapShot()
|
||||||
|
{
|
||||||
|
ModCollection[] snapshot;
|
||||||
|
lock (_collectionsLock)
|
||||||
|
{
|
||||||
|
snapshot = _collections.Skip(1).ToArray();
|
||||||
|
}
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue