Send IPC OnProfileUpdate when currently used template was changed in editor, fix Profile.GetActiveProfileIdOnCharacter IPC ignoring DefaultLocalPlayerProfile
This commit is contained in:
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}");
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user