// Assets/_Project/Scripts/Gameplay/SpellSlot.cs
using System;
using Unity.Netcode;
using TD.Core;
namespace TD.Gameplay
{
///
/// One granted builder spell in a . Replicated as part of
/// a ; the entry's index in that list IS the hotkey slot
/// (grant order == key order), so no separate slot index field is needed.
///
///
/// One struct, not parallel lists. is set once at grant time;
/// is rewritten on every cast. NetworkList{T}'s
/// indexer setter (spells[i] = newValue) short-circuits the write when
/// Equals on the old value returns true (see for the
/// documented case that first surfaced this). Comparing only would mean
/// a cooldown update — same Kind, new CooldownEndServerTime — never actually replicates.
/// therefore compares every field.
///
[Serializable]
public struct SpellSlot : INetworkSerializable, IEquatable
{
/// Which spell occupies this slot. Fixed for the slot's lifetime.
public BuilderSpellKind Kind;
///
/// NetworkManager.ServerTime.Time at which this slot is next ready to cast.
/// 0 (or any value <= current server time) means ready now.
///
public double CooldownEndServerTime;
public static SpellSlot CreateReady(BuilderSpellKind kind)
{
return new SpellSlot { Kind = kind, CooldownEndServerTime = 0d };
}
// ----- INetworkSerializable ---------------------------------------
public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter
{
byte kindByte = (byte)Kind;
serializer.SerializeValue(ref kindByte);
Kind = (BuilderSpellKind)kindByte;
serializer.SerializeValue(ref CooldownEndServerTime);
}
// ----- IEquatable -------------------------------------------------
//
// Full-field comparison — see remarks above. Without this, cooldown writes
// (Kind unchanged, only CooldownEndServerTime updated) would be silently dropped
// by NetworkList's indexer setter.
public bool Equals(SpellSlot other) =>
Kind == other.Kind && CooldownEndServerTime == other.CooldownEndServerTime;
public override bool Equals(object obj) => obj is SpellSlot other && Equals(other);
public override int GetHashCode() => (int)Kind;
}
}