Send IPC OnProfileUpdate when currently used template was changed in editor, fix Profile.GetActiveProfileIdOnCharacter IPC ignoring DefaultLocalPlayerProfile

This commit is contained in:
RisaDev
2024-11-23 19:41:42 +03:00
parent 4ee62205ff
commit e4e10e0f9a
6 changed files with 82 additions and 14 deletions

View File

@@ -15,6 +15,9 @@ using CustomizePlus.GameData.Extensions;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using CustomizePlus.Templates.Data;
using CustomizePlus.Templates.Events;
using Penumbra.GameData.Actors;
namespace CustomizePlus.Api; namespace CustomizePlus.Api;
@@ -144,7 +147,7 @@ public partial class CustomizePlusIpc
if (actor == null || !actor.Value.Valid || !actor.Value.IsCharacter) if (actor == null || !actor.Value.Valid || !actor.Value.IsCharacter)
return ((int)ErrorCode.InvalidCharacter, null); return ((int)ErrorCode.InvalidCharacter, null);
var profile = _profileManager.GetProfileByActor(actor.Value, true); var profile = _profileManager.GetActiveProfileByActor(actor.Value);
if (profile == null) if (profile == null)
return ((int)ErrorCode.ProfileNotFound, null); return ((int)ErrorCode.ProfileNotFound, null);
@@ -268,6 +271,35 @@ public partial class CustomizePlusIpc
} }
} }
//Send profile update if any of the templates were changed in currently active profile
private void OnTemplateChanged(TemplateChanged.Type type, Template? template, object? arg3)
{
if (type != TemplateChanged.Type.EditorDisabled)
return;
(ActorIdentifier actorIdentifier, bool hasChanges) = ((ActorIdentifier, bool))arg3;
if (!hasChanges || actorIdentifier.Type != IdentifierType.Player)
return;
var actor = _gameObjectService.GetLocalPlayerActor();
if (!actor.Valid || !actorIdentifier.PlayerName.EqualsCi(actor.Utf8Name))
return;
var profile = _profileManager.GetActiveProfileByActor(actor);
if (profile == null) //safety check
return;
if (!profile.Templates.Contains(template!))
return;
ICharacter? localPlayerCharacter = (ICharacter?)_gameObjectService.GetDalamudGameObjectFromActor(actor);
if (localPlayerCharacter == null)
return;
OnProfileUpdateInternal(localPlayerCharacter, profile);
}
//warn: intended limitation - ignores default profiles because why you would use default profile on your own character //warn: intended limitation - ignores default profiles because why you would use default profile on your own character
private void OnArmatureChanged(ArmatureChanged.Type type, Armature armature, object? arg3) private void OnArmatureChanged(ArmatureChanged.Type type, Armature armature, object? arg3)
{ {

View File

@@ -4,6 +4,8 @@ using CustomizePlus.Game.Services;
using CustomizePlus.GameData.Services; using CustomizePlus.GameData.Services;
using CustomizePlus.Profiles; using CustomizePlus.Profiles;
using CustomizePlus.Profiles.Events; using CustomizePlus.Profiles.Events;
using CustomizePlus.Templates.Data;
using CustomizePlus.Templates.Events;
using Dalamud.Plugin; using Dalamud.Plugin;
using ECommonsLite.EzIpcManager; using ECommonsLite.EzIpcManager;
using OtterGui.Log; using OtterGui.Log;
@@ -29,6 +31,7 @@ public partial class CustomizePlusIpc : IDisposable
private readonly CutsceneService _cutsceneService; private readonly CutsceneService _cutsceneService;
private readonly ArmatureChanged _armatureChangedEvent; private readonly ArmatureChanged _armatureChangedEvent;
private readonly TemplateChanged _templateChangedEvent;
/// <summary> /// <summary>
/// Shows if IPC failed to initialize or any other unrecoverable fatal error occured. /// Shows if IPC failed to initialize or any other unrecoverable fatal error occured.
@@ -43,7 +46,8 @@ public partial class CustomizePlusIpc : IDisposable
GameObjectService gameObjectService, GameObjectService gameObjectService,
ProfileFileSystem profileFileSystem, ProfileFileSystem profileFileSystem,
CutsceneService cutsceneService, CutsceneService cutsceneService,
ArmatureChanged armatureChangedEvent) ArmatureChanged armatureChangedEvent,
TemplateChanged templateChangedEvent)
{ {
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_logger = logger; _logger = logger;
@@ -54,14 +58,17 @@ public partial class CustomizePlusIpc : IDisposable
_cutsceneService = cutsceneService; _cutsceneService = cutsceneService;
_armatureChangedEvent = armatureChangedEvent; _armatureChangedEvent = armatureChangedEvent;
_templateChangedEvent = templateChangedEvent;
EzIPC.Init(this, "CustomizePlus"); EzIPC.Init(this, "CustomizePlus");
_armatureChangedEvent.Subscribe(OnArmatureChanged, ArmatureChanged.Priority.CustomizePlusIpc); _armatureChangedEvent.Subscribe(OnArmatureChanged, ArmatureChanged.Priority.CustomizePlusIpc);
_templateChangedEvent.Subscribe(OnTemplateChanged, TemplateChanged.Priority.CustomizePlusIpc);
} }
public void Dispose() public void Dispose()
{ {
_armatureChangedEvent.Unsubscribe(OnArmatureChanged); _armatureChangedEvent.Unsubscribe(OnArmatureChanged);
_templateChangedEvent.Unsubscribe(OnTemplateChanged);
} }
} }

View File

@@ -428,7 +428,15 @@ public unsafe sealed class ArmatureManager : IDisposable
if (type == TemplateChanged.Type.EditorEnabled || if (type == TemplateChanged.Type.EditorEnabled ||
type == TemplateChanged.Type.EditorDisabled) type == TemplateChanged.Type.EditorDisabled)
{ {
foreach (var armature in GetArmaturesForCharacter((ActorIdentifier)arg3!)) ActorIdentifier actor;
bool hasChanges;
if(type == TemplateChanged.Type.EditorEnabled)
actor = (ActorIdentifier)arg3;
else
(actor, hasChanges) = ((ActorIdentifier, bool))arg3;
foreach (var armature in GetArmaturesForCharacter(actor))
{ {
armature.IsPendingProfileRebind = true; armature.IsPendingProfileRebind = true;
_logger.Debug($"ArmatureManager.OnTemplateChange template editor enabled/disabled: {type}, pending profile set for {armature}"); _logger.Debug($"ArmatureManager.OnTemplateChange template editor enabled/disabled: {type}, pending profile set for {armature}");

View File

@@ -432,7 +432,8 @@ public partial class ProfileManager : IDisposable
/// <summary> /// <summary>
/// Return profile by actor identifier, does not return temporary profiles. /// Return profile by actor identifier, does not return temporary profiles.
/// </summary> /// </summary>
public Profile? GetProfileByActor(Actor actor, bool enabledOnly = false) /// todo: use GetEnabledProfilesByActor
public Profile? GetActiveProfileByActor(Actor actor)
{ {
var actorIdentifier = actor.GetIdentifier(_actorManager); var actorIdentifier = actor.GetIdentifier(_actorManager);
@@ -442,14 +443,17 @@ public partial class ProfileManager : IDisposable
if (actorIdentifier.Type == IdentifierType.Owned && !actorIdentifier.IsOwnedByLocalPlayer()) if (actorIdentifier.Type == IdentifierType.Owned && !actorIdentifier.IsOwnedByLocalPlayer())
return null; return null;
var query = Profiles.Where(p => p.Characters.Any(x => x.MatchesIgnoringOwnership(actorIdentifier)) && !p.IsTemporary); var query = Profiles.Where(p => p.Characters.Any(x => x.MatchesIgnoringOwnership(actorIdentifier)) && !p.IsTemporary && p.Enabled);
if (enabledOnly)
query = query.Where(x => x.Enabled);
var profile = query.OrderByDescending(x => x.Priority).FirstOrDefault(); var profile = query.OrderByDescending(x => x.Priority).FirstOrDefault();
if(profile == null) if(profile == null)
{
if (DefaultLocalPlayerProfile?.Enabled == true)
return DefaultLocalPlayerProfile;
return null; return null;
}
return profile; return profile;
} }

View File

@@ -9,6 +9,7 @@ using CustomizePlus.Profiles.Enums;
using CustomizePlus.Templates.Data; using CustomizePlus.Templates.Data;
using CustomizePlus.Templates.Events; using CustomizePlus.Templates.Events;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Log; using OtterGui.Log;
@@ -160,6 +161,10 @@ public class TemplateEditorManager : IDisposable
_logger.Debug($"Disabling editor profile"); _logger.Debug($"Disabling editor profile");
//todo: can be optimized by storing actual reference to original template somewhere
var template = _templateManager.GetTemplate(CurrentlyEditedTemplateId);
var hasChanges = HasChanges;
CurrentlyEditedTemplateId = Guid.Empty; CurrentlyEditedTemplateId = Guid.Empty;
CurrentlyEditedTemplate = null; CurrentlyEditedTemplate = null;
EditorProfile.Enabled = false; EditorProfile.Enabled = false;
@@ -167,21 +172,35 @@ public class TemplateEditorManager : IDisposable
IsEditorActive = false; IsEditorActive = false;
HasChanges = false; HasChanges = false;
_event.Invoke(TemplateChanged.Type.EditorDisabled, null, Character); _event.Invoke(TemplateChanged.Type.EditorDisabled, template, (Character, hasChanges));
return true; return true;
} }
public void SaveChanges(bool asCopy = false) public void SaveChangesAndDisableEditor(bool asCopy = false)
{ {
if (!IsEditorActive || IsEditorPaused)
return;
if(!HasChanges)
{
DisableEditor();
return;
}
var targetTemplate = _templateManager.GetTemplate(CurrentlyEditedTemplateId); var targetTemplate = _templateManager.GetTemplate(CurrentlyEditedTemplateId);
if (targetTemplate == null) if (targetTemplate == null)
throw new Exception($"Fatal editor error: Template with ID {CurrentlyEditedTemplateId} not found in template manager"); throw new Exception($"Fatal editor error: Template with ID {CurrentlyEditedTemplateId} not found in template manager");
if (asCopy) if (asCopy)
{
targetTemplate = _templateManager.Clone(targetTemplate, $"{targetTemplate.Name} - Copy {Guid.NewGuid().ToString().Substring(0, 4)}", false); targetTemplate = _templateManager.Clone(targetTemplate, $"{targetTemplate.Name} - Copy {Guid.NewGuid().ToString().Substring(0, 4)}", false);
HasChanges = false; //do this so EditorDisabled event sends proper info about the state of *currently edited* template
}
_templateManager.ApplyBoneChangesAndSave(targetTemplate, CurrentlyEditedTemplate!); _templateManager.ApplyBoneChangesAndSave(targetTemplate, CurrentlyEditedTemplate!);
DisableEditor();
} }
public bool ChangeEditorCharacter(ActorIdentifier character) public bool ChangeEditorCharacter(ActorIdentifier character)

View File

@@ -341,8 +341,7 @@ public class BoneEditorPanel
ImGui.SetCursorPos(new Vector2(xPos, yPos)); ImGui.SetCursorPos(new Vector2(xPos, yPos));
if (ImGui.Button("Save", buttonWidth)) if (ImGui.Button("Save", buttonWidth))
{ {
_editorManager.SaveChanges(); _editorManager.SaveChangesAndDisableEditor();
_editorManager.DisableEditor();
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
@@ -350,8 +349,7 @@ public class BoneEditorPanel
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button("Save as a copy", buttonWidth)) if (ImGui.Button("Save as a copy", buttonWidth))
{ {
_editorManager.SaveChanges(true); _editorManager.SaveChangesAndDisableEditor(true);
_editorManager.DisableEditor();
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }