63 lines
2.7 KiB
C#
63 lines
2.7 KiB
C#
// Assets/_Project/Scripts/Gameplay/SpellSlot.cs
|
|
using System;
|
|
using Unity.Netcode;
|
|
using TD.Core;
|
|
|
|
namespace TD.Gameplay
|
|
{
|
|
/// <summary>
|
|
/// One granted builder spell in a <see cref="PlayerSpellLoadout"/>. Replicated as part of
|
|
/// a <see cref="NetworkList{T}"/>; the entry's index in that list IS the hotkey slot
|
|
/// (grant order == key order), so no separate slot index field is needed.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <b>One struct, not parallel lists.</b> <see cref="Kind"/> is set once at grant time;
|
|
/// <see cref="CooldownEndServerTime"/> is rewritten on every cast. <c>NetworkList{T}</c>'s
|
|
/// indexer setter (<c>spells[i] = newValue</c>) short-circuits the write when
|
|
/// <c>Equals</c> on the old value returns true (see <see cref="BuildJob"/> for the
|
|
/// documented case that first surfaced this). Comparing only <see cref="Kind"/> would mean
|
|
/// a cooldown update — same Kind, new CooldownEndServerTime — never actually replicates.
|
|
/// <see cref="Equals"/> therefore compares every field.
|
|
/// </remarks>
|
|
[Serializable]
|
|
public struct SpellSlot : INetworkSerializable, IEquatable<SpellSlot>
|
|
{
|
|
/// <summary>Which spell occupies this slot. Fixed for the slot's lifetime.</summary>
|
|
public BuilderSpellKind Kind;
|
|
|
|
/// <summary>
|
|
/// <c>NetworkManager.ServerTime.Time</c> at which this slot is next ready to cast.
|
|
/// 0 (or any value <= current server time) means ready now.
|
|
/// </summary>
|
|
public double CooldownEndServerTime;
|
|
|
|
public static SpellSlot CreateReady(BuilderSpellKind kind)
|
|
{
|
|
return new SpellSlot { Kind = kind, CooldownEndServerTime = 0d };
|
|
}
|
|
|
|
// ----- INetworkSerializable ---------------------------------------
|
|
|
|
public void NetworkSerialize<T>(BufferSerializer<T> 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;
|
|
}
|
|
}
|