bit field swapped for normal list at API boundaries
This commit is contained in:
parent
157b77ebfa
commit
bf3c008777
1 changed files with 17 additions and 20 deletions
|
|
@ -13,10 +13,12 @@ namespace TD.Gameplay
|
||||||
/// <see cref="PlayerBuffManager"/>.
|
/// <see cref="PlayerBuffManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para><b>Bitmask, not a list.</b> A builder effect carries no per-grant state (no level,
|
/// <para><b>List of granted kinds.</b> A builder effect carries no per-grant state (no
|
||||||
/// no enable/disable toggle) — it's either granted or it isn't — so the granted set is one
|
/// level, no enable/disable toggle) — it's either granted or it isn't — so the granted set
|
||||||
/// <see cref="NetworkVariable{T}"/> bitmask keyed by <see cref="BuilderEffectKind"/> rather
|
/// is a <see cref="NetworkList{T}"/> of <see cref="BuilderEffectKind"/> values. Stored as
|
||||||
/// than a <c>NetworkList</c>. "Has effect" and "grant effect" are both O(1) bit ops.</para>
|
/// <c>byte</c> because <c>NetworkList<T></c> requires <c>T : IEquatable<T></c>
|
||||||
|
/// and plain enums don't implement that (see <see cref="TD.Gameplay.BuildJob"/> for the
|
||||||
|
/// same constraint on a struct); <c>byte</c> already does, for free.</para>
|
||||||
///
|
///
|
||||||
/// <para><b>Granted via draft.</b> <see cref="TD.Gameplay.Draft.BuilderEffectDraftOption"/>
|
/// <para><b>Granted via draft.</b> <see cref="TD.Gameplay.Draft.BuilderEffectDraftOption"/>
|
||||||
/// calls <see cref="ServerGrantEffect"/> when a player picks it. Effects are permanent for
|
/// calls <see cref="ServerGrantEffect"/> when a player picks it. Effects are permanent for
|
||||||
|
|
@ -60,13 +62,10 @@ namespace TD.Gameplay
|
||||||
|
|
||||||
// ----- Networked state --------------------------------------------
|
// ----- Networked state --------------------------------------------
|
||||||
|
|
||||||
// One bit per BuilderEffectKind. readPerm Everyone (consistent with the other
|
// Granted effect kinds, stored as byte (see class remarks for why not the enum
|
||||||
// per-player managers); writePerm Server.
|
// directly). readPerm Everyone (consistent with the other per-player managers);
|
||||||
private readonly NetworkVariable<uint> grantedMask = new NetworkVariable<uint>(
|
// writePerm Server — both are NetworkList's defaults.
|
||||||
value: 0,
|
private readonly NetworkList<byte> grantedKinds = new NetworkList<byte>();
|
||||||
readPerm: NetworkVariableReadPermission.Everyone,
|
|
||||||
writePerm: NetworkVariableWritePermission.Server
|
|
||||||
);
|
|
||||||
|
|
||||||
/// <summary>Fired on every peer when a new effect is granted.</summary>
|
/// <summary>Fired on every peer when a new effect is granted.</summary>
|
||||||
public event System.Action OnUpgradesChanged;
|
public event System.Action OnUpgradesChanged;
|
||||||
|
|
@ -76,23 +75,23 @@ namespace TD.Gameplay
|
||||||
public override void OnNetworkSpawn()
|
public override void OnNetworkSpawn()
|
||||||
{
|
{
|
||||||
s_byClientId[OwnerClientId] = this;
|
s_byClientId[OwnerClientId] = this;
|
||||||
grantedMask.OnValueChanged += HandleMaskChanged;
|
grantedKinds.OnListChanged += HandleGrantedKindsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNetworkDespawn()
|
public override void OnNetworkDespawn()
|
||||||
{
|
{
|
||||||
grantedMask.OnValueChanged -= HandleMaskChanged;
|
grantedKinds.OnListChanged -= HandleGrantedKindsChanged;
|
||||||
|
|
||||||
if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this)
|
if (s_byClientId.TryGetValue(OwnerClientId, out var registered) && registered == this)
|
||||||
s_byClientId.Remove(OwnerClientId);
|
s_byClientId.Remove(OwnerClientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleMaskChanged(uint previous, uint current) => OnUpgradesChanged?.Invoke();
|
private void HandleGrantedKindsChanged(NetworkListEvent<byte> change) => OnUpgradesChanged?.Invoke();
|
||||||
|
|
||||||
// ----- Read API -----------------------------------------------------
|
// ----- Read API -----------------------------------------------------
|
||||||
|
|
||||||
/// <summary>True if this player has been granted the given effect.</summary>
|
/// <summary>True if this player has been granted the given effect.</summary>
|
||||||
public bool PlayerHasEffect(BuilderEffectKind kind) => (grantedMask.Value & BitFor(kind)) != 0;
|
public bool PlayerHasEffect(BuilderEffectKind kind) => grantedKinds.Contains((byte)kind);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns this player's <see cref="BuilderEffectDefinition"/> for <paramref name="kind"/>
|
/// Returns this player's <see cref="BuilderEffectDefinition"/> for <paramref name="kind"/>
|
||||||
|
|
@ -113,13 +112,11 @@ namespace TD.Gameplay
|
||||||
{
|
{
|
||||||
if (!IsServer) return false;
|
if (!IsServer) return false;
|
||||||
|
|
||||||
uint bit = BitFor(kind);
|
byte value = (byte)kind;
|
||||||
if ((grantedMask.Value & bit) != 0) return false;
|
if (grantedKinds.Contains(value)) return false;
|
||||||
|
|
||||||
grantedMask.Value |= bit;
|
grantedKinds.Add(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint BitFor(BuilderEffectKind kind) => 1u << (int)kind;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue