Files
BSO-Mod/PositionHud.cs
MrMahoandClaude Opus 5.5 718e108f02 Mod 0.5.1: F8 entfernt, automatisch neu verbinden; Releases ueber Gitea
Verbunden wird nur beim Start ueber die Lobby, bricht die Verbindung ab alle 10 s neu (nicht nach
Ablehnung oder Konto-Problem). release.ps1 legt jetzt Gitea-Releases mit bso-release.json an.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 21:01:17 +01:00

113 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using BSO.Net;
namespace BSO
{
/// <summary>
/// Anzeige oben links: eigene Position (LocalPlayer) und Online-Status mit allen Mitspielern (Multiplayer).
/// F9 blendet ein/aus, F10 schreibt alle Entities in eine Datei.
///
/// Update rechnet (wenn die Engine-Uhr weiterlaeuft), Draw gibt den fertigen Text bei jedem Durchlauf aus - die
/// Engine zeigt Vision::Message-Text nur fuer einen Durchlauf, sonst flackert die Anzeige.
/// </summary>
public static class PositionHud
{
const int X = 10, Y = 10, Line = 18;
static bool visible = true, rateLogged;
static int frame;
static string status = "";
static byte[][] lines = Array.Empty<byte[]>();
static readonly Stopwatch rateClock = Stopwatch.StartNew();
static int draws;
public static void Update()
{
frame++;
if (Input.Pressed(Input.F9)) visible = !visible;
if (!LocalPlayer.InScene) { lines = Array.Empty<byte[]>(); return; } // Menue / Laden
if (Input.Pressed(Input.F10))
{
Entities.Dump(LocalPlayer.Camera);
status = "Entities gespeichert: BSO\\entities.txt";
}
// Text nur alle paar Durchlaeufe neu bauen - Draw gibt ihn dazwischen unveraendert aus
if (frame % 5 != 0 && lines.Length > 0) return;
PlayerState me = LocalPlayer.State;
var text = new List<string>
{
$"BSO {Bootstrap.ModVersion} [F9] Anzeige [F10] Entities [F11] Vollbild/Fenster",
me.Mode switch
{
PlayerMode.InBus => $"Du: im Bus {LocalPlayer.Bus.Pos} {LocalPlayer.Speed * 0.036f:0} km/h",
PlayerMode.OnFoot => $"Du: zu Fuss {LocalPlayer.Character.Pos}" + (LocalPlayer.Bus.Valid ? $" Bus {Meters(LocalPlayer.Bus.Pos - LocalPlayer.Character.Pos)} entfernt" : ""),
_ => "Du: -"
},
"",
};
AddOnline(text, me);
if (status.Length > 0) text.Add(status);
lines = text.ConvertAll(Vision.ToAscii).ToArray();
}
static void AddOnline(List<string> text, PlayerState me)
{
switch (Multiplayer.Status)
{
case Multiplayer.NetStatus.Offline when Multiplayer.AccountProblem != null:
text.Add(Multiplayer.AccountProblem);
return;
case Multiplayer.NetStatus.Offline when !Config.Current.AutoConnect:
text.Add("Allein unterwegs - zusammen spielen: im Launcher unter Freunde & Lobby");
return;
case Multiplayer.NetStatus.Offline:
text.Add($"Offline - verbinde gleich neu mit {Multiplayer.ServerDisplay} als {Multiplayer.PlayerName}");
if (Multiplayer.LastError.Length > 0) text.Add(" " + Multiplayer.LastError);
return;
case Multiplayer.NetStatus.Connecting:
text.Add($"Verbinde mit {Multiplayer.ServerDisplay} ...");
return;
}
if (!Multiplayer.Welcomed)
{
text.Add($"Verbinde mit {Multiplayer.ServerDisplay} ... warte auf Server");
return;
}
string ping = Multiplayer.PingMs >= 0 ? $"{Multiplayer.PingMs} ms" : "...";
text.Add($"Online: \"{Multiplayer.ServerName}\" ({ping}) - {Multiplayer.Players.Count + 1} Spieler");
foreach (Multiplayer.Remote p in Multiplayer.Players.Values.OrderBy(p => p.HasState ? p.State.DistanceTo(me) : float.MaxValue))
{
if (!p.HasState || p.State.Mode == PlayerMode.Menu) { text.Add($" {p.Name,-16} im Menue"); continue; }
string mode = p.State.Mode == PlayerMode.InBus ? "Bus " : "zu Fuss ";
string dist = me.Mode == PlayerMode.Menu ? "" : $"{p.State.DistanceTo(me) / 100,6:0} m";
text.Add($" {p.Name,-16} {mode} {dist} {p.State.Speed * 0.036f,3:0} km/h");
}
}
static string Meters(Vec3 d) => $"{d.Length / 100:0} m";
public static void Draw()
{
CountDraws();
if (!visible) return;
byte[][] current = lines;
for (int i = 0; i < current.Length; i++) Vision.Print(X, Y + i * Line, current[i]);
}
static void CountDraws()
{
draws++;
if (rateLogged || rateClock.ElapsedMilliseconds < 5000) return;
if (!LocalPlayer.InScene) { draws = 0; rateClock.Restart(); return; } // erst im Spiel messen
rateLogged = true;
Bootstrap.Log($"Anzeige: {draws / 5} Durchlaeufe pro Sekunde");
}
}
}