using SoulHarvest.Common; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.IO; using Terraria; using Terraria.DataStructures; using Terraria.ID; using Terraria.ModLoader; namespace SoulHarvest.Projectiles; /// /// Server/single-player reservation cache. A single slash may report the same /// target more than once during its damage window, but only one transport cue is /// needed for that slash/target pair. Separate cuts keep separate action tokens. /// internal sealed class ReaperVoidHitCueReservationSystem : ModSystem { private const ulong ReservationFrames = 300UL; private const int MaximumReservations = 4096; private static readonly Dictionary Reservations = []; private static readonly Queue ReservationOrder = []; internal static bool TryReserve(int owner, int actionId, int target) { ulong now = Main.GameUpdateCount; Prune(now); ReservationKey key = new(owner, actionId, target); if (Reservations.TryGetValue(key, out ulong tick) && now >= tick && now - tick <= ReservationFrames) { return false; } while (Reservations.Count >= MaximumReservations && ReservationOrder.Count > 0) RemoveOldest(); Reservations[key] = now; ReservationOrder.Enqueue(new ReservationEntry(key, now)); return true; } internal static void Release(int owner, int actionId, int target) => Reservations.Remove(new ReservationKey(owner, actionId, target)); public override void OnWorldUnload() => Clear(); public override void Unload() => Clear(); private static void Prune(ulong now) { while (ReservationOrder.Count > 0) { ReservationEntry oldest = ReservationOrder.Peek(); if (now >= oldest.Tick && now - oldest.Tick <= ReservationFrames) break; RemoveOldest(); } } private static void RemoveOldest() { ReservationEntry oldest = ReservationOrder.Dequeue(); if (Reservations.TryGetValue(oldest.Key, out ulong tick) && tick == oldest.Tick) Reservations.Remove(oldest.Key); } private static void Clear() { Reservations.Clear(); ReservationOrder.Clear(); } private readonly record struct ReservationKey(int Owner, int ActionId, int Target); private readonly record struct ReservationEntry(ReservationKey Key, ulong Tick); }