85 lines
3.5 KiB
C#
85 lines
3.5 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace PlaytimeHistory;
|
|
|
|
// Every database write, as data, so the writer can run them in order off the game thread and keep
|
|
// them in the spool file while the database is down. Each one is safe to run twice: inserts are
|
|
// keyed (session_key, segment_key) and closes only touch rows still open, so a write that's sent
|
|
// again after a lost reply changes nothing.
|
|
[JsonPolymorphic(TypeDiscriminatorPropertyName = "op")]
|
|
[JsonDerivedType(typeof(ServerSeen), "server_seen")]
|
|
[JsonDerivedType(typeof(RecoverStale), "recover_stale")]
|
|
[JsonDerivedType(typeof(SessionOpen), "session_open")]
|
|
[JsonDerivedType(typeof(SessionClose), "session_close")]
|
|
[JsonDerivedType(typeof(SegmentOpen), "segment_open")]
|
|
[JsonDerivedType(typeof(SegmentRestate), "segment_restate")]
|
|
[JsonDerivedType(typeof(SegmentClose), "segment_close")]
|
|
[JsonDerivedType(typeof(Heartbeat), "heartbeat")]
|
|
[JsonDerivedType(typeof(OnlineSnapshot), "online_snapshot")]
|
|
[JsonDerivedType(typeof(EventRecord), "event")]
|
|
public abstract record Op;
|
|
|
|
public sealed record ServerSeen(int ServerId, string Address, string Hostname, DateTime At) : Op;
|
|
|
|
// Closes whatever this server left open (a crash, or a kill without an unload) at its last heartbeat.
|
|
public sealed record RecoverStale(int ServerId, bool CountSpectatorTime) : Op;
|
|
|
|
public sealed record SessionOpen(
|
|
string SessionKey, ulong SteamId, int ServerId, string Nickname, DateTime StartedAt, string Map,
|
|
int PlayersOnline, int MaxPlayers, string? CountryIso, string? CountryName, string? City,
|
|
string PluginVersion) : Op;
|
|
|
|
public sealed record SessionClose(
|
|
string SessionKey, ulong SteamId, DateTime EndedAt, EndKind EndKind, string Map,
|
|
int? DisconnectReason, string? DisconnectReasonName, MatchStats? Stats, int RoundsPlayed,
|
|
PingStats? Ping) : Op;
|
|
|
|
public sealed record SegmentOpen(
|
|
string SegmentKey, string SessionKey, ulong SteamId, int ServerId, string Map, int Team, bool? Alive,
|
|
DateTime StartedAt) : Op;
|
|
|
|
// The state changed within the second the segment started: change it instead of leaving a
|
|
// zero-length segment behind.
|
|
public sealed record SegmentRestate(string SegmentKey, int Team, bool? Alive) : Op;
|
|
|
|
public sealed record SegmentClose(string SegmentKey, DateTime EndedAt, bool CountSpectatorTime) : Op;
|
|
|
|
public sealed record Heartbeat(int ServerId, DateTime At) : Op;
|
|
|
|
public sealed record OnlineSnapshot(int ServerId, DateTime At, int Players, int Bots, int MaxPlayers, string Map) : Op;
|
|
|
|
// A kill, bomb plant or bomb defuse, as it happens. The kill-only fields are null otherwise.
|
|
public sealed record EventRecord(
|
|
string EventKey, int ServerId, string? SessionKey, ulong SteamId, EventKind Kind, DateTime At, string Map, int Team,
|
|
string? Weapon = null, bool? Headshot = null, bool? Noscope = null, bool? Thrusmoke = null, bool? Wallbang = null,
|
|
bool? Blind = null, ulong? VictimSteamId = null, bool? VictimBot = null, int? Site = null) : Op;
|
|
|
|
public sealed record MatchStats(int Kills, int Deaths, int Assists, int Headshots, int Damage, int Mvp, int Score);
|
|
|
|
public sealed record PingStats(int Avg, int Min, int Max, int Samples);
|
|
|
|
public enum EndKind
|
|
{
|
|
Open = 0,
|
|
Disconnect = 1,
|
|
MapChange = 2,
|
|
Unload = 3,
|
|
Stale = 4,
|
|
}
|
|
|
|
public enum EventKind
|
|
{
|
|
Kill = 1,
|
|
BombPlanted = 2,
|
|
BombDefused = 3,
|
|
}
|
|
|
|
public static class Teams
|
|
{
|
|
public const int None = 0;
|
|
public const int Spectator = 1;
|
|
public const int T = 2;
|
|
public const int CT = 3;
|
|
|
|
public static bool Playing(int team) => team is T or CT;
|
|
}
|