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;
/// <summary>
/// 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.
/// </summary>
internal sealed class ReaperVoidHitCueReservationSystem : ModSystem
{
private const ulong ReservationFrames = 300UL;
private const int MaximumReservations = 4096;
private static readonly Dictionary<ReservationKey, ulong> Reservations = [];
private static readonly Queue<ReservationEntry> 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);
}
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;
/// <summary>
/// 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.
/// </summary>
internal sealed class ReaperVoidHitCueReservationSystem : ModSystem
{
private const ulong ReservationFrames = 300UL;
private const int MaximumReservations = 4096;
private static readonly Dictionary<ReservationKey, ulong> Reservations = [];
private static readonly Queue<ReservationEntry> 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);
}