Fixes, IPC
* Armature manager now assigns permanent ActorIdentifier to armatures * Slight changes to make sure penumbra redraw doesn't break temporary profiles * Profile selection UI now gets updated on login/logout in order to display correct colors * Changed logic of setting Armature.IsVisible * Implemented OnProfileUpdate IPC
This commit is contained in:
@@ -17,6 +17,10 @@ using CustomizePlus.Templates.Events;
|
|||||||
using CustomizePlus.Profiles.Events;
|
using CustomizePlus.Profiles.Events;
|
||||||
using CustomizePlus.Templates.Data;
|
using CustomizePlus.Templates.Data;
|
||||||
using CustomizePlus.GameData.Data;
|
using CustomizePlus.GameData.Data;
|
||||||
|
using CustomizePlus.Core.Extensions;
|
||||||
|
using CustomizePlus.Armatures.Events;
|
||||||
|
using CustomizePlus.Armatures.Data;
|
||||||
|
using CustomizePlus.GameData.Extensions;
|
||||||
|
|
||||||
namespace CustomizePlus.Api.Compatibility;
|
namespace CustomizePlus.Api.Compatibility;
|
||||||
|
|
||||||
@@ -28,8 +32,8 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
private readonly ProfileManager _profileManager;
|
private readonly ProfileManager _profileManager;
|
||||||
private readonly GameObjectService _gameObjectService;
|
private readonly GameObjectService _gameObjectService;
|
||||||
|
|
||||||
private readonly TemplateChanged _templateChangedEvent;
|
|
||||||
private readonly ProfileChanged _profileChangedEvent;
|
private readonly ProfileChanged _profileChangedEvent;
|
||||||
|
private readonly ArmatureChanged _armatureChangedEvent;
|
||||||
|
|
||||||
private const int _configurationVersion = 3;
|
private const int _configurationVersion = 3;
|
||||||
|
|
||||||
@@ -37,10 +41,10 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
public const string GetProfileFromCharacterLabel = $"CustomizePlus.{nameof(GetProfileFromCharacter)}";
|
public const string GetProfileFromCharacterLabel = $"CustomizePlus.{nameof(GetProfileFromCharacter)}";
|
||||||
public const string SetProfileToCharacterLabel = $"CustomizePlus.{nameof(SetProfileToCharacter)}";
|
public const string SetProfileToCharacterLabel = $"CustomizePlus.{nameof(SetProfileToCharacter)}";
|
||||||
public const string RevertCharacterLabel = $"CustomizePlus.{nameof(RevertCharacter)}";
|
public const string RevertCharacterLabel = $"CustomizePlus.{nameof(RevertCharacter)}";
|
||||||
//public const string OnProfileUpdateLabel = $"CustomizePlus.{nameof(OnProfileUpdate)}"; //I'm honestly not sure this is even used by mare
|
public const string OnProfileUpdateLabel = $"CustomizePlus.{nameof(OnProfileUpdate)}";
|
||||||
public static readonly (int, int) ApiVersion = (3, 0);
|
public static readonly (int, int) ApiVersion = (3, 0);
|
||||||
|
|
||||||
//Sends local player's profile on hooks reload (plugin startup) as well as any updates to their profile.
|
//Sends local player's profile every time their active profile is changed
|
||||||
//If no profile is applied sends null
|
//If no profile is applied sends null
|
||||||
internal ICallGateProvider<string?, string?, object?>? ProviderOnProfileUpdate;
|
internal ICallGateProvider<string?, string?, object?>? ProviderOnProfileUpdate;
|
||||||
internal ICallGateProvider<Character?, object>? ProviderRevertCharacter;
|
internal ICallGateProvider<Character?, object>? ProviderRevertCharacter;
|
||||||
@@ -53,29 +57,72 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
DalamudPluginInterface pluginInterface,
|
DalamudPluginInterface pluginInterface,
|
||||||
Logger logger,
|
Logger logger,
|
||||||
ProfileManager profileManager,
|
ProfileManager profileManager,
|
||||||
GameObjectService gameObjectService//,
|
GameObjectService gameObjectService,
|
||||||
/*TemplateChanged templateChangedEvent,
|
ArmatureChanged armatureChangedEvent,
|
||||||
ProfileChanged profileChangedEvent*/)
|
ProfileChanged profileChangedEvent)
|
||||||
{
|
{
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
_gameObjectService = gameObjectService;
|
_gameObjectService = gameObjectService;
|
||||||
/* _templateChangedEvent = templateChangedEvent;
|
_profileChangedEvent = profileChangedEvent;
|
||||||
_profileChangedEvent = profileChangedEvent;*/
|
_armatureChangedEvent = armatureChangedEvent;
|
||||||
|
|
||||||
InitializeProviders();
|
InitializeProviders();
|
||||||
|
|
||||||
/*_templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.CustomizePlusIpc);
|
_profileChangedEvent.Subscribe(OnProfileChange, ProfileChanged.Priority.CustomizePlusIpc);
|
||||||
_profileChangedEvent.Subscribe(OnProfileChange, ProfileChanged.Priority.CustomizePlusIpc);*/
|
_armatureChangedEvent.Subscribe(OnArmatureChanged, ArmatureChanged.Priority.CustomizePlusIpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_profileChangedEvent.Unsubscribe(OnProfileChange);
|
||||||
|
_armatureChangedEvent.Unsubscribe(OnArmatureChanged);
|
||||||
DisposeProviders();
|
DisposeProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//warn: limitation - ignores default profiles but why you would use default profile on your own character
|
||||||
|
private void OnProfileChange(ProfileChanged.Type type, Profile? profile, object? arg3)
|
||||||
|
{
|
||||||
|
if (type != ProfileChanged.Type.AddedTemplate &&
|
||||||
|
type != ProfileChanged.Type.RemovedTemplate &&
|
||||||
|
type != ProfileChanged.Type.MovedTemplate &&
|
||||||
|
type != ProfileChanged.Type.ChangedTemplate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (profile == null ||
|
||||||
|
!profile.Enabled ||
|
||||||
|
profile.CharacterName.Text != _gameObjectService.GetCurrentPlayerName())
|
||||||
|
return;
|
||||||
|
|
||||||
|
OnProfileUpdate(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnArmatureChanged(ArmatureChanged.Type type, Armature armature, object? arg3)
|
||||||
|
{
|
||||||
|
string currentPlayerName = _gameObjectService.GetCurrentPlayerName();
|
||||||
|
|
||||||
|
if (armature.ActorIdentifier.ToNameWithoutOwnerName() != currentPlayerName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (type == ArmatureChanged.Type.Created ||
|
||||||
|
type == ArmatureChanged.Type.Rebound)
|
||||||
|
{
|
||||||
|
if(armature.Profile == null)
|
||||||
|
_logger.Warning("Armature created/rebound and profile is null");
|
||||||
|
|
||||||
|
OnProfileUpdate(armature.Profile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == ArmatureChanged.Type.Deleted)
|
||||||
|
{
|
||||||
|
OnProfileUpdate(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeProviders()
|
private void InitializeProviders()
|
||||||
{
|
{
|
||||||
_logger.Debug("Initializing legacy Customize+ IPC providers.");
|
_logger.Debug("Initializing legacy Customize+ IPC providers.");
|
||||||
@@ -121,7 +168,7 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
{
|
{
|
||||||
_logger.Error($"Error registering legacy Customize+ IPC provider for {RevertCharacterLabel}: {ex}");
|
_logger.Error($"Error registering legacy Customize+ IPC provider for {RevertCharacterLabel}: {ex}");
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProviderOnProfileUpdate = _pluginInterface.GetIpcProvider<string?, string?, object?>(OnProfileUpdateLabel);
|
ProviderOnProfileUpdate = _pluginInterface.GetIpcProvider<string?, string?, object?>(OnProfileUpdateLabel);
|
||||||
@@ -129,7 +176,7 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Error($"Error registering legacy Customize+ IPC provider for {OnProfileUpdateLabel}: {ex}");
|
_logger.Error($"Error registering legacy Customize+ IPC provider for {OnProfileUpdateLabel}: {ex}");
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeProviders()
|
private void DisposeProviders()
|
||||||
@@ -143,8 +190,7 @@ public class CustomizePlusIpc : IDisposable
|
|||||||
|
|
||||||
private void OnProfileUpdate(Profile? profile)
|
private void OnProfileUpdate(Profile? profile)
|
||||||
{
|
{
|
||||||
//Get player's body profile string and send IPC message
|
_logger.Debug($"Sending local player update message: {(profile != null ? profile.ToString() : "no profile")}");
|
||||||
_logger.Debug($"Sending local player update message: {profile?.Name ?? "no profile"} - {profile?.CharacterName ?? "no profile"}");
|
|
||||||
|
|
||||||
var convertedProfile = profile != null ? GetVersion3Profile(profile) : null;
|
var convertedProfile = profile != null ? GetVersion3Profile(profile) : null;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ public unsafe class Armature
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsVisible { get; set; }
|
public bool IsVisible { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents date and time when actor associated with this armature was last seen.
|
||||||
|
/// Implemented mostly as a armature cleanup protection hack for mare and penumbra.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime LastSeen { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether or not this armature has successfully built itself with bone information.
|
/// Gets a value indicating whether or not this armature has successfully built itself with bone information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -41,12 +47,6 @@ public unsafe class Armature
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPendingProfileRebind { get; set; }
|
public bool IsPendingProfileRebind { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents date and time until which any kind of removal protections will not be applying to this armature.
|
|
||||||
/// Implemented mostly as a armature cleanup protection hack due to how mare works when downloading files for the first time
|
|
||||||
/// </summary>
|
|
||||||
public DateTime ProtectedUntil { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For debugging purposes, each armature is assigned a globally-unique ID number upon creation.
|
/// For debugging purposes, each armature is assigned a globally-unique ID number upon creation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -147,7 +147,7 @@ public unsafe class Armature
|
|||||||
Profile = profile;
|
Profile = profile;
|
||||||
IsVisible = false;
|
IsVisible = false;
|
||||||
|
|
||||||
ProtectFromRemoval();
|
UpdateLastSeen();
|
||||||
|
|
||||||
Profile.Armatures.Add(this);
|
Profile.Armatures.Add(this);
|
||||||
|
|
||||||
@@ -257,11 +257,14 @@ public unsafe class Armature
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply removal protection for 30 seconds starting from current time. For the most part this is a hack for mare.
|
/// Update last time actor for this armature was last seen in the game
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ProtectFromRemoval()
|
public void UpdateLastSeen(DateTime? dateTime = null)
|
||||||
{
|
{
|
||||||
ProtectedUntil = DateTime.UtcNow.AddSeconds(30);
|
if(dateTime == null)
|
||||||
|
dateTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
LastSeen = (DateTime)dateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe List<List<ModelBone>> ParseBonesFromObject(Armature arm, CharacterBase* cBase)
|
private static unsafe List<List<ModelBone>> ParseBonesFromObject(Armature arm, CharacterBase* cBase)
|
||||||
|
|||||||
@@ -7,17 +7,19 @@ namespace CustomizePlus.Armatures.Events;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Triggered when armature is changed
|
/// Triggered when armature is changed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ArmatureChanged() : EventWrapper<ArmatureChanged.Type, Armature?, object?, ArmatureChanged.Priority>(nameof(ArmatureChanged))
|
public sealed class ArmatureChanged() : EventWrapper<ArmatureChanged.Type, Armature, object?, ArmatureChanged.Priority>(nameof(ArmatureChanged))
|
||||||
{
|
{
|
||||||
public enum Type
|
public enum Type
|
||||||
{
|
{
|
||||||
//Created,
|
Created,
|
||||||
Deleted
|
Deleted,
|
||||||
|
Rebound
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
ProfileManager
|
ProfileManager,
|
||||||
|
CustomizePlusIpc
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DeletionReason
|
public enum DeletionReason
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using CustomizePlus.GameData.Data;
|
|||||||
using CustomizePlus.GameData.Services;
|
using CustomizePlus.GameData.Services;
|
||||||
using CustomizePlus.GameData.Extensions;
|
using CustomizePlus.GameData.Extensions;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
namespace CustomizePlus.Armatures.Services;
|
namespace CustomizePlus.Armatures.Services;
|
||||||
|
|
||||||
@@ -106,15 +107,21 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
_objectManager.Update();
|
_objectManager.Update();
|
||||||
|
|
||||||
var currentTime = DateTime.UtcNow;
|
var currentTime = DateTime.UtcNow;
|
||||||
|
var armatureExpirationDateTime = currentTime.AddSeconds(-30);
|
||||||
foreach (var kvPair in Armatures.ToList())
|
foreach (var kvPair in Armatures.ToList())
|
||||||
{
|
{
|
||||||
var armature = kvPair.Value;
|
var armature = kvPair.Value;
|
||||||
if (!_objectManager.ContainsKey(kvPair.Value.ActorIdentifier) &&
|
if (!_objectManager.ContainsKey(kvPair.Value.ActorIdentifier) &&
|
||||||
currentTime > armature.ProtectedUntil) //Only remove armatures which are no longer protected
|
armature.LastSeen <= armatureExpirationDateTime) //Only remove armatures which haven't been seen for a while
|
||||||
{
|
{
|
||||||
_logger.Debug($"Removing armature {armature} because {kvPair.Key.IncognitoDebug()} is gone");
|
_logger.Debug($"Removing armature {armature} because {kvPair.Key.IncognitoDebug()} is gone");
|
||||||
RemoveArmature(armature, ArmatureChanged.DeletionReason.Gone);
|
RemoveArmature(armature, ArmatureChanged.DeletionReason.Gone);
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//armature is considered visible if 1 or less seconds passed since last time we've seen the actor
|
||||||
|
armature.IsVisible = armature.LastSeen.AddSeconds(1) >= currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
Profile? GetProfileForActor(ActorIdentifier identifier)
|
Profile? GetProfileForActor(ActorIdentifier identifier)
|
||||||
@@ -134,28 +141,32 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
|
|
||||||
foreach (var obj in _objectManager)
|
foreach (var obj in _objectManager)
|
||||||
{
|
{
|
||||||
if (!Armatures.ContainsKey(obj.Key))
|
var actorIdentifier = obj.Key.CreatePermanent();
|
||||||
|
if (!Armatures.ContainsKey(actorIdentifier))
|
||||||
{
|
{
|
||||||
var activeProfile = GetProfileForActor(obj.Key);
|
var activeProfile = GetProfileForActor(actorIdentifier);
|
||||||
if (activeProfile == null)
|
if (activeProfile == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var newArm = new Armature(obj.Key, activeProfile);
|
var newArm = new Armature(actorIdentifier, activeProfile);
|
||||||
TryLinkSkeleton(newArm);
|
TryLinkSkeleton(newArm);
|
||||||
Armatures.Add(obj.Key, newArm);
|
Armatures.Add(actorIdentifier, newArm);
|
||||||
_logger.Debug($"Added '{newArm}' for {obj.Key.IncognitoDebug()} to cache");
|
_logger.Debug($"Added '{newArm}' for {actorIdentifier.IncognitoDebug()} to cache");
|
||||||
|
_event.Invoke(ArmatureChanged.Type.Created, newArm, activeProfile);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var armature = Armatures[obj.Key];
|
var armature = Armatures[actorIdentifier];
|
||||||
|
|
||||||
|
armature.UpdateLastSeen(currentTime);
|
||||||
|
|
||||||
if (armature.IsPendingProfileRebind)
|
if (armature.IsPendingProfileRebind)
|
||||||
{
|
{
|
||||||
_logger.Debug($"Armature {armature} is pending profile rebind, rebinding...");
|
_logger.Debug($"Armature {armature} is pending profile rebind, rebinding...");
|
||||||
armature.IsPendingProfileRebind = false;
|
armature.IsPendingProfileRebind = false;
|
||||||
|
|
||||||
var activeProfile = GetProfileForActor(obj.Key);
|
var activeProfile = GetProfileForActor(actorIdentifier);
|
||||||
if (activeProfile == armature.Profile)
|
if (activeProfile == armature.Profile)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -166,14 +177,19 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Profile oldProfile = armature.Profile;
|
||||||
|
|
||||||
armature.Profile.Armatures.Remove(armature);
|
armature.Profile.Armatures.Remove(armature);
|
||||||
armature.Profile = activeProfile;
|
armature.Profile = activeProfile;
|
||||||
activeProfile.Armatures.Add(armature);
|
activeProfile.Armatures.Add(armature);
|
||||||
armature.RebuildBoneTemplateBinding();
|
armature.RebuildBoneTemplateBinding();
|
||||||
|
|
||||||
|
_event.Invoke(ArmatureChanged.Type.Rebound, armature, activeProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
armature.IsVisible = armature.Profile.Enabled && TryLinkSkeleton(armature); //todo: remove armatures which are not visible?
|
//Needed because skeleton sometimes appears to be not ready when armature is created
|
||||||
|
//and also because we want to augment armature with new bones if they are available
|
||||||
|
TryLinkSkeleton(armature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,7 +512,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
if (armature.Profile == profile)
|
if (armature.Profile == profile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
armature.ProtectFromRemoval();
|
armature.UpdateLastSeen();
|
||||||
|
|
||||||
armature.IsPendingProfileRebind = true;
|
armature.IsPendingProfileRebind = true;
|
||||||
|
|
||||||
@@ -516,7 +532,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
|||||||
foreach (var armature in profile.Armatures)
|
foreach (var armature in profile.Armatures)
|
||||||
{
|
{
|
||||||
if (type == ProfileChanged.Type.TemporaryProfileDeleted)
|
if (type == ProfileChanged.Type.TemporaryProfileDeleted)
|
||||||
armature.ProtectFromRemoval(); //just to be safe
|
armature.UpdateLastSeen(); //just to be safe
|
||||||
|
|
||||||
armature.IsPendingProfileRebind = true;
|
armature.IsPendingProfileRebind = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ public class GameObjectService
|
|||||||
{
|
{
|
||||||
if (kvPair.Value.Objects.Count > 1) //in gpose we can have more than a single object for one actor
|
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)
|
foreach (var obj in kvPair.Value.Objects)
|
||||||
yield return (kvPair.Key, obj);
|
yield return (kvPair.Key.CreatePermanent(), obj);
|
||||||
else
|
else
|
||||||
yield return (kvPair.Key, kvPair.Value.Objects[0]);
|
yield return (kvPair.Key.CreatePermanent(), kvPair.Value.Objects[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -545,7 +545,7 @@ public class ProfileManager : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnArmatureChange(ArmatureChanged.Type type, Armature? armature, object? arg3)
|
private void OnArmatureChange(ArmatureChanged.Type type, Armature armature, object? arg3)
|
||||||
{
|
{
|
||||||
if (type == ArmatureChanged.Type.Deleted)
|
if (type == ArmatureChanged.Type.Deleted)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public class StateMonitoringTab
|
|||||||
|
|
||||||
ImGui.Text($"Profile: {armature.Profile.Name.Text.Incognify()} ({armature.Profile.UniqueId})");
|
ImGui.Text($"Profile: {armature.Profile.Name.Text.Incognify()} ({armature.Profile.UniqueId})");
|
||||||
ImGui.Text($"Actor: {armature.ActorIdentifier.IncognitoDebug()}");
|
ImGui.Text($"Actor: {armature.ActorIdentifier.IncognitoDebug()}");
|
||||||
ImGui.Text($"Protection: {(armature.ProtectedUntil >= DateTime.UtcNow ? "Active" : "NOT active")} [{armature.ProtectedUntil} (UTC)]");
|
ImGui.Text($"Last seen: {armature.LastSeen} (UTC)");
|
||||||
//ImGui.Text("Profile:");
|
//ImGui.Text("Profile:");
|
||||||
//DrawSingleProfile($"armature-{armature.GetHashCode()}", armature.Profile);
|
//DrawSingleProfile($"armature-{armature.GetHashCode()}", armature.Profile);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
private readonly ProfileManager _profileManager;
|
private readonly ProfileManager _profileManager;
|
||||||
private readonly ProfileChanged _event;
|
private readonly ProfileChanged _event;
|
||||||
private readonly GameObjectService _gameObjectService;
|
private readonly GameObjectService _gameObjectService;
|
||||||
|
private readonly IClientState _clientState;
|
||||||
|
|
||||||
private Profile? _cloneProfile;
|
private Profile? _cloneProfile;
|
||||||
private string _newName = string.Empty;
|
private string _newName = string.Empty;
|
||||||
@@ -51,16 +52,21 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
PluginConfiguration configuration,
|
PluginConfiguration configuration,
|
||||||
ProfileManager profileManager,
|
ProfileManager profileManager,
|
||||||
ProfileChanged @event,
|
ProfileChanged @event,
|
||||||
GameObjectService gameObjectService)
|
GameObjectService gameObjectService,
|
||||||
|
IClientState clientState)
|
||||||
: base(fileSystem, keyState, logger, allowMultipleSelection: true)
|
: base(fileSystem, keyState, logger, allowMultipleSelection: true)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_profileManager = profileManager;
|
_profileManager = profileManager;
|
||||||
_event = @event;
|
_event = @event;
|
||||||
_gameObjectService = gameObjectService;
|
_gameObjectService = gameObjectService;
|
||||||
|
_clientState = clientState;
|
||||||
|
|
||||||
_event.Subscribe(OnProfileChange, ProfileChanged.Priority.ProfileFileSystemSelector);
|
_event.Subscribe(OnProfileChange, ProfileChanged.Priority.ProfileFileSystemSelector);
|
||||||
|
|
||||||
|
_clientState.Login += OnLoginLogout;
|
||||||
|
_clientState.Logout += OnLoginLogout;
|
||||||
|
|
||||||
AddButton(NewButton, 0);
|
AddButton(NewButton, 0);
|
||||||
AddButton(CloneButton, 20);
|
AddButton(CloneButton, 20);
|
||||||
AddButton(DeleteButton, 1000);
|
AddButton(DeleteButton, 1000);
|
||||||
@@ -71,6 +77,8 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
{
|
{
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
_event.Unsubscribe(OnProfileChange);
|
_event.Unsubscribe(OnProfileChange);
|
||||||
|
_clientState.Login -= OnLoginLogout;
|
||||||
|
_clientState.Logout -= OnLoginLogout;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override uint ExpandedFolderColor
|
protected override uint ExpandedFolderColor
|
||||||
@@ -131,6 +139,11 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnLoginLogout()
|
||||||
|
{
|
||||||
|
SetFilterDirty();
|
||||||
|
}
|
||||||
|
|
||||||
private void NewButton(Vector2 size)
|
private void NewButton(Vector2 size)
|
||||||
{
|
{
|
||||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size, "Create a new profile with default configuration.", false,
|
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size, "Create a new profile with default configuration.", false,
|
||||||
|
|||||||
Reference in New Issue
Block a user