297 lines
10 KiB
C#
297 lines
10 KiB
C#
namespace Fragalytics.Web.Models;
|
|
|
|
public static class DemoStatuses
|
|
{
|
|
public const string Uploaded = "uploaded";
|
|
public const string Queued = "queued";
|
|
public const string Processing = "processing";
|
|
public const string Parsed = "parsed";
|
|
public const string Failed = "failed";
|
|
}
|
|
|
|
public static class ClipJobStatuses
|
|
{
|
|
public const string Pending = "pending";
|
|
public const string Rendering = "rendering";
|
|
public const string Rendered = "rendered";
|
|
public const string Failed = "failed";
|
|
}
|
|
|
|
public static class EventTypes
|
|
{
|
|
public const string Kill = "kill";
|
|
}
|
|
|
|
public static class ClipMediaFormats
|
|
{
|
|
public const string Mp4Extension = ".mp4";
|
|
public const string WebMExtension = ".webm";
|
|
public const string Mp4ContentType = "video/mp4";
|
|
public const string WebMContentType = "video/webm";
|
|
|
|
public static readonly HashSet<string> AllowedExtensions = new(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
Mp4Extension,
|
|
WebMExtension
|
|
};
|
|
|
|
public static string InferContentType(string extension)
|
|
{
|
|
return extension.Equals(WebMExtension, StringComparison.OrdinalIgnoreCase)
|
|
? WebMContentType
|
|
: Mp4ContentType;
|
|
}
|
|
|
|
public static string GetSuggestedFileExtension(string outputFormat)
|
|
{
|
|
return outputFormat.Equals("webm", StringComparison.OrdinalIgnoreCase)
|
|
? WebMExtension
|
|
: Mp4Extension;
|
|
}
|
|
}
|
|
|
|
public sealed class AppState
|
|
{
|
|
public int NextDemoId { get; set; } = 1;
|
|
public int NextMatchId { get; set; } = 1;
|
|
public int NextPlayerId { get; set; } = 1;
|
|
public int NextRoundId { get; set; } = 1;
|
|
public int NextEventId { get; set; } = 1;
|
|
public int NextHighlightId { get; set; } = 1;
|
|
public int NextClipJobId { get; set; } = 1;
|
|
public int NextClipAssetId { get; set; } = 1;
|
|
public int NextScoringProfileId { get; set; } = 1;
|
|
|
|
public List<DemoRecord> Demos { get; set; } = [];
|
|
public List<MatchRecord> Matches { get; set; } = [];
|
|
public List<PlayerRecord> Players { get; set; } = [];
|
|
public List<RoundRecord> Rounds { get; set; } = [];
|
|
public List<EventRecord> Events { get; set; } = [];
|
|
public List<HighlightRecord> Highlights { get; set; } = [];
|
|
public List<ClipJobRecord> ClipJobs { get; set; } = [];
|
|
public List<ClipAssetRecord> ClipAssets { get; set; } = [];
|
|
public List<ScoringProfileRecord> ScoringProfiles { get; set; } = [];
|
|
}
|
|
|
|
public sealed class DemoRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public string OriginalFileName { get; set; } = string.Empty;
|
|
public string StoredPath { get; set; } = string.Empty;
|
|
public string ParserBackend { get; set; } = string.Empty;
|
|
public string Status { get; set; } = DemoStatuses.Uploaded;
|
|
public string? ErrorMessage { get; set; }
|
|
public DateTime UploadedAtUtc { get; set; } = DateTime.UtcNow;
|
|
public DateTime? ProcessedAtUtc { get; set; }
|
|
public int? MatchId { get; set; }
|
|
}
|
|
|
|
public sealed class MatchRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int DemoId { get; set; }
|
|
public string? MapName { get; set; }
|
|
public string? ServerName { get; set; }
|
|
public int? TickRate { get; set; }
|
|
public int TotalRounds { get; set; }
|
|
public string? TeamCtName { get; set; }
|
|
public string? TeamTName { get; set; }
|
|
public DateTime ParsedAtUtc { get; set; } = DateTime.UtcNow;
|
|
}
|
|
|
|
public sealed class PlayerRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int MatchId { get; set; }
|
|
public string SteamId { get; set; } = string.Empty;
|
|
public string Name { get; set; } = string.Empty;
|
|
public string? TeamName { get; set; }
|
|
public string? Side { get; set; }
|
|
}
|
|
|
|
public sealed class RoundRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int MatchId { get; set; }
|
|
public int Number { get; set; }
|
|
public int? StartTick { get; set; }
|
|
public int? EndTick { get; set; }
|
|
public string? WinnerSide { get; set; }
|
|
public string? WinnerTeamName { get; set; }
|
|
public string? Reason { get; set; }
|
|
}
|
|
|
|
public sealed class EventRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int MatchId { get; set; }
|
|
public int? RoundId { get; set; }
|
|
public string EventType { get; set; } = EventTypes.Kill;
|
|
public int Tick { get; set; }
|
|
public double? Second { get; set; }
|
|
public int? ActorPlayerId { get; set; }
|
|
public int? TargetPlayerId { get; set; }
|
|
public string? Weapon { get; set; }
|
|
public bool IsHeadshot { get; set; }
|
|
public bool IsWallbang { get; set; }
|
|
public bool IsSmokeKill { get; set; }
|
|
public int? KillerAliveCount { get; set; }
|
|
public int? EnemyAliveCount { get; set; }
|
|
public string? KillerNameSnapshot { get; set; }
|
|
public string? VictimNameSnapshot { get; set; }
|
|
}
|
|
|
|
public sealed class HighlightRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int MatchId { get; set; }
|
|
public int? RoundId { get; set; }
|
|
public int SourceEventId { get; set; }
|
|
public double Score { get; set; }
|
|
public List<string> Tags { get; set; } = [];
|
|
public List<ScoreExplanationRecord> Explanation { get; set; } = [];
|
|
public string ScoringVersion { get; set; } = string.Empty;
|
|
public int StartTick { get; set; }
|
|
public int EndTick { get; set; }
|
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
|
}
|
|
|
|
public sealed class ScoreExplanationRecord
|
|
{
|
|
public string Reason { get; set; } = string.Empty;
|
|
public double Value { get; set; }
|
|
public string Detail { get; set; } = string.Empty;
|
|
}
|
|
|
|
public sealed class ClipJobRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int HighlightId { get; set; }
|
|
public string Renderer { get; set; } = RenderBackendNames.FutureRenderer;
|
|
public string Status { get; set; } = ClipJobStatuses.Pending;
|
|
public int StartTick { get; set; }
|
|
public int EndTick { get; set; }
|
|
public Dictionary<string, string> Payload { get; set; } = [];
|
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
|
public int? ClipAssetId { get; set; }
|
|
public int AttemptCount { get; set; }
|
|
public int MaxAttempts { get; set; } = 2;
|
|
public string? ErrorMessage { get; set; }
|
|
public DateTime? LastAttemptedAtUtc { get; set; }
|
|
public DateTime? RetryAfterUtc { get; set; }
|
|
public DateTime? StartedAtUtc { get; set; }
|
|
public DateTime? CompletedAtUtc { get; set; }
|
|
}
|
|
|
|
public sealed class RenderJobContract
|
|
{
|
|
public const string CurrentVersion = "1";
|
|
public const string DefaultCameraMode = "killer_pov";
|
|
public const string DefaultOutputFormat = "mp4";
|
|
public const string DefaultResolution = "1920x1080";
|
|
public const string DefaultFps = "60";
|
|
|
|
public string Version { get; set; } = CurrentVersion;
|
|
public int DemoId { get; set; }
|
|
public int MatchId { get; set; }
|
|
public int HighlightId { get; set; }
|
|
public int SourceEventId { get; set; }
|
|
public int StartTick { get; set; }
|
|
public int EndTick { get; set; }
|
|
public string CameraMode { get; set; } = DefaultCameraMode;
|
|
public string OutputFormat { get; set; } = DefaultOutputFormat;
|
|
public string Resolution { get; set; } = DefaultResolution;
|
|
public string Fps { get; set; } = DefaultFps;
|
|
|
|
public Dictionary<string, string> ToPayload()
|
|
{
|
|
return new Dictionary<string, string>
|
|
{
|
|
["version"] = Version,
|
|
["demoId"] = DemoId.ToString(),
|
|
["matchId"] = MatchId.ToString(),
|
|
["highlightId"] = HighlightId.ToString(),
|
|
["sourceEventId"] = SourceEventId.ToString(),
|
|
["startTick"] = StartTick.ToString(),
|
|
["endTick"] = EndTick.ToString(),
|
|
["cameraMode"] = CameraMode,
|
|
["outputFormat"] = OutputFormat,
|
|
["resolution"] = Resolution,
|
|
["fps"] = Fps
|
|
};
|
|
}
|
|
|
|
public static RenderJobContract FromPayload(IReadOnlyDictionary<string, string> payload)
|
|
{
|
|
return new RenderJobContract
|
|
{
|
|
Version = ReadString(payload, "version", CurrentVersion),
|
|
DemoId = ReadInt(payload, "demoId"),
|
|
MatchId = ReadInt(payload, "matchId"),
|
|
HighlightId = ReadInt(payload, "highlightId"),
|
|
SourceEventId = ReadInt(payload, "sourceEventId"),
|
|
StartTick = ReadInt(payload, "startTick"),
|
|
EndTick = ReadInt(payload, "endTick"),
|
|
CameraMode = ReadString(payload, "cameraMode", DefaultCameraMode),
|
|
OutputFormat = ReadString(payload, "outputFormat", DefaultOutputFormat),
|
|
Resolution = ReadString(payload, "resolution", DefaultResolution),
|
|
Fps = ReadString(payload, "fps", DefaultFps)
|
|
};
|
|
}
|
|
|
|
public string GetSuggestedFileExtension()
|
|
{
|
|
return ClipMediaFormats.GetSuggestedFileExtension(OutputFormat);
|
|
}
|
|
|
|
private static int ReadInt(IReadOnlyDictionary<string, string> payload, string key)
|
|
{
|
|
return payload.TryGetValue(key, out var raw) && int.TryParse(raw, out var value) ? value : 0;
|
|
}
|
|
|
|
private static string ReadString(IReadOnlyDictionary<string, string> payload, string key, string fallback)
|
|
{
|
|
return payload.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : fallback;
|
|
}
|
|
}
|
|
|
|
public sealed class ClipAssetRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public int ClipJobId { get; set; }
|
|
public string FileName { get; set; } = string.Empty;
|
|
public string StoredPath { get; set; } = string.Empty;
|
|
public string ContentType { get; set; } = ClipMediaFormats.Mp4ContentType;
|
|
public long FileSizeBytes { get; set; }
|
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
|
}
|
|
|
|
public sealed class ScoringProfileRecord
|
|
{
|
|
public int Id { get; set; }
|
|
public string Name { get; set; } = "default";
|
|
public string Version { get; set; } = string.Empty;
|
|
public bool IsActive { get; set; } = true;
|
|
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
|
public HighlightScoringRules Rules { get; set; } = new();
|
|
}
|
|
|
|
public sealed class HighlightScoringRules
|
|
{
|
|
public string Name { get; set; } = "default";
|
|
public Dictionary<string, double> Weights { get; set; } = new();
|
|
public ClipWindowRules Clip { get; set; } = new();
|
|
public ScoreThresholdRules Thresholds { get; set; } = new();
|
|
}
|
|
|
|
public sealed class ClipWindowRules
|
|
{
|
|
public int PreTicks { get; set; } = 160;
|
|
public int PostTicks { get; set; } = 96;
|
|
}
|
|
|
|
public sealed class ScoreThresholdRules
|
|
{
|
|
public double HighlightScoreMin { get; set; } = 18;
|
|
}
|