77 lines
4.2 KiB
C#
77 lines
4.2 KiB
C#
using System.Text.Json;
|
|
|
|
namespace CsWeb.Services
|
|
{
|
|
// View helpers: tiny, dependency-free formatting shared by the pages. Content-only — no markup decisions here.
|
|
public static class Fmt
|
|
{
|
|
public static string ModeName(string? mode) => mode?.ToLowerInvariant() switch
|
|
{
|
|
"tdm" => "TDM",
|
|
"gungame" => "Gun Game",
|
|
"survival" => "Survival",
|
|
_ => mode ?? "?",
|
|
};
|
|
|
|
// Matches the plugin's win-banner format (m:ss.fff).
|
|
public static string RunTime(long ms) => $"{ms / 60000}:{ms / 1000 % 60:D2}.{ms % 1000:D3}";
|
|
|
|
public static string Age<T>(Cached<T> c) where T : class =>
|
|
c.Data is null ? "no data yet"
|
|
: c.Online ? "live"
|
|
: $"last seen {(int)c.Age.TotalSeconds}s ago";
|
|
|
|
// One-line mode summary for a server card, from the status payload's mode-specific Extra block.
|
|
public static string ExtraLine(StatusPayload s)
|
|
{
|
|
var e = s.Extra;
|
|
if (e.ValueKind != JsonValueKind.Object) return "";
|
|
return s.Mode switch
|
|
{
|
|
"survival" when e.TryGetProperty("RunActive", out var run) && run.GetBoolean()
|
|
&& e.TryGetProperty("Wave", out var w) && e.TryGetProperty("WaveCount", out var wc)
|
|
=> $"Wave {w.GetInt32()}/{wc.GetInt32()}",
|
|
"survival" => "Between runs",
|
|
"gungame" when e.TryGetProperty("Ladder", out var l) => $"{l.GetArrayLength()}-rung ladder",
|
|
"tdm" when e.TryGetProperty("KillGoal", out var kg) => $"First to {kg.GetInt32()} kills",
|
|
_ => "",
|
|
};
|
|
}
|
|
|
|
// A player's current GG weapon: their rung indexed into the ladder the GG driver ships in Extra.
|
|
public static string? RungWeapon(StatusPayload s, HumanRow h)
|
|
{
|
|
if (s.Mode != "gungame" || s.Extra.ValueKind != JsonValueKind.Object) return null;
|
|
if (!s.Extra.TryGetProperty("Ladder", out var l) || l.ValueKind != JsonValueKind.Array) return null;
|
|
int n = l.GetArrayLength();
|
|
if (n == 0) return null;
|
|
return l[Math.Clamp(h.Rung, 0, n - 1)].GetString();
|
|
}
|
|
|
|
// Best-effort display for raw weapon designer names in balance payloads (the site has no engine name table;
|
|
// status payloads carry pre-rendered display names, this is only for the guides' config-derived lists).
|
|
public static string PrettyWeapon(string w) =>
|
|
w.StartsWith("weapon_", StringComparison.Ordinal) ? w[7..].Replace('_', ' ').ToUpperInvariant() : w;
|
|
|
|
public static int IntOf(JsonElement obj, string prop, int fallback = 0) =>
|
|
obj.ValueKind == JsonValueKind.Object && obj.TryGetProperty(prop, out var v) && v.TryGetInt32(out int i) ? i : fallback;
|
|
|
|
public static double NumOf(JsonElement obj, string prop, double fallback = 0) =>
|
|
obj.ValueKind == JsonValueKind.Object && obj.TryGetProperty(prop, out var v) && v.ValueKind == JsonValueKind.Number ? v.GetDouble() : fallback;
|
|
|
|
public static bool BoolOf(JsonElement obj, string prop, bool fallback = false) =>
|
|
obj.ValueKind == JsonValueKind.Object && obj.TryGetProperty(prop, out var v) && (v.ValueKind == JsonValueKind.True || v.ValueKind == JsonValueKind.False) ? v.GetBoolean() : fallback;
|
|
|
|
public static string StrOf(JsonElement obj, string prop, string fallback = "") =>
|
|
obj.ValueKind == JsonValueKind.Object && obj.TryGetProperty(prop, out var v) && v.ValueKind == JsonValueKind.String ? v.GetString() ?? fallback : fallback;
|
|
|
|
// Survival card Detail strings are FORMAT TEMPLATES ("{0} = level x PerPick" per the card defs) that the in-game
|
|
// draft fills at render time. The guide shows the per-pick line, so format with one pick's worth.
|
|
public static string CardDetail(string template, double perPick)
|
|
{
|
|
if (string.IsNullOrEmpty(template)) return "";
|
|
try { return string.Format(System.Globalization.CultureInfo.InvariantCulture, template, perPick); }
|
|
catch (FormatException) { return template; } // malformed template -> show raw rather than nothing
|
|
}
|
|
}
|
|
}
|