Even almoster...

This commit is contained in:
Ottermandias 2022-04-20 11:03:19 +02:00
parent 65bd1d1b52
commit 8dd681bdda
19 changed files with 2625 additions and 1865 deletions

View file

@ -81,6 +81,29 @@ public partial class ModCollection
_modManager.ModPathChanged -= OnModPathChanged;
}
// Returns true if the name is not empty, it is not the name of the empty collection
// and no existing collection results in the same filename as name.
public bool CanAddCollection( string name, out string fixedName )
{
if( name.Length == 0 )
{
fixedName = string.Empty;
return false;
}
name = name.RemoveInvalidPathSymbols().ToLowerInvariant();
if( name.Length == 0
|| name == Empty.Name.ToLowerInvariant()
|| _collections.Any( c => c.Name.RemoveInvalidPathSymbols().ToLowerInvariant() == name ) )
{
fixedName = string.Empty;
return false;
}
fixedName = name;
return true;
}
// Add a new collection of the given name.
// If duplicate is not-null, the new collection will be a duplicate of it.
// If the name of the collection would result in an already existing filename, skip it.
@ -88,12 +111,9 @@ public partial class ModCollection
// Also sets the current collection to the new collection afterwards.
public bool AddCollection( string name, ModCollection? duplicate )
{
var nameFixed = name.RemoveInvalidPathSymbols().ToLowerInvariant();
if( nameFixed.Length == 0
|| nameFixed == Empty.Name.ToLowerInvariant()
|| _collections.Any( c => c.Name.RemoveInvalidPathSymbols().ToLowerInvariant() == nameFixed ) )
if( !CanAddCollection( name, out var fixedName ) )
{
PluginLog.Warning( $"The new collection {name} would lead to the same path as one that already exists." );
PluginLog.Warning( $"The new collection {name} would lead to the same path {fixedName} as one that already exists." );
return false;
}
@ -108,6 +128,7 @@ public partial class ModCollection
// Remove the given collection if it exists and is neither the empty nor the default-named collection.
// If the removed collection was active, it also sets the corresponding collection to the appropriate default.
// Also removes the collection from inheritances of all other collections.
public bool RemoveCollection( int idx )
{
if( idx <= Empty.Index || idx >= _collections.Count )
@ -140,9 +161,18 @@ public partial class ModCollection
var collection = _collections[ idx ];
collection.Delete();
_collections.RemoveAt( idx );
for( var i = idx; i < _collections.Count; ++i )
foreach( var c in _collections )
{
--_collections[ i ].Index;
var inheritedIdx = c._inheritance.IndexOf( collection );
if( inheritedIdx >= 0 )
{
c.RemoveInheritance( inheritedIdx );
}
if( c.Index > idx )
{
--c.Index;
}
}
CollectionChanged.Invoke( Type.Inactive, collection, null );

View file

@ -137,7 +137,7 @@ public partial class ModCollection
return false;
}
_settings[ idx ] = inherit ? null : this[ idx ].Settings ?? ModSettings2.DefaultSettings( Penumbra.ModManager.Mods[ idx ] );
_settings[ idx ] = inherit ? null : this[ idx ].Settings?.DeepCopy() ?? ModSettings2.DefaultSettings( Penumbra.ModManager.Mods[ idx ] );
return true;
}

View file

@ -23,23 +23,57 @@ public partial class ModCollection
// Iterate over all collections inherited from in depth-first order.
// Skip already visited collections to avoid circular dependencies.
public IEnumerable< ModCollection > GetFlattenedInheritance()
{
yield return this;
=> InheritedCollections( this ).Distinct();
foreach( var collection in _inheritance.SelectMany( c => c.GetFlattenedInheritance() )
.Where( c => !ReferenceEquals( this, c ) )
.Distinct() )
{
yield return collection;
}
// All inherited collections in application order without filtering for duplicates.
private static IEnumerable< ModCollection > InheritedCollections( ModCollection collection )
=> collection.Inheritance.SelectMany( InheritedCollections ).Prepend( collection );
// Reasons why a collection can not be inherited from.
public enum ValidInheritance
{
Valid,
Self, // Can not inherit from self
Empty, // Can not inherit from the empty collection
Contained, // Already inherited from
Circle, // Inheritance would lead to a circle.
}
// Check whether a collection can be inherited from.
public ValidInheritance CheckValidInheritance( ModCollection? collection )
{
if( collection == null || ReferenceEquals( collection, Empty ) )
{
return ValidInheritance.Empty;
}
if( ReferenceEquals( collection, this ) )
{
return ValidInheritance.Self;
}
if( _inheritance.Contains( collection ) )
{
return ValidInheritance.Contained;
}
if( InheritedCollections( collection ).Any( c => c == this ) )
{
return ValidInheritance.Circle;
}
return ValidInheritance.Valid;
}
private bool CheckForCircle( ModCollection collection )
=> ReferenceEquals( collection, this ) || _inheritance.Any( c => c.CheckForCircle( collection ) );
// Add a new collection to the inheritance list.
// We do not check if this collection would be visited before,
// only that it is unique in the list itself.
public bool AddInheritance( ModCollection collection )
{
if( ReferenceEquals( collection, this ) || _inheritance.Contains( collection ) )
if( CheckValidInheritance( collection ) != ValidInheritance.Valid )
{
return false;
}