@@ -71,6 +71,8 @@ public void Delete(ModCollection collection)
7171 [
7272 ModCollection . Empty ,
7373 ] ;
74+
75+ private readonly Lock _collectionsLock = new ( ) ;
7476
7577 /// <remarks> A list of all collections ever created still existing by their local id. </remarks>
7678 private readonly ConcurrentDictionary < LocalCollectionId , ModCollection >
@@ -79,8 +81,11 @@ private readonly ConcurrentDictionary<LocalCollectionId, ModCollection>
7981
8082 public readonly ModCollection DefaultNamed ;
8183
82- /// <remarks> Incremented by 1 because the empty collection gets Zero. </remarks>
83- public LocalCollectionId CurrentCollectionId { get ; private set ; } = LocalCollectionId . Zero + 1 ;
84+ /// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
85+ private int _currentCollectionIdValue = 1 ;
86+
87+ /// <remarks> Starts at 1 because the empty collection gets Zero. </remarks>
88+ public LocalCollectionId CurrentCollectionId => new ( _currentCollectionIdValue ) ;
8489
8590 /// <summary> Default enumeration skips the empty collection. </summary>
8691 public IEnumerator < ModCollection > GetEnumerator ( )
@@ -162,8 +167,12 @@ public bool AddCollection(string name, ModCollection? duplicate)
162167 if ( name . Length == 0 )
163168 return false ;
164169
165- var newCollection = Create ( name , _collections . Count , duplicate ) ;
166- _collections . Add ( newCollection ) ;
170+ ModCollection newCollection ;
171+ lock ( _collectionsLock )
172+ {
173+ newCollection = Create ( name , _collections . Count , duplicate ) ;
174+ _collections . Add ( newCollection ) ;
175+ }
167176 _saveService . ImmediateSave ( new ModCollectionSave ( _modStorage , newCollection ) ) ;
168177 Penumbra . Messager . NotificationMessage ( $ "Created new collection { newCollection . Identity . AnonymizedName } .", NotificationType . Success , false ) ;
169178 _communicator . CollectionChange . Invoke ( CollectionType . Inactive , null , newCollection , string . Empty ) ;
@@ -189,10 +198,13 @@ public bool RemoveCollection(ModCollection collection)
189198
190199 Delete ( collection ) ;
191200 _saveService . ImmediateDelete ( new ModCollectionSave ( _modStorage , collection ) ) ;
192- _collections . RemoveAt ( collection . Identity . Index ) ;
193- // Update indices.
194- for ( var i = collection . Identity . Index ; i < Count ; ++ i )
195- _collections [ i ] . Identity . Index = i ;
201+ lock ( _collectionsLock )
202+ {
203+ _collections . RemoveAt ( collection . Identity . Index ) ;
204+ // Update indices.
205+ for ( var i = collection . Identity . Index ; i < Count ; ++ i )
206+ _collections [ i ] . Identity . Index = i ;
207+ }
196208
197209 Penumbra . Messager . NotificationMessage ( $ "Deleted collection { collection . Identity . AnonymizedName } .", NotificationType . Success , false ) ;
198210 _communicator . CollectionChange . Invoke ( CollectionType . Inactive , collection , null , string . Empty ) ;
@@ -316,38 +328,41 @@ private ModCollection SetDefaultNamedCollection()
316328 /// <summary> Move all settings in all collections to unused settings. </summary>
317329 private void OnModDiscoveryStarted ( )
318330 {
319- foreach ( var collection in this )
331+ var snapshot = GetModSnapShot ( ) ;
332+ foreach ( var collection in snapshot )
320333 collection . Settings . PrepareModDiscovery ( _modStorage ) ;
321334 }
322335
323336 /// <summary> Restore all settings in all collections to mods. </summary>
324337 private void OnModDiscoveryFinished ( )
325338 {
339+ var snapshot = GetModSnapShot ( ) ;
326340 // Re-apply all mod settings.
327- foreach ( var collection in this )
341+ foreach ( var collection in snapshot )
328342 collection . Settings . ApplyModSettings ( collection , _saveService , _modStorage ) ;
329343 }
330344
331345 /// <summary> Add or remove a mod from all collections, or re-save all collections where the mod has settings. </summary>
332346 private void OnModPathChange ( ModPathChangeType type , Mod mod , DirectoryInfo ? oldDirectory ,
333347 DirectoryInfo ? newDirectory )
334348 {
349+ var snapshot = GetModSnapShot ( ) ;
335350 switch ( type )
336351 {
337352 case ModPathChangeType . Added :
338- foreach ( var collection in this )
353+ foreach ( var collection in snapshot )
339354 collection . Settings . AddMod ( mod ) ;
340355 break ;
341356 case ModPathChangeType . Deleted :
342- foreach ( var collection in this )
357+ foreach ( var collection in snapshot )
343358 collection . Settings . RemoveMod ( mod ) ;
344359 break ;
345360 case ModPathChangeType . Moved :
346- foreach ( var collection in this . Where ( collection => collection . GetOwnSettings ( mod . Index ) != null ) )
361+ foreach ( var collection in snapshot . Where ( collection => collection . GetOwnSettings ( mod . Index ) != null ) )
347362 _saveService . QueueSave ( new ModCollectionSave ( _modStorage , collection ) ) ;
348363 break ;
349364 case ModPathChangeType . Reloaded :
350- foreach ( var collection in this )
365+ foreach ( var collection in snapshot )
351366 {
352367 if ( collection . GetOwnSettings ( mod . Index ) ? . Settings . FixAll ( mod ) ?? false )
353368 _saveService . QueueSave ( new ModCollectionSave ( _modStorage , collection ) ) ;
@@ -365,8 +380,9 @@ private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? gro
365380 type . HandlingInfo ( out var requiresSaving , out _ , out _ ) ;
366381 if ( ! requiresSaving )
367382 return ;
368-
369- foreach ( var collection in this )
383+
384+ var snapshot = GetModSnapShot ( ) ;
385+ foreach ( var collection in snapshot )
370386 {
371387 if ( collection . GetOwnSettings ( mod . Index ) ? . HandleChanges ( type , mod , group , option , movedToIdx ) ?? false )
372388 _saveService . QueueSave ( new ModCollectionSave ( _modStorage , collection ) ) ;
@@ -380,11 +396,22 @@ private void OnModFileChanged(Mod mod, FileRegistry file)
380396 if ( file . CurrentUsage == 0 )
381397 return ;
382398
383- foreach ( var collection in this )
399+ var snapshot = GetModSnapShot ( ) ;
400+ foreach ( var collection in snapshot )
384401 {
385402 var ( settings , _) = collection . GetActualSettings ( mod . Index ) ;
386403 if ( settings is { Enabled : true } )
387404 collection . Counters . IncrementChange ( ) ;
388405 }
389406 }
407+
408+ private ModCollection [ ] GetModSnapShot ( )
409+ {
410+ ModCollection [ ] snapshot ;
411+ lock ( _collectionsLock )
412+ {
413+ snapshot = _collections . Skip ( 1 ) . ToArray ( ) ;
414+ }
415+ return snapshot ;
416+ }
390417}
0 commit comments