diff --git a/CustomizePlus/Armatures/Services/ArmatureManager.cs b/CustomizePlus/Armatures/Services/ArmatureManager.cs index c885ab7..ac920ea 100644 --- a/CustomizePlus/Armatures/Services/ArmatureManager.cs +++ b/CustomizePlus/Armatures/Services/ArmatureManager.cs @@ -368,9 +368,9 @@ public unsafe sealed class ArmatureManager : IDisposable if (type == TemplateChanged.Type.EditorCharacterChanged) { - (var characterName, var profile) = ((string, Profile))arg3; + (var character, var profile) = ((ActorIdentifier, Profile))arg3; - foreach (var armature in GetArmaturesForCharacterName(characterName)) + foreach (var armature in GetArmaturesForCharacter(character)) { armature.IsPendingProfileRebind = true; _logger.Debug($"ArmatureManager.OnTemplateChange Editor profile character name changed, armature rebind scheduled: {type}, {armature}"); @@ -383,7 +383,7 @@ public unsafe sealed class ArmatureManager : IDisposable foreach (var armature in profile.Armatures) armature.IsPendingProfileRebind = true; - _logger.Debug($"ArmatureManager.OnTemplateChange Editor profile character name changed, armature rebind scheduled: {type}, profile: {profile.Name.Text.Incognify()}->{profile.Enabled}, new name: {characterName.Incognify()}"); + _logger.Debug($"ArmatureManager.OnTemplateChange Editor profile character name changed, armature rebind scheduled: {type}, profile: {profile.Name.Text.Incognify()}->{profile.Enabled}, new name: {character.Incognito(null)}"); return; } @@ -391,7 +391,7 @@ public unsafe sealed class ArmatureManager : IDisposable if (type == TemplateChanged.Type.EditorEnabled || type == TemplateChanged.Type.EditorDisabled) { - foreach (var armature in GetArmaturesForCharacterName((string)arg3!)) + foreach (var armature in GetArmaturesForCharacter((ActorIdentifier)arg3!)) { armature.IsPendingProfileRebind = true; _logger.Debug($"ArmatureManager.OnTemplateChange template editor enabled/disabled: {type}, pending profile set for {armature}"); @@ -516,17 +516,6 @@ public unsafe sealed class ArmatureManager : IDisposable profile!.Armatures.ForEach(x => x.IsPendingProfileRebind = true); } - private IEnumerable GetArmaturesForCharacterName(string characterName) - { - foreach(var kvPair in Armatures) - { - (var actorIdentifier, _) = _gameObjectService.GetTrueActorForSpecialTypeActor(kvPair.Key); - - if(actorIdentifier.ToNameWithoutOwnerName() == characterName) - yield return kvPair.Value; - } - } - private IEnumerable GetArmaturesForCharacter(ActorIdentifier actorIdentifier) { foreach (var kvPair in Armatures) diff --git a/CustomizePlus/Configuration/Data/PluginConfiguration.cs b/CustomizePlus/Configuration/Data/PluginConfiguration.cs index 9c57d0e..7d3e4e7 100644 --- a/CustomizePlus/Configuration/Data/PluginConfiguration.cs +++ b/CustomizePlus/Configuration/Data/PluginConfiguration.cs @@ -11,6 +11,8 @@ using CustomizePlus.Core.Data; using CustomizePlus.Configuration.Services; using CustomizePlus.UI.Windows; using Dalamud.Interface.ImGuiNotification; +using Penumbra.GameData.Actors; +using CustomizePlus.Core.Helpers; namespace CustomizePlus.Configuration.Data; @@ -66,9 +68,8 @@ public class PluginConfiguration : IPluginConfiguration, ISavable public bool ShowLiveBones { get; set; } = true; public bool BoneMirroringEnabled { get; set; } = false; - public bool LimitLookupToOwnedObjects { get; set; } = false; - public string? PreviewCharacterName { get; set; } = null; + public ActorIdentifier PreviewCharacter { get; set; } = ActorIdentifier.Invalid; public int EditorValuesPrecision { get; set; } = 3; @@ -134,6 +135,7 @@ public class PluginConfiguration : IPluginConfiguration, ISavable JsonConvert.PopulateObject(text, this, new JsonSerializerSettings { Error = HandleDeserializationError, + Converters = new List { new ActorIdentifierJsonConverter() } }); } catch (Exception ex) @@ -153,6 +155,7 @@ public class PluginConfiguration : IPluginConfiguration, ISavable { using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }; var serializer = new JsonSerializer { Formatting = Formatting.Indented }; + serializer.Converters.Add(new ActorIdentifierJsonConverter()); serializer.Serialize(jWriter, this); } diff --git a/CustomizePlus/Core/Helpers/ActorIdentifierJsonConverter.cs b/CustomizePlus/Core/Helpers/ActorIdentifierJsonConverter.cs new file mode 100644 index 0000000..d967780 --- /dev/null +++ b/CustomizePlus/Core/Helpers/ActorIdentifierJsonConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Nodes; +using System.Text.Json; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Penumbra.GameData.Actors; +using Newtonsoft.Json.Linq; + +namespace CustomizePlus.Core.Helpers; + +internal sealed class ActorIdentifierJsonConverter : JsonConverter +{ + public override ActorIdentifier ReadJson(JsonReader reader, Type objectType, ActorIdentifier existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer) + { + JObject obj = JObject.Load(reader); + + if (Penumbra.GameData.Actors.ActorIdentifierExtensions.Manager == null) + throw new Exception("Penumbra.GameData.Actors.ActorIdentifierExtensions.Manager is not ready"); + + return Penumbra.GameData.Actors.ActorIdentifierExtensions.Manager.FromJson(obj); + } + + public override void WriteJson(JsonWriter writer, ActorIdentifier value, Newtonsoft.Json.JsonSerializer serializer) + { + value.ToJson().WriteTo(writer); + } +} \ No newline at end of file diff --git a/CustomizePlus/Core/Services/SupportLogBuilderService.cs b/CustomizePlus/Core/Services/SupportLogBuilderService.cs index 25c4aa0..4d03c0a 100644 --- a/CustomizePlus/Core/Services/SupportLogBuilderService.cs +++ b/CustomizePlus/Core/Services/SupportLogBuilderService.cs @@ -46,8 +46,7 @@ public class SupportLogBuilderService sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n"); sb.Append($"> **`Plugin enabled: `** {_configuration.PluginEnabled}\n"); sb.AppendLine("**Settings -> Editor Settings**"); - sb.Append($"> **`Limit to my creatures (editor): `** {_configuration.EditorConfiguration.LimitLookupToOwnedObjects}\n"); - sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacterName?.Incognify() ?? "Not set"}\n"); + sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacter.Incognito(null)}\n"); sb.Append($"> **`Set preview character on login: `** {_configuration.EditorConfiguration.SetPreviewToCurrentCharacterOnLogin}\n"); sb.Append($"> **`Root editing: `** {_configuration.EditorConfiguration.RootPositionEditingEnabled}\n"); sb.AppendLine("**Settings -> Profile application**"); diff --git a/CustomizePlus/Game/Services/GameObjectService.cs b/CustomizePlus/Game/Services/GameObjectService.cs index 46fdd22..6cd9677 100644 --- a/CustomizePlus/Game/Services/GameObjectService.cs +++ b/CustomizePlus/Game/Services/GameObjectService.cs @@ -9,6 +9,7 @@ using ObjectManager = CustomizePlus.GameData.Services.ObjectManager; using DalamudGameObject = Dalamud.Game.ClientState.Objects.Types.IGameObject; using CustomizePlus.Configuration.Data; using FFXIVClientStructs.FFXIV.Client.Game.Object; +using Penumbra.GameData.Files.ShaderStructs; namespace CustomizePlus.Game.Services; @@ -59,8 +60,6 @@ public class GameObjectService /// /// Case sensitive /// - /// - /// public IEnumerable<(ActorIdentifier, Actor)> FindActorsByName(string name) { _objectManager.Update(); @@ -85,6 +84,36 @@ public class GameObjectService } } + /// + /// Searches using CompareIgnoringOwnership + /// + public IEnumerable<(ActorIdentifier, Actor)> FindActorsByIdentifier(ActorIdentifier identifier) + { + if (!identifier.IsValid) + yield break; + + _objectManager.Update(); + + foreach (var kvPair in _objectManager.Identifiers) + { + var objectIdentifier = kvPair.Key; + + (objectIdentifier, _) = GetTrueActorForSpecialTypeActor(objectIdentifier); + + if (!objectIdentifier.IsValid) + continue; + + if (identifier.CompareIgnoringOwnership(objectIdentifier)) + { + if (kvPair.Value.Objects.Count > 1) //in gpose we can have more than a single object for one actor + foreach (var obj in kvPair.Value.Objects) + yield return (kvPair.Key.CreatePermanent(), obj); + else + yield return (kvPair.Key.CreatePermanent(), kvPair.Value.Objects[0]); + } + } + } + public Actor GetLocalPlayerActor() { _objectManager.Update(); diff --git a/CustomizePlus/Plugin.cs b/CustomizePlus/Plugin.cs index 637cd61..b515460 100644 --- a/CustomizePlus/Plugin.cs +++ b/CustomizePlus/Plugin.cs @@ -21,6 +21,7 @@ using CustomizePlus.Core.Extensions; using CustomizePlus.Templates; using CustomizePlus.Profiles; using CustomizePlus.Armatures.Services; +using Penumbra.GameData.Actors; namespace CustomizePlus; @@ -44,6 +45,8 @@ public sealed class Plugin : IDalamudPlugin _services = ServiceManagerBuilder.CreateProvider(pluginInterface, Logger); + _services.GetService(); //needs to be initialized early for config to be read properly + //temporary var v3ConfigFixer = _services.GetService(); v3ConfigFixer.FixV3ConfigIfNeeded(); diff --git a/CustomizePlus/Templates/TemplateEditorManager.cs b/CustomizePlus/Templates/TemplateEditorManager.cs index 77339f2..b586c23 100644 --- a/CustomizePlus/Templates/TemplateEditorManager.cs +++ b/CustomizePlus/Templates/TemplateEditorManager.cs @@ -11,6 +11,7 @@ using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using OtterGui.Classes; using OtterGui.Log; +using Penumbra.GameData.Actors; using System; using System.Collections.Generic; using System.Linq; @@ -63,12 +64,22 @@ public class TemplateEditorManager : IDisposable /// /// Name of the preview character for the editor /// - public string CharacterName => EditorProfile.CharacterName; + public ActorIdentifier Character => EditorProfile.Character; /// /// Checks if preview character exists at the time of call /// - public bool IsCharacterFound => _gameObjectService.FindActorsByName(CharacterName).Count() > 0; + public bool IsCharacterFound + { + get + { + //todo: check with mounts/companions + var playerName = _gameObjectService.GetCurrentPlayerName(); + return _gameObjectService.FindActorsByIdentifier(Character) + .Where(x => x.Item1.Type != Penumbra.GameData.Enums.IdentifierType.Owned || x.Item1.PlayerName.ToString() == playerName) + .Any(); + } + } public bool IsKeepOnlyEditorProfileActive { get; set; } //todo @@ -89,13 +100,13 @@ public class TemplateEditorManager : IDisposable _clientState.Login += OnLogin; - EditorProfile = new Profile() - { + EditorProfile = new Profile() + { Templates = new List