mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-21 15:27:51 +01:00
This commit is contained in:
parent
7b451c5097
commit
bb957c1119
50 changed files with 2016 additions and 1247 deletions
|
|
@ -1,169 +1,172 @@
|
|||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods.Manager;
|
||||
|
||||
public class ModCacheManager : IDisposable, Luna.IRequiredService
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
private readonly ModStorage _modManager;
|
||||
private bool _updatingItems;
|
||||
|
||||
public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage, Configuration config)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_identifier = identifier;
|
||||
_modManager = modStorage;
|
||||
_config = config;
|
||||
|
||||
_communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ModCacheManager);
|
||||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
||||
identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation(), TaskScheduler.Default);
|
||||
OnModDiscoveryFinished();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
|
||||
_communicator.ModPathChanged.Unsubscribe(OnModPathChange);
|
||||
_communicator.ModDataChanged.Unsubscribe(OnModDataChange);
|
||||
_communicator.ModDiscoveryFinished.Unsubscribe(OnModDiscoveryFinished);
|
||||
}
|
||||
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModOptionChangeType.GroupAdded:
|
||||
case ModOptionChangeType.GroupDeleted:
|
||||
case ModOptionChangeType.OptionAdded:
|
||||
case ModOptionChangeType.OptionDeleted:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateCounts(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.GroupTypeChanged:
|
||||
UpdateHasOptions(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionFilesChanged:
|
||||
case ModOptionChangeType.OptionFilesAdded:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateFileCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionSwapsChanged:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateSwapCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionMetaChanged:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateMetaCount(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
case ModPathChangeType.Reloaded:
|
||||
RefreshWithChangedItems(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
if ((arguments.Type & (ModDataChangeType.LocalTags | ModDataChangeType.ModTags)) is not 0)
|
||||
UpdateTags(arguments.Mod);
|
||||
}
|
||||
|
||||
private void OnModDiscoveryFinished()
|
||||
{
|
||||
if (!_identifier.Awaiter.IsCompletedSuccessfully || _updatingItems)
|
||||
{
|
||||
Parallel.ForEach(_modManager, RefreshWithoutChangedItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, RefreshWithChangedItems);
|
||||
_updatingItems = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIdentifierCreation()
|
||||
{
|
||||
if (_updatingItems)
|
||||
return;
|
||||
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||
_updatingItems = false;
|
||||
}
|
||||
|
||||
private static void UpdateFileCount(Mod mod)
|
||||
=> mod.TotalFileCount = mod.AllDataContainers.Sum(s => s.Files.Count);
|
||||
|
||||
private static void UpdateSwapCount(Mod mod)
|
||||
=> mod.TotalSwapCount = mod.AllDataContainers.Sum(s => s.FileSwaps.Count);
|
||||
|
||||
private static void UpdateMetaCount(Mod mod)
|
||||
=> mod.TotalManipulations = mod.AllDataContainers.Sum(s => s.Manipulations.Count);
|
||||
|
||||
private static void UpdateHasOptions(Mod mod)
|
||||
=> mod.HasOptions = mod.Groups.Any(o => o.IsOption);
|
||||
|
||||
private static void UpdateTags(Mod mod)
|
||||
=> mod.AllTagsLower = string.Join('\0', mod.ModTags.Concat(mod.LocalTags).Select(s => s.ToLowerInvariant()));
|
||||
|
||||
private void UpdateChangedItems(Mod mod)
|
||||
{
|
||||
mod.ChangedItems.Clear();
|
||||
|
||||
_identifier.AddChangedItems(mod.Default, mod.ChangedItems);
|
||||
foreach (var group in mod.Groups)
|
||||
group.AddChangedItems(_identifier, mod.ChangedItems);
|
||||
|
||||
if (_config.HideMachinistOffhandFromChangedItems)
|
||||
mod.ChangedItems.RemoveMachinistOffhands();
|
||||
|
||||
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
||||
++mod.LastChangedItemsUpdate;
|
||||
}
|
||||
|
||||
private static void UpdateCounts(Mod mod)
|
||||
{
|
||||
mod.TotalFileCount = mod.Default.Files.Count;
|
||||
mod.TotalSwapCount = mod.Default.FileSwaps.Count;
|
||||
mod.TotalManipulations = mod.Default.Manipulations.Count;
|
||||
mod.HasOptions = false;
|
||||
foreach (var group in mod.Groups)
|
||||
{
|
||||
mod.HasOptions |= group.IsOption;
|
||||
var (files, swaps, manips) = group.GetCounts();
|
||||
mod.TotalFileCount += files;
|
||||
mod.TotalSwapCount += swaps;
|
||||
mod.TotalManipulations += manips;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshWithChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
UpdateChangedItems(mod);
|
||||
}
|
||||
|
||||
private void RefreshWithoutChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
}
|
||||
}
|
||||
using Luna;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.Mods.Manager.OptionEditor;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Mods.Manager;
|
||||
|
||||
public class ModCacheManager : IDisposable, IRequiredService
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly ObjectIdentification _identifier;
|
||||
private readonly ModStorage _modManager;
|
||||
private readonly SaveService _saveService;
|
||||
private bool _updatingItems;
|
||||
|
||||
public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage, Configuration config,
|
||||
SaveService saveService)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_identifier = identifier;
|
||||
_modManager = modStorage;
|
||||
_config = config;
|
||||
_saveService = saveService;
|
||||
|
||||
_communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ModCacheManager);
|
||||
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager);
|
||||
_communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager);
|
||||
|
||||
identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation(), TaskScheduler.Default);
|
||||
OnModDiscoveryFinished();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModOptionChanged.Unsubscribe(OnModOptionChange);
|
||||
_communicator.ModPathChanged.Unsubscribe(OnModPathChange);
|
||||
_communicator.ModDataChanged.Unsubscribe(OnModDataChange);
|
||||
_communicator.ModDiscoveryFinished.Unsubscribe(OnModDiscoveryFinished);
|
||||
}
|
||||
|
||||
private void OnModOptionChange(in ModOptionChanged.Arguments arguments)
|
||||
{
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModOptionChangeType.GroupAdded:
|
||||
case ModOptionChangeType.GroupDeleted:
|
||||
case ModOptionChangeType.OptionAdded:
|
||||
case ModOptionChangeType.OptionDeleted:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateCounts(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.GroupTypeChanged: UpdateHasOptions(arguments.Mod); break;
|
||||
case ModOptionChangeType.OptionFilesChanged:
|
||||
case ModOptionChangeType.OptionFilesAdded:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateFileCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionSwapsChanged:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateSwapCount(arguments.Mod);
|
||||
break;
|
||||
case ModOptionChangeType.OptionMetaChanged:
|
||||
UpdateChangedItems(arguments.Mod);
|
||||
UpdateMetaCount(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModPathChange(in ModPathChanged.Arguments arguments)
|
||||
{
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModPathChangeType.Added:
|
||||
case ModPathChangeType.Reloaded:
|
||||
RefreshWithChangedItems(arguments.Mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnModDataChange(in ModDataChanged.Arguments arguments)
|
||||
{
|
||||
if ((arguments.Type & (ModDataChangeType.LocalTags | ModDataChangeType.ModTags)) is not 0)
|
||||
UpdateTags(arguments.Mod);
|
||||
}
|
||||
|
||||
private void OnModDiscoveryFinished()
|
||||
{
|
||||
if (!_identifier.Awaiter.IsCompletedSuccessfully || _updatingItems)
|
||||
{
|
||||
Parallel.ForEach(_modManager, RefreshWithoutChangedItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, RefreshWithChangedItems);
|
||||
_updatingItems = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIdentifierCreation()
|
||||
{
|
||||
if (_updatingItems)
|
||||
return;
|
||||
|
||||
_updatingItems = true;
|
||||
Parallel.ForEach(_modManager, UpdateChangedItems);
|
||||
_updatingItems = false;
|
||||
}
|
||||
|
||||
private static void UpdateFileCount(Mod mod)
|
||||
=> mod.TotalFileCount = mod.AllDataContainers.Sum(s => s.Files.Count);
|
||||
|
||||
private static void UpdateSwapCount(Mod mod)
|
||||
=> mod.TotalSwapCount = mod.AllDataContainers.Sum(s => s.FileSwaps.Count);
|
||||
|
||||
private static void UpdateMetaCount(Mod mod)
|
||||
=> mod.TotalManipulations = mod.AllDataContainers.Sum(s => s.Manipulations.Count);
|
||||
|
||||
private static void UpdateHasOptions(Mod mod)
|
||||
=> mod.HasOptions = mod.Groups.Any(o => o.IsOption);
|
||||
|
||||
private static void UpdateTags(Mod mod)
|
||||
=> mod.AllTagsLower = string.Join('\0', mod.ModTags.Concat(mod.LocalTags).Select(s => s.ToLowerInvariant()));
|
||||
|
||||
private void UpdateChangedItems(Mod mod)
|
||||
{
|
||||
mod.ChangedItems.Clear();
|
||||
|
||||
_identifier.AddChangedItems(mod.Default, mod.ChangedItems);
|
||||
foreach (var group in mod.Groups)
|
||||
group.AddChangedItems(_identifier, mod.ChangedItems);
|
||||
|
||||
if (_config.HideMachinistOffhandFromChangedItems)
|
||||
mod.ChangedItems.RemoveMachinistOffhands();
|
||||
|
||||
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
|
||||
++mod.LastChangedItemsUpdate;
|
||||
}
|
||||
|
||||
private static void UpdateCounts(Mod mod)
|
||||
{
|
||||
mod.TotalFileCount = mod.Default.Files.Count;
|
||||
mod.TotalSwapCount = mod.Default.FileSwaps.Count;
|
||||
mod.TotalManipulations = mod.Default.Manipulations.Count;
|
||||
mod.HasOptions = false;
|
||||
foreach (var group in mod.Groups)
|
||||
{
|
||||
mod.HasOptions |= group.IsOption;
|
||||
var (files, swaps, manips) = group.GetCounts();
|
||||
mod.TotalFileCount += files;
|
||||
mod.TotalSwapCount += swaps;
|
||||
mod.TotalManipulations += manips;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshWithChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
UpdateChangedItems(mod);
|
||||
}
|
||||
|
||||
private void RefreshWithoutChangedItems(Mod mod)
|
||||
{
|
||||
UpdateTags(mod);
|
||||
UpdateCounts(mod);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
74
Penumbra/Mods/Manager/ModConfigUpdater.cs
Normal file
74
Penumbra/Mods/Manager/ModConfigUpdater.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using Luna;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections.Manager;
|
||||
using Penumbra.Communication;
|
||||
using Penumbra.Services;
|
||||
|
||||
namespace Penumbra.Mods.Manager;
|
||||
|
||||
public class ModConfigUpdater : IDisposable, IRequiredService
|
||||
{
|
||||
private readonly CommunicatorService _communicator;
|
||||
private readonly SaveService _saveService;
|
||||
private readonly ModStorage _mods;
|
||||
private readonly CollectionStorage _collections;
|
||||
|
||||
public ModConfigUpdater(CommunicatorService communicator, SaveService saveService, ModStorage mods, CollectionStorage collections)
|
||||
{
|
||||
_communicator = communicator;
|
||||
_saveService = saveService;
|
||||
_mods = mods;
|
||||
_collections = collections;
|
||||
|
||||
_communicator.ModSettingChanged.Subscribe(OnModSettingChanged, ModSettingChanged.Priority.ModConfigUpdater);
|
||||
}
|
||||
|
||||
public IEnumerable<Mod> ListUnusedMods(TimeSpan age)
|
||||
{
|
||||
var cutoff = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - (int)age.TotalMilliseconds;
|
||||
foreach (var mod in _mods)
|
||||
{
|
||||
// Skip actively ignored mods.
|
||||
if (mod.IgnoreLastConfig)
|
||||
continue;
|
||||
|
||||
// Skip mods that had settings changed since the given maximum age.
|
||||
if (mod.LastConfigEdit >= cutoff)
|
||||
continue;
|
||||
|
||||
// Skip mods that are currently permanently enabled or have any temporary settings.
|
||||
if (_collections.Any(c => c.GetOwnSettings(mod.Index)?.Enabled is true || c.GetTempSettings(mod.Index) is not null))
|
||||
continue;
|
||||
|
||||
yield return mod;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnModSettingChanged(in ModSettingChanged.Arguments arguments)
|
||||
{
|
||||
if (arguments.Inherited)
|
||||
return;
|
||||
|
||||
switch (arguments.Type)
|
||||
{
|
||||
case ModSettingChange.Inheritance:
|
||||
case ModSettingChange.MultiInheritance:
|
||||
case ModSettingChange.MultiEnableState:
|
||||
case ModSettingChange.TemporaryMod:
|
||||
case ModSettingChange.Edited:
|
||||
return;
|
||||
}
|
||||
|
||||
if (arguments.Mod is { } mod)
|
||||
{
|
||||
mod.LastConfigEdit = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
_communicator.ModDataChanged.Invoke(new ModDataChanged.Arguments(ModDataChangeType.LastConfigEdit, mod, null));
|
||||
_saveService.Save(SaveType.Delay, new ModLocalData(mod));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_communicator.ModSettingChanged.Unsubscribe(OnModSettingChanged);
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,8 @@ public enum ModDataChangeType : uint
|
|||
PreferredChangedItems = 0x004000,
|
||||
RequiredFeatures = 0x008000,
|
||||
FileSystemFolder = 0x010000,
|
||||
FileSystemSortOrder = 0x020000,
|
||||
FileSystemSortOrder = 0x020000,
|
||||
LastConfigEdit = 0x040000,
|
||||
}
|
||||
|
||||
public class ModDataEditor(SaveService saveService, CommunicatorService communicatorService, ItemData itemData) : Luna.IService
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ public sealed class ModTab : TwoPanelLayout, ITab<TabType>
|
|||
public override ReadOnlySpan<byte> Label
|
||||
=> "Mods2"u8;
|
||||
|
||||
public ModTab(ModFileSystemDrawer drawer, ModPanel panel, CollectionSelectHeader collectionHeader)
|
||||
public ModTab(ModFileSystemDrawer drawer, ModPanel panel, CollectionSelectHeader collectionHeader, RedrawFooter redrawFooter)
|
||||
{
|
||||
LeftHeader = drawer.Header;
|
||||
LeftFooter = drawer.Footer;
|
||||
LeftPanel = drawer;
|
||||
RightPanel = panel;
|
||||
RightHeader = collectionHeader;
|
||||
RightFooter = redrawFooter;
|
||||
}
|
||||
|
||||
public void DrawContent()
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ public sealed class Mod : IMod, IFileSystemValue<Mod>
|
|||
// Local Data
|
||||
public DataPath Path { get; } = new();
|
||||
public long ImportDate { get; internal set; } = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
|
||||
public long LastConfigEdit { get; internal set; } = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
|
||||
public bool IgnoreLastConfig { get; internal set; } = false;
|
||||
public IReadOnlyList<string> LocalTags { get; internal set; } = [];
|
||||
public string Note { get; internal set; } = string.Empty;
|
||||
public HashSet<CustomItemId> PreferredChangedItems { get; internal set; } = [];
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
{ nameof(Mod.Note), JToken.FromObject(mod.Note) },
|
||||
{ nameof(Mod.Favorite), JToken.FromObject(mod.Favorite) },
|
||||
{ nameof(Mod.PreferredChangedItems), JToken.FromObject(mod.PreferredChangedItems) },
|
||||
{ nameof(Mod.LastConfigEdit), JToken.FromObject(mod.LastConfigEdit) },
|
||||
};
|
||||
|
||||
if (mod.Path.Folder.Length > 0)
|
||||
|
|
@ -40,12 +41,14 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
{
|
||||
var dataFile = editor.SaveService.FileNames.LocalDataFile(mod);
|
||||
|
||||
var importDate = 0L;
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var importDate = now;
|
||||
var localTags = Enumerable.Empty<string>();
|
||||
var favorite = false;
|
||||
var note = string.Empty;
|
||||
var fileSystemFolder = string.Empty;
|
||||
string? sortOrderName = null;
|
||||
var lastConfigEdit = now;
|
||||
|
||||
HashSet<CustomItemId> preferredChangedItems = [];
|
||||
|
||||
|
|
@ -56,10 +59,11 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
var text = File.ReadAllText(dataFile);
|
||||
var json = JObject.Parse(text);
|
||||
|
||||
importDate = json[nameof(Mod.ImportDate)]?.Value<long>() ?? importDate;
|
||||
favorite = json[nameof(Mod.Favorite)]?.Value<bool>() ?? favorite;
|
||||
note = json[nameof(Mod.Note)]?.Value<string>() ?? note;
|
||||
localTags = (json[nameof(Mod.LocalTags)] as JArray)?.Values<string>().OfType<string>() ?? localTags;
|
||||
importDate = json[nameof(Mod.ImportDate)]?.Value<long>() ?? importDate;
|
||||
lastConfigEdit = json[nameof(Mod.LastConfigEdit)]?.Value<long>() ?? lastConfigEdit;
|
||||
favorite = json[nameof(Mod.Favorite)]?.Value<bool>() ?? favorite;
|
||||
note = json[nameof(Mod.Note)]?.Value<string>() ?? note;
|
||||
localTags = (json[nameof(Mod.LocalTags)] as JArray)?.Values<string>().OfType<string>() ?? localTags;
|
||||
preferredChangedItems =
|
||||
(json[nameof(Mod.PreferredChangedItems)] as JArray)?.Values<ulong>().Select(i => (CustomItemId)i).ToHashSet()
|
||||
?? mod.DefaultPreferredItems;
|
||||
|
|
@ -84,6 +88,12 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
changes |= ModDataChangeType.ImportDate;
|
||||
}
|
||||
|
||||
if (mod.LastConfigEdit != lastConfigEdit)
|
||||
{
|
||||
mod.LastConfigEdit = lastConfigEdit;
|
||||
changes |= ModDataChangeType.LastConfigEdit;
|
||||
}
|
||||
|
||||
changes |= UpdateTags(mod, null, localTags);
|
||||
|
||||
if (mod.Favorite != favorite)
|
||||
|
|
@ -124,11 +134,11 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
|
||||
internal static ModDataChangeType UpdateTags(Mod mod, IEnumerable<string>? newModTags, IEnumerable<string>? newLocalTags)
|
||||
{
|
||||
if (newModTags == null && newLocalTags == null)
|
||||
if (newModTags is null && newLocalTags is null)
|
||||
return 0;
|
||||
|
||||
ModDataChangeType type = 0;
|
||||
if (newModTags != null)
|
||||
if (newModTags is not null)
|
||||
{
|
||||
var modTags = newModTags.Where(t => t.Length > 0).Distinct().ToArray();
|
||||
if (!modTags.SequenceEqual(mod.ModTags))
|
||||
|
|
@ -139,7 +149,7 @@ public readonly struct ModLocalData(Mod mod) : ISavable
|
|||
}
|
||||
}
|
||||
|
||||
if (newLocalTags != null)
|
||||
if (newLocalTags is not null)
|
||||
{
|
||||
var localTags = newLocalTags!.Where(t => t.Length > 0 && !mod.ModTags.Contains(t)).Distinct().ToArray();
|
||||
if (!localTags.SequenceEqual(mod.LocalTags))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue