mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Lots of collection progress.
This commit is contained in:
parent
d908f22a17
commit
3f33bab296
22 changed files with 666 additions and 636 deletions
|
|
@ -31,8 +31,6 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
public (int, int) ApiVersion
|
||||
=> (4, 19);
|
||||
|
||||
private readonly Dictionary<ModCollection, ModCollection.ModSettingChangeDelegate> _delegates = new();
|
||||
|
||||
public event Action<string>? PreSettingsPanelDraw;
|
||||
public event Action<string>? PostSettingsPanelDraw;
|
||||
|
||||
|
|
@ -110,10 +108,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
private CollectionResolver _collectionResolver;
|
||||
private CutsceneService _cutsceneService;
|
||||
private ModImportManager _modImportManager;
|
||||
private CollectionEditor _collectionEditor;
|
||||
|
||||
public unsafe PenumbraApi(CommunicatorService communicator, Penumbra penumbra, ModManager modManager, ResourceLoader resourceLoader,
|
||||
Configuration config, CollectionManager collectionManager, DalamudServices dalamud, TempCollectionManager tempCollections,
|
||||
TempModManager tempMods, ActorService actors, CollectionResolver collectionResolver, CutsceneService cutsceneService, ModImportManager modImportManager)
|
||||
TempModManager tempMods, ActorService actors, CollectionResolver collectionResolver, CutsceneService cutsceneService, ModImportManager modImportManager, CollectionEditor collectionEditor)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_penumbra = penumbra;
|
||||
|
|
@ -127,17 +126,16 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
_actors = actors;
|
||||
_collectionResolver = collectionResolver;
|
||||
_cutsceneService = cutsceneService;
|
||||
_modImportManager = modImportManager;
|
||||
_modImportManager = modImportManager;
|
||||
_collectionEditor = collectionEditor;
|
||||
|
||||
_lumina = (Lumina.GameData?)_dalamud.GameData.GetType()
|
||||
.GetField("gameData", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
?.GetValue(_dalamud.GameData);
|
||||
foreach (var collection in _collectionManager.Storage)
|
||||
SubscribeToCollection(collection);
|
||||
|
||||
_communicator.CollectionChange.Subscribe(SubscribeToNewCollections);
|
||||
_resourceLoader.ResourceLoaded += OnResourceLoaded;
|
||||
_communicator.ModPathChanged.Subscribe(ModPathChangeSubscriber);
|
||||
_communicator.ModPathChanged.Subscribe(ModPathChangeSubscriber);
|
||||
_communicator.ModSettingChanged.Subscribe(OnModSettingChange, -1000);
|
||||
}
|
||||
|
||||
public unsafe void Dispose()
|
||||
|
|
@ -145,15 +143,9 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
if (!Valid)
|
||||
return;
|
||||
|
||||
foreach (var collection in _collectionManager.Storage)
|
||||
{
|
||||
if (_delegates.TryGetValue(collection, out var del))
|
||||
collection.ModSettingChanged -= del;
|
||||
}
|
||||
|
||||
_resourceLoader.ResourceLoaded -= OnResourceLoaded;
|
||||
_communicator.CollectionChange.Unsubscribe(SubscribeToNewCollections);
|
||||
_communicator.ModPathChanged.Unsubscribe(ModPathChangeSubscriber);
|
||||
_communicator.ModPathChanged.Unsubscribe(ModPathChangeSubscriber);
|
||||
_communicator.ModSettingChanged.Unsubscribe(OnModSettingChange);
|
||||
_lumina = null;
|
||||
_communicator = null!;
|
||||
_penumbra = null!;
|
||||
|
|
@ -167,6 +159,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
_actors = null!;
|
||||
_collectionResolver = null!;
|
||||
_cutsceneService = null!;
|
||||
_modImportManager = null!;
|
||||
_collectionEditor = null!;
|
||||
}
|
||||
|
||||
public event ChangedItemClick? ChangedItemClicked;
|
||||
|
|
@ -702,7 +696,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return PenumbraApiEc.ModMissing;
|
||||
|
||||
|
||||
return collection.SetModInheritance(mod.Index, inherit) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
return _collectionEditor.SetModInheritance(collection, mod, inherit) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
}
|
||||
|
||||
public PenumbraApiEc TrySetMod(string collectionName, string modDirectory, string modName, bool enabled)
|
||||
|
|
@ -714,7 +708,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||
return PenumbraApiEc.ModMissing;
|
||||
|
||||
return collection.SetModState(mod.Index, enabled) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
return _collectionEditor.SetModState(collection, mod, enabled) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
}
|
||||
|
||||
public PenumbraApiEc TrySetModPriority(string collectionName, string modDirectory, string modName, int priority)
|
||||
|
|
@ -726,7 +720,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
if (!_modManager.TryGetMod(modDirectory, modName, out var mod))
|
||||
return PenumbraApiEc.ModMissing;
|
||||
|
||||
return collection.SetModPriority(mod.Index, priority) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
return _collectionEditor.SetModPriority(collection, mod, priority) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
}
|
||||
|
||||
public PenumbraApiEc TrySetModSetting(string collectionName, string modDirectory, string modName, string optionGroupName,
|
||||
|
|
@ -749,7 +743,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
var setting = mod.Groups[groupIdx].Type == GroupType.Multi ? 1u << optionIdx : (uint)optionIdx;
|
||||
|
||||
return collection.SetModSetting(mod.Index, groupIdx, setting) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
return _collectionEditor.SetModSetting(collection, mod, groupIdx, setting) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
}
|
||||
|
||||
public PenumbraApiEc TrySetModSettings(string collectionName, string modDirectory, string modName, string optionGroupName,
|
||||
|
|
@ -789,7 +783,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
}
|
||||
}
|
||||
|
||||
return collection.SetModSetting(mod.Index, groupIdx, setting) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
return _collectionEditor.SetModSetting(collection, mod, groupIdx, setting) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -797,17 +791,13 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
{
|
||||
CheckInitialized();
|
||||
|
||||
var sourceModIdx = _modManager
|
||||
.FirstOrDefault(m => string.Equals(m.ModPath.Name, modDirectoryFrom, StringComparison.OrdinalIgnoreCase))?.Index
|
||||
?? -1;
|
||||
var targetModIdx = _modManager
|
||||
.FirstOrDefault(m => string.Equals(m.ModPath.Name, modDirectoryTo, StringComparison.OrdinalIgnoreCase))?.Index
|
||||
?? -1;
|
||||
var sourceMod = _modManager.FirstOrDefault(m => string.Equals(m.ModPath.Name, modDirectoryFrom, StringComparison.OrdinalIgnoreCase));
|
||||
var targetMod = _modManager.FirstOrDefault(m => string.Equals(m.ModPath.Name, modDirectoryTo, StringComparison.OrdinalIgnoreCase));
|
||||
if (string.IsNullOrEmpty(collectionName))
|
||||
foreach (var collection in _collectionManager.Storage)
|
||||
collection.CopyModSettings(sourceModIdx, modDirectoryFrom, targetModIdx, modDirectoryTo);
|
||||
_collectionEditor.CopyModSettings(collection, sourceMod, modDirectoryFrom, targetMod, modDirectoryTo);
|
||||
else if (_collectionManager.Storage.ByName(collectionName, out var collection))
|
||||
collection.CopyModSettings(sourceModIdx, modDirectoryFrom, targetModIdx, modDirectoryTo);
|
||||
_collectionEditor.CopyModSettings(collection, sourceMod, modDirectoryFrom, targetMod, modDirectoryTo);
|
||||
else
|
||||
return PenumbraApiEc.CollectionMissing;
|
||||
|
||||
|
|
@ -1127,29 +1117,6 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return true;
|
||||
}
|
||||
|
||||
private void SubscribeToCollection(ModCollection c)
|
||||
{
|
||||
var name = c.Name;
|
||||
|
||||
void Del(ModSettingChange type, int idx, int _, int _2, bool inherited)
|
||||
=> ModSettingChanged?.Invoke(type, name, idx >= 0 ? _modManager[idx].ModPath.Name : string.Empty, inherited);
|
||||
|
||||
_delegates[c] = Del;
|
||||
c.ModSettingChanged += Del;
|
||||
}
|
||||
|
||||
private void SubscribeToNewCollections(CollectionType type, ModCollection? oldCollection, ModCollection? newCollection, string _)
|
||||
{
|
||||
if (type != CollectionType.Inactive)
|
||||
return;
|
||||
|
||||
if (oldCollection != null && _delegates.TryGetValue(oldCollection, out var del))
|
||||
oldCollection.ModSettingChanged -= del;
|
||||
|
||||
if (newCollection != null)
|
||||
SubscribeToCollection(newCollection);
|
||||
}
|
||||
|
||||
public void InvokePreSettingsPanel(string modDirectory)
|
||||
=> PreSettingsPanelDraw?.Invoke(modDirectory);
|
||||
|
||||
|
|
@ -1166,4 +1133,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
var b = ByteString.FromStringUnsafe(name, false);
|
||||
return _actors.AwaitedService.CreatePlayer(b, worldId);
|
||||
}
|
||||
|
||||
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int _1, int _2, bool inherited)
|
||||
=> ModSettingChanged?.Invoke(type, collection.Name, mod?.ModPath.Name ?? string.Empty, inherited);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
|
|
@ -16,6 +18,7 @@ public class CollectionCacheManager : IDisposable, IReadOnlyDictionary<ModCollec
|
|||
{
|
||||
private readonly ActiveCollections _active;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly CharacterUtility _characterUtility;
|
||||
|
||||
private readonly Dictionary<ModCollection, ModCollectionCache> _cache = new();
|
||||
|
||||
|
|
@ -46,17 +49,23 @@ public class CollectionCacheManager : IDisposable, IReadOnlyDictionary<ModCollec
|
|||
public IEnumerable<ModCollection> Active
|
||||
=> _cache.Keys.Where(c => c.Index > ModCollection.Empty.Index);
|
||||
|
||||
public CollectionCacheManager(ActiveCollections active, CommunicatorService communicator)
|
||||
public CollectionCacheManager(ActiveCollections active, CommunicatorService communicator, CharacterUtility characterUtility)
|
||||
{
|
||||
_active = active;
|
||||
_communicator = communicator;
|
||||
_active = active;
|
||||
_communicator = communicator;
|
||||
_characterUtility = characterUtility;
|
||||
|
||||
_communicator.CollectionChange.Subscribe(OnCollectionChange);
|
||||
_communicator.ModPathChanged.Subscribe(OnModChangeAddition, -100);
|
||||
_communicator.ModPathChanged.Subscribe(OnModChangeRemoval, 100);
|
||||
_communicator.TemporaryGlobalModChange.Subscribe(OnGlobalModChange);
|
||||
_communicator.ModOptionChanged.Subscribe(OnModOptionChange, -100);
|
||||
_communicator.ModSettingChanged.Subscribe(OnModSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Subscribe(OnCollectionInheritanceChange);
|
||||
CreateNecessaryCaches();
|
||||
|
||||
if (!_characterUtility.Ready)
|
||||
_characterUtility.LoadingFinished += IncrementCounters;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -66,6 +75,9 @@ public class CollectionCacheManager : IDisposable, IReadOnlyDictionary<ModCollec
|
|||
_communicator.ModPathChanged.Unsubscribe(OnModChangeRemoval);
|
||||
_communicator.TemporaryGlobalModChange.Unsubscribe(OnGlobalModChange);
|
||||
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
|
||||
_communicator.ModSettingChanged.Unsubscribe(OnModSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Unsubscribe(OnCollectionInheritanceChange);
|
||||
_characterUtility.LoadingFinished -= IncrementCounters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -170,4 +182,57 @@ public class CollectionCacheManager : IDisposable, IReadOnlyDictionary<ModCollec
|
|||
collection._cache!.AddMod(mod, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Increment the counter to ensure new files are loaded after applying meta changes. </summary>
|
||||
private void IncrementCounters()
|
||||
{
|
||||
foreach (var (collection, _) in _cache)
|
||||
++collection.ChangeCounter;
|
||||
_characterUtility.LoadingFinished -= IncrementCounters;
|
||||
}
|
||||
|
||||
private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool _)
|
||||
{
|
||||
if (collection._cache == null)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ModSettingChange.Inheritance:
|
||||
collection._cache.ReloadMod(mod!, true);
|
||||
break;
|
||||
case ModSettingChange.EnableState:
|
||||
if (oldValue == 0)
|
||||
collection._cache.AddMod(mod!, true);
|
||||
else if (oldValue == 1)
|
||||
collection._cache.RemoveMod(mod!, true);
|
||||
else if (collection[mod!.Index].Settings?.Enabled == true)
|
||||
collection._cache.ReloadMod(mod!, true);
|
||||
else
|
||||
collection._cache.RemoveMod(mod!, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.Priority:
|
||||
if (collection._cache.Conflicts(mod!).Count > 0)
|
||||
collection._cache.ReloadMod(mod!, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.Setting:
|
||||
if (collection[mod!.Index].Settings?.Enabled == true)
|
||||
collection._cache.ReloadMod(mod!, true);
|
||||
|
||||
break;
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
collection._cache.FullRecalculation(collection == _active.Default);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inheritance changes are too big to check for relevance,
|
||||
/// just recompute everything.
|
||||
/// </summary>
|
||||
private void OnCollectionInheritanceChange(ModCollection collection, bool _)
|
||||
=> collection._cache?.FullRecalculation(collection == _active.Default);
|
||||
}
|
||||
|
|
|
|||
230
Penumbra/Collections/Manager/CollectionEditor.cs
Normal file
230
Penumbra/Collections/Manager/CollectionEditor.cs
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OtterGui;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Collections.Manager;
|
||||
|
||||
public class CollectionEditor
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly SaveService _saveService;
|
||||
|
||||
public CollectionEditor(SaveService saveService, CommunicatorService communicator)
|
||||
{
|
||||
_saveService = saveService;
|
||||
_communicator = communicator;
|
||||
}
|
||||
|
||||
/// <summary> Enable or disable the mod inheritance of mod idx. </summary>
|
||||
public bool SetModInheritance(ModCollection collection, Mod mod, bool inherit)
|
||||
{
|
||||
if (!FixInheritance(collection, mod, inherit))
|
||||
return false;
|
||||
|
||||
InvokeChange(collection, ModSettingChange.Inheritance, mod, inherit ? 0 : 1, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the enabled state mod idx to newValue if it differs from the current enabled state.
|
||||
/// If the mod is currently inherited, stop the inheritance.
|
||||
/// </summary>
|
||||
public bool SetModState(ModCollection collection, Mod mod, bool newValue)
|
||||
{
|
||||
var oldValue = collection._settings[mod.Index]?.Enabled ?? collection[mod.Index].Settings?.Enabled ?? false;
|
||||
if (newValue == oldValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance(collection, mod, false);
|
||||
collection._settings[mod.Index]!.Enabled = newValue;
|
||||
InvokeChange(collection, ModSettingChange.EnableState, mod, inheritance ? -1 : newValue ? 0 : 1, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Enable or disable the mod inheritance of every mod in mods. </summary>
|
||||
public void SetMultipleModInheritances(ModCollection collection, IEnumerable<Mod> mods, bool inherit)
|
||||
{
|
||||
if (!mods.Aggregate(false, (current, mod) => current | FixInheritance(collection, mod, inherit)))
|
||||
return;
|
||||
|
||||
InvokeChange(collection, ModSettingChange.MultiInheritance, null, -1, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the enabled state of every mod in mods to the new value.
|
||||
/// If the mod is currently inherited, stop the inheritance.
|
||||
/// </summary>
|
||||
public void SetMultipleModStates(ModCollection collection, IEnumerable<Mod> mods, bool newValue)
|
||||
{
|
||||
var changes = false;
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
var oldValue = collection._settings[mod.Index]?.Enabled;
|
||||
if (newValue == oldValue)
|
||||
continue;
|
||||
|
||||
FixInheritance(collection, mod, false);
|
||||
collection._settings[mod.Index]!.Enabled = newValue;
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (!changes)
|
||||
return;
|
||||
|
||||
InvokeChange(collection, ModSettingChange.MultiEnableState, null, -1, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the priority of mod idx to newValue if it differs from the current priority.
|
||||
/// If the mod is currently inherited, stop the inheritance.
|
||||
/// </summary>
|
||||
public bool SetModPriority(ModCollection collection, Mod mod, int newValue)
|
||||
{
|
||||
var oldValue = collection._settings[mod.Index]?.Priority ?? collection[mod.Index].Settings?.Priority ?? 0;
|
||||
if (newValue == oldValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance(collection, mod, false);
|
||||
collection._settings[mod.Index]!.Priority = newValue;
|
||||
InvokeChange(collection, ModSettingChange.Priority, mod, inheritance ? -1 : oldValue, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a given setting group settingName of mod idx to newValue if it differs from the current value and fix it if necessary.
|
||||
/// /// If the mod is currently inherited, stop the inheritance.
|
||||
/// </summary>
|
||||
public bool SetModSetting(ModCollection collection, Mod mod, int groupIdx, uint newValue)
|
||||
{
|
||||
var settings = collection._settings[mod.Index] != null
|
||||
? collection._settings[mod.Index]!.Settings
|
||||
: collection[mod.Index].Settings?.Settings;
|
||||
var oldValue = settings?[groupIdx] ?? mod.Groups[groupIdx].DefaultSettings;
|
||||
if (oldValue == newValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance(collection, mod, false);
|
||||
collection._settings[mod.Index]!.SetValue(mod, groupIdx, newValue);
|
||||
InvokeChange(collection, ModSettingChange.Setting, mod, inheritance ? -1 : (int)oldValue, groupIdx);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Copy the settings of an existing (sourceMod != null) or stored (sourceName) mod to another mod, if they exist. </summary>
|
||||
public bool CopyModSettings(ModCollection collection, Mod? sourceMod, string sourceName, Mod? targetMod, string targetName)
|
||||
{
|
||||
if (targetName.Length == 0 && targetMod == null || sourceName.Length == 0)
|
||||
return false;
|
||||
|
||||
// If the source mod exists, convert its settings to saved settings or null if its inheriting.
|
||||
// If it does not exist, check unused settings.
|
||||
// If it does not exist and has no unused settings, also use null.
|
||||
ModSettings.SavedSettings? savedSettings = sourceMod != null
|
||||
? collection._settings[sourceMod.Index] != null
|
||||
? new ModSettings.SavedSettings(collection._settings[sourceMod.Index]!, sourceMod)
|
||||
: null
|
||||
: collection._unusedSettings.TryGetValue(sourceName, out var s)
|
||||
? s
|
||||
: null;
|
||||
|
||||
if (targetMod != null)
|
||||
{
|
||||
if (savedSettings != null)
|
||||
{
|
||||
// The target mod exists and the source settings are not inheriting, convert and fix the settings and copy them.
|
||||
// This triggers multiple events.
|
||||
savedSettings.Value.ToSettings(targetMod, out var settings);
|
||||
SetModState(collection, targetMod, settings.Enabled);
|
||||
SetModPriority(collection, targetMod, settings.Priority);
|
||||
foreach (var (value, index) in settings.Settings.WithIndex())
|
||||
SetModSetting(collection, targetMod, index, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The target mod exists, but the source is inheriting, set the target to inheriting.
|
||||
// This triggers events.
|
||||
SetModInheritance(collection, targetMod, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The target mod does not exist.
|
||||
// Either copy the unused source settings directly if they are not inheriting,
|
||||
// or remove any unused settings for the target if they are inheriting.
|
||||
if (savedSettings != null)
|
||||
collection._unusedSettings[targetName] = savedSettings.Value;
|
||||
else
|
||||
collection._unusedSettings.Remove(targetName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change one of the available mod settings for mod idx discerned by type.
|
||||
/// If type == Setting, settingName should be a valid setting for that mod, otherwise it will be ignored.
|
||||
/// The setting will also be automatically fixed if it is invalid for that setting group.
|
||||
/// For boolean parameters, newValue == 0 will be treated as false and != 0 as true.
|
||||
/// </summary>
|
||||
public bool ChangeModSetting(ModCollection collection, ModSettingChange type, Mod mod, int newValue, int groupIdx)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ModSettingChange.Inheritance => SetModInheritance(collection, mod, newValue != 0),
|
||||
ModSettingChange.EnableState => SetModState(collection, mod, newValue != 0),
|
||||
ModSettingChange.Priority => SetModPriority(collection, mod, newValue),
|
||||
ModSettingChange.Setting => SetModSetting(collection, mod, groupIdx, (uint)newValue),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set inheritance of a mod without saving,
|
||||
/// to be used as an intermediary.
|
||||
/// </summary>
|
||||
private static bool FixInheritance(ModCollection collection, Mod mod, bool inherit)
|
||||
{
|
||||
var settings = collection._settings[mod.Index];
|
||||
if (inherit == (settings == null))
|
||||
return false;
|
||||
|
||||
collection._settings[mod.Index] = inherit ? null : collection[mod.Index].Settings?.DeepCopy() ?? ModSettings.DefaultSettings(mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary> Queue saves and trigger changes for any non-inherited change in a collection, then trigger changes for all inheritors. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private void InvokeChange(ModCollection changedCollection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx)
|
||||
{
|
||||
_saveService.QueueSave(changedCollection);
|
||||
_communicator.ModSettingChanged.Invoke(changedCollection, type, mod, oldValue, groupIdx, false);
|
||||
RecurseInheritors(changedCollection, type, mod, oldValue, groupIdx);
|
||||
}
|
||||
|
||||
/// <summary> Trigger changes in all inherited collections. </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private void RecurseInheritors(ModCollection directParent, ModSettingChange type, Mod? mod, int oldValue, int groupIdx)
|
||||
{
|
||||
foreach (var directInheritor in directParent.DirectParentOf)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
_communicator.ModSettingChanged.Invoke(directInheritor, type, null, oldValue, groupIdx, true);
|
||||
break;
|
||||
default:
|
||||
if (directInheritor._settings[mod!.Index] == null)
|
||||
_communicator.ModSettingChanged.Invoke(directInheritor, type, mod, oldValue, groupIdx, true);
|
||||
break;
|
||||
}
|
||||
|
||||
RecurseInheritors(directInheritor, type, mod, oldValue, groupIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,14 +7,16 @@ public class CollectionManager
|
|||
public readonly InheritanceManager Inheritances;
|
||||
public readonly CollectionCacheManager Caches;
|
||||
public readonly TempCollectionManager Temp;
|
||||
public readonly CollectionEditor Editor;
|
||||
|
||||
public CollectionManager(CollectionStorage storage, ActiveCollections active, InheritanceManager inheritances,
|
||||
CollectionCacheManager caches, TempCollectionManager temp)
|
||||
CollectionCacheManager caches, TempCollectionManager temp, CollectionEditor editor)
|
||||
{
|
||||
Storage = storage;
|
||||
Active = active;
|
||||
Inheritances = inheritances;
|
||||
Caches = caches;
|
||||
Temp = temp;
|
||||
Editor = editor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using OtterGui;
|
||||
using OtterGui.Filesystem;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Collections.Manager;
|
||||
|
||||
/// <summary>
|
||||
/// ModCollections can inherit from an arbitrary number of other collections.
|
||||
/// This is transitive, so a collection A inheriting from B also inherits from everything B inherits.
|
||||
/// Circular dependencies are resolved by distinctness.
|
||||
/// </summary>
|
||||
public class InheritanceManager : IDisposable
|
||||
{
|
||||
public enum ValidInheritance
|
||||
{
|
||||
Valid,
|
||||
/// <summary> Can not inherit from self </summary>
|
||||
Self,
|
||||
/// <summary> Can not inherit from the empty collection </summary>
|
||||
Empty,
|
||||
/// <summary> Already inherited from </summary>
|
||||
Contained,
|
||||
/// <summary> Inheritance would lead to a circle. </summary>
|
||||
Circle,
|
||||
}
|
||||
|
||||
private readonly CollectionStorage _storage;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly SaveService _saveService;
|
||||
|
|
@ -26,22 +48,88 @@ public class InheritanceManager : IDisposable
|
|||
_communicator.CollectionChange.Unsubscribe(OnCollectionChange);
|
||||
}
|
||||
|
||||
/// <summary> Check whether a collection can be inherited from. </summary>
|
||||
public static ValidInheritance CheckValidInheritance(ModCollection potentialInheritor, ModCollection? potentialParent)
|
||||
{
|
||||
if (potentialParent == null || ReferenceEquals(potentialParent, ModCollection.Empty))
|
||||
return ValidInheritance.Empty;
|
||||
|
||||
if (ReferenceEquals(potentialParent, potentialInheritor))
|
||||
return ValidInheritance.Self;
|
||||
|
||||
if (potentialInheritor.DirectlyInheritsFrom.Contains(potentialParent))
|
||||
return ValidInheritance.Contained;
|
||||
|
||||
if (ModCollection.InheritedCollections(potentialParent).Any(c => ReferenceEquals(c, potentialInheritor)))
|
||||
return ValidInheritance.Circle;
|
||||
|
||||
return ValidInheritance.Valid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool AddInheritance(ModCollection inheritor, ModCollection parent)
|
||||
=> AddInheritance(inheritor, parent, true);
|
||||
|
||||
/// <summary> Remove an existing inheritance from a collection. </summary>
|
||||
public void RemoveInheritance(ModCollection inheritor, int idx)
|
||||
{
|
||||
var parent = inheritor.DirectlyInheritsFrom[idx];
|
||||
((List<ModCollection>)inheritor.DirectlyInheritsFrom).RemoveAt(idx);
|
||||
((List<ModCollection>)parent.DirectParentOf).Remove(inheritor);
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
RecurseInheritanceChanges(inheritor);
|
||||
Penumbra.Log.Debug($"Removed {parent.AnonymizedName} from {inheritor.AnonymizedName} inheritances.");
|
||||
}
|
||||
|
||||
/// <summary> Order in the inheritance list is relevant. </summary>
|
||||
public void MoveInheritance(ModCollection inheritor, int from, int to)
|
||||
{
|
||||
if (!((List<ModCollection>)inheritor.DirectlyInheritsFrom).Move(from, to))
|
||||
return;
|
||||
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
RecurseInheritanceChanges(inheritor);
|
||||
Penumbra.Log.Debug($"Moved {inheritor.AnonymizedName}s inheritance {from} to {to}.");
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="AddInheritance(ModCollection, ModCollection)"/>
|
||||
private bool AddInheritance(ModCollection inheritor, ModCollection parent, bool invokeEvent)
|
||||
{
|
||||
if (CheckValidInheritance(inheritor, parent) != ValidInheritance.Valid)
|
||||
return false;
|
||||
|
||||
((List<ModCollection>)inheritor.DirectlyInheritsFrom).Add(parent);
|
||||
((List<ModCollection>)parent.DirectParentOf).Add(inheritor);
|
||||
if (invokeEvent)
|
||||
{
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, false);
|
||||
RecurseInheritanceChanges(inheritor);
|
||||
}
|
||||
|
||||
Penumbra.Log.Debug($"Added {parent.AnonymizedName} to {inheritor.AnonymizedName} inheritances.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inheritances can not be setup before all collections are read,
|
||||
/// so this happens after reading the collections in the constructor, consuming the stored strings.
|
||||
/// </summary>
|
||||
private void ApplyInheritances()
|
||||
{
|
||||
foreach (var (collection, inheritances, changes) in _storage.ConsumeInheritanceNames())
|
||||
foreach (var (collection, directParents, changes) in _storage.ConsumeInheritanceNames())
|
||||
{
|
||||
var localChanges = changes;
|
||||
foreach (var subCollection in inheritances)
|
||||
foreach (var parent in directParents)
|
||||
{
|
||||
if (collection.AddInheritance(subCollection, false))
|
||||
if (AddInheritance(collection, parent, false))
|
||||
continue;
|
||||
|
||||
localChanges = true;
|
||||
Penumbra.ChatService.NotificationMessage($"{collection.Name} can not inherit from {subCollection.Name}, removed.", "Warning",
|
||||
Penumbra.ChatService.NotificationMessage($"{collection.Name} can not inherit from {parent.Name}, removed.", "Warning",
|
||||
NotificationType.Warning);
|
||||
}
|
||||
|
||||
|
|
@ -55,14 +143,22 @@ public class InheritanceManager : IDisposable
|
|||
if (collectionType is not CollectionType.Inactive || old == null)
|
||||
return;
|
||||
|
||||
foreach (var inheritance in old.Inheritance)
|
||||
old.ClearSubscriptions(inheritance);
|
||||
|
||||
foreach (var c in _storage)
|
||||
{
|
||||
var inheritedIdx = c._inheritance.IndexOf(old);
|
||||
var inheritedIdx = c.DirectlyInheritsFrom.IndexOf(old);
|
||||
if (inheritedIdx >= 0)
|
||||
c.RemoveInheritance(inheritedIdx);
|
||||
RemoveInheritance(c, inheritedIdx);
|
||||
|
||||
((List<ModCollection>)c.DirectParentOf).Remove(old);
|
||||
}
|
||||
}
|
||||
|
||||
private void RecurseInheritanceChanges(ModCollection newInheritor)
|
||||
{
|
||||
foreach (var inheritor in newInheritor.DirectParentOf)
|
||||
{
|
||||
_communicator.CollectionInheritanceChanged.Invoke(inheritor, true);
|
||||
RecurseInheritanceChanges(inheritor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,21 +50,12 @@ public class ModCollectionCache : IDisposable
|
|||
public ModCollectionCache( ModCollection collection )
|
||||
{
|
||||
_collection = collection;
|
||||
MetaManipulations = new MetaManager( _collection );
|
||||
_collection.ModSettingChanged += OnModSettingChange;
|
||||
_collection.InheritanceChanged += OnInheritanceChange;
|
||||
if( !Penumbra.CharacterUtility.Ready )
|
||||
{
|
||||
Penumbra.CharacterUtility.LoadingFinished += IncrementCounter;
|
||||
}
|
||||
MetaManipulations = new MetaManager( _collection );
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MetaManipulations.Dispose();
|
||||
_collection.ModSettingChanged -= OnModSettingChange;
|
||||
_collection.InheritanceChanged -= OnInheritanceChange;
|
||||
Penumbra.CharacterUtility.LoadingFinished -= IncrementCounter;
|
||||
}
|
||||
|
||||
// Resolve a given game path according to this collection.
|
||||
|
|
@ -133,58 +124,6 @@ public class ModCollectionCache : IDisposable
|
|||
return ret;
|
||||
}
|
||||
|
||||
private void OnModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
case ModSettingChange.Inheritance:
|
||||
ReloadMod( Penumbra.ModManager[ modIdx ], true );
|
||||
break;
|
||||
case ModSettingChange.EnableState:
|
||||
if( oldValue == 0 )
|
||||
{
|
||||
AddMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
else if( oldValue == 1 )
|
||||
{
|
||||
RemoveMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
else if( _collection[ modIdx ].Settings?.Enabled == true )
|
||||
{
|
||||
ReloadMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
|
||||
break;
|
||||
case ModSettingChange.Priority:
|
||||
if( Conflicts( Penumbra.ModManager[ modIdx ] ).Count > 0 )
|
||||
{
|
||||
ReloadMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
|
||||
break;
|
||||
case ModSettingChange.Setting:
|
||||
if( _collection[ modIdx ].Settings?.Enabled == true )
|
||||
{
|
||||
ReloadMod( Penumbra.ModManager[ modIdx ], true );
|
||||
}
|
||||
|
||||
break;
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
FullRecalculation(_collection == Penumbra.CollectionManager.Active.Default);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Inheritance changes are too big to check for relevance,
|
||||
// just recompute everything.
|
||||
private void OnInheritanceChange( bool _ )
|
||||
=> FullRecalculation(_collection == Penumbra.CollectionManager.Active.Default);
|
||||
|
||||
public void FullRecalculation(bool isDefault)
|
||||
{
|
||||
ResolvedFiles.Clear();
|
||||
|
|
|
|||
|
|
@ -1,138 +0,0 @@
|
|||
using Penumbra.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Penumbra.Api.Enums;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
||||
public partial class ModCollection
|
||||
{
|
||||
// If the change type is a bool, oldValue will be 1 for true and 0 for false.
|
||||
// optionName will only be set for type == Setting.
|
||||
public delegate void ModSettingChangeDelegate( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool inherited );
|
||||
public event ModSettingChangeDelegate ModSettingChanged;
|
||||
|
||||
// Enable or disable the mod inheritance of mod idx.
|
||||
public bool SetModInheritance( int idx, bool inherit )
|
||||
{
|
||||
if (!FixInheritance(idx, inherit))
|
||||
return false;
|
||||
|
||||
ModSettingChanged.Invoke( ModSettingChange.Inheritance, idx, inherit ? 0 : 1, 0, false );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Set the enabled state mod idx to newValue if it differs from the current enabled state.
|
||||
// If mod idx is currently inherited, stop the inheritance.
|
||||
public bool SetModState( int idx, bool newValue )
|
||||
{
|
||||
var oldValue = _settings[ idx ]?.Enabled ?? this[ idx ].Settings?.Enabled ?? false;
|
||||
if (newValue == oldValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance( idx, false );
|
||||
_settings[ idx ]!.Enabled = newValue;
|
||||
ModSettingChanged.Invoke( ModSettingChange.EnableState, idx, inheritance ? -1 : newValue ? 0 : 1, 0, false );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Enable or disable the mod inheritance of every mod in mods.
|
||||
public void SetMultipleModInheritances( IEnumerable< Mod > mods, bool inherit )
|
||||
{
|
||||
if( mods.Aggregate( false, ( current, mod ) => current | FixInheritance( mod.Index, inherit ) ) )
|
||||
ModSettingChanged.Invoke( ModSettingChange.MultiInheritance, -1, -1, 0, false );
|
||||
}
|
||||
|
||||
// Set the enabled state of every mod in mods to the new value.
|
||||
// If the mod is currently inherited, stop the inheritance.
|
||||
public void SetMultipleModStates( IEnumerable< Mod > mods, bool newValue )
|
||||
{
|
||||
var changes = false;
|
||||
foreach( var mod in mods )
|
||||
{
|
||||
var oldValue = _settings[ mod.Index ]?.Enabled;
|
||||
if (newValue == oldValue)
|
||||
continue;
|
||||
|
||||
FixInheritance( mod.Index, false );
|
||||
_settings[ mod.Index ]!.Enabled = newValue;
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if( changes )
|
||||
{
|
||||
ModSettingChanged.Invoke( ModSettingChange.MultiEnableState, -1, -1, 0, false );
|
||||
}
|
||||
}
|
||||
|
||||
// Set the priority of mod idx to newValue if it differs from the current priority.
|
||||
// If mod idx is currently inherited, stop the inheritance.
|
||||
public bool SetModPriority( int idx, int newValue )
|
||||
{
|
||||
var oldValue = _settings[ idx ]?.Priority ?? this[ idx ].Settings?.Priority ?? 0;
|
||||
if (newValue == oldValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance( idx, false );
|
||||
_settings[ idx ]!.Priority = newValue;
|
||||
ModSettingChanged.Invoke( ModSettingChange.Priority, idx, inheritance ? -1 : oldValue, 0, false );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Set a given setting group settingName of mod idx to newValue if it differs from the current value and fix it if necessary.
|
||||
// If mod idx is currently inherited, stop the inheritance.
|
||||
public bool SetModSetting( int idx, int groupIdx, uint newValue )
|
||||
{
|
||||
var settings = _settings[ idx ] != null ? _settings[ idx ]!.Settings : this[ idx ].Settings?.Settings;
|
||||
var oldValue = settings?[ groupIdx ] ?? Penumbra.ModManager[idx].Groups[groupIdx].DefaultSettings;
|
||||
if (oldValue == newValue)
|
||||
return false;
|
||||
|
||||
var inheritance = FixInheritance( idx, false );
|
||||
_settings[ idx ]!.SetValue( Penumbra.ModManager[ idx ], groupIdx, newValue );
|
||||
ModSettingChanged.Invoke( ModSettingChange.Setting, idx, inheritance ? -1 : ( int )oldValue, groupIdx, false );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Change one of the available mod settings for mod idx discerned by type.
|
||||
// If type == Setting, settingName should be a valid setting for that mod, otherwise it will be ignored.
|
||||
// The setting will also be automatically fixed if it is invalid for that setting group.
|
||||
// For boolean parameters, newValue == 0 will be treated as false and != 0 as true.
|
||||
public bool ChangeModSetting( ModSettingChange type, int idx, int newValue, int groupIdx )
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ModSettingChange.Inheritance => SetModInheritance( idx, newValue != 0 ),
|
||||
ModSettingChange.EnableState => SetModState( idx, newValue != 0 ),
|
||||
ModSettingChange.Priority => SetModPriority( idx, newValue ),
|
||||
ModSettingChange.Setting => SetModSetting( idx, groupIdx, ( uint )newValue ),
|
||||
_ => throw new ArgumentOutOfRangeException( nameof( type ), type, null ),
|
||||
};
|
||||
}
|
||||
|
||||
// Set inheritance of a mod without saving,
|
||||
// to be used as an intermediary.
|
||||
private bool FixInheritance( int idx, bool inherit )
|
||||
{
|
||||
var settings = _settings[ idx ];
|
||||
if( inherit == ( settings == null ) )
|
||||
return false;
|
||||
|
||||
_settings[ idx ] = inherit ? null : this[ idx ].Settings?.DeepCopy() ?? ModSettings.DefaultSettings( Penumbra.ModManager[ idx ] );
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SaveOnChange( ModSettingChange _1, int _2, int _3, int _4, bool inherited )
|
||||
=> SaveOnChange( inherited );
|
||||
|
||||
private void SaveOnChange( bool inherited )
|
||||
{
|
||||
if( !inherited )
|
||||
Penumbra.SaveService.QueueSave(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ public partial class ModCollection : ISavable
|
|||
// Custom deserialization that is converted with the constructor.
|
||||
var settings = obj[nameof(Settings)]?.ToObject<Dictionary<string, ModSettings.SavedSettings>>()
|
||||
?? new Dictionary<string, ModSettings.SavedSettings>();
|
||||
inheritance = obj[nameof(Inheritance)]?.ToObject<List<string>>() ?? (IReadOnlyList<string>)Array.Empty<string>();
|
||||
inheritance = obj["Inheritance"]?.ToObject<List<string>>() ?? (IReadOnlyList<string>)Array.Empty<string>();
|
||||
|
||||
return new ModCollection(name, version, settings);
|
||||
}
|
||||
|
|
@ -86,8 +86,8 @@ public partial class ModCollection : ISavable
|
|||
j.WriteEndObject();
|
||||
|
||||
// Inherit by collection name.
|
||||
j.WritePropertyName(nameof(Inheritance));
|
||||
x.Serialize(j, Inheritance.Select(c => c.Name));
|
||||
j.WritePropertyName("Inheritance");
|
||||
x.Serialize(j, DirectlyInheritsFrom.Select(c => c.Name));
|
||||
j.WriteEndObject();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
using OtterGui.Filesystem;
|
||||
using Penumbra.Mods;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Penumbra.Api.Enums;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
||||
// ModCollections can inherit from an arbitrary number of other collections.
|
||||
// This is transitive, so a collection A inheriting from B also inherits from everything B inherits.
|
||||
// Circular dependencies are resolved by distinctness.
|
||||
public partial class ModCollection
|
||||
{
|
||||
// A change in inheritance usually requires complete recomputation.
|
||||
// The bool signifies whether the change was in an already inherited collection.
|
||||
public event Action< bool > InheritanceChanged;
|
||||
|
||||
internal readonly List< ModCollection > _inheritance = new();
|
||||
|
||||
public IReadOnlyList< ModCollection > Inheritance
|
||||
=> _inheritance;
|
||||
|
||||
// Iterate over all collections inherited from in depth-first order.
|
||||
// Skip already visited collections to avoid circular dependencies.
|
||||
public IEnumerable< ModCollection > GetFlattenedInheritance()
|
||||
=> InheritedCollections( this ).Distinct();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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, bool invokeEvent )
|
||||
{
|
||||
if( CheckValidInheritance( collection ) != ValidInheritance.Valid )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_inheritance.Add( collection );
|
||||
// Changes in inherited collections may need to trigger further changes here.
|
||||
collection.ModSettingChanged += OnInheritedModSettingChange;
|
||||
collection.InheritanceChanged += OnInheritedInheritanceChange;
|
||||
if( invokeEvent )
|
||||
{
|
||||
InheritanceChanged.Invoke( false );
|
||||
}
|
||||
|
||||
Penumbra.Log.Debug( $"Added {collection.AnonymizedName} to {AnonymizedName} inheritances." );
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveInheritance( int idx )
|
||||
{
|
||||
var inheritance = _inheritance[ idx ];
|
||||
ClearSubscriptions( inheritance );
|
||||
_inheritance.RemoveAt( idx );
|
||||
InheritanceChanged.Invoke( false );
|
||||
Penumbra.Log.Debug( $"Removed {inheritance.AnonymizedName} from {AnonymizedName} inheritances." );
|
||||
}
|
||||
|
||||
internal void ClearSubscriptions( ModCollection other )
|
||||
{
|
||||
other.ModSettingChanged -= OnInheritedModSettingChange;
|
||||
other.InheritanceChanged -= OnInheritedInheritanceChange;
|
||||
}
|
||||
|
||||
// Order in the inheritance list is relevant.
|
||||
public void MoveInheritance( int from, int to )
|
||||
{
|
||||
if( _inheritance.Move( from, to ) )
|
||||
{
|
||||
InheritanceChanged.Invoke( false );
|
||||
Penumbra.Log.Debug( $"Moved {AnonymizedName}s inheritance {from} to {to}." );
|
||||
}
|
||||
}
|
||||
|
||||
// Carry changes in collections inherited from forward if they are relevant for this collection.
|
||||
private void OnInheritedModSettingChange( ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool _ )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
ModSettingChanged.Invoke( type, modIdx, oldValue, groupIdx, true );
|
||||
return;
|
||||
default:
|
||||
if( modIdx < 0 || modIdx >= _settings.Count )
|
||||
{
|
||||
Penumbra.Log.Warning(
|
||||
$"Collection state broken, Mod {modIdx} in inheritance does not exist. ({_settings.Count} mods exist)." );
|
||||
return;
|
||||
}
|
||||
|
||||
if( _settings[ modIdx ] == null )
|
||||
{
|
||||
ModSettingChanged.Invoke( type, modIdx, oldValue, groupIdx, true );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInheritedInheritanceChange( bool _ )
|
||||
=> InheritanceChanged.Invoke( true );
|
||||
|
||||
// Obtain the actual settings for a given mod via index.
|
||||
// Also returns the collection the settings are taken from.
|
||||
// If no collection provides settings for this mod, this collection is returned together with null.
|
||||
public (ModSettings? Settings, ModCollection Collection) this[ Index idx ]
|
||||
{
|
||||
get
|
||||
{
|
||||
if( Index <= 0 )
|
||||
{
|
||||
return ( ModSettings.Empty, this );
|
||||
}
|
||||
|
||||
foreach( var collection in GetFlattenedInheritance() )
|
||||
{
|
||||
var settings = collection._settings[ idx ];
|
||||
if( settings != null )
|
||||
{
|
||||
return ( settings, collection );
|
||||
}
|
||||
}
|
||||
|
||||
return ( null, this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using Penumbra.Mods;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Collections;
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ namespace Penumbra.Collections;
|
|||
// - any change in settings or inheritance of the collection causes a Save.
|
||||
public partial class ModCollection
|
||||
{
|
||||
public const int CurrentVersion = 1;
|
||||
public const int CurrentVersion = 1;
|
||||
public const string DefaultCollectionName = "Default";
|
||||
public const string EmptyCollection = "None";
|
||||
public const string EmptyCollection = "None";
|
||||
|
||||
public static readonly ModCollection Empty = CreateEmpty();
|
||||
|
||||
|
|
@ -51,18 +51,18 @@ public partial class ModCollection
|
|||
=> Enumerable.Range(0, _settings.Count).Select(i => this[i].Settings);
|
||||
|
||||
// Settings for deleted mods will be kept via directory name.
|
||||
private readonly Dictionary<string, ModSettings.SavedSettings> _unusedSettings;
|
||||
internal readonly Dictionary<string, ModSettings.SavedSettings> _unusedSettings;
|
||||
|
||||
// Constructor for duplication.
|
||||
private ModCollection(string name, ModCollection duplicate)
|
||||
{
|
||||
Name = name;
|
||||
Version = duplicate.Version;
|
||||
_settings = duplicate._settings.ConvertAll(s => s?.DeepCopy());
|
||||
_unusedSettings = duplicate._unusedSettings.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.DeepCopy());
|
||||
_inheritance = duplicate._inheritance.ToList();
|
||||
ModSettingChanged += SaveOnChange;
|
||||
InheritanceChanged += SaveOnChange;
|
||||
Name = name;
|
||||
Version = duplicate.Version;
|
||||
_settings = duplicate._settings.ConvertAll(s => s?.DeepCopy());
|
||||
_unusedSettings = duplicate._unusedSettings.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.DeepCopy());
|
||||
DirectlyInheritsFrom = duplicate.DirectlyInheritsFrom.ToList();
|
||||
foreach (var c in DirectlyInheritsFrom)
|
||||
((List<ModCollection>)c.DirectParentOf).Add(this);
|
||||
}
|
||||
|
||||
// Constructor for reading from files.
|
||||
|
|
@ -76,8 +76,6 @@ public partial class ModCollection
|
|||
ApplyModSettings();
|
||||
|
||||
Migration.Migrate(Penumbra.SaveService, this);
|
||||
ModSettingChanged += SaveOnChange;
|
||||
InheritanceChanged += SaveOnChange;
|
||||
}
|
||||
|
||||
// Create a new, unique empty collection of a given name.
|
||||
|
|
@ -87,11 +85,11 @@ public partial class ModCollection
|
|||
// Create a new temporary collection that does not save and has a negative index.
|
||||
public static ModCollection CreateNewTemporary(string name, int changeCounter)
|
||||
{
|
||||
var collection = new ModCollection(name, Empty);
|
||||
collection.ModSettingChanged -= collection.SaveOnChange;
|
||||
collection.InheritanceChanged -= collection.SaveOnChange;
|
||||
collection.Index = ~Penumbra.TempCollections.Count;
|
||||
collection.ChangeCounter = changeCounter;
|
||||
var collection = new ModCollection(name, Empty)
|
||||
{
|
||||
Index = ~Penumbra.TempCollections.Count,
|
||||
ChangeCounter = changeCounter,
|
||||
};
|
||||
collection.CreateCache(false);
|
||||
return collection;
|
||||
}
|
||||
|
|
@ -162,55 +160,43 @@ public partial class ModCollection
|
|||
Penumbra.SaveService.ImmediateSave(this);
|
||||
}
|
||||
|
||||
public bool CopyModSettings(int modIdx, string modName, int targetIdx, string targetName)
|
||||
{
|
||||
if (targetName.Length == 0 && targetIdx < 0 || modName.Length == 0 && modIdx < 0)
|
||||
return false;
|
||||
|
||||
// If the source mod exists, convert its settings to saved settings or null if its inheriting.
|
||||
// If it does not exist, check unused settings.
|
||||
// If it does not exist and has no unused settings, also use null.
|
||||
ModSettings.SavedSettings? savedSettings = modIdx >= 0
|
||||
? _settings[modIdx] != null
|
||||
? new ModSettings.SavedSettings(_settings[modIdx]!, Penumbra.ModManager[modIdx])
|
||||
: null
|
||||
: _unusedSettings.TryGetValue(modName, out var s)
|
||||
? s
|
||||
: null;
|
||||
|
||||
if (targetIdx >= 0)
|
||||
{
|
||||
if (savedSettings != null)
|
||||
{
|
||||
// The target mod exists and the source settings are not inheriting, convert and fix the settings and copy them.
|
||||
// This triggers multiple events.
|
||||
savedSettings.Value.ToSettings(Penumbra.ModManager[targetIdx], out var settings);
|
||||
SetModState(targetIdx, settings.Enabled);
|
||||
SetModPriority(targetIdx, settings.Priority);
|
||||
foreach (var (value, index) in settings.Settings.WithIndex())
|
||||
SetModSetting(targetIdx, index, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The target mod exists, but the source is inheriting, set the target to inheriting.
|
||||
// This triggers events.
|
||||
SetModInheritance(targetIdx, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The target mod does not exist.
|
||||
// Either copy the unused source settings directly if they are not inheriting,
|
||||
// or remove any unused settings for the target if they are inheriting.
|
||||
if (savedSettings != null)
|
||||
_unusedSettings[targetName] = savedSettings.Value;
|
||||
else
|
||||
_unusedSettings.Remove(targetName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> Name;
|
||||
|
||||
/// <summary>
|
||||
/// Obtain the actual settings for a given mod via index.
|
||||
/// Also returns the collection the settings are taken from.
|
||||
/// If no collection provides settings for this mod, this collection is returned together with null.
|
||||
/// </summary>
|
||||
public (ModSettings? Settings, ModCollection Collection) this[Index idx]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Index <= 0)
|
||||
return (ModSettings.Empty, this);
|
||||
|
||||
foreach (var collection in GetFlattenedInheritance())
|
||||
{
|
||||
var settings = collection._settings[idx];
|
||||
if (settings != null)
|
||||
return (settings, collection);
|
||||
}
|
||||
|
||||
return (null, this);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly IReadOnlyList<ModCollection> DirectlyInheritsFrom = new List<ModCollection>();
|
||||
public readonly IReadOnlyList<ModCollection> DirectParentOf = new List<ModCollection>();
|
||||
|
||||
/// <summary> All inherited collections in application order without filtering for duplicates. </summary>
|
||||
public static IEnumerable<ModCollection> InheritedCollections(ModCollection collection)
|
||||
=> collection.DirectlyInheritsFrom.SelectMany(InheritedCollections).Prepend(collection);
|
||||
|
||||
/// <summary>
|
||||
/// Iterate over all collections inherited from in depth-first order.
|
||||
/// Skip already visited collections to avoid circular dependencies.
|
||||
/// </summary>
|
||||
public IEnumerable<ModCollection> GetFlattenedInheritance()
|
||||
=> InheritedCollections(this).Distinct();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ using Dalamud.Game.Text.SeStringHandling;
|
|||
using ImGuiNET;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.Interop.Services;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -23,18 +23,20 @@ public class CommandHandler : IDisposable
|
|||
{
|
||||
private const string CommandName = "/penumbra";
|
||||
|
||||
private readonly CommandManager _commandManager;
|
||||
private readonly RedrawService _redrawService;
|
||||
private readonly ChatGui _chat;
|
||||
private readonly Configuration _config;
|
||||
private readonly ConfigWindow _configWindow;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CommandManager _commandManager;
|
||||
private readonly RedrawService _redrawService;
|
||||
private readonly ChatGui _chat;
|
||||
private readonly Configuration _config;
|
||||
private readonly ConfigWindow _configWindow;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly Penumbra _penumbra;
|
||||
private readonly Penumbra _penumbra;
|
||||
private readonly CollectionEditor _collectionEditor;
|
||||
|
||||
public CommandHandler(Framework framework, CommandManager commandManager, ChatGui chat, RedrawService redrawService, Configuration config,
|
||||
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorService actors, Penumbra penumbra)
|
||||
ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorService actors, Penumbra penumbra,
|
||||
CollectionEditor collectionEditor)
|
||||
{
|
||||
_commandManager = commandManager;
|
||||
_redrawService = redrawService;
|
||||
|
|
@ -45,6 +47,7 @@ public class CommandHandler : IDisposable
|
|||
_actors = actors.AwaitedService;
|
||||
_chat = chat;
|
||||
_penumbra = penumbra;
|
||||
_collectionEditor = collectionEditor;
|
||||
framework.RunOnFrameworkThread(() =>
|
||||
{
|
||||
_commandManager.AddHandler(CommandName, new CommandInfo(OnCommand)
|
||||
|
|
@ -455,14 +458,15 @@ public class CommandHandler : IDisposable
|
|||
|
||||
collection = string.Equals(lowerName, ModCollection.Empty.Name, StringComparison.OrdinalIgnoreCase)
|
||||
? ModCollection.Empty
|
||||
: _collectionManager.Storage.ByName(lowerName, out var c) ? c : null;
|
||||
: _collectionManager.Storage.ByName(lowerName, out var c)
|
||||
? c
|
||||
: null;
|
||||
if (collection != null)
|
||||
return true;
|
||||
|
||||
_chat.Print(new SeStringBuilder().AddText("The collection ").AddRed(collectionName, true).AddText(" does not exist.")
|
||||
.BuiltString);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
private static bool? ParseTrueFalseToggle(string value)
|
||||
|
|
@ -498,51 +502,47 @@ public class CommandHandler : IDisposable
|
|||
|
||||
private bool HandleModState(int settingState, ModCollection collection, Mod mod)
|
||||
{
|
||||
var settings = collection!.Settings[mod.Index];
|
||||
var settings = collection.Settings[mod.Index];
|
||||
switch (settingState)
|
||||
{
|
||||
case 0:
|
||||
if (collection.SetModState(mod.Index, true))
|
||||
{
|
||||
Print(() => new SeStringBuilder().AddText("Enabled mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
}
|
||||
if (!_collectionEditor.SetModState(collection, mod, true))
|
||||
return false;
|
||||
|
||||
Print(() => new SeStringBuilder().AddText("Enabled mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case 1:
|
||||
if (collection.SetModState(mod.Index, false))
|
||||
{
|
||||
Print(() => new SeStringBuilder().AddText("Disabled mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
}
|
||||
if (!_collectionEditor.SetModState(collection, mod, false))
|
||||
return false;
|
||||
|
||||
Print(() => new SeStringBuilder().AddText("Disabled mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case 2:
|
||||
var setting = !(settings?.Enabled ?? false);
|
||||
if (collection.SetModState(mod.Index, setting))
|
||||
{
|
||||
Print(() => new SeStringBuilder().AddText(setting ? "Enabled mod " : "Disabled mod ").AddPurple(mod.Name, true)
|
||||
.AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
}
|
||||
if (!_collectionEditor.SetModState(collection, mod, setting))
|
||||
return false;
|
||||
|
||||
Print(() => new SeStringBuilder().AddText(setting ? "Enabled mod " : "Disabled mod ").AddPurple(mod.Name, true)
|
||||
.AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(".").BuiltString);
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case 3:
|
||||
if (collection.SetModInheritance(mod.Index, true))
|
||||
{
|
||||
Print(() => new SeStringBuilder().AddText("Set mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(" to inherit.").BuiltString);
|
||||
return true;
|
||||
}
|
||||
if (!_collectionEditor.SetModInheritance(collection, mod, true))
|
||||
return false;
|
||||
|
||||
Print(() => new SeStringBuilder().AddText("Set mod ").AddPurple(mod.Name, true).AddText(" in collection ")
|
||||
.AddYellow(collection.Name, true)
|
||||
.AddText(" to inherit.").BuiltString);
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public class Penumbra : IDalamudPlugin
|
|||
|
||||
void PrintCollection(ModCollection c)
|
||||
=> sb.Append($"**Collection {c.AnonymizedName}**\n"
|
||||
+ $"> **`Inheritances: `** {c.Inheritance.Count}\n"
|
||||
+ $"> **`Inheritances: `** {c.DirectlyInheritsFrom.Count}\n"
|
||||
+ $"> **`Enabled Mods: `** {c.ActualSettings.Count(s => s is { Enabled: true })}\n"
|
||||
+ $"> **`Conflicts (Solved/Total): `** {c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority && x.Solved ? x.Conflicts.Count : 0)}/{c.AllConflicts.SelectMany(x => x).Sum(x => x.HasPriority ? x.Conflicts.Count : 0)}\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ public class PenumbraNew
|
|||
.AddSingleton<InheritanceManager>()
|
||||
.AddSingleton<CollectionCacheManager>()
|
||||
.AddSingleton<TempCollectionManager>()
|
||||
.AddSingleton<CollectionEditor>()
|
||||
.AddSingleton<CollectionManager>();
|
||||
|
||||
// Add Mod Services
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -171,6 +173,44 @@ public sealed class ModPathChanged : EventWrapper<Action<ModPathChangeType, Mod,
|
|||
=> Invoke(this, changeType, mod, oldModDirectory, newModDirectory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a mod setting is changed.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the collection in which the setting was changed. </item>
|
||||
/// <item>Parameter is the type of change. </item>
|
||||
/// <item>Parameter is the mod the setting was changed for, unless it was a multi-change. </item>
|
||||
/// <item>Parameter is the old value of the setting before the change as int. </item>
|
||||
/// <item>Parameter is the index of the changed group if the change type is Setting. </item>
|
||||
/// <item>Parameter is whether the change was inherited from another collection. </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class ModSettingChanged : EventWrapper<Action<ModCollection, ModSettingChange, Mod?, int, int, bool>>
|
||||
{
|
||||
public ModSettingChanged()
|
||||
: base(nameof(ModSettingChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool inherited)
|
||||
=> Invoke(this, collection, type, mod, oldValue, groupIdx, inherited);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered whenever a collections inheritances change.
|
||||
/// <list type="number">
|
||||
/// <item>Parameter is the collection whose ancestors were changed. </item>
|
||||
/// <item>Parameter is whether the change was itself inherited, i.e. if it happened in a direct parent (false) or a more removed ancestor (true). </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public sealed class CollectionInheritanceChanged : EventWrapper<Action<ModCollection, bool>>
|
||||
{
|
||||
public CollectionInheritanceChanged()
|
||||
: base(nameof(CollectionInheritanceChanged))
|
||||
{ }
|
||||
|
||||
public void Invoke(ModCollection collection, bool inherited)
|
||||
=> Invoke(this, collection, inherited);
|
||||
}
|
||||
|
||||
public class CommunicatorService : IDisposable
|
||||
{
|
||||
/// <inheritdoc cref="Services.CollectionChange"/>
|
||||
|
|
@ -179,30 +219,36 @@ public class CommunicatorService : IDisposable
|
|||
/// <inheritdoc cref="Services.TemporaryGlobalModChange"/>
|
||||
public readonly TemporaryGlobalModChange TemporaryGlobalModChange = new();
|
||||
|
||||
/// <inheritdoc cref="Services.CreatingCharacterBase "/>
|
||||
/// <inheritdoc cref="Services.CreatingCharacterBase"/>
|
||||
public readonly CreatingCharacterBase CreatingCharacterBase = new();
|
||||
|
||||
/// <inheritdoc cref="Services.CreatedCharacterBase "/>
|
||||
/// <inheritdoc cref="Services.CreatedCharacterBase"/>
|
||||
public readonly CreatedCharacterBase CreatedCharacterBase = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModDataChanged "/>
|
||||
/// <inheritdoc cref="Services.ModDataChanged"/>
|
||||
public readonly ModDataChanged ModDataChanged = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModOptionChanged "/>
|
||||
/// <inheritdoc cref="Services.ModOptionChanged"/>
|
||||
public readonly ModOptionChanged ModOptionChanged = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModDiscoveryStarted "/>
|
||||
/// <inheritdoc cref="Services.ModDiscoveryStarted"/>
|
||||
public readonly ModDiscoveryStarted ModDiscoveryStarted = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModDiscoveryFinished "/>
|
||||
/// <inheritdoc cref="Services.ModDiscoveryFinished"/>
|
||||
public readonly ModDiscoveryFinished ModDiscoveryFinished = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModDirectoryChanged "/>
|
||||
/// <inheritdoc cref="Services.ModDirectoryChanged"/>
|
||||
public readonly ModDirectoryChanged ModDirectoryChanged = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModPathChanged "/>
|
||||
/// <inheritdoc cref="Services.ModPathChanged"/>
|
||||
public readonly ModPathChanged ModPathChanged = new();
|
||||
|
||||
/// <inheritdoc cref="Services.ModSettingChanged"/>
|
||||
public readonly ModSettingChanged ModSettingChanged = new();
|
||||
|
||||
/// <inheritdoc cref="Services.CollectionInheritanceChanged"/>
|
||||
public readonly CollectionInheritanceChanged CollectionInheritanceChanged = new();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CollectionChange.Dispose();
|
||||
|
|
@ -215,5 +261,7 @@ public class CommunicatorService : IDisposable
|
|||
ModDiscoveryFinished.Dispose();
|
||||
ModDirectoryChanged.Dispose();
|
||||
ModPathChanged.Dispose();
|
||||
ModSettingChanged.Dispose();
|
||||
CollectionInheritanceChanged.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ public class ConfigMigrationService
|
|||
if (jObject[nameof(ModCollection.Name)]?.ToObject<string>() == ForcedCollection)
|
||||
continue;
|
||||
|
||||
jObject[nameof(ModCollection.Inheritance)] = JToken.FromObject(new List<string> { ForcedCollection });
|
||||
jObject[nameof(ModCollection.DirectlyInheritsFrom)] = JToken.FromObject(new List<string> { ForcedCollection });
|
||||
File.WriteAllText(collection.FullName, jObject.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
};
|
||||
|
||||
_communicator.CollectionChange.Subscribe(OnCollectionChange);
|
||||
_collectionManager.Active.Current.ModSettingChanged += OnSettingChange;
|
||||
_communicator.ModSettingChanged.Subscribe(OnSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange);
|
||||
_communicator.ModOptionChanged.Subscribe(OnModOptionChange);
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +103,8 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
public void Dispose()
|
||||
{
|
||||
_communicator.CollectionChange.Unsubscribe(OnCollectionChange);
|
||||
_collectionManager.Active.Current.ModSettingChanged -= OnSettingChange;
|
||||
_communicator.ModSettingChanged.Unsubscribe(OnSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Unsubscribe(OnInheritanceChange);
|
||||
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
|
||||
}
|
||||
|
||||
|
|
@ -744,21 +746,29 @@ public class ItemSwapTab : IDisposable, ITab
|
|||
if (collectionType != CollectionType.Current || _mod == null || newCollection == null)
|
||||
return;
|
||||
|
||||
UpdateMod(_mod, _mod.Index < newCollection.Settings.Count ? newCollection.Settings[_mod.Index] : null);
|
||||
newCollection.ModSettingChanged += OnSettingChange;
|
||||
if (oldCollection != null)
|
||||
oldCollection.ModSettingChanged -= OnSettingChange;
|
||||
UpdateMod(_mod, _mod.Index < newCollection.Settings.Count ? newCollection[_mod.Index].Settings : null);
|
||||
}
|
||||
|
||||
private void OnSettingChange(ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool inherited)
|
||||
private void OnSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool inherited)
|
||||
{
|
||||
if (modIdx != _mod?.Index)
|
||||
|
||||
if (collection != _collectionManager.Active.Current || mod != _mod)
|
||||
return;
|
||||
|
||||
_swapData.LoadMod(_mod, _modSettings);
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
private void OnInheritanceChange(ModCollection collection, bool _)
|
||||
{
|
||||
if (collection != _collectionManager.Active.Current || _mod == null)
|
||||
return;
|
||||
|
||||
UpdateMod(_mod, collection[_mod.Index].Settings);
|
||||
_swapData.LoadMod(_mod, _modSettings);
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
private void OnModOptionChange(ModOptionChangeType type, Mod mod, int a, int b, int c)
|
||||
{
|
||||
if (type is ModOptionChangeType.PrepareChange || mod != _mod)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public class InheritanceUi
|
|||
private const int InheritedCollectionHeight = 9;
|
||||
private const string InheritanceDragDropLabel = "##InheritanceMove";
|
||||
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
|
||||
public InheritanceUi(CollectionManager collectionManager)
|
||||
=> _collectionManager = collectionManager;
|
||||
|
|
@ -118,7 +118,7 @@ public class InheritanceUi
|
|||
|
||||
_seenInheritedCollections.Clear();
|
||||
_seenInheritedCollections.Add(_collectionManager.Active.Current);
|
||||
foreach (var collection in _collectionManager.Active.Current.Inheritance.ToList())
|
||||
foreach (var collection in _collectionManager.Active.Current.DirectlyInheritsFrom.ToList())
|
||||
DrawInheritance(collection);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ public class InheritanceUi
|
|||
|
||||
using var target = ImRaii.DragDropTarget();
|
||||
if (target.Success && ImGuiUtil.IsDropping(InheritanceDragDropLabel))
|
||||
_inheritanceAction = (_collectionManager.Active.Current.Inheritance.IndexOf(_movedInheritance!), -1);
|
||||
_inheritanceAction = (_collectionManager.Active.Current.DirectlyInheritsFrom.IndexOf(_movedInheritance!), -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -157,9 +157,9 @@ public class InheritanceUi
|
|||
if (_inheritanceAction.Value.Item1 >= 0)
|
||||
{
|
||||
if (_inheritanceAction.Value.Item2 == -1)
|
||||
_collectionManager.Active.Current.RemoveInheritance(_inheritanceAction.Value.Item1);
|
||||
_collectionManager.Inheritances.RemoveInheritance(_collectionManager.Active.Current, _inheritanceAction.Value.Item1);
|
||||
else
|
||||
_collectionManager.Active.Current.MoveInheritance(_inheritanceAction.Value.Item1, _inheritanceAction.Value.Item2);
|
||||
_collectionManager.Inheritances.MoveInheritance(_collectionManager.Active.Current, _inheritanceAction.Value.Item1, _inheritanceAction.Value.Item2);
|
||||
}
|
||||
|
||||
_inheritanceAction = null;
|
||||
|
|
@ -173,22 +173,22 @@ public class InheritanceUi
|
|||
{
|
||||
DrawNewInheritanceCombo();
|
||||
ImGui.SameLine();
|
||||
var inheritance = _collectionManager.Active.Current.CheckValidInheritance(_newInheritance);
|
||||
var inheritance = InheritanceManager.CheckValidInheritance(_collectionManager.Active.Current, _newInheritance);
|
||||
var tt = inheritance switch
|
||||
{
|
||||
ModCollection.ValidInheritance.Empty => "No valid collection to inherit from selected.",
|
||||
ModCollection.ValidInheritance.Valid => $"Let the {TutorialService.SelectedCollection} inherit from this collection.",
|
||||
ModCollection.ValidInheritance.Self => "The collection can not inherit from itself.",
|
||||
ModCollection.ValidInheritance.Contained => "Already inheriting from this collection.",
|
||||
ModCollection.ValidInheritance.Circle => "Inheriting from this collection would lead to cyclic inheritance.",
|
||||
InheritanceManager.ValidInheritance.Empty => "No valid collection to inherit from selected.",
|
||||
InheritanceManager.ValidInheritance.Valid => $"Let the {TutorialService.SelectedCollection} inherit from this collection.",
|
||||
InheritanceManager.ValidInheritance.Self => "The collection can not inherit from itself.",
|
||||
InheritanceManager.ValidInheritance.Contained => "Already inheriting from this collection.",
|
||||
InheritanceManager.ValidInheritance.Circle => "Inheriting from this collection would lead to cyclic inheritance.",
|
||||
_ => string.Empty,
|
||||
};
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), UiHelpers.IconButtonSize, tt,
|
||||
inheritance != ModCollection.ValidInheritance.Valid, true)
|
||||
&& _collectionManager.Active.Current.AddInheritance(_newInheritance!, true))
|
||||
inheritance != InheritanceManager.ValidInheritance.Valid, true)
|
||||
&& _collectionManager.Inheritances.AddInheritance(_collectionManager.Active.Current, _newInheritance!))
|
||||
_newInheritance = null;
|
||||
|
||||
if (inheritance != ModCollection.ValidInheritance.Valid)
|
||||
if (inheritance != InheritanceManager.ValidInheritance.Valid)
|
||||
_newInheritance = null;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -234,14 +234,14 @@ public class InheritanceUi
|
|||
{
|
||||
ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton);
|
||||
_newInheritance ??= _collectionManager.Storage.FirstOrDefault(c
|
||||
=> c != _collectionManager.Active.Current && !_collectionManager.Active.Current.Inheritance.Contains(c))
|
||||
=> c != _collectionManager.Active.Current && !_collectionManager.Active.Current.DirectlyInheritsFrom.Contains(c))
|
||||
?? ModCollection.Empty;
|
||||
using var combo = ImRaii.Combo("##newInheritance", _newInheritance.Name);
|
||||
if (!combo)
|
||||
return;
|
||||
|
||||
foreach (var collection in _collectionManager.Storage
|
||||
.Where(c => _collectionManager.Active.Current.CheckValidInheritance(c) == ModCollection.ValidInheritance.Valid)
|
||||
.Where(c => InheritanceManager.CheckValidInheritance(_collectionManager.Active.Current, c) == InheritanceManager.ValidInheritance.Valid)
|
||||
.OrderBy(c => c.Name))
|
||||
{
|
||||
if (ImGui.Selectable(collection.Name, _newInheritance == collection))
|
||||
|
|
@ -261,8 +261,8 @@ public class InheritanceUi
|
|||
|
||||
if (_movedInheritance != null)
|
||||
{
|
||||
var idx1 = _collectionManager.Active.Current.Inheritance.IndexOf(_movedInheritance);
|
||||
var idx2 = _collectionManager.Active.Current.Inheritance.IndexOf(collection);
|
||||
var idx1 = _collectionManager.Active.Current.DirectlyInheritsFrom.IndexOf(_movedInheritance);
|
||||
var idx2 = _collectionManager.Active.Current.DirectlyInheritsFrom.IndexOf(collection);
|
||||
if (idx1 >= 0 && idx2 >= 0)
|
||||
_inheritanceAction = (idx1, idx2);
|
||||
}
|
||||
|
|
@ -292,7 +292,7 @@ public class InheritanceUi
|
|||
if (ImGui.GetIO().KeyCtrl && ImGui.IsItemClicked(ImGuiMouseButton.Right))
|
||||
{
|
||||
if (withDelete && ImGui.GetIO().KeyShift)
|
||||
_inheritanceAction = (_collectionManager.Active.Current.Inheritance.IndexOf(collection), -1);
|
||||
_inheritanceAction = (_collectionManager.Active.Current.DirectlyInheritsFrom.IndexOf(collection), -1);
|
||||
else
|
||||
_newCurrentCollection = collection;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
SetFilterTooltip();
|
||||
|
||||
SelectionChanged += OnSelectionChange;
|
||||
_communicator.CollectionChange.Subscribe(OnCollectionChange);
|
||||
_collectionManager.Active.Current.ModSettingChanged += OnSettingChange;
|
||||
_collectionManager.Active.Current.InheritanceChanged += OnInheritanceChange;
|
||||
_communicator.CollectionChange.Subscribe(OnCollectionChange);
|
||||
_communicator.ModSettingChanged.Subscribe(OnSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Subscribe(OnInheritanceChange);
|
||||
_communicator.ModDataChanged.Subscribe(OnModDataChange);
|
||||
_communicator.ModDiscoveryStarted.Subscribe(StoreCurrentSelection);
|
||||
_communicator.ModDiscoveryFinished.Subscribe(RestoreLastSelection);
|
||||
|
|
@ -88,8 +88,8 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
_communicator.ModDiscoveryStarted.Unsubscribe(StoreCurrentSelection);
|
||||
_communicator.ModDiscoveryFinished.Unsubscribe(RestoreLastSelection);
|
||||
_communicator.ModDataChanged.Unsubscribe(OnModDataChange);
|
||||
_collectionManager.Active.Current.ModSettingChanged -= OnSettingChange;
|
||||
_collectionManager.Active.Current.InheritanceChanged -= OnInheritanceChange;
|
||||
_communicator.ModSettingChanged.Unsubscribe(OnSettingChange);
|
||||
_communicator.CollectionInheritanceChanged.Unsubscribe(OnInheritanceChange);
|
||||
_communicator.CollectionChange.Unsubscribe(OnCollectionChange);
|
||||
}
|
||||
|
||||
|
|
@ -267,9 +267,9 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
});
|
||||
|
||||
if (inherit)
|
||||
_collectionManager.Active.Current.SetMultipleModInheritances(mods, enabled);
|
||||
_collectionManager.Editor.SetMultipleModInheritances(_collectionManager.Active.Current, mods, enabled);
|
||||
else
|
||||
_collectionManager.Active.Current.SetMultipleModStates(mods, enabled);
|
||||
_collectionManager.Editor.SetMultipleModStates(_collectionManager.Active.Current, mods, enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -360,11 +360,13 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
|
||||
#region Automatic cache update functions.
|
||||
|
||||
private void OnSettingChange(ModSettingChange type, int modIdx, int oldValue, int groupIdx, bool inherited)
|
||||
private void OnSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int oldValue, int groupIdx, bool inherited)
|
||||
{
|
||||
// TODO: maybe make more efficient
|
||||
if (collection != _collectionManager.Active.Current)
|
||||
return;
|
||||
|
||||
SetFilterDirty();
|
||||
if (modIdx == Selected?.Index)
|
||||
if (mod == Selected)
|
||||
OnSelectionChange(Selected, Selected, default);
|
||||
}
|
||||
|
||||
|
|
@ -382,8 +384,11 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
}
|
||||
}
|
||||
|
||||
private void OnInheritanceChange(bool _)
|
||||
private void OnInheritanceChange(ModCollection collection, bool _)
|
||||
{
|
||||
if (collection != _collectionManager.Active.Current)
|
||||
return;
|
||||
|
||||
SetFilterDirty();
|
||||
OnSelectionChange(Selected, Selected, default);
|
||||
}
|
||||
|
|
@ -393,18 +398,6 @@ public sealed class ModFileSystemSelector : FileSystemSelector<Mod, ModFileSyste
|
|||
if (collectionType != CollectionType.Current || oldCollection == newCollection)
|
||||
return;
|
||||
|
||||
if (oldCollection != null)
|
||||
{
|
||||
oldCollection.ModSettingChanged -= OnSettingChange;
|
||||
oldCollection.InheritanceChanged -= OnInheritanceChange;
|
||||
}
|
||||
|
||||
if (newCollection != null)
|
||||
{
|
||||
newCollection.ModSettingChanged += OnSettingChange;
|
||||
newCollection.InheritanceChanged += OnInheritanceChange;
|
||||
}
|
||||
|
||||
SetFilterDirty();
|
||||
OnSelectionChange(Selected, Selected, default);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ public class ModPanelHeader : IDisposable
|
|||
}
|
||||
|
||||
// Author
|
||||
var author = mod.Author.IsEmpty ? string.Empty : $"by {mod.Author}";
|
||||
if (author != _modAuthor)
|
||||
if (mod.Author != _modAuthor)
|
||||
{
|
||||
_modAuthor = author;
|
||||
var author = mod.Author.IsEmpty ? string.Empty : $"by {mod.Author}";
|
||||
_modAuthor = mod.Author.Text;
|
||||
_modAuthorWidth = ImGui.CalcTextSize(author).X;
|
||||
_secondRowWidth = _modAuthorWidth + _modWebsiteButtonWidth + ImGui.GetStyle().ItemSpacing.X;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ namespace Penumbra.UI.ModsTab;
|
|||
public class ModPanelSettingsTab : ITab
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly CollectionManager _collectionManager;
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly TutorialService _tutorial;
|
||||
private readonly PenumbraApi _api;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ModManager _modManager;
|
||||
|
||||
private bool _inherited;
|
||||
private ModSettings _settings = null!;
|
||||
|
|
@ -114,7 +114,7 @@ public class ModPanelSettingsTab : ITab
|
|||
using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg);
|
||||
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
|
||||
if (ImGui.Button($"These settings are inherited from {_collection.Name}.", width))
|
||||
_collectionManager.Active.Current.SetModInheritance(_selector.Selected!.Index, false);
|
||||
_collectionManager.Editor.SetModInheritance(_collectionManager.Active.Current, _selector.Selected!, false);
|
||||
|
||||
ImGuiUtil.HoverTooltip("You can click this button to copy the current settings to the current selection.\n"
|
||||
+ "You can also just change any setting, which will copy the settings with the single setting changed to the current selection.");
|
||||
|
|
@ -128,7 +128,7 @@ public class ModPanelSettingsTab : ITab
|
|||
return;
|
||||
|
||||
_modManager.SetKnown(_selector.Selected!);
|
||||
_collectionManager.Active.Current.SetModState(_selector.Selected!.Index, enabled);
|
||||
_collectionManager.Editor.SetModState(_collectionManager.Active.Current, _selector.Selected!, enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -146,7 +146,7 @@ public class ModPanelSettingsTab : ITab
|
|||
if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue)
|
||||
{
|
||||
if (_currentPriority != _settings.Priority)
|
||||
_collectionManager.Active.Current.SetModPriority(_selector.Selected!.Index, _currentPriority.Value);
|
||||
_collectionManager.Editor.SetModPriority(_collectionManager.Active.Current, _selector.Selected!, _currentPriority.Value);
|
||||
|
||||
_currentPriority = null;
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ public class ModPanelSettingsTab : ITab
|
|||
var scroll = ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0;
|
||||
ImGui.SameLine(ImGui.GetWindowWidth() - ImGui.CalcTextSize(text).X - ImGui.GetStyle().FramePadding.X * 2 - scroll);
|
||||
if (ImGui.Button(text))
|
||||
_collectionManager.Active.Current.SetModInheritance(_selector.Selected!.Index, true);
|
||||
_collectionManager.Editor.SetModInheritance(_collectionManager.Active.Current, _selector.Selected!, true);
|
||||
|
||||
ImGuiUtil.HoverTooltip("Remove current settings from this collection so that it can inherit them.\n"
|
||||
+ "If no inherited collection has settings for this mod, it will be disabled.");
|
||||
|
|
@ -191,7 +191,7 @@ public class ModPanelSettingsTab : ITab
|
|||
id.Push(idx2);
|
||||
var option = group[idx2];
|
||||
if (ImGui.Selectable(option.Name, idx2 == selectedOption))
|
||||
_collectionManager.Active.Current.SetModSetting(_selector.Selected!.Index, groupIdx, (uint)idx2);
|
||||
_collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, (uint)idx2);
|
||||
|
||||
if (option.Description.Length > 0)
|
||||
{
|
||||
|
|
@ -227,7 +227,7 @@ public class ModPanelSettingsTab : ITab
|
|||
{
|
||||
using var id = ImRaii.PushId(groupIdx);
|
||||
var selectedOption = _empty ? (int)group.DefaultSettings : (int)_settings.Settings[groupIdx];
|
||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||
|
||||
void DrawOptions()
|
||||
{
|
||||
|
|
@ -236,7 +236,7 @@ public class ModPanelSettingsTab : ITab
|
|||
using var i = ImRaii.PushId(idx);
|
||||
var option = group[idx];
|
||||
if (ImGui.RadioButton(option.Name, selectedOption == idx))
|
||||
_collectionManager.Active.Current.SetModSetting(_selector.Selected!.Index, groupIdx, (uint)idx);
|
||||
_collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, (uint)idx);
|
||||
|
||||
if (option.Description.Length <= 0)
|
||||
continue;
|
||||
|
|
@ -264,7 +264,7 @@ public class ModPanelSettingsTab : ITab
|
|||
var shown = ImGui.GetStateStorage().GetBool(collapseId, true);
|
||||
var buttonTextShow = $"Show {group.Count} Options";
|
||||
var buttonTextHide = $"Hide {group.Count} Options";
|
||||
var buttonWidth = Math.Max(ImGui.CalcTextSize(buttonTextShow).X, ImGui.CalcTextSize(buttonTextHide).X)
|
||||
var buttonWidth = Math.Max(ImGui.CalcTextSize(buttonTextShow).X, ImGui.CalcTextSize(buttonTextHide).X)
|
||||
+ 2 * ImGui.GetStyle().FramePadding.X;
|
||||
minWidth = Math.Max(buttonWidth, minWidth);
|
||||
if (shown)
|
||||
|
|
@ -276,10 +276,9 @@ public class ModPanelSettingsTab : ITab
|
|||
draw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
var width = Math.Max(ImGui.GetItemRectSize().X, minWidth);
|
||||
var endPos = ImGui.GetCursorPos();
|
||||
|
||||
var width = Math.Max(ImGui.GetItemRectSize().X, minWidth);
|
||||
var endPos = ImGui.GetCursorPos();
|
||||
ImGui.SetCursorPos(pos);
|
||||
if (ImGui.Button(buttonTextHide, new Vector2(width, 0)))
|
||||
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
||||
|
|
@ -292,7 +291,7 @@ public class ModPanelSettingsTab : ITab
|
|||
+ ImGui.GetStyle().ItemInnerSpacing.X
|
||||
+ ImGui.GetFrameHeight()
|
||||
+ ImGui.GetStyle().FramePadding.X;
|
||||
var width = Math.Max(optionWidth, minWidth);
|
||||
var width = Math.Max(optionWidth, minWidth);
|
||||
if (ImGui.Button(buttonTextShow, new Vector2(width, 0)))
|
||||
ImGui.GetStateStorage().SetBool(collapseId, !shown);
|
||||
}
|
||||
|
|
@ -305,9 +304,9 @@ public class ModPanelSettingsTab : ITab
|
|||
/// </summary>
|
||||
private void DrawMultiGroup(IModGroup group, int groupIdx)
|
||||
{
|
||||
using var id = ImRaii.PushId(groupIdx);
|
||||
var flags = _empty ? group.DefaultSettings : _settings.Settings[groupIdx];
|
||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||
using var id = ImRaii.PushId(groupIdx);
|
||||
var flags = _empty ? group.DefaultSettings : _settings.Settings[groupIdx];
|
||||
var minWidth = Widget.BeginFramedGroup(group.Name, group.Description);
|
||||
|
||||
void DrawOptions()
|
||||
{
|
||||
|
|
@ -321,7 +320,7 @@ public class ModPanelSettingsTab : ITab
|
|||
if (ImGui.Checkbox(option.Name, ref setting))
|
||||
{
|
||||
flags = setting ? flags | flag : flags & ~flag;
|
||||
_collectionManager.Active.Current.SetModSetting(_selector.Selected!.Index, groupIdx, flags);
|
||||
_collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, flags);
|
||||
}
|
||||
|
||||
if (option.Description.Length > 0)
|
||||
|
|
@ -349,10 +348,10 @@ public class ModPanelSettingsTab : ITab
|
|||
if (ImGui.Selectable("Enable All"))
|
||||
{
|
||||
flags = group.Count == 32 ? uint.MaxValue : (1u << group.Count) - 1u;
|
||||
_collectionManager.Active.Current.SetModSetting(_selector.Selected!.Index, groupIdx, flags);
|
||||
_collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, flags);
|
||||
}
|
||||
|
||||
if (ImGui.Selectable("Disable All"))
|
||||
_collectionManager.Active.Current.SetModSetting(_selector.Selected!.Index, groupIdx, 0);
|
||||
_collectionManager.Editor.SetModSetting(_collectionManager.Active.Current, _selector.Selected!, groupIdx, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class ModsTab : ITab
|
|||
+ $"{_selector.SortMode.Name} Sort Mode\n"
|
||||
+ $"{_selector.SelectedLeaf?.Name ?? "NULL"} Selected Leaf\n"
|
||||
+ $"{_selector.Selected?.Name ?? "NULL"} Selected Mod\n"
|
||||
+ $"{string.Join(", ", _collectionManager.Active.Current.Inheritance.Select(c => c.AnonymizedName))} Inheritances\n"
|
||||
+ $"{string.Join(", ", _collectionManager.Active.Current.DirectlyInheritsFrom.Select(c => c.AnonymizedName))} Inheritances\n"
|
||||
+ $"{_selector.SelectedSettingCollection.AnonymizedName} Collection\n");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue