using TMPro;
using UnityEngine;
namespace FloodSWE.Networking
{
///
/// Binds SweServerRuntime diagnostics to user-provided TMP text fields.
///
public sealed class SweServerDiagnosticsHud : MonoBehaviour
{
[Header("References")]
[SerializeField] private SweServerRuntime serverRuntime;
[SerializeField] private TMP_Text simulationText;
[SerializeField] private TMP_Text connectionText;
[SerializeField] private TMP_Text commandText;
[SerializeField] private TMP_Text forcingText;
[SerializeField] private TMP_Text tileLoadText;
[Header("Behavior")]
[SerializeField] private bool autoFindRuntime = true;
[SerializeField] private float refreshIntervalSeconds = 0.15f;
[Header("Labels")]
[SerializeField] private string connectedLabel = "Connected";
[SerializeField] private string staleLabel = "Stale";
[SerializeField] private string disconnectedLabel = "Disconnected";
[SerializeField] private string unknownAgeLabel = "n/a";
[SerializeField] private string numberFormat = "0.00";
[Header("Colors")]
[SerializeField] private Color connectedColor = new Color(0.4f, 1.0f, 0.4f);
[SerializeField] private Color staleColor = new Color(1.0f, 0.9f, 0.3f);
[SerializeField] private Color disconnectedColor = new Color(1.0f, 0.5f, 0.5f);
private float nextRefreshTime;
private void OnEnable()
{
if (serverRuntime == null && autoFindRuntime)
{
serverRuntime = FindFirstObjectByType();
}
Refresh(true);
}
private void Update()
{
if (Time.unscaledTime < nextRefreshTime)
{
return;
}
Refresh(false);
}
private void Refresh(bool immediate)
{
nextRefreshTime = Time.unscaledTime + Mathf.Max(0.02f, refreshIntervalSeconds);
if (serverRuntime == null)
{
SetText(simulationText, "Sim Speed: n/a");
SetText(connectionText, "Connection: runtime missing");
SetText(commandText, "Last Command: n/a");
SetText(forcingText, "Forcing: n/a");
SetText(tileLoadText, "Tile Load: runtime missing");
if (connectionText != null)
{
connectionText.color = disconnectedColor;
}
return;
}
string simLine = $"Sim Speed: {serverRuntime.SimulatedSecondsPerSecond.ToString(numberFormat)} sim-s/s";
if (!serverRuntime.HasSimulationThroughput)
{
simLine = "Sim Speed: warming up";
}
SetText(simulationText, simLine);
string state;
Color stateColor;
if (!serverRuntime.HasConnectedClients)
{
state = disconnectedLabel;
stateColor = disconnectedColor;
}
else if (serverRuntime.HasRecentClientSignal)
{
state = connectedLabel;
stateColor = connectedColor;
}
else
{
state = staleLabel;
stateColor = staleColor;
}
string connectionLine =
$"Connection: {state} | clients={serverRuntime.ConnectedClientCount} | endpoint={serverRuntime.QuestEndpointLabel}";
SetText(connectionText, connectionLine);
if (connectionText != null)
{
connectionText.color = stateColor;
}
string age = float.IsInfinity(serverRuntime.LastCommandAgeSeconds)
? unknownAgeLabel
: $"{serverRuntime.LastCommandAgeSeconds.ToString(numberFormat)}s";
string commandLine =
$"Last Command: {serverRuntime.LastCommandName} from {serverRuntime.LastCommandSender} ({age}) | " +
$"ctrl={serverRuntime.DecodedControlPackets}/{serverRuntime.ReceivedControlPackets} invalid={serverRuntime.InvalidControlPackets} ack={serverRuntime.AckPacketsSent}";
SetText(commandText, commandLine);
string forcingLine =
$"Forcing: {serverRuntime.LastForcingStatus} | cells={serverRuntime.LastForcedCellCount} | tile={serverRuntime.ActiveTileLabel}";
SetText(forcingText, forcingLine);
string tileLine =
$"Tile Load: {serverRuntime.TileLoadSummary} | framePayload={serverRuntime.LastFramePayloadBytes}B " +
$"frames={serverRuntime.TransmittedFramePackets} dropped={serverRuntime.DroppedFramePackets}";
SetText(tileLoadText, tileLine);
if (immediate)
{
nextRefreshTime = Time.unscaledTime;
}
}
private static void SetText(TMP_Text target, string value)
{
if (target == null || target.text == value)
{
return;
}
target.text = value;
}
}
}