From 00bc17c57a38c9153331b0cb85ec63962fc4fdb5 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 5 Jul 2023 16:13:11 +0200 Subject: [PATCH] Move some stuff to shared things, improve some filesystem rename handling. --- OtterGui | 2 +- Penumbra.GameData/Data/HumanModelList.cs | 44 +++++++++++++++ .../Manager/IndividualCollections.Files.cs | 1 + .../Manager/IndividualCollections.cs | 1 + .../PathResolving/CollectionResolver.cs | 31 +++-------- .../ResourceTree/ResourceTreeFactory.cs | 2 +- Penumbra/Mods/Manager/ModFileSystem.cs | 20 +++---- Penumbra/Services/ServiceManager.cs | 6 +-- .../CollectionTab/IndividualAssignmentUi.cs | 18 +------ Penumbra/UI/CollectionTab/NpcCombo.cs | 54 ------------------- Penumbra/UI/CollectionTab/WorldCombo.cs | 24 --------- 11 files changed, 67 insertions(+), 136 deletions(-) create mode 100644 Penumbra.GameData/Data/HumanModelList.cs delete mode 100644 Penumbra/UI/CollectionTab/NpcCombo.cs delete mode 100644 Penumbra/UI/CollectionTab/WorldCombo.cs diff --git a/OtterGui b/OtterGui index adce3030..d43be328 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit adce3030c9dc125f2ebbaefbef6c756977c047c3 +Subproject commit d43be3287a4782be091635e81ef2ec64849ba462 diff --git a/Penumbra.GameData/Data/HumanModelList.cs b/Penumbra.GameData/Data/HumanModelList.cs new file mode 100644 index 00000000..d4177e51 --- /dev/null +++ b/Penumbra.GameData/Data/HumanModelList.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Linq; +using Dalamud; +using Dalamud.Data; +using Dalamud.Plugin; +using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; +using Lumina.Excel.GeneratedSheets; + +namespace Penumbra.GameData.Data; + +public sealed class HumanModelList : DataSharer +{ + public const string Tag = "HumanModels"; + public const int CurrentVersion = 1; + + private readonly BitArray _humanModels; + + public HumanModelList(DalamudPluginInterface pluginInterface, DataManager gameData) + : base(pluginInterface, ClientLanguage.English, CurrentVersion) + { + _humanModels = TryCatchData(Tag, () => GetValidHumanModels(gameData)); + } + + public bool IsHuman(uint modelId) + => modelId < _humanModels.Count && _humanModels[(int)modelId]; + + protected override void DisposeInternal() + { + DisposeTag(Tag); + } + + /// + /// Go through all ModelChara rows and return a bitfield of those that resolve to human models. + /// + private static BitArray GetValidHumanModels(DataManager gameData) + { + var sheet = gameData.GetExcelSheet()!; + var ret = new BitArray((int)sheet.RowCount, false); + foreach (var (_, idx) in sheet.Select((m, i) => (m, i)).Where(p => p.m.Type == (byte)CharacterBase.ModelType.Human)) + ret[idx] = true; + + return ret; + } +} diff --git a/Penumbra/Collections/Manager/IndividualCollections.Files.cs b/Penumbra/Collections/Manager/IndividualCollections.Files.cs index d670fc42..c719891e 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Files.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Files.cs @@ -4,6 +4,7 @@ using System.Linq; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Interface.Internal.Notifications; using Newtonsoft.Json.Linq; +using OtterGui.Custom; using Penumbra.GameData.Actors; using Penumbra.Services; using Penumbra.String; diff --git a/Penumbra/Collections/Manager/IndividualCollections.cs b/Penumbra/Collections/Manager/IndividualCollections.cs index a3005f07..91ab49c3 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Dalamud.Game.ClientState.Objects.Enums; +using OtterGui.Custom; using OtterGui.Filesystem; using Penumbra.GameData.Actors; using Penumbra.Services; diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index c5b797fd..8220c629 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -1,15 +1,11 @@ using System; -using System.Collections; -using System.Linq; -using Dalamud.Data; using Dalamud.Game.ClientState; using Dalamud.Game.Gui; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; -using Lumina.Excel.GeneratedSheets; -using OtterGui; using Penumbra.Collections; -using Penumbra.Collections.Manager; +using Penumbra.Collections.Manager; using Penumbra.GameData.Actors; +using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.Services; using Penumbra.Util; @@ -23,7 +19,7 @@ public unsafe class CollectionResolver { private readonly PerformanceTracker _performance; private readonly IdentifiedCollectionCache _cache; - private readonly BitArray _validHumanModels; + private readonly HumanModelList _humanModels; private readonly ClientState _clientState; private readonly GameGui _gameGui; @@ -36,8 +32,8 @@ public unsafe class CollectionResolver private readonly DrawObjectState _drawObjectState; public CollectionResolver(PerformanceTracker performance, IdentifiedCollectionCache cache, ClientState clientState, GameGui gameGui, - DataManager gameData, ActorService actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager, - TempCollectionManager tempCollections, DrawObjectState drawObjectState) + ActorService actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager, + TempCollectionManager tempCollections, DrawObjectState drawObjectState, HumanModelList humanModels) { _performance = performance; _cache = cache; @@ -49,7 +45,7 @@ public unsafe class CollectionResolver _collectionManager = collectionManager; _tempCollections = tempCollections; _drawObjectState = drawObjectState; - _validHumanModels = GetValidHumanModels(gameData); + _humanModels = humanModels; } /// @@ -115,7 +111,7 @@ public unsafe class CollectionResolver /// Return whether the given ModelChara id refers to a human-type model. public bool IsModelHuman(uint modelCharaId) - => modelCharaId < _validHumanModels.Length && _validHumanModels[(int)modelCharaId]; + => _humanModels.IsHuman(modelCharaId); /// Return whether the given character has a human model. public bool IsModelHuman(Character* character) @@ -254,17 +250,4 @@ public unsafe class CollectionResolver return CheckYourself(id, owner) ?? CollectionByAttributes(owner, ref notYetReady); } - - /// - /// Go through all ModelChara rows and return a bitfield of those that resolve to human models. - /// - private static BitArray GetValidHumanModels(DataManager gameData) - { - var sheet = gameData.GetExcelSheet()!; - var ret = new BitArray((int)sheet.RowCount, false); - foreach (var (_, idx) in sheet.WithIndex().Where(p => p.Value.Type == (byte)CharacterBase.ModelType.Human)) - ret[idx] = true; - - return ret; - } } diff --git a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs index 2408bf67..9189327c 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs @@ -4,7 +4,7 @@ using Dalamud.Data; using Dalamud.Game.ClientState.Objects; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Object; -using Penumbra.GameData; +using OtterGui.Custom; using Penumbra.GameData.Actors; using Penumbra.Interop.PathResolving; using Penumbra.Services; diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs index 79554797..8e6e729c 100644 --- a/Penumbra/Mods/Manager/ModFileSystem.cs +++ b/Penumbra/Mods/Manager/ModFileSystem.cs @@ -83,12 +83,12 @@ public sealed class ModFileSystem : FileSystem, IDisposable, ISavable // Update sort order when defaulted mod names change. private void OnDataChange(ModDataChangeType type, Mod mod, string? oldName) { - if (type.HasFlag(ModDataChangeType.Name) && oldName != null) - { - var old = oldName.FixName(); - if (Find(old, out var child) && child is not Folder) - Rename(child, mod.Name.Text); - } + if (!type.HasFlag(ModDataChangeType.Name) || oldName == null || !FindLeaf(mod, out var leaf)) + return; + + var old = oldName.FixName(); + if (old == leaf.Name || leaf.Name.IsDuplicateName(out var baseName, out _) && baseName == old) + RenameWithDuplicates(leaf, mod.Name.Text); } // Update the filesystem if a mod has been added or removed. @@ -98,13 +98,7 @@ public sealed class ModFileSystem : FileSystem, IDisposable, ISavable switch (type) { case ModPathChangeType.Added: - var originalName = mod.Name.Text.FixName(); - var name = originalName; - var counter = 1; - while (Find(name, out _)) - name = $"{originalName} ({++counter})"; - - CreateLeaf(Root, name, mod); + CreateDuplicateLeaf(Root, mod.Name.Text, mod); break; case ModPathChangeType.Deleted: if (FindLeaf(mod, out var leaf)) diff --git a/Penumbra/Services/ServiceManager.cs b/Penumbra/Services/ServiceManager.cs index 1ab1f313..782d40a0 100644 --- a/Penumbra/Services/ServiceManager.cs +++ b/Penumbra/Services/ServiceManager.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using Dalamud.Plugin; using Microsoft.Extensions.DependencyInjection; using OtterGui.Classes; @@ -18,7 +17,7 @@ using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; using Penumbra.UI; using Penumbra.UI.AdvancedWindow; -using Penumbra.UI.Classes; +using Penumbra.UI.Classes; using Penumbra.UI.ModsTab; using Penumbra.UI.Tabs; @@ -70,7 +69,8 @@ public static class ServiceManager .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddSingleton(); private static IServiceCollection AddInterop(this IServiceCollection services) => services.AddSingleton() diff --git a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs index 81e0a862..376b7ad8 100644 --- a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs +++ b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using Dalamud.Game.ClientState.Objects.Enums; using ImGuiNET; -using OtterGui.Raii; +using OtterGui.Custom; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.Communication; @@ -63,22 +63,8 @@ public class IndividualAssignmentUi : IDisposable public void DrawObjectKindCombo(float width) { - if (!_ready) - return; - - ImGui.SetNextItemWidth(width); - using var combo = ImRaii.Combo("##newKind", _newKind.ToName()); - if (!combo) - return; - - foreach (var kind in ObjectKinds) - { - if (!ImGui.Selectable(kind.ToName(), _newKind == kind)) - continue; - - _newKind = kind; + if (_ready && IndividualHelpers.DrawObjectKindCombo(width, _newKind, out _newKind, ObjectKinds)) UpdateIdentifiersInternal(); - } } public void DrawNewPlayerCollection(float width) diff --git a/Penumbra/UI/CollectionTab/NpcCombo.cs b/Penumbra/UI/CollectionTab/NpcCombo.cs deleted file mode 100644 index 7095a78b..00000000 --- a/Penumbra/UI/CollectionTab/NpcCombo.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Dalamud.Utility; -using ImGuiNET; -using OtterGui.Widgets; - -namespace Penumbra.UI.CollectionTab; - -public sealed class NpcCombo : FilterComboCache<(string Name, uint[] Ids)> -{ - private readonly string _label; - - public NpcCombo(string label, IReadOnlyDictionary names) - : base(() => names.GroupBy(kvp => kvp.Value).Select(g => (g.Key, g.Select(g => g.Key).ToArray())).OrderBy(g => g.Key, Comparer) - .ToList()) - => _label = label; - - protected override string ToString((string Name, uint[] Ids) obj) - => obj.Name; - - protected override bool DrawSelectable(int globalIdx, bool selected) - { - var (name, ids) = Items[globalIdx]; - var ret = ImGui.Selectable(name, selected); - if (ImGui.IsItemHovered()) - ImGui.SetTooltip(string.Join('\n', ids.Select(i => i.ToString()))); - - return ret; - } - - public bool Draw(float width) - => Draw(_label, CurrentSelection.Name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); - - - /// Compare strings in a way that letters and numbers are sorted before any special symbols. - private class NameComparer : IComparer - { - public int Compare(string? x, string? y) - { - if (x.IsNullOrEmpty() || y.IsNullOrEmpty()) - return StringComparer.OrdinalIgnoreCase.Compare(x, y); - - return (char.IsAsciiLetterOrDigit(x[0]), char.IsAsciiLetterOrDigit(y[0])) switch - { - (true, false) => -1, - (false, true) => 1, - _ => StringComparer.OrdinalIgnoreCase.Compare(x, y), - }; - } - } - - private static readonly NameComparer Comparer = new(); -} diff --git a/Penumbra/UI/CollectionTab/WorldCombo.cs b/Penumbra/UI/CollectionTab/WorldCombo.cs deleted file mode 100644 index 5441dbaa..00000000 --- a/Penumbra/UI/CollectionTab/WorldCombo.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using ImGuiNET; -using OtterGui.Widgets; - -namespace Penumbra.UI.CollectionTab; - -public sealed class WorldCombo : FilterComboCache> -{ - private static readonly KeyValuePair AllWorldPair = new(ushort.MaxValue, "Any World"); - - public WorldCombo(IReadOnlyDictionary worlds) - : base(worlds.OrderBy(kvp => kvp.Value).Prepend(AllWorldPair)) - { - CurrentSelection = AllWorldPair; - CurrentSelectionIdx = 0; - } - - protected override string ToString(KeyValuePair obj) - => obj.Value; - - public bool Draw(float width) - => Draw("##worldCombo", CurrentSelection.Value, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); -}