ui/SpectatorUI.razor

A UI Razor component for spectator and results HUD. It shows current spectated player with input glyphs for prev/next, and when match results are active it shows the winner name and a countdown to lobby return.

Networking
@using Sandbox.UI;
@inherits PanelComponent

<root>
    @if (isSpectating)
    {
        <div class="spectator">
            <div class="spectator-target">Spectating: @(spectatingName ?? "...")</div>
            <div class="spectator-hints">
                <span class="hint hint-prev">
                    Prev
                    <Image class="glyph" [email protected]("Attack1", InputGlyphSize.Medium, GlyphStyle.Light) />
                </span>
                <span class="hint hint-next">
                    <Image class="glyph" [email protected]("Attack2", InputGlyphSize.Medium, GlyphStyle.Light) /> Next
                </span>
            </div>
        </div>
    }

    @if (isShowingResults)
    {
        <div class="results">
            <div class="results-name">@(winnerName ?? "...")</div>
            <div class="results-wins">WINS!</div>
            <div class="results-countdown">Returning to lobby in @resultsSecondsRemaining…</div>
        </div>
    }
</root>

@code {
    [Property] public GameManager GameManager { get; set; }
    [Property] public VictoryManager VictoryManager { get; set; }

    private bool isSpectating;
    private string spectatingName;
    private bool isShowingResults;
    private string winnerName;
    private int resultsSecondsRemaining;

    protected override void OnUpdate()
    {
        isShowingResults = VictoryManager?.IsShowingResults ?? false;

        if (isShowingResults)
        {
            GameObject winnerGameObject = VictoryManager.Winner;
            winnerName = winnerGameObject.IsValid()
                ? winnerGameObject.Network?.Owner?.DisplayName ?? "Winner"
                : "Nobody";
            resultsSecondsRemaining = System.Math.Max(0, (int)System.Math.Ceiling((float)VictoryManager.ResultsTimer));
        }
        else
        {
            winnerName = null;
            resultsSecondsRemaining = 0;
        }

        SpectatorMode spectator = SpectatorMode.Current;
        isSpectating = !isShowingResults && spectator != null && spectator.IsActive;
        spectatingName = isSpectating ? spectator.SpectatingName : null;
    }

    protected override int BuildHash() => System.HashCode.Combine(isSpectating, spectatingName,
        isShowingResults, winnerName, resultsSecondsRemaining, Input.UsingController);
}