draft options working; spells won't cast though

This commit is contained in:
Ian Woods 2026-07-14 20:56:50 -07:00
parent 2429efbf6a
commit 7cf15dcaa6
37 changed files with 1340 additions and 0 deletions

View file

@ -0,0 +1,63 @@
// 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 &lt;= 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;
}
}