Ping measurement and display (console: ping)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 22:45:11 +02:00
co-authored by Claude Opus 5.5
parent b408be7559
commit 6d349399ab
4 changed files with 76 additions and 2 deletions
+7
View File
@@ -13,6 +13,7 @@ namespace MSCO
"disconnect - leave the server / game\n" + "disconnect - leave the server / game\n" +
"host [port] / join <ip> [port] - direct LAN game (no Steam)\n" + "host [port] / join <ip> [port] - direct LAN game (no Steam)\n" +
"save - save the game (host / singleplayer)\n" + "save - save the game (host / singleplayer)\n" +
"ping [on|off] - show your ping to the server (toggle)\n" +
"/admin - admin menu (kick / ban / teleport / cheats)\n" + "/admin - admin menu (kick / ban / teleport / cheats)\n" +
"vehicles | rig - debug info about vehicles / player models\n" + "vehicles | rig - debug info about vehicles / player models\n" +
"debug - toggle sync debug output\n" + "debug - toggle sync debug output\n" +
@@ -61,6 +62,12 @@ namespace MSCO
case "save": case "save":
mp.SaveGame(); mp.SaveGame();
break; break;
case "ping":
// "ping" schaltet die Anzeige um, "ping on/off" setzt sie
if (args.Length > 1) mp.ShowPing = args[1].ToLower() == "on" || args[1] == "1";
else mp.ShowPing = !mp.ShowPing;
print("Ping: " + mp.PingText + " (display " + (mp.ShowPing ? "on" : "off") + ")");
break;
case "admin": case "admin":
case "/admin": case "/admin":
mp.OpenAdminMenu(); mp.OpenAdminMenu();
+66 -1
View File
@@ -64,6 +64,9 @@ namespace MSCO
Steamworks.CSteamID pendingLobby; // Einladung, die noch angenommen werden muss Steamworks.CSteamID pendingLobby; // Einladung, die noch angenommen werden muss
Steamworks.CSteamID steamHost; // Client: Steam-ID des Hosts Steamworks.CSteamID steamHost; // Client: Steam-ID des Hosts
float nextPing; float nextPing;
float pingMs = -1f; // geglättete Laufzeit zum Server/Host (-1 = noch unbekannt)
const string PrefShowPing = "MSCO_ShowPing";
GUIStyle pingStyle;
float savingMessageUntil; float savingMessageUntil;
GUIStyle hudStyle, savingStyle; GUIStyle hudStyle, savingStyle;
Texture2D hudBackground; Texture2D hudBackground;
@@ -221,6 +224,48 @@ namespace MSCO
return list; return list;
} }
// ---------------------------------------------------------------- Ping
/// <summary>Laufzeit zum Server/Host in ms (-1 = unbekannt, z.B. alter Server oder man ist selbst Host).</summary>
public float PingMs { get { return pingMs; } }
/// <summary>Ping-Anzeige oben rechts (Konsole: "ping"), bleibt gespeichert.</summary>
public bool ShowPing
{
get { return PlayerPrefs.GetInt(PrefShowPing, 0) == 1; }
set { PlayerPrefs.SetInt(PrefShowPing, value ? 1 : 0); }
}
/// <summary>Text für Anzeige und Konsole.</summary>
public string PingText
{
get
{
if (session == null) return "not connected";
if (session.IsHost) return "you are the host";
return pingMs < 0f ? "measuring..." : Mathf.RoundToInt(pingMs) + " ms";
}
}
void DrawPing()
{
if (!ShowPing || session == null) return;
if (pingStyle == null)
{
pingStyle = UiTheme.Panel9(new Color(0.06f, 0.06f, 0.07f, 0.85f), 6);
pingStyle.fontSize = 12;
pingStyle.fontStyle = FontStyle.Bold;
pingStyle.alignment = TextAnchor.MiddleCenter;
pingStyle.padding = new RectOffset(10, 10, 0, 0);
}
// Farbe nach Qualität: grün < 80 ms, gelb < 150 ms, sonst rot
Color color = pingMs < 0f ? UiTheme.Muted : pingMs < 80f ? UiTheme.Online : pingMs < 150f ? UiTheme.Pending : UiTheme.Danger;
pingStyle.normal.textColor = color;
var content = new GUIContent("PING " + PingText);
float width = pingStyle.CalcSize(content).x;
GUI.Box(new Rect(Screen.width - width - 12, 8, width, 24), content, pingStyle);
}
// ---------------------------------------------------------------- Cheats (Admin-Menü) // ---------------------------------------------------------------- Cheats (Admin-Menü)
/// <summary>Cheats nur im Spiel und nur für Server-Admins bzw. den P2P-Host.</summary> /// <summary>Cheats nur im Spiel und nur für Server-Admins bzw. den P2P-Host.</summary>
@@ -637,7 +682,8 @@ namespace MSCO
if (Time.realtimeSinceStartup >= nextPing) if (Time.realtimeSinceStartup >= nextPing)
{ {
nextPing = Time.realtimeSinceStartup + PingInterval; nextPing = Time.realtimeSinceStartup + PingInterval;
session.SendToAll(MsgType.Ping); float sentAt = Time.realtimeSinceStartup;
session.SendToAll(MsgType.Ping, NetSession.Build(w => w.Write(sentAt))); // Zeitstempel für die Ping-Messung
} }
foreach (NetEvent e in session.Poll()) foreach (NetEvent e in session.Poll())
@@ -704,6 +750,7 @@ namespace MSCO
if (session != null && session.IsSteam) steam.Leave(); if (session != null && session.IsSteam) steam.Leave();
session = null; session = null;
handshakeDone = false; handshakeDone = false;
pingMs = -1f;
teleportToHost = false; teleportToHost = false;
dedicated = false; dedicated = false;
connectingToServer = false; connectingToServer = false;
@@ -752,6 +799,22 @@ namespace MSCO
{ {
BinaryReader r = m.Reader(); BinaryReader r = m.Reader();
// Ping-Messung: der Host schickt den Zeitstempel sofort zurück, der Client rechnet die Laufzeit aus
if (m.Type == MsgType.Ping)
{
if (session.IsHost && m.Payload.Length >= 4) session.SendTo(peerId, MsgType.Pong, m.Payload);
return;
}
if (m.Type == MsgType.Pong)
{
if (!session.IsHost && m.Payload.Length >= 4)
{
float rtt = (Time.realtimeSinceStartup - r.ReadSingle()) * 1000f;
if (rtt >= 0f && rtt < 60000f) pingMs = pingMs < 0f ? rtt : Mathf.Lerp(pingMs, rtt, 0.4f);
}
return;
}
if (IsGameMessage(m.Type)) if (IsGameMessage(m.Type))
{ {
int from; int from;
@@ -1374,6 +1437,7 @@ namespace MSCO
if (MenuHelper.InMenu) if (MenuHelper.InMenu)
{ {
lobby.Draw(this); lobby.Draw(this);
DrawPing();
overlays.Draw(this, false); overlays.Draw(this, false);
return; return;
} }
@@ -1383,6 +1447,7 @@ namespace MSCO
GUI.Label(new Rect(0, Screen.height / 2f - 40, Screen.width, 80), "SAVING GAME...", savingStyle); GUI.Label(new Rect(0, Screen.height / 2f - 40, Screen.width, 80), "SAVING GAME...", savingStyle);
if (session != null) DrawHud(); if (session != null) DrawHud();
DrawPing();
overlays.Draw(this, session != null); overlays.Draw(this, session != null);
} }
+2 -1
View File
@@ -38,7 +38,8 @@ namespace MSCO
AdminResult = 27, // Server -> Client: string Meldung AdminResult = 27, // Server -> Client: string Meldung
Chat = 28, // Chatnachricht (string) Chat = 28, // Chatnachricht (string)
VarSync = 29, // Fahrzeugzustand: int n, je [int key, byte typ, wert] VarSync = 29, // Fahrzeugzustand: int n, je [int key, byte typ, wert]
Teleport = 30 // Admin holt einen Spieler zu sich: 3 float Position Teleport = 30, // Admin holt einen Spieler zu sich: 3 float Position
Pong = 31 // Antwort auf Ping mit demselben Zeitstempel (Laufzeit messen)
} }
public struct Message public struct Message
+1
View File
@@ -69,6 +69,7 @@ In der F8-Konsole direkt, in der MSCLoader-Konsole mit `mp` davor (z.B. `mp conn
| `disconnect` | Server / Spiel verlassen | | `disconnect` | Server / Spiel verlassen |
| `host [port]` / `join <ip> [port]` | LAN-Testsitzung ohne Steam | | `host [port]` / `join <ip> [port]` | LAN-Testsitzung ohne Steam |
| `save` | Spiel speichern (Host / Einzelspieler) | | `save` | Spiel speichern (Host / Einzelspieler) |
| `ping [on\|off]` | Ping zum Server oben rechts anzeigen (grün < 80 ms, gelb < 150 ms, rot darüber) |
| `admin` bzw. `/admin` im Chat | Admin-Menü | | `admin` bzw. `/admin` im Chat | Admin-Menü |
| `vehicles`, `rig` | Diagnose: Fahrzeuge / Spielermodelle | | `vehicles`, `rig` | Diagnose: Fahrzeuge / Spielermodelle |
| `debug` | Sync-Debugausgaben an/aus | | `debug` | Sync-Debugausgaben an/aus |