diff --git a/Dalamud/Game/ClientState/Statuses/Status.cs b/Dalamud/Game/ClientState/Statuses/Status.cs
index 2775f8f9b..160b15de5 100644
--- a/Dalamud/Game/ClientState/Statuses/Status.cs
+++ b/Dalamud/Game/ClientState/Statuses/Status.cs
@@ -1,61 +1,49 @@
+using System.Diagnostics.CodeAnalysis;
+
using Dalamud.Data;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Lumina.Excel;
+using CSStatus = FFXIVClientStructs.FFXIV.Client.Game.Status;
+
namespace Dalamud.Game.ClientState.Statuses;
///
-/// This class represents a status effect an actor is afflicted by.
+/// Interface representing a status.
///
-public unsafe class Status
+public interface IStatus : IEquatable
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// Status address.
- internal Status(IntPtr address)
- {
- this.Address = address;
- }
-
///
/// Gets the address of the status in memory.
///
- public IntPtr Address { get; }
+ nint Address { get; }
///
/// Gets the status ID of this status.
///
- public uint StatusId => this.Struct->StatusId;
+ uint StatusId { get; }
///
/// Gets the GameData associated with this status.
///
- public RowRef GameData => LuminaUtils.CreateRef(this.Struct->StatusId);
+ RowRef GameData { get; }
///
/// Gets the parameter value of the status.
///
- public ushort Param => this.Struct->Param;
-
- ///
- /// Gets the stack count of this status.
- /// Only valid if this is a non-food status.
- ///
- [Obsolete($"Replaced with {nameof(Param)}", true)]
- public byte StackCount => (byte)this.Struct->Param;
+ ushort Param { get; }
///
/// Gets the time remaining of this status.
///
- public float RemainingTime => this.Struct->RemainingTime;
+ float RemainingTime { get; }
///
/// Gets the source ID of this status.
///
- public uint SourceId => this.Struct->SourceObject.ObjectId;
+ uint SourceId { get; }
///
/// Gets the source actor associated with this status.
@@ -63,7 +51,55 @@ public unsafe class Status
///
/// This iterates the actor table, it should be used with care.
///
+ IGameObject? SourceObject { get; }
+}
+
+///
+/// This struct represents a status effect an actor is afflicted by.
+///
+/// A pointer to the Status.
+internal unsafe readonly struct Status(CSStatus* ptr) : IStatus
+{
+ ///
+ public nint Address => (nint)ptr;
+
+ ///
+ public uint StatusId => ptr->StatusId;
+
+ ///
+ public RowRef GameData => LuminaUtils.CreateRef(ptr->StatusId);
+
+ ///
+ public ushort Param => ptr->Param;
+
+ ///
+ public float RemainingTime => ptr->RemainingTime;
+
+ ///
+ public uint SourceId => ptr->SourceObject.ObjectId;
+
+ ///
public IGameObject? SourceObject => Service.Get().SearchById(this.SourceId);
- private FFXIVClientStructs.FFXIV.Client.Game.Status* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Status*)this.Address;
+ public static bool operator ==(Status x, Status y) => x.Equals(y);
+
+ public static bool operator !=(Status x, Status y) => !(x == y);
+
+ ///
+ public bool Equals(IStatus? other)
+ {
+ return this.StatusId == other.StatusId && this.SourceId == other.SourceId && this.Param == other.Param && this.RemainingTime == other.RemainingTime;
+ }
+
+ ///
+ public override bool Equals([NotNullWhen(true)] object? obj)
+ {
+ return obj is Status fate && this.Equals(fate);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(this.StatusId, this.SourceId, this.Param, this.RemainingTime);
+ }
}