namespace GeoSus.Server; using System.Text.Json; using System.Text.Json.Serialization; // Konfigurace serveru - všechny herní konstanty public class ServerConfig { // Síťové public int TcpPort { get; set; } = 7777; public int HttpPort { get; set; } = 8088; public int MaxPacketSizeBytes { get; set; } = 1048576; // 1MB // Timing public int TickMs { get; set; } = 200; public int PositionBroadcastRateMs { get; set; } = 1000; // Pohyb & Anti-Cheat public double MaxSpeedMps { get; set; } = 12.0; public double MovementValidationWindowSec { get; set; } = 5.0; public double TeleportThresholdMeters { get; set; } = 50.0; public int CheatScoreWarnThreshold { get; set; } = 10; public int CheatScoreRestrictThreshold { get; set; } = 25; public int CheatScoreKickThreshold { get; set; } = 50; // Zabíjení public double KillDistanceM { get; set; } = 10.0; public int KillCooldownMs { get; set; } = 30000; // Meetingy public double MeetingArrivalRadiusM { get; set; } = 15.0; public int ArrivalBaseMs { get; set; } = 30000; public int ArrivalSafetyMarginMs { get; set; } = 500; public int AllowedLateMs { get; set; } = 2000; public int DiscussionPhaseMs { get; set; } = 30000; public int VotingPhaseMs { get; set; } = 45000; // Emergency meeting public int EmergencyMeetingCooldownMs { get; set; } = 60000; public int MaxEmergencyMeetingsPerPlayer { get; set; } = 1; public double EmergencyMeetingCallRadiusM { get; set; } = 15.0; // Vzdálenost od středu mapy pro svolání emergency meeting public double ReportDistanceM { get; set; } = 5.0; // Tasky public double TaskStartDistanceM { get; set; } = 3.0; public int TaskLeaveDebounceMs { get; set; } = 2000; public int TaskProgressKeepaliveMs { get; set; } = 5000; // Persistence public int SnapshotEvents { get; set; } = 200; public int SnapshotIntervalMs { get; set; } = 300000; public int WalMaxSizeMb { get; set; } = 10; public string DataPath { get; set; } = "data"; // Host Migration public int HostTimeoutMs { get; set; } = 15000; public int ReconnectWindowMs { get; set; } = 60000; // Lobby public int IdleLobbyTtlMs { get; set; } = 3600000; public int JoinCodeTtlMs { get; set; } = 86400000; // 24h public int MaxPlayersPerLobby { get; set; } = 15; public int JoinRateLimitPerMinute { get; set; } = 10; // Security public int SessionKeySizeBytes { get; set; } = 32; // AES-256 public int RsaKeySizeBits { get; set; } = 2048; // Stats API public int StatsApiRateLimit { get; set; } = 100; // per minute per IP public string? StatsApiKey { get; set; } = null; // Hra - výchozí hodnoty pro nové lobby public int DefaultImpostorCount { get; set; } = 1; public int DefaultTaskCount { get; set; } = 5; public TiePolicy DefaultTiePolicy { get; set; } = TiePolicy.NoEject; // Sabotage system public int SabotageCooldownMs { get; set; } = 30000; // 30s between sabotages public int CommsBlackoutDurationMs { get; set; } = 30000; // 30s max duration (or until repaired) public int CriticalMeltdownDeadlineMs { get; set; } = 45000; // 45s to fix or impostor wins public double RepairStationDistanceM { get; set; } = 5.0; // Must be within 5m to repair public int RepairStationHoldMs { get; set; } = 3000; // Must hold for 3s to complete repair public int SimultaneousRepairWindowMs { get; set; } = 5000; // 5s window for both stations to be repaired // Overpass API (Map Data) public string OverpassApiUrl { get; set; } = "https://overpass-api.de/api/interpreter"; public int OverpassTimeoutSec { get; set; } = 30; public int OverpassCacheMaxEntries { get; set; } = 100; public bool OverpassEnabled { get; set; } = true; public double MinTaskSpacingMeters { get; set; } = 20.0; // Minimum spacing between tasks public static ServerConfig Load(string path) { ServerConfig config; if (File.Exists(path)) { var json = File.ReadAllText(path); config = JsonSerializer.Deserialize(json, JsonOptions.Default) ?? new ServerConfig(); } else { config = new ServerConfig(); } // Override z environment variables (pro Docker) config.ApplyEnvironmentOverrides(); return config; } /// /// Aplikuje override hodnot z environment variables. /// Prefix: GEOSUS_ /// Příklady: GEOSUS_TCP_PORT=7777, GEOSUS_HTTP_PORT=8088 /// private void ApplyEnvironmentOverrides() { // Síťové if (int.TryParse(Environment.GetEnvironmentVariable("GEOSUS_TCP_PORT"), out var tcpPort)) TcpPort = tcpPort; if (int.TryParse(Environment.GetEnvironmentVariable("GEOSUS_HTTP_PORT"), out var httpPort)) HttpPort = httpPort; // Data path var dataPath = Environment.GetEnvironmentVariable("GEOSUS_DATA_PATH"); if (!string.IsNullOrEmpty(dataPath)) DataPath = dataPath; // Overpass API var overpassUrl = Environment.GetEnvironmentVariable("GEOSUS_OVERPASS_URL"); if (!string.IsNullOrEmpty(overpassUrl)) OverpassApiUrl = overpassUrl; // Stats API key var apiKey = Environment.GetEnvironmentVariable("GEOSUS_API_KEY"); if (!string.IsNullOrEmpty(apiKey)) StatsApiKey = apiKey; } public void Save(string path) { var json = JsonSerializer.Serialize(this, JsonOptions.Indented); File.WriteAllText(path, json); } } public enum TiePolicy { NoEject, Random, EjectLowestId } public static class JsonOptions { public static readonly JsonSerializerOptions Default = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter() }, WriteIndented = false }; public static readonly JsonSerializerOptions Indented = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new JsonStringEnumConverter() }, WriteIndented = true }; }