33 lines
1.8 KiB
C#
33 lines
1.8 KiB
C#
namespace ICRebuild.Core;
|
|
|
|
// The audited SetStatus ABI uses a byte result/flag and a full 64-bit GameObjectId.
|
|
public delegate byte StatusSetter(nint manager, int index, ushort statusId, float remaining,
|
|
ushort param, ulong source, byte refreshFlags);
|
|
|
|
public static class StatusBlockPolicy
|
|
{
|
|
public const string ClientVersion = "2026.10.06.0000.0000";
|
|
public const string BaselineClientVersion = "2026.09.15.0000.0000";
|
|
public static bool IsAuditedVersion(string? version) => version is ClientVersion or BaselineClientVersion;
|
|
public const int ManagerOffset = 0x23B0;
|
|
public const int EntityIdOffset = 0x78;
|
|
public const uint DefaultStatusId = 1257;
|
|
|
|
public static bool IsLocal(GameFrame frame, nint manager, nint currentPlayer, uint currentEntityId) =>
|
|
frame.Ready && !frame.IsReplay && frame.LocalAddress != 0 &&
|
|
frame.LocalStatusManagerAddress == frame.LocalAddress + ManagerOffset &&
|
|
manager == frame.LocalStatusManagerAddress && currentPlayer == frame.LocalAddress &&
|
|
frame.LocalEntityId is not (0 or 0xE0000000) && currentEntityId == frame.LocalEntityId;
|
|
|
|
public static bool IsSelected(int index, ushort statusId, IReadOnlySet<uint> selected) =>
|
|
(uint)index < 60 && statusId != 0 && selected.Contains(statusId) &&
|
|
StatusCatalog.AuditedBlockCandidates.Contains(statusId);
|
|
|
|
// Never skip the setter: an empty slot must still replace its previous status and
|
|
// report native changes to the batch caller, which then refreshes the status flags.
|
|
public static byte Forward(StatusSetter original, bool block, nint manager, int index,
|
|
ushort statusId, float remaining, ushort param, ulong source, byte refreshFlags) =>
|
|
block ? original(manager, index, 0, 0, 0, 0, refreshFlags)
|
|
: original(manager, index, statusId, remaining, param, source, refreshFlags);
|
|
}
|