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:
@@ -31,6 +31,12 @@ public unsafe class Armature
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets a value indicating whether or not this armature has successfully built itself with bone information.
|
||||
/// </summary>
|
||||
@@ -41,12 +47,6 @@ public unsafe class Armature
|
||||
/// </summary>
|
||||
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>
|
||||
/// For debugging purposes, each armature is assigned a globally-unique ID number upon creation.
|
||||
/// </summary>
|
||||
@@ -147,7 +147,7 @@ public unsafe class Armature
|
||||
Profile = profile;
|
||||
IsVisible = false;
|
||||
|
||||
ProtectFromRemoval();
|
||||
UpdateLastSeen();
|
||||
|
||||
Profile.Armatures.Add(this);
|
||||
|
||||
@@ -257,11 +257,14 @@ public unsafe class Armature
|
||||
}
|
||||
|
||||
/// <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>
|
||||
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)
|
||||
|
||||
@@ -7,17 +7,19 @@ namespace CustomizePlus.Armatures.Events;
|
||||
/// <summary>
|
||||
/// Triggered when armature is changed
|
||||
/// </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
|
||||
{
|
||||
//Created,
|
||||
Deleted
|
||||
Created,
|
||||
Deleted,
|
||||
Rebound
|
||||
}
|
||||
|
||||
public enum Priority
|
||||
{
|
||||
ProfileManager
|
||||
ProfileManager,
|
||||
CustomizePlusIpc
|
||||
}
|
||||
|
||||
public enum DeletionReason
|
||||
|
||||
@@ -19,6 +19,7 @@ using CustomizePlus.GameData.Data;
|
||||
using CustomizePlus.GameData.Services;
|
||||
using CustomizePlus.GameData.Extensions;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CustomizePlus.Armatures.Services;
|
||||
|
||||
@@ -106,15 +107,21 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
_objectManager.Update();
|
||||
|
||||
var currentTime = DateTime.UtcNow;
|
||||
var armatureExpirationDateTime = currentTime.AddSeconds(-30);
|
||||
foreach (var kvPair in Armatures.ToList())
|
||||
{
|
||||
var armature = kvPair.Value;
|
||||
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");
|
||||
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)
|
||||
@@ -134,28 +141,32 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
var newArm = new Armature(obj.Key, activeProfile);
|
||||
var newArm = new Armature(actorIdentifier, activeProfile);
|
||||
TryLinkSkeleton(newArm);
|
||||
Armatures.Add(obj.Key, newArm);
|
||||
_logger.Debug($"Added '{newArm}' for {obj.Key.IncognitoDebug()} to cache");
|
||||
Armatures.Add(actorIdentifier, newArm);
|
||||
_logger.Debug($"Added '{newArm}' for {actorIdentifier.IncognitoDebug()} to cache");
|
||||
_event.Invoke(ArmatureChanged.Type.Created, newArm, activeProfile);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var armature = Armatures[obj.Key];
|
||||
var armature = Armatures[actorIdentifier];
|
||||
|
||||
armature.UpdateLastSeen(currentTime);
|
||||
|
||||
if (armature.IsPendingProfileRebind)
|
||||
{
|
||||
_logger.Debug($"Armature {armature} is pending profile rebind, rebinding...");
|
||||
armature.IsPendingProfileRebind = false;
|
||||
|
||||
var activeProfile = GetProfileForActor(obj.Key);
|
||||
var activeProfile = GetProfileForActor(actorIdentifier);
|
||||
if (activeProfile == armature.Profile)
|
||||
continue;
|
||||
|
||||
@@ -166,14 +177,19 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
continue;
|
||||
}
|
||||
|
||||
Profile oldProfile = armature.Profile;
|
||||
|
||||
armature.Profile.Armatures.Remove(armature);
|
||||
armature.Profile = activeProfile;
|
||||
activeProfile.Armatures.Add(armature);
|
||||
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)
|
||||
return;
|
||||
|
||||
armature.ProtectFromRemoval();
|
||||
armature.UpdateLastSeen();
|
||||
|
||||
armature.IsPendingProfileRebind = true;
|
||||
|
||||
@@ -516,7 +532,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
foreach (var armature in profile.Armatures)
|
||||
{
|
||||
if (type == ProfileChanged.Type.TemporaryProfileDeleted)
|
||||
armature.ProtectFromRemoval(); //just to be safe
|
||||
armature.UpdateLastSeen(); //just to be safe
|
||||
|
||||
armature.IsPendingProfileRebind = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user