From 0a8104ccdbbf0da2f6e4716261570e57e4938f2e Mon Sep 17 00:00:00 2001 From: RisaDev <151885272+RisaDev@users.noreply.github.com> Date: Fri, 18 Oct 2024 23:15:46 +0300 Subject: [PATCH] Reimplemented profile conversion to V5 using some heuristics based on excel sheets --- .../CustomizePlus.GameData.csproj | 2 +- .../Data/ReverseNameDicts.cs | 65 +++++++++++++++ .../Bases/ReverseNameDictionary.cs | 83 +++++++++++++++++++ .../ReverseSearchDictBNpc.cs | 33 ++++++++ .../ReverseSearchDictCompanion.cs | 33 ++++++++ .../ReverseSearchDictENpc.cs | 33 ++++++++ .../ReverseSearchDictMount.cs | 56 +++++++++++++ .../Helpers/V3ProfileToV4Converter.cs | 2 +- CustomizePlus/Core/Services/CommandService.cs | 7 +- .../Core/Services/SupportLogBuilderService.cs | 14 ++-- CustomizePlus/Profiles/Data/Profile.cs | 5 +- .../Profiles/ProfileManager.ProfileLoading.cs | 37 ++++++++- CustomizePlus/Profiles/ProfileManager.cs | 28 +++---- .../Tabs/Debug/StateMonitoringTab.cs | 3 +- .../MainWindow/Tabs/Profiles/ProfilePanel.cs | 4 +- 15 files changed, 367 insertions(+), 38 deletions(-) create mode 100644 CustomizePlus.GameData/Data/ReverseNameDicts.cs create mode 100644 CustomizePlus.GameData/ReverseSearchDictionaries/Bases/ReverseNameDictionary.cs create mode 100644 CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictBNpc.cs create mode 100644 CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictCompanion.cs create mode 100644 CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictENpc.cs create mode 100644 CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictMount.cs diff --git a/CustomizePlus.GameData/CustomizePlus.GameData.csproj b/CustomizePlus.GameData/CustomizePlus.GameData.csproj index f10e52c..53b705d 100644 --- a/CustomizePlus.GameData/CustomizePlus.GameData.csproj +++ b/CustomizePlus.GameData/CustomizePlus.GameData.csproj @@ -1,4 +1,4 @@ - + net8.0-windows diff --git a/CustomizePlus.GameData/Data/ReverseNameDicts.cs b/CustomizePlus.GameData/Data/ReverseNameDicts.cs new file mode 100644 index 0000000..ff6dc88 --- /dev/null +++ b/CustomizePlus.GameData/Data/ReverseNameDicts.cs @@ -0,0 +1,65 @@ +using CustomizePlus.GameData.ReverseSearchDictionaries; +using Dalamud.Game.ClientState.Objects.Enums; +using OtterGui.Services; +using Penumbra.GameData.DataContainers; +using Penumbra.GameData.Structs; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace CustomizePlus.GameData.Data; + +/// A collection service for all the name dictionaries required for reverse name search. +/// note: this is mvp for profile upgrading purposes, not intended to be used for anything else. +public sealed class ReverseNameDicts( + ReverseSearchDictMount _mounts, + ReverseSearchDictCompanion _companions, + ReverseSearchDictBNpc _bNpcs, + ReverseSearchDictENpc _eNpcs) + : IAsyncService +{ + /// Valid Mount ids by name in title case. + public readonly ReverseSearchDictMount Mounts = _mounts; + + /// Valid Companion ids by name in title case. + public readonly ReverseSearchDictCompanion Companions = _companions; + + /// Valid BNPC ids by name in title case. + public readonly ReverseSearchDictBNpc BNpcs = _bNpcs; + + /// Valid ENPC ids by name in title case. + public readonly ReverseSearchDictENpc ENpcs = _eNpcs; + + /// Finished when all name dictionaries are finished. + public Task Awaiter { get; } = + Task.WhenAll(_mounts.Awaiter, _companions.Awaiter, _bNpcs.Awaiter, _eNpcs.Awaiter); + + /// + public bool Finished + => Awaiter.IsCompletedSuccessfully; + + /// Convert a given name for a certain ObjectKind to an ID. + /// default or a valid id. + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public uint ToID(ObjectKind kind, string name) + => TryGetID(kind, name, out var ret) ? ret : default; + + /// Convert a given ID for a certain ObjectKind to a name. + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + public bool TryGetID(ObjectKind kind, string name, [NotNullWhen(true)] out uint npcId) + { + npcId = default; + return kind switch + { + ObjectKind.MountType => Mounts.TryGetValue(name, out npcId), + ObjectKind.Companion => Companions.TryGetValue(name, out npcId), + ObjectKind.BattleNpc => BNpcs.TryGetValue(name, out npcId), + ObjectKind.EventNpc => ENpcs.TryGetValue(name, out npcId), + _ => false, + }; + } +} \ No newline at end of file diff --git a/CustomizePlus.GameData/ReverseSearchDictionaries/Bases/ReverseNameDictionary.cs b/CustomizePlus.GameData/ReverseSearchDictionaries/Bases/ReverseNameDictionary.cs new file mode 100644 index 0000000..d9d3bb2 --- /dev/null +++ b/CustomizePlus.GameData/ReverseSearchDictionaries/Bases/ReverseNameDictionary.cs @@ -0,0 +1,83 @@ +using Dalamud.Plugin.Services; +using Dalamud.Plugin; +using FFXIVClientStructs.FFXIV.Common.Lua; +using OtterGui.Log; +using Penumbra.GameData.Data; +using Penumbra.GameData.DataContainers.Bases; +using Penumbra.GameData.Structs; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CustomizePlus.GameData.ReverseSearchDictionaries.Bases; + +/// A base class for dictionaries from NPC names to their IDs. +/// The plugin interface. +/// A logger. +/// The data manger to fetch the data from. +/// The name of the data share. +/// The version of the data share. +/// The factory function to create the data from. +public abstract class ReverseNameDictionary( + IDalamudPluginInterface pluginInterface, + Logger log, + IDataManager gameData, + string name, + int version, + Func> factory) + : DataSharer>(pluginInterface, log, name, gameData.Language, version, factory), + IReadOnlyDictionary +{ + /// + public IEnumerator> GetEnumerator() + => Value.Select(kvp => new KeyValuePair(kvp.Key, new NpcId(kvp.Value))).GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public int Count + => Value.Count; + + /// + public bool ContainsKey(string key) + => Value.ContainsKey(key); + + /// + public bool TryGetValue(string key, [NotNullWhen(true)] out NpcId value) + { + if (!Value.TryGetValue(key, out var uintVal)) + { + value = default; + return false; + } + + value = new NpcId(uintVal); + return true; + } + + /// + public NpcId this[string key] + => new NpcId(Value[key]); + + /// + public IEnumerable Keys + => Value.Keys; + + /// + public IEnumerable Values + => Value.Values.Select(k => new NpcId(k)); + + /// + protected override long ComputeMemory() + => DataUtility.DictionaryMemory(16, Count) + Keys.Sum(v => v.Length * 2); //this seems to be only used by diagnostics stuff so I don't particularly care for this to be correct. + + /// + protected override int ComputeTotalCount() + => Count; +} diff --git a/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictBNpc.cs b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictBNpc.cs new file mode 100644 index 0000000..3a22e54 --- /dev/null +++ b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictBNpc.cs @@ -0,0 +1,33 @@ +using Dalamud.Plugin.Services; +using Dalamud.Plugin; +using OtterGui.Log; +using Penumbra.GameData.Data; +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; +using Lumina.Excel.GeneratedSheets; +using CustomizePlus.GameData.ReverseSearchDictionaries.Bases; + +namespace CustomizePlus.GameData.ReverseSearchDictionaries; + +/// A dictionary that matches names to battle npc ids. +public sealed class ReverseSearchDictBNpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData) + : ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchBNpcs", 7, () => CreateBNpcData(gameData)) +{ + /// Create the data. + private static IReadOnlyDictionary CreateBNpcData(IDataManager gameData) + { + var sheet = gameData.GetExcelSheet(gameData.Language)!; + var dict = new Dictionary((int)sheet.RowCount); + foreach (var n in sheet.Where(n => n.Singular.RawData.Length > 0)) + dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, n.Article), n.RowId); + return dict.ToFrozenDictionary(); + } + + /// + public bool TryGetValue(string key, [NotNullWhen(true)] out uint value) + => Value.TryGetValue(key, out value); + + /// + public uint this[string key] + => Value[key]; +} diff --git a/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictCompanion.cs b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictCompanion.cs new file mode 100644 index 0000000..4c26193 --- /dev/null +++ b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictCompanion.cs @@ -0,0 +1,33 @@ +using Dalamud.Plugin.Services; +using Dalamud.Plugin; +using OtterGui.Log; +using Penumbra.GameData.Data; +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; +using Lumina.Excel.GeneratedSheets; +using CustomizePlus.GameData.ReverseSearchDictionaries.Bases; + +namespace CustomizePlus.GameData.ReverseSearchDictionaries; + +/// A dictionary that matches companion names to their ids. +public sealed class ReverseSearchDictCompanion(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData) + : ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchCompanions", 7, () => CreateCompanionData(gameData)) +{ + /// Create the data. + private static IReadOnlyDictionary CreateCompanionData(IDataManager gameData) + { + var sheet = gameData.GetExcelSheet(gameData.Language)!; + var dict = new Dictionary((int)sheet.RowCount); + foreach (var c in sheet.Where(c => c.Singular.RawData.Length > 0 && c.Order < ushort.MaxValue)) + dict.TryAdd(DataUtility.ToTitleCaseExtended(c.Singular, c.Article), c.RowId); + return dict.ToFrozenDictionary(); + } + + /// + public bool TryGetValue(string key, [NotNullWhen(true)] out uint value) + => Value.TryGetValue(key, out value); + + /// + public uint this[string key] + => Value[key]; +} \ No newline at end of file diff --git a/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictENpc.cs b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictENpc.cs new file mode 100644 index 0000000..81405a8 --- /dev/null +++ b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictENpc.cs @@ -0,0 +1,33 @@ +using Dalamud.Plugin.Services; +using Dalamud.Plugin; +using OtterGui.Log; +using Penumbra.GameData.Data; +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; +using Lumina.Excel.GeneratedSheets; +using CustomizePlus.GameData.ReverseSearchDictionaries.Bases; + +namespace CustomizePlus.GameData.ReverseSearchDictionaries; + +/// A dictionary that matches names to event npc ids. +public sealed class ReverseSearchDictENpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData) + : ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchENpcs", 7, () => CreateENpcData(gameData)) +{ + /// Create the data. + private static IReadOnlyDictionary CreateENpcData(IDataManager gameData) + { + var sheet = gameData.GetExcelSheet(gameData.Language)!; + var dict = new Dictionary((int)sheet.RowCount); + foreach (var n in sheet.Where(e => e.Singular.RawData.Length > 0)) + dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, n.Article), n.RowId); + return dict.ToFrozenDictionary(); + } + + /// + public bool TryGetValue(string key, [NotNullWhen(true)] out uint value) + => Value.TryGetValue(key, out value); + + /// + public uint this[string key] + => Value[key]; +} \ No newline at end of file diff --git a/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictMount.cs b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictMount.cs new file mode 100644 index 0000000..db8cdc3 --- /dev/null +++ b/CustomizePlus.GameData/ReverseSearchDictionaries/ReverseSearchDictMount.cs @@ -0,0 +1,56 @@ +using Dalamud.Plugin.Services; +using Dalamud.Plugin; +using OtterGui.Log; +using Penumbra.GameData.Data; +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; +using Lumina.Excel.GeneratedSheets; +using CustomizePlus.GameData.ReverseSearchDictionaries.Bases; +using Dalamud.Utility; + +namespace CustomizePlus.GameData.ReverseSearchDictionaries; + +/// A dictionary that matches names to mount ids. +public sealed class ReverseSearchDictMount(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData) + : ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchMounts", 7, () => CreateMountData(gameData)) +{ + /// Create the data. + private static IReadOnlyDictionary CreateMountData(IDataManager gameData) + { + var sheet = gameData.GetExcelSheet(gameData.Language)!; + var dict = new Dictionary((int)sheet.RowCount); + // Add some custom data. + dict.TryAdd("Falcon (Porter)", 119); + dict.TryAdd("Hippo Cart (Quest)", 295); + dict.TryAdd("Hippo Cart (Quest)", 296); + dict.TryAdd("Miw Miisv (Quest)", 298); + dict.TryAdd("Moon-hopper (Quest)", 309); + foreach (var m in sheet) + { + if (m.Singular.RawData.Length > 0 && m.Order >= 0) + { + dict.TryAdd(DataUtility.ToTitleCaseExtended(m.Singular, m.Article), m.RowId); + } + else if (m.Unknown18.RawData.Length > 0) + { + // Try to transform some file names into category names. + var whistle = m.Unknown18.ToDalamudString().ToString(); + whistle = whistle.Replace("SE_Bt_Etc_", string.Empty) + .Replace("Mount_", string.Empty) + .Replace("_call", string.Empty) + .Replace("Whistle", string.Empty); + dict.TryAdd($"? {whistle} #{m.RowId}", m.RowId); + } + } + + return dict.ToFrozenDictionary(); + } + + /// + public bool TryGetValue(string key, [NotNullWhen(true)] out uint value) + => Value.TryGetValue(key, out value); + + /// + public uint this[string key] + => Value[key]; +} \ No newline at end of file diff --git a/CustomizePlus/Configuration/Helpers/V3ProfileToV4Converter.cs b/CustomizePlus/Configuration/Helpers/V3ProfileToV4Converter.cs index f4cdac4..6d7b037 100644 --- a/CustomizePlus/Configuration/Helpers/V3ProfileToV4Converter.cs +++ b/CustomizePlus/Configuration/Helpers/V3ProfileToV4Converter.cs @@ -14,7 +14,7 @@ internal static class V3ProfileToV4Converter var profile = new Profile { Name = $"{v3Profile.ProfileName} - {v3Profile.CharacterName}", - CharacterName = v3Profile.CharacterName, + //CharacterName = v3Profile.CharacterName, //todo CreationDate = v3Profile.CreationDate, ModifiedDate = DateTimeOffset.UtcNow, Enabled = v3Profile.Enabled, diff --git a/CustomizePlus/Core/Services/CommandService.cs b/CustomizePlus/Core/Services/CommandService.cs index 246d413..1002393 100644 --- a/CustomizePlus/Core/Services/CommandService.cs +++ b/CustomizePlus/Core/Services/CommandService.cs @@ -13,6 +13,7 @@ using static System.Windows.Forms.AxHost; using CustomizePlus.Profiles.Data; using CustomizePlus.Configuration.Data; using Dalamud.Interface.ImGuiNotification; +using CustomizePlus.GameData.Extensions; namespace CustomizePlus.Core.Services; @@ -182,10 +183,10 @@ public class CommandService : IDisposable if (!isTurningOffAllProfiles) { profileName = subArgumentList[1].Trim(); - targetProfile = _profileManager.Profiles.FirstOrDefault(x => x.Name == profileName && x.CharacterName == characterName); + targetProfile = _profileManager.Profiles.FirstOrDefault(x => x.Name == profileName && x.Character.ToNameWithoutOwnerName() == characterName); } else - targetProfile = _profileManager.Profiles.FirstOrDefault(x => x.CharacterName == characterName && x.Enabled); + targetProfile = _profileManager.Profiles.FirstOrDefault(x => x.Character.ToNameWithoutOwnerName() == characterName && x.Enabled); if (targetProfile == null) { @@ -224,7 +225,7 @@ public class CommandService : IDisposable .AddText(" was successfully ") .AddBlue(state != null ? ((bool)state ? "enabled" : "disabled") : "toggled") .AddText(" for ") - .AddRed(targetProfile.CharacterName).BuiltString); + .AddRed(targetProfile.Character.ToNameWithoutOwnerName()).BuiltString); } catch (Exception e) { diff --git a/CustomizePlus/Core/Services/SupportLogBuilderService.cs b/CustomizePlus/Core/Services/SupportLogBuilderService.cs index 4d03c0a..89ce76a 100644 --- a/CustomizePlus/Core/Services/SupportLogBuilderService.cs +++ b/CustomizePlus/Core/Services/SupportLogBuilderService.cs @@ -1,17 +1,13 @@ -using CustomizePlus.Armatures.Services; +using System; +using System.Linq; +using System.Text; +using CustomizePlus.Armatures.Services; using CustomizePlus.Configuration.Data; using CustomizePlus.Core.Data; using CustomizePlus.Core.Extensions; using CustomizePlus.Profiles; using CustomizePlus.Templates; using Dalamud.Plugin; -using OtterGui.Services; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; namespace CustomizePlus.Core.Services; @@ -72,7 +68,7 @@ public class SupportLogBuilderService sb.Append($"> > **`{profile.ToString(),-32}`*\n"); sb.Append($"> > **`Name: `** {profile.Name.Text.Incognify()}\n"); sb.Append($"> > **`Type: `** {profile.ProfileType} \n"); - sb.Append($"> > **`Character name: `** {profile.CharacterName.Text.Incognify()}\n"); + sb.Append($"> > **`Character name: `** {profile.Character.Incognito(null)}\n"); sb.Append($"> > **`Templates:`**\n"); sb.Append($"> > > **`Count: `** {profile.Templates.Count}\n"); foreach (var template in profile.Templates) diff --git a/CustomizePlus/Profiles/Data/Profile.cs b/CustomizePlus/Profiles/Data/Profile.cs index 841e4a9..ed6154b 100644 --- a/CustomizePlus/Profiles/Data/Profile.cs +++ b/CustomizePlus/Profiles/Data/Profile.cs @@ -29,8 +29,8 @@ public sealed class Profile : ISavable public List Armatures = new(); - [Obsolete("To be removed in the future versions")] - public LowerString CharacterName { get; set; } = LowerString.Empty; + /* [Obsolete("To be removed in the future versions")] + public LowerString CharacterName { get; set; } = LowerString.Empty;*/ public ActorIdentifier Character { get; set; } = ActorIdentifier.Invalid; @@ -101,7 +101,6 @@ public sealed class Profile : ISavable ["UniqueId"] = UniqueId, ["CreationDate"] = CreationDate, ["ModifiedDate"] = ModifiedDate, - ["CharacterName"] = CharacterName.Text, ["Character"] = Character.ToJson(), ["Name"] = Name.Text, ["Enabled"] = Enabled, diff --git a/CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs b/CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs index 43b014c..d286ca6 100644 --- a/CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs +++ b/CustomizePlus/Profiles/ProfileManager.ProfileLoading.cs @@ -11,6 +11,8 @@ using System.IO; using System.Linq; using Penumbra.String; using Penumbra.GameData.Structs; +using Dalamud.Game.ClientState.Objects.Enums; +using Penumbra.GameData.Gui; namespace CustomizePlus.Profiles; @@ -91,7 +93,39 @@ public partial class ProfileManager : IDisposable { var profile = LoadProfileV4V5(obj); - profile.CharacterName = new LowerString(obj["CharacterName"]?.ToObject()?.Trim() ?? throw new ArgumentNullException("CharacterName")); + var characterName = obj["CharacterName"]?.ToObject()?.Trim() ?? throw new ArgumentNullException("CharacterName"); + + if (string.IsNullOrWhiteSpace(characterName)) + return profile; + + var nameWordsCnt = characterName.Split(' ').Length; + if (nameWordsCnt == 2) + profile.Character = _actorManager.CreatePlayer(ByteString.FromStringUnsafe(characterName, false), WorldId.AnyWorld); + else if (_reverseNameDicts.TryGetID(ObjectKind.EventNpc, characterName, out var id)) + profile.Character = _actorManager.CreateNpc(ObjectKind.EventNpc, new NpcId(id)); + else if (_reverseNameDicts.TryGetID(ObjectKind.BattleNpc, characterName, out id)) + profile.Character = _actorManager.CreateNpc(ObjectKind.BattleNpc, new NpcId(id)); + else if (_reverseNameDicts.TryGetID(ObjectKind.MountType, characterName, out id)) + { + var currentPlayer = _actorManager.GetCurrentPlayer(); + profile.Character = _actorManager.CreateOwned(currentPlayer.PlayerName, currentPlayer.HomeWorld, ObjectKind.MountType, new NpcId(id)); + } + else if (_reverseNameDicts.TryGetID(ObjectKind.Companion, characterName, out id)) + { + var currentPlayer = _actorManager.GetCurrentPlayer(); + profile.Character = _actorManager.CreateOwned(currentPlayer.PlayerName, currentPlayer.HomeWorld, ObjectKind.Companion, new NpcId(id)); + } + else + { + _logger.Warning($"Unable to automatically migrate \"{profile.Name}\" to V5, unknown character name: {characterName}"); + _messageService.NotificationMessage($"Unable to detect character type for profile \"{profile.Name}\", please set character for this profile manually.", Dalamud.Interface.ImGuiNotification.NotificationType.Error); + } + + if (profile.Character.IsValid) + { + _logger.Debug($"Upgraded profile \"{profile.Name}\" to V5: {characterName} -> {profile.Character}. Save queued."); + _saveService.QueueSave(profile); + } return profile; } @@ -103,7 +137,6 @@ public partial class ProfileManager : IDisposable var character = _actorManager.FromJson(obj["Character"] as JObject); profile.Character = character; - profile.CharacterName = new LowerString(obj["CharacterName"]?.ToObject()?.Trim() ?? throw new ArgumentNullException("CharacterName")); //temp return profile; } diff --git a/CustomizePlus/Profiles/ProfileManager.cs b/CustomizePlus/Profiles/ProfileManager.cs index 77421aa..802731c 100644 --- a/CustomizePlus/Profiles/ProfileManager.cs +++ b/CustomizePlus/Profiles/ProfileManager.cs @@ -28,6 +28,8 @@ using Penumbra.GameData.Interop; using System.Runtime.Serialization; using CustomizePlus.Game.Services; using ObjectManager = CustomizePlus.GameData.Services.ObjectManager; +using System.Threading.Tasks; +using OtterGui.Classes; namespace CustomizePlus.Profiles; @@ -44,6 +46,8 @@ public partial class ProfileManager : IDisposable private readonly ActorManager _actorManager; private readonly GameObjectService _gameObjectService; private readonly ObjectManager _objectManager; + private readonly ReverseNameDicts _reverseNameDicts; + private readonly MessageService _messageService; private readonly ProfileChanged _event; private readonly TemplateChanged _templateChangedEvent; private readonly ReloadEvent _reloadEvent; @@ -63,6 +67,8 @@ public partial class ProfileManager : IDisposable ActorManager actorManager, GameObjectService gameObjectService, ObjectManager objectManager, + ReverseNameDicts reverseNameDicts, + MessageService messageService, ProfileChanged @event, TemplateChanged templateChangedEvent, ReloadEvent reloadEvent, @@ -76,6 +82,8 @@ public partial class ProfileManager : IDisposable _actorManager = actorManager; _gameObjectService = gameObjectService; _objectManager = objectManager; + _reverseNameDicts = reverseNameDicts; + _messageService = messageService; _event = @event; _templateChangedEvent = templateChangedEvent; _templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ProfileManager); @@ -86,7 +94,7 @@ public partial class ProfileManager : IDisposable CreateProfileFolder(saveService); - LoadProfiles(); + _reverseNameDicts.Awaiter.ContinueWith(_ => LoadProfiles(), TaskScheduler.Default); } public void Dispose() @@ -467,7 +475,7 @@ public partial class ProfileManager : IDisposable if (actorIdentifier.Type == IdentifierType.Owned && !actorIdentifier.IsOwnedByLocalPlayer()) return false; - return profile.CharacterName.Text == name || profile.Character.MatchesIgnoringOwnership(actorIdentifier); + return profile.Character.MatchesIgnoringOwnership(actorIdentifier); } if (_templateEditorManager.IsEditorActive && _templateEditorManager.EditorProfile.Enabled && IsProfileAppliesToCurrentActor(_templateEditorManager.EditorProfile)) @@ -475,20 +483,8 @@ public partial class ProfileManager : IDisposable foreach (var profile in Profiles) { - if(IsProfileAppliesToCurrentActor(profile)) - { - //todo: temp for migrations to v5 - //todo: make sure this works for minions and stuff - if (!profile.Character.IsValid) - { - _logger.Warning($"No character for profile {profile}, but character has been found as: {actorIdentifier}, will set."); - profile.Character = actorIdentifier; - _saveService.QueueSave(profile); - } - - if (profile.Enabled) - yield return profile; - } + if(profile.Enabled && IsProfileAppliesToCurrentActor(profile)) + yield return profile; } if (DefaultLocalPlayerProfile != null && DefaultLocalPlayerProfile.Enabled) diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs index f07f3d6..bdfc28c 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs @@ -134,7 +134,8 @@ public class StateMonitoringTab private void DrawSingleProfile(string prefix, Profile profile) { string name = profile.Name; - string characterName = profile.CharacterName; + string characterName = profile.Character.Type == Penumbra.GameData.Enums.IdentifierType.Owned ? + profile.Character.ToNameWithoutOwnerName() : profile.Character.ToString(); #if INCOGNIFY_STRINGS name = name.Incognify(); diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs index c566ae5..656f538 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Profiles/ProfilePanel.cs @@ -210,7 +210,7 @@ public class ProfilePanel ImGuiUtil.DrawFrameColumn("Character"); ImGui.TableNextColumn(); width = new Vector2(ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize("Limit to my creatures").X - 68, 0); - //name = _newCharacterName ?? _selector.Selected!.CharacterName; + ImGui.SetNextItemWidth(width.X); if (!_selector.IncognitoMode) @@ -220,7 +220,7 @@ public class ProfilePanel { ImGui.Text(_selector.Selected!.Character.IsValid ? $"Applies to {(_selector.Selected?.Character.Type == Penumbra.GameData.Enums.IdentifierType.Owned ? _selector.Selected?.Character.ToNameWithoutOwnerName() : _selector.Selected?.Character.ToString())}" : "No valid character selected for the profile"); - ImGui.Text($"Legacy: {_selector.Selected!.CharacterName.Text ?? "None"}"); + ImGui.Separator(); _actorAssignmentUi.DrawWorldCombo(width.X / 2);