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:
RisaDev
2024-01-23 01:40:01 +03:00
parent 6dbd6a62ff
commit 7011914a4e
8 changed files with 124 additions and 44 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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;
}