A server-authoritative pot component for a card game that tracks total chips and per-player contributions. Host-only methods add contributions, award or split the pot among winners, apply a rake, compute a seat's contribution, and clear the pot. Total is network-synced for clients to read.
namespace CardGames;
/// <summary>
/// A shared pool of chips that players contribute to during a round. The host tracks contributions and awards the pot to winners.
/// </summary>
public sealed class Pot : Component
{
/// <summary>
/// Total chips in the pot. Host writes; everyone reads (for a chips-on-the-table layer or HUD).
/// </summary>
[Sync] public long Total { get; set; }
/// <summary>
/// Chips a player put into the pot. Host-only bookkeeping (e.g. to refund an uncalled bet).
/// </summary>
private readonly record struct Contribution( Connection Player, long Amount );
// Not synced - clients only need the Total.
private readonly List<Contribution> _contributions = new();
/// <summary>
/// Chips this seat has contributed to the pot.
/// </summary>
public long ContributionOf( Seat seat )
{
if ( seat is null ) return 0;
var player = Connection.Find( seat.Player );
long total = 0;
foreach ( var c in _contributions )
if ( c.Player == player )
total += c.Amount;
return total;
}
/// <summary>
/// Host: add chips to the pot, tracked against the seat that put them in.
/// </summary>
public void Contribute( Seat seat, long amount )
{
if ( !Networking.IsHost || seat is null || amount <= 0 ) return;
_contributions.Add( new Contribution( Connection.Find( seat.Player ), amount ) );
Total += amount;
}
/// <summary>
/// Host: hand the whole pot to one seat, then empty it.
/// </summary>
public void Award( Seat seat )
{
if ( !Networking.IsHost || seat is null ) return;
seat.Currency += Total;
Clear();
}
/// <summary>
/// Host: split the pot as evenly as possible between winners (any odd chip goes to the first), then empty it.
/// </summary>
public void Split( IReadOnlyList<Seat> winners )
{
if ( !Networking.IsHost || winners is null || winners.Count == 0 ) return;
long each = Total / winners.Count;
long remainder = Total - each * winners.Count;
for ( int i = 0; i < winners.Count; i++ )
if ( winners[i] is not null )
winners[i].Currency += each + (i == 0 ? remainder : 0);
Clear();
}
/// <summary>
/// Host: skim a fraction of the pot for the house (rake). Returns the chips taken.
/// </summary>
public long Rake( float fraction )
{
if ( !Networking.IsHost || fraction <= 0f ) return 0;
long rake = (long)(Total * Math.Clamp( fraction, 0f, 1f ));
Total -= rake;
return rake;
}
/// <summary>
/// Host: empty the pot and forget all contributions.
/// </summary>
public void Clear()
{
if ( !Networking.IsHost ) return;
_contributions.Clear();
Total = 0;
}
}