XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
UTF-8
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);
}