Fix some bugs and start work on new collections tab.

This commit is contained in:
Ottermandias 2023-04-18 18:44:53 +02:00
parent e9fc57022e
commit fba5bc6820
26 changed files with 1346 additions and 717 deletions

View file

@ -13,24 +13,35 @@ using Penumbra.Util;
namespace Penumbra.Collections.Manager;
public class ActiveCollectionData
{
public ModCollection Current { get; internal set; } = ModCollection.Empty;
public ModCollection Default { get; internal set; } = ModCollection.Empty;
public ModCollection Interface { get; internal set; } = ModCollection.Empty;
public readonly ModCollection?[] SpecialCollections = new ModCollection?[Enum.GetValues<Api.Enums.ApiCollectionType>().Length - 3];
}
public class ActiveCollections : ISavable, IDisposable
{
public const int Version = 1;
private readonly CollectionStorage _storage;
private readonly CommunicatorService _communicator;
private readonly SaveService _saveService;
private readonly CollectionStorage _storage;
private readonly CommunicatorService _communicator;
private readonly SaveService _saveService;
private readonly ActiveCollectionData _data;
public ActiveCollections(Configuration config, CollectionStorage storage, ActorService actors, CommunicatorService communicator, SaveService saveService)
public ActiveCollections(Configuration config, CollectionStorage storage, ActorService actors, CommunicatorService communicator, SaveService saveService, ActiveCollectionData data)
{
_storage = storage;
_communicator = communicator;
_saveService = saveService;
_data = data;
Current = storage.DefaultNamed;
Default = storage.DefaultNamed;
Interface = storage.DefaultNamed;
Individuals = new IndividualCollections(actors.AwaitedService, config);
_communicator.CollectionChange.Subscribe(OnCollectionChange);
_communicator.CollectionChange.Subscribe(OnCollectionChange, -100);
LoadCollections();
UpdateCurrentCollectionInUse();
}
@ -39,16 +50,28 @@ public class ActiveCollections : ISavable, IDisposable
=> _communicator.CollectionChange.Unsubscribe(OnCollectionChange);
/// <summary> The collection currently selected for changing settings. </summary>
public ModCollection Current { get; private set; }
public ModCollection Current
{
get => _data.Current;
private set => _data.Current = value;
}
/// <summary> Whether the currently selected collection is used either directly via assignment or via inheritance. </summary>
public bool CurrentCollectionInUse { get; private set; }
/// <summary> The collection used for general file redirections and all characters not specifically named. </summary>
public ModCollection Default { get; private set; }
public ModCollection Default
{
get => _data.Default;
private set => _data.Default = value;
}
/// <summary> The collection used for all files categorized as UI files. </summary>
public ModCollection Interface { get; private set; }
public ModCollection Interface
{
get => _data.Interface;
private set => _data.Interface = value;
}
/// <summary> The list of individual assignments. </summary>
public readonly IndividualCollections Individuals;
@ -58,16 +81,17 @@ public class ActiveCollections : ISavable, IDisposable
=> Individuals.TryGetCollection(identifier, out var c) ? c : Default;
/// <summary> The list of group assignments. </summary>
private readonly ModCollection?[] _specialCollections = new ModCollection?[Enum.GetValues<Api.Enums.ApiCollectionType>().Length - 3];
private ModCollection?[] SpecialCollections
=> _data.SpecialCollections;
/// <summary> Return all actually assigned group assignments. </summary>
public IEnumerable<KeyValuePair<CollectionType, ModCollection>> SpecialAssignments
{
get
{
for (var i = 0; i < _specialCollections.Length; ++i)
for (var i = 0; i < SpecialCollections.Length; ++i)
{
var collection = _specialCollections[i];
var collection = SpecialCollections[i];
if (collection != null)
yield return new KeyValuePair<CollectionType, ModCollection>((CollectionType)i, collection);
}
@ -82,7 +106,7 @@ public class ActiveCollections : ISavable, IDisposable
public ModCollection? ByType(CollectionType type, ActorIdentifier identifier)
{
if (type.IsSpecial())
return _specialCollections[(int)type];
return SpecialCollections[(int)type];
return type switch
{
@ -94,13 +118,13 @@ public class ActiveCollections : ISavable, IDisposable
};
}
/// <summary> Create a special collection if it does not exist and set it to Empty. </summary>
/// <summary> Create a special collection if it does not exist and set it to the current default. </summary>
public bool CreateSpecialCollection(CollectionType collectionType)
{
if (!collectionType.IsSpecial() || _specialCollections[(int)collectionType] != null)
if (!collectionType.IsSpecial() || SpecialCollections[(int)collectionType] != null)
return false;
_specialCollections[(int)collectionType] = Default;
SpecialCollections[(int)collectionType] = Default;
_communicator.CollectionChange.Invoke(collectionType, null, Default, string.Empty);
return true;
}
@ -111,11 +135,11 @@ public class ActiveCollections : ISavable, IDisposable
if (!collectionType.IsSpecial())
return;
var old = _specialCollections[(int)collectionType];
var old = SpecialCollections[(int)collectionType];
if (old == null)
return;
_specialCollections[(int)collectionType] = null;
SpecialCollections[(int)collectionType] = null;
_communicator.CollectionChange.Invoke(collectionType, old, null, string.Empty);
}
@ -144,7 +168,38 @@ public class ActiveCollections : ISavable, IDisposable
_saveService.QueueSave(this);
}
/// <summary> Set a active collection, can be used to set Default, Current, Interface, Special, or Individual collections. </summary>
/// <summary> Set and create an active collection, can be used to set Default, Current, Interface, Special, or Individual collections. </summary>
public void SetCollection(ModCollection? collection, CollectionType collectionType, ActorIdentifier[] identifiers)
{
if (collectionType is CollectionType.Individual && identifiers.Length > 0 && identifiers[0].IsValid)
{
var idx = Individuals.Index(identifiers[0]);
if (idx >= 0)
{
if (collection == null)
RemoveIndividualCollection(idx);
else
SetCollection(collection, collectionType, idx);
}
else if (collection != null)
{
CreateIndividualCollection(identifiers);
SetCollection(collection, CollectionType.Individual, Individuals.Count - 1);
}
}
else
{
if (collection == null)
RemoveSpecialCollection(collectionType);
else
{
CreateSpecialCollection(collectionType);
SetCollection(collection, collectionType);
}
}
}
/// <summary> Set an active collection, can be used to set Default, Current, Interface, Special, or Individual collections. </summary>
public void SetCollection(ModCollection collection, CollectionType collectionType, int individualIndex = -1)
{
var oldCollection = collectionType switch
@ -154,7 +209,7 @@ public class ActiveCollections : ISavable, IDisposable
CollectionType.Current => Current,
CollectionType.Individual when individualIndex >= 0 && individualIndex < Individuals.Count => Individuals[individualIndex].Collection,
CollectionType.Individual => null,
_ when collectionType.IsSpecial() => _specialCollections[(int)collectionType] ?? Default,
_ when collectionType.IsSpecial() => SpecialCollections[(int)collectionType] ?? Default,
_ => null,
};
@ -178,7 +233,7 @@ public class ActiveCollections : ISavable, IDisposable
break;
default:
_specialCollections[(int)collectionType] = collection;
SpecialCollections[(int)collectionType] = collection;
break;
}
@ -205,7 +260,7 @@ public class ActiveCollections : ISavable, IDisposable
{ nameof(Interface), Interface.Name },
{ nameof(Current), Current.Name },
};
foreach (var (type, collection) in _specialCollections.WithIndex().Where(p => p.Value != null)
foreach (var (type, collection) in SpecialCollections.WithIndex().Where(p => p.Value != null)
.Select(p => ((CollectionType)p.Index, p.Value!)))
jObj.Add(type.ToString(), collection.Name);
@ -215,7 +270,7 @@ public class ActiveCollections : ISavable, IDisposable
}
private void UpdateCurrentCollectionInUse()
=> CurrentCollectionInUse = _specialCollections
=> CurrentCollectionInUse = SpecialCollections
.OfType<ModCollection>()
.Prepend(Interface)
.Prepend(Default)
@ -240,9 +295,9 @@ public class ActiveCollections : ISavable, IDisposable
if (oldCollection == Current)
SetCollection(Default.Index > ModCollection.Empty.Index ? Default : _storage.DefaultNamed, CollectionType.Current);
for (var i = 0; i < _specialCollections.Length; ++i)
for (var i = 0; i < SpecialCollections.Length; ++i)
{
if (oldCollection == _specialCollections[i])
if (oldCollection == SpecialCollections[i])
SetCollection(ModCollection.Empty, (CollectionType)i);
}
@ -329,7 +384,7 @@ public class ActiveCollections : ISavable, IDisposable
}
else
{
_specialCollections[(int)type] = typeCollection;
SpecialCollections[(int)type] = typeCollection;
}
}
}
@ -398,24 +453,6 @@ public class ActiveCollections : ISavable, IDisposable
: string.Empty;
}
break;
// The group of all Characters is redundant if they are all equal to Default or unassigned.
case CollectionType.MalePlayerCharacter:
case CollectionType.MaleNonPlayerCharacter:
case CollectionType.FemalePlayerCharacter:
case CollectionType.FemaleNonPlayerCharacter:
var first = ByType(CollectionType.MalePlayerCharacter) ?? Default;
var second = ByType(CollectionType.MaleNonPlayerCharacter) ?? Default;
var third = ByType(CollectionType.FemalePlayerCharacter) ?? Default;
var fourth = ByType(CollectionType.FemaleNonPlayerCharacter) ?? Default;
if (first.Index == second.Index
&& first.Index == third.Index
&& first.Index == fourth.Index
&& first.Index == Default.Index)
return
"Assignment is currently redundant due to the group [Male, Female, Player, NPC] Characters being unassigned or identical to each other and Default.\n"
+ "You can keep just the Default Assignment.";
break;
// Children and Elderly are redundant if they are identical to both Male NPCs and Female NPCs, or if they are unassigned to Default.
case CollectionType.NonPlayerChild: