Modify log format

Thank you for downloading the log from QQ, I don't know where to find it
Thank you for selling NikoCat233 for 180
Thank you for betraying us
This commit is contained in:
FangkuaiYa committed 2026-06-28 22:56:39 +08:00
1 parent a575991eaa
commit b4d259688f
30 files changed
+236 -189

No files matched your search

@@ -59,7 +59,7 @@ public sealed class LanguageService
{
_tables.Clear();
LoadAll();
_logger.LogInformation("[Language] Reloaded all language files.");
_logger.LogInformation("LanguageReloaded all language files.");
}
/// <summary>
@@ -84,7 +84,7 @@ public sealed class LanguageService
}
}
_logger.LogDebug("[Language] Plugin added {Count} keys for {Lang}", table.Count, langCode);
_logger.LogDebug("LanguagePlugin added {Count} keys for {Lang}", table.Count, langCode);
}
}
@@ -111,15 +111,15 @@ public sealed class LanguageService
var table = JsonSerializer.Deserialize<Dictionary<string, string>>(json)
?? new Dictionary<string, string>();
_tables[code] = table;
_logger.LogDebug("[Language] Loaded {Code} ({Count} keys)", code, table.Count);
_logger.LogDebug("LanguageLoaded {Code} ({Count} keys)", code, table.Count);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Language] Failed to load {File}", file);
_logger.LogWarning(ex, "LanguageFailed to load {File}", file);
}
}
_logger.LogInformation("[Language] Loaded {Count} language file(s).", _tables.Count);
_logger.LogInformation("LanguageLoaded {Count} language file(s).", _tables.Count);
}
private void EnsureDefaults()
+4 -4
View File
@@ -80,7 +80,7 @@ namespace Empostor.Server.Http
|| _config.Password == "admin123")
{
_logger.LogWarning(
"[Admin] SECURITY: Default or empty admin password detected! Set a strong password in config.json -> Admin.Password to protect the admin panel.");
"AdminSECURITY: Default or empty admin password detected! Set a strong password in config.json -> Admin.Password to protect the admin panel.");
}
}
@@ -117,7 +117,7 @@ namespace Empostor.Server.Http
&& DateTime.UtcNow - entry.FirstAttempt < LoginLockoutDuration)
{
var remaining = (int)(LoginLockoutDuration - (DateTime.UtcNow - entry.FirstAttempt)).TotalMinutes;
_logger.LogWarning("[Admin] Rate-limited login attempt from {Ip} (locked out for ~{Min}m more)", ip, Math.Max(1, remaining));
_logger.LogWarning("AdminRate-limited login attempt from {Ip} (locked out for ~{Min}m more)", ip, Math.Max(1, remaining));
return Content(LoginHtml.Replace("<!--ERR-->",
$"<p style='color:var(--r);margin-top:8px'>Too many failed attempts. Try again in {Math.Max(1, remaining)} minute(s).</p>"),
"text/html; charset=utf-8");
@@ -138,7 +138,7 @@ namespace Empostor.Server.Http
_ => (1, DateTime.UtcNow),
(_, e) => (e.Count + 1, e.FirstAttempt));
_logger.LogWarning("[Admin] Failed login from {Ip} (attempt {Count})", ip,
_logger.LogWarning("AdminFailed login from {Ip} (attempt {Count})", ip,
_loginFailures.TryGetValue(ip, out var updated) ? updated.Count : 1);
return Content(LoginHtml.Replace("<!--ERR-->",
"<p style='color:var(--r);margin-top:8px'>Incorrect password.</p>"),
@@ -291,7 +291,7 @@ namespace Empostor.Server.Http
return BadRequest(Err("No host character"));
}
await host.SendChatAsync($"[Admin] {req.Message}");
await host.SendChatAsync($"Admin{req.Message}");
return Ok(new { ok = true });
}
+3 -3
View File
@@ -25,7 +25,7 @@ public sealed class HelloController : ControllerBase
{
if (!System.IO.File.Exists(IndexFile))
{
_logger.LogWarning("[HelloController] Pages/index.html not found, serving fallback.");
_logger.LogWarning("HelloControllerPages/index.html not found, serving fallback.");
return Content(FallbackHtml(), "text/html; charset=utf-8");
}
@@ -52,13 +52,13 @@ public sealed class HelloController : ControllerBase
if (!Directory.Exists(PagesDir))
{
Directory.CreateDirectory(PagesDir);
_logger.LogInformation("[HelloController] Created Pages/ directory at {Path}", PagesDir);
_logger.LogInformation("HelloControllerCreated Pages/ directory at {Path}", PagesDir);
}
if (!System.IO.File.Exists(IndexFile))
{
System.IO.File.WriteAllText(IndexFile, DefaultIndexHtml());
_logger.LogInformation("[HelloController] Written default Pages/index.html");
_logger.LogInformation("HelloControllerWritten default Pages/index.html");
}
}
}
@@ -96,7 +96,7 @@ namespace Empostor.Server.Http
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Marketplace] Failed to fetch {Url}", url);
_logger.LogWarning(ex, "MarketplaceFailed to fetch {Url}", url);
return StatusCode(502, new { error = "Failed to fetch marketplace: " + ex.Message });
}
}
@@ -148,12 +148,12 @@ namespace Empostor.Server.Http
var bytes = await client.GetByteArrayAsync(req.DownloadUrl);
await System.IO.File.WriteAllBytesAsync(Path.Combine(PluginsDir, fileName), bytes);
_logger.LogInformation("[Marketplace] Installed {File} from {Url}", fileName, req.DownloadUrl);
_logger.LogInformation("MarketplaceInstalled {File} from {Url}", fileName, req.DownloadUrl);
return Ok(new { installed = fileName, restartRequired = true });
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Marketplace] Install failed: {Url}", req.DownloadUrl);
_logger.LogWarning(ex, "MarketplaceInstall failed: {Url}", req.DownloadUrl);
return StatusCode(500, new { error = ex.Message });
}
}
@@ -184,7 +184,7 @@ namespace Empostor.Server.Http
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Update] GitHub check failed");
_logger.LogWarning(ex, "UpdateGitHub check failed");
return StatusCode(502, new { error = ex.Message });
}
}
@@ -54,7 +54,7 @@ public sealed class PrivacyController : ControllerBase
return Unauthorized(new { error = "Invalid token." });
System.IO.File.WriteAllText(PrivacyFile, content);
_logger.LogInformation("[PrivacyController] Privacy policy updated.");
_logger.LogInformation("PrivacyControllerPrivacy policy updated.");
return Ok(new { success = true });
}
catch (Exception ex)
@@ -78,7 +78,7 @@ public sealed class PrivacyController : ControllerBase
if (!System.IO.File.Exists(PrivacyFile))
{
System.IO.File.WriteAllText(PrivacyFile, DefaultPrivacyHtml());
_logger.LogInformation("[PrivacyController] Written default Pages/privacy.html");
_logger.LogInformation("PrivacyControllerWritten default Pages/privacy.html");
}
}
}
+46 -42
View File
@@ -65,7 +65,7 @@ public sealed class TokenController : ControllerBase
{
if (string.IsNullOrEmpty(authorization) || !authorization.StartsWith("Bearer "))
{
_logger.LogWarning("[TokenController] Missing or invalid Authorization header");
_logger.LogWarning("TokenController missing or invalid Authorization header");
return Unauthorized(new { error = "Missing or invalid authorization" });
}
@@ -73,7 +73,7 @@ public sealed class TokenController : ControllerBase
var productUserId = ExtractProductUserIdFromJwt(eosToken);
if (string.IsNullOrEmpty(productUserId))
{
_logger.LogWarning("[TokenController] Could not extract PUID from token");
_logger.LogWarning("TokenController could not extract PUID from token");
return Unauthorized(new { error = "Invalid token content" });
}
@@ -101,6 +101,10 @@ public sealed class TokenController : ControllerBase
FriendCodeConfirmed = _nikoFriendCodeConfirmed,
};
// Extract name from friend code (e.g., "ufolud" from "ufolud#1234")
var playerName = friendCode?.Split('#')[0] ?? productUserId[..Math.Min(8, productUserId.Length)];
authInfo.Name = playerName;
if (deltaPort > 0)
{
// Port allocated — store by port and start delta listener for UDP matching
@@ -108,8 +112,8 @@ public sealed class TokenController : ControllerBase
_ = _deltaListenerManager.StartDeltaListenerAsync(deltaPort);
_logger.LogInformation(
"[TokenController] Authenticated: PUID={Puid} FriendCode={FC} DeltaPort={Port} IP={Ip}",
productUserId, friendCode, deltaPort, clientIp);
"TokenUser {Name} {Puid} {FriendCode} {Ip} {Port} added.",
playerName, productUserId, friendCode, clientIp, deltaPort);
}
else
{
@@ -120,8 +124,8 @@ public sealed class TokenController : ControllerBase
}
_logger.LogInformation(
"[TokenController] Authenticated: PUID={Puid} FriendCode={FC} Port=0 (IP fallback) IP={Ip}",
productUserId, friendCode, clientIp);
"TokenUser {Name} {Puid} {FriendCode} {Ip} {Port} added.",
playerName, productUserId, friendCode, clientIp, 0);
}
var response = new TokenResponse
@@ -139,7 +143,7 @@ public sealed class TokenController : ControllerBase
}
catch (Exception ex)
{
_logger.LogError(ex, "[TokenController] Unexpected error");
_logger.LogError(ex, "TokenController unexpected error");
return StatusCode(500, new { error = "Internal server error" });
}
}
@@ -189,13 +193,13 @@ public sealed class TokenController : ControllerBase
if (cached != null)
{
_logger.LogInformation(
"[TokenController] FriendCode found in cache: PUID={Puid} FC={FC}",
"TokenControllerFriendCode found in cache: PUID={Puid} FC={FC}",
productUserId, cached);
return cached;
}
var mode = _authApiConfig.Mode;
_logger.LogDebug("[TokenController] AuthApi mode: {Mode}", mode);
_logger.LogDebug("TokenControllerAuthApi mode: {Mode}", mode);
string? friendCode = null;
@@ -221,7 +225,7 @@ public sealed class TokenController : ControllerBase
if (nikoKeyIsCustom)
{
_logger.LogDebug("[TokenController] Both mode: trying Niko first (custom key)");
_logger.LogDebug("TokenController Both mode: trying Niko first (custom key)");
friendCode = await FetchFromNikoAsync(eosToken, productUserId);
if (string.IsNullOrEmpty(friendCode))
{
@@ -230,7 +234,7 @@ public sealed class TokenController : ControllerBase
}
else
{
_logger.LogDebug("[TokenController] Both mode: trying Ume first (default Niko key)");
_logger.LogDebug("TokenController Both mode: trying Ume first (default Niko key)");
friendCode = await FetchFromUmeAsync(eosToken, productUserId);
if (string.IsNullOrEmpty(friendCode))
{
@@ -253,7 +257,7 @@ public sealed class TokenController : ControllerBase
{
friendCode = GenerateFallbackFriendCode(productUserId);
_logger.LogWarning(
"[TokenController] FriendCode fetch failed for PUID={Puid}, using fallback: {FC}",
"TokenController FriendCode fetch failed for PUID={Puid}, using fallback: {FC}",
productUserId, friendCode);
}
else
@@ -333,13 +337,13 @@ public sealed class TokenController : ControllerBase
if (!response.IsSuccessStatusCode)
{
_logger.LogWarning(
"[TokenController] Innersloth API returned {Status} for PUID={Puid}",
"TokenControllerInnersloth API returned {Status} for PUID={Puid}",
response.StatusCode, productUserId);
return null;
}
var json = await response.Content.ReadAsStringAsync();
_logger.LogInformation("[TokenController] Innersloth raw response: {Json}", json);
_logger.LogInformation("TokenControllerInnersloth raw response: {Json}", json);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
var attrs = root.TryGetProperty("data", out var data)
@@ -351,18 +355,18 @@ public sealed class TokenController : ControllerBase
{
var fc = $"{username}#{discriminator}";
_logger.LogInformation(
"[TokenController] FriendCode fetched from Innersloth: PUID={Puid} FC={FC}",
"TokenControllerFriendCode fetched from Innersloth: PUID={Puid} FC={FC}",
productUserId, fc);
return fc;
}
_logger.LogWarning(
"[TokenController] Missing username/discriminator in Innersloth response for PUID={Puid}",
"TokenControllerMissing username/discriminator in Innersloth response for PUID={Puid}",
productUserId);
}
catch (Exception ex)
{
_logger.LogError(ex, "[TokenController] Exception calling Innersloth API for PUID={Puid}", productUserId);
_logger.LogError(ex, "TokenControllerException calling Innersloth API for PUID={Puid}", productUserId);
}
return null;
@@ -372,7 +376,7 @@ public sealed class TokenController : ControllerBase
{
if (string.IsNullOrEmpty(_authApiConfig.NikoApiKey))
{
_logger.LogWarning("[TokenController] NikoApiKey is empty, skipping Niko API");
_logger.LogWarning("TokenControllerNikoApiKey is empty, skipping Niko API");
return null;
}
@@ -400,7 +404,7 @@ public sealed class TokenController : ControllerBase
if (!putResp.IsSuccessStatusCode)
{
_logger.LogWarning(
"[TokenController] Niko PUT returned {Status} for PUID={Puid}",
"TokenControllerNiko PUT returned {Status} for PUID={Puid}",
putResp.StatusCode, productUserId);
return null;
}
@@ -410,14 +414,14 @@ public sealed class TokenController : ControllerBase
if (createResult == null || string.IsNullOrEmpty(createResult.VerifyCode))
{
_logger.LogWarning(
"[TokenController] Niko PUT response missing VerifyCode for PUID={Puid}", productUserId);
"TokenControllerNiko PUT response missing VerifyCode for PUID={Puid}", productUserId);
return null;
}
var verifyCode = createResult.VerifyCode;
_nikoVerifyCode = verifyCode;
_logger.LogInformation(
"[TokenController] Niko verify request created: Code={Code} for PUID={Puid}",
"TokenControllerNiko verify request created: Code={Code} for PUID={Puid}",
verifyCode, productUserId);
// Proxy EOS token to Niko to trigger HTTP auth
@@ -454,14 +458,14 @@ public sealed class TokenController : ControllerBase
&& !string.Equals(result.Puid, productUserId, StringComparison.OrdinalIgnoreCase))
{
_logger.LogWarning(
"[TokenController] Niko PUID mismatch: expected={Expected} got={Got}",
"TokenControllerNiko PUID mismatch: expected={Expected} got={Got}",
productUserId, result.Puid);
return null;
}
_nikoFriendCodeConfirmed = true;
_logger.LogInformation(
"[TokenController] FriendCode fetched from Niko: PUID={Puid} FC={FC} Status={Status}",
"TokenControllerFriendCode fetched from Niko: PUID={Puid} FC={FC} Status={Status}",
productUserId, result.FriendCode, result.VerifyStatus);
_ = DeleteNikoVerificationAsync(client, apiUrl, verifyCode);
@@ -470,17 +474,17 @@ public sealed class TokenController : ControllerBase
}
_logger.LogDebug(
"[TokenController] Niko poll {Attempt}: Status={Status} for PUID={Puid}",
"TokenControllerNiko poll {Attempt}: Status={Status} for PUID={Puid}",
i + 1, result.VerifyStatus ?? "null", productUserId);
}
_logger.LogInformation(
"[TokenController] Niko friend code not yet available for PUID={Puid}, VerifyCode={Code} deferred to handshake",
"TokenControllerNiko friend code not yet available for PUID={Puid}, VerifyCode={Code} deferred to handshake",
productUserId, verifyCode);
}
catch (Exception ex)
{
_logger.LogError(ex, "[TokenController] Exception calling Niko API for PUID={Puid}", productUserId);
_logger.LogError(ex, "TokenControllerException calling Niko API for PUID={Puid}", productUserId);
}
return null;
@@ -500,13 +504,13 @@ public sealed class TokenController : ControllerBase
var resp = await client.SendAsync(req);
_logger.LogDebug(
"[TokenController] Niko proxy auth returned {Status} for PUID={Puid}",
"TokenControllerNiko proxy auth returned {Status} for PUID={Puid}",
resp.StatusCode, productUserId);
}
catch (Exception ex)
{
_logger.LogWarning(ex,
"[TokenController] Failed to proxy EOS token to Niko for PUID={Puid}", productUserId);
"TokenControllerFailed to proxy EOS token to Niko for PUID={Puid}", productUserId);
}
}
@@ -537,7 +541,7 @@ public sealed class TokenController : ControllerBase
if (string.IsNullOrEmpty(_authApiConfig.RelayApiBaseUrl)
|| string.IsNullOrEmpty(_authApiConfig.RelayApiKey))
{
_logger.LogWarning("[TokenController] RelayApi config incomplete, skipping relay");
_logger.LogWarning("TokenControllerRelayApi config incomplete, skipping relay");
return null;
}
@@ -563,7 +567,7 @@ public sealed class TokenController : ControllerBase
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning(
"[TokenController] Relay returned {Status} for PUID={Puid}",
"TokenControllerRelay returned {Status} for PUID={Puid}",
resp.StatusCode, productUserId);
return null;
}
@@ -573,7 +577,7 @@ public sealed class TokenController : ControllerBase
if (result == null || string.IsNullOrEmpty(result.FriendCode))
{
_logger.LogWarning(
"[TokenController] Relay response missing FriendCode for PUID={Puid}",
"TokenControllerRelay response missing FriendCode for PUID={Puid}",
productUserId);
return null;
}
@@ -582,19 +586,19 @@ public sealed class TokenController : ControllerBase
|| !string.Equals(result.ProductUserId, productUserId, StringComparison.OrdinalIgnoreCase))
{
_logger.LogWarning(
"[TokenController] Relay PUID mismatch: expected={Expected} got={Got}",
"TokenControllerRelay PUID mismatch: expected={Expected} got={Got}",
productUserId, result.ProductUserId);
return null;
}
_logger.LogInformation(
"[TokenController] FriendCode from Relay: PUID={Puid} FC={FC}",
"TokenControllerFriendCode from Relay: PUID={Puid} FC={FC}",
productUserId, result.FriendCode);
return result.FriendCode;
}
catch (Exception ex)
{
_logger.LogError(ex, "[TokenController] Exception calling Relay for PUID={Puid}", productUserId);
_logger.LogError(ex, "TokenControllerException calling Relay for PUID={Puid}", productUserId);
}
return null;
@@ -605,7 +609,7 @@ public sealed class TokenController : ControllerBase
if (string.IsNullOrEmpty(_authApiConfig.UmeApiBaseUrl)
|| string.IsNullOrEmpty(_authApiConfig.UmeApiKey))
{
_logger.LogWarning("[TokenController] UmeApi config incomplete, skipping Ume");
_logger.LogWarning("TokenControllerUmeApi config incomplete, skipping Ume");
return null;
}
@@ -629,13 +633,13 @@ public sealed class TokenController : ControllerBase
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning(
"[TokenController] Ume returned {Status} for PUID={Puid}",
"TokenControllerUme returned {Status} for PUID={Puid}",
resp.StatusCode, productUserId);
return null;
}
var json = await resp.Content.ReadAsStringAsync();
_logger.LogInformation("[TokenController] Ume raw response: {Json}", json);
_logger.LogInformation("TokenControllerUme raw response: {Json}", json);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
@@ -643,7 +647,7 @@ public sealed class TokenController : ControllerBase
if (status != "Verified")
{
_logger.LogWarning(
"[TokenController] Ume VerifyStatus={Status} for PUID={Puid}",
"TokenControllerUme VerifyStatus={Status} for PUID={Puid}",
status, productUserId);
return null;
}
@@ -652,7 +656,7 @@ public sealed class TokenController : ControllerBase
if (string.IsNullOrEmpty(friendCode))
{
_logger.LogWarning(
"[TokenController] Ume response missing FriendCode for PUID={Puid}",
"TokenControllerUme response missing FriendCode for PUID={Puid}",
productUserId);
return null;
}
@@ -662,19 +666,19 @@ public sealed class TokenController : ControllerBase
|| !string.Equals(returnedPuid, productUserId, StringComparison.OrdinalIgnoreCase))
{
_logger.LogWarning(
"[TokenController] Ume PUID mismatch: expected={Expected} got={Got}",
"TokenControllerUme PUID mismatch: expected={Expected} got={Got}",
productUserId, returnedPuid);
return null;
}
_logger.LogInformation(
"[TokenController] FriendCode from Ume: PUID={Puid} FC={FC}",
"TokenControllerFriendCode from Ume: PUID={Puid} FC={FC}",
productUserId, friendCode);
return friendCode;
}
catch (Exception ex)
{
_logger.LogError(ex, "[TokenController] Exception calling Ume for PUID={Puid}", productUserId);
_logger.LogError(ex, "TokenControllerException calling Ume for PUID={Puid}", productUserId);
}
return null;
+16 -11
View File
@@ -65,7 +65,7 @@ namespace Empostor.Server.Net
bool LogUnknownCategory(CheatCategory category)
{
_logger.LogWarning("Unknown cheat category {Category} was used when reporting", category);
_logger.LogWarning("Client [{Id}] unknown cheat category {Category} when reporting", Id, category);
return true;
}
@@ -91,7 +91,7 @@ namespace Empostor.Server.Net
var supportCode = Random.Shared.Next(0, 999_999).ToString("000-000");
_logger.LogWarning("Client {Name} ({Id}) was caught cheating: [{SupportCode}] [{Context}-{Category}] {Message}", Name, Id, supportCode, context.Name, category, message);
_logger.LogWarning("Client [{Id}]{Name} was caught cheating: [{SupportCode}] [{Context}-{Category}] {Message}", Id, Name, supportCode, context.Name, category, message);
if (Player is { } player)
{
@@ -118,7 +118,7 @@ namespace Empostor.Server.Net
{
var flag = reader.Tag;
_logger.LogTrace("[{0}] Server got {1}.", Id, MessageFlags.FlagToString(flag));
_logger.LogTrace("Client [{Id}] received {Flag}", Id, MessageFlags.FlagToString(flag));
switch (flag)
{
@@ -278,13 +278,13 @@ namespace Empostor.Server.Net
if (packed.Tag != MessageFlags.GameDataTo)
{
_logger.LogWarning("PackedGameDataTo contained non-GameDataTo flag {0}.", packed.Tag);
_logger.LogWarning("Client [{Id}] PackedGameDataTo contained non-GameDataTo flag {Flag}", Id, packed.Tag);
return;
}
if (packed.ReadInt32() != Player!.Game.Code)
{
_logger.LogWarning("PackedGameDataTo contained GameDataTo for the wrong game.");
_logger.LogWarning("Client [{Id}] PackedGameDataTo contained GameDataTo for wrong game", Id);
return;
}
@@ -390,7 +390,7 @@ namespace Empostor.Server.Net
break;
}
_logger.LogWarning("Server received unknown flag {0}.", flag);
_logger.LogWarning("Client [{Id}] sent unknown flag {Flag}", Id, flag);
break;
}
@@ -402,7 +402,8 @@ namespace Empostor.Server.Net
reader.Position < reader.Length)
{
_logger.LogWarning(
"Server did not consume all bytes from {0} ({1} < {2}).",
"Client [{Id}] unconsumed bytes for flag {Flag} ({Pos} < {Len})",
Id,
flag,
reader.Position,
reader.Length);
@@ -423,10 +424,14 @@ namespace Empostor.Server.Net
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception caught in client disconnection.");
_logger.LogError(ex, "Exception caught in client [{Id}] disconnection.", Id);
}
_logger.LogInformation("Client {0} disconnecting, reason: {1}", Id, reason);
var platform = PlatformSpecificData?.Platform.ToString().ToLowerInvariant() ?? "unknown";
var hashPuid = ProductUserId?.Length >= 9 ? ProductUserId[..9] : ProductUserId ?? "0";
var fc = FriendCode ?? "unknown";
_logger.LogInformation("Client {Id} {Name} {FriendCode} {HashPuid} {Platform} disconnecting, reason: {Reason}",
Id, Name, fc, hashPuid, platform, reason);
_clientManager.Remove(this);
await _gameManager.OnClientDisconnectAsync(this);
}
@@ -454,7 +459,7 @@ namespace Empostor.Server.Net
return true;
}
_logger.LogWarning("[{0}] Client sent packet only allowed by the host ({1}).", Id, game.HostId);
_logger.LogWarning("Client [{Id}] sent packet only allowed by the host ({HostId})", Id, game.HostId);
return false;
}
@@ -480,7 +485,7 @@ namespace Empostor.Server.Net
return true;
}
_logger.LogWarning("[{0}] Client sent PackedGameDataTo only allowed by the host ({1}).", Id, game.HostId);
_logger.LogWarning("Client [{Id}] sent PackedGameDataTo only allowed by the host ({HostId})", Id, game.HostId);
return false;
}
@@ -59,23 +59,24 @@ namespace Empostor.Server.Net.Manager
_authApiConfig = authApiConfig.Value;
_portPool = portPool;
if (_compatibilityConfig.AllowFutureGameVersions)
{
_logger.LogWarning("AllowFutureGameVersions, which allows future Among Us versions to connect that were unknown at the time this Impostor was built");
}
if (_compatibilityConfig.AllowHostAuthority)
{
_logger.LogWarning("AllowHostAuthority, which allows game hosts to control more game features, but it uses less well tested code on the client, which causes some bugs");
}
if (_compatibilityConfig.AllowVersionMixing)
{
_logger.LogWarning("AllowVersionMixing, which allows players to join games created on different game versions that they may not be 100% compatible with");
}
if (_compatibilityConfig.AllowFutureGameVersions || _compatibilityConfig.AllowHostAuthority || _compatibilityConfig.AllowVersionMixing)
{
_logger.LogWarning("One or more compatibility options were enabled, please mention these when seeking support:");
if (_compatibilityConfig.AllowFutureGameVersions)
{
_logger.LogWarning("AllowFutureGameVersions");
}
if (_compatibilityConfig.AllowHostAuthority)
{
_logger.LogWarning("AllowHostAuthority");
}
if (_compatibilityConfig.AllowVersionMixing)
{
_logger.LogWarning("AllowVersionMixing");
}
_logger.LogWarning("One or more compatibility options were enabled, please mention these when seeking support");
}
}
@@ -97,11 +98,13 @@ namespace Empostor.Server.Net.Manager
PlatformSpecificData? platformSpecificData,
int deltaPort = 0)
{
var id = NextId();
var versionCompare = _compatibilityManager.CanConnectToServer(clientVersion);
if (versionCompare == ICompatibilityManager.VersionCompareResult.ServerTooOld
&& _compatibilityConfig.AllowFutureGameVersions && platformSpecificData != null)
{
_logger.LogWarning("Client connected using future version: {v}", clientVersion);
_logger.LogWarning("Client [{Id}]{Name} connected using future version {Version}", id, name, clientVersion);
}
else if (versionCompare != ICompatibilityManager.VersionCompareResult.Compatible
|| platformSpecificData == null)
@@ -126,7 +129,7 @@ namespace Empostor.Server.Net.Manager
return;
}
_logger.LogInformation("Player {Name} connected with host authority.", name);
_logger.LogInformation("Client [{Id}]{Name} connected with host authority", id, name);
}
if (name.Length > 10) { await connection.CustomDisconnectAsync(DisconnectReason.Custom, DisconnectMessages.UsernameLength); return; }
@@ -158,28 +161,25 @@ namespace Empostor.Server.Net.Manager
friendCode = nikoResult.Value.FriendCode;
authInfo.FriendCode = friendCode;
authInfo.FriendCodeConfirmed = true;
_logger.LogInformation(
"[Auth] {Name}: Niko PUID matched via port={Port} → FriendCode={FC} PUID={Puid}",
name, deltaPort, friendCode, authInfo.ProductUserId);
}
else
{
_logger.LogWarning(
"[Auth] {Name}: Niko PUID mismatch (expected={Expected}, got={Got}) — keeping existing FC",
"Niko PUID mismatch for {Name}: expected {Expected} got {Got}",
name, authInfo.ProductUserId, nikoResult.Value.Puid);
}
}
}
_logger.LogInformation(
"[Auth] {Name}: matched via port={Port} → FriendCode={FC} PUID={Puid}",
name, deltaPort, friendCode, authInfo.ProductUserId);
"Client [{Id}]{Name} from port {Port} is authorized as {FriendCode} {HashPuid}",
id, name, deltaPort, friendCode ?? "unknown", HashPuid(authInfo.ProductUserId));
}
else
{
_logger.LogWarning(
"[Auth] {Name}: port={Port} has no auth info (expired or unknown), falling back to IP",
name, deltaPort);
"Client [{Id}]{Name} port {Port} has no auth info, falling back to IP",
id, name, deltaPort);
}
}
@@ -191,14 +191,14 @@ namespace Empostor.Server.Net.Manager
{
friendCode = authInfo.FriendCode;
_logger.LogInformation(
"[Auth] {Name}: matched via IP={Ip} → FriendCode={FC}",
name, NormalizeIp(clientIp), friendCode);
"Client [{Id}]{Name} from {Ip} is authorized as {FriendCode} {HashPuid}",
id, name, NormalizeIp(clientIp), friendCode ?? "unknown", HashPuid(authInfo.ProductUserId));
}
else
{
_logger.LogWarning(
"[Auth] {Name}: no auth info found (deltaPort={DP}, IP={Ip}) — FriendCode will be null",
name, deltaPort, NormalizeIp(clientIp));
"Client [{Id}]{Name}: no auth info found (port={Port}, ip={Ip})",
id, name, deltaPort, NormalizeIp(clientIp));
}
}
@@ -207,16 +207,15 @@ namespace Empostor.Server.Net.Manager
client.ProductUserId = authInfo?.ProductUserId;
client.DeltaPort = deltaPort;
var id = NextId();
client.Id = id;
_logger.LogTrace("Client connected: Id={Id} Name={Name} FriendCode={FC} DeltaPort={DP}", id, name, client.FriendCode ?? "(none)", deltaPort);
_logger.LogDebug("Client [{Id}]{Name} connected with FriendCode={FC} DeltaPort={DP}", id, name, client.FriendCode ?? "(none)", deltaPort);
_clients.TryAdd(id, client);
await _eventManager.CallAsync(new ClientConnectedEvent(connection, client));
}
public void Remove(IClient client)
{
_logger.LogTrace("Client {Id} disconnected.", client.Id);
_logger.LogDebug("Client [{Id}] removed from client manager", client.Id);
_clients.TryRemove(client.Id, out _);
if (client is ClientBase cb && cb.DeltaPort > 0)
@@ -261,12 +260,12 @@ namespace Empostor.Server.Net.Manager
if (string.IsNullOrEmpty(friendCode)
|| (status != "HttpPending" && status != "Verified"))
{
_logger.LogDebug("[Auth] Niko GET status={Status} for VerifyCode={Code}", status, verifyCode);
_logger.LogDebug("Niko GET status={Status} for VerifyCode={Code}", status, verifyCode);
return null;
}
_logger.LogInformation(
"[Auth] Niko GET success: FC={FC} PUID={Puid} Status={Status}",
"Niko GET success: FC={FC} PUID={Puid} Status={Status}",
friendCode, puid, status);
_ = DeleteNikoVerifyAsync(apiUrl, verifyCode);
@@ -275,7 +274,7 @@ namespace Empostor.Server.Net.Manager
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Auth] Niko GET failed for VerifyCode={Code}", verifyCode);
_logger.LogWarning(ex, "Niko GET failed for VerifyCode={Code}", verifyCode);
return null;
}
}
@@ -308,5 +307,16 @@ namespace Empostor.Server.Net.Manager
return addr.IsIPv4MappedToIPv6 ? addr.MapToIPv4().ToString() : addr.ToString();
}
private static string HashPuid(string puid)
{
if (string.IsNullOrEmpty(puid) || puid.Length < 9)
{
return puid ?? "0";
}
// Use first 9 characters of the PUID as the short hash
return puid[..9];
}
}
}
@@ -77,7 +77,7 @@ namespace Empostor.Server.Net.Manager
return;
}
_logger.LogDebug("Remove game with code {0} ({1}).", GameCodeParser.IntToGameName(gameCode), gameCode);
_logger.LogInformation("Remove game with code {CodeName} ({Code}).", GameCodeParser.IntToGameName(gameCode), gameCode);
await _eventManager.CallAsync(new GameDestroyedEvent(game));
}
+9 -9
View File
@@ -79,7 +79,7 @@ namespace Empostor.Server.Net
};
await _mainListener.StartAsync();
_logger.LogInformation("[Matchmaker] UDP listener started on {EP}", ipEndPoint);
_logger.LogInformation("Matchmaker UDP listener started on {EP}", ipEndPoint);
}
/// <summary>
@@ -89,13 +89,13 @@ namespace Empostor.Server.Net
{
if (_mainEndPoint == null)
{
_logger.LogError("[Matchmaker] Cannot start delta listener: main endpoint not initialized");
_logger.LogError("Matchmaker cannot start delta listener: main endpoint not initialized");
return;
}
if (_deltaListeners.ContainsKey(port))
{
_logger.LogDebug("[Matchmaker] Delta listener for port {Port} already running", port);
_logger.LogDebug("Matchmaker delta listener for port {Port} already running", port);
return;
}
@@ -120,11 +120,11 @@ namespace Empostor.Server.Net
// Open firewall for this port
await _firewall.OpenPortAsync((ushort)port);
_logger.LogInformation("[Matchmaker] Delta UDP listener started on port {Port}", port);
_logger.LogInformation("Matchmaker delta UDP listener started on port {Port}", port);
}
catch (SocketException ex)
{
_logger.LogError(ex, "[Matchmaker] Failed to start delta listener on port {Port} (may be in use)", port);
_logger.LogError(ex, "Matchmaker failed to start delta listener on port {Port} (may be in use)", port);
// Return the port — it's unusable
_portPool.ReturnPort(port);
}
@@ -140,11 +140,11 @@ namespace Empostor.Server.Net
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Matchmaker] Error disposing delta listener on port {Port}", port);
_logger.LogWarning(ex, "Matchmaker error disposing delta listener on port {Port}", port);
}
await _firewall.ClosePortAsync((ushort)port);
_logger.LogInformation("[Matchmaker] Delta UDP listener stopped on port {Port}", port);
_logger.LogInformation("Matchmaker delta UDP listener stopped on port {Port}", port);
}
}
@@ -160,11 +160,11 @@ namespace Empostor.Server.Net
try
{
await listener.DisposeAsync();
_logger.LogDebug("[Matchmaker] Stopped delta listener on port {Port}", port);
_logger.LogDebug("Matchmaker stopped delta listener on port {Port}", port);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Matchmaker] Error stopping delta listener on port {Port}", port);
_logger.LogWarning(ex, "Matchmaker error stopping delta listener on port {Port}", port);
}
}
+3 -7
View File
@@ -38,7 +38,7 @@ namespace Empostor.Server.Net
await _matchmaker.StartAsync(endpoint);
_logger.LogInformation(
"Matchmaker is listening on {0}:{1}, the public server ip is {2}:{3}.",
"Matchmaker is listening on {Address}:{Port}, the public server ip is {PublicIp}:{PublicPort}.",
endpoint.Address,
endpoint.Port,
_serverConfig.ResolvePublicIp(),
@@ -47,16 +47,12 @@ namespace Empostor.Server.Net
if (_portPool.IsEnabled)
{
_logger.LogInformation(
"Delta port pool enabled: range {Start}-{End}, firewall UFW={Ufw} Firewalld={Fwd}",
_serverConfig.DeltaPortStart,
_serverConfig.DeltaPortEnd,
_serverConfig.UseUfw,
_serverConfig.UseFirewalld);
"Delta Matchmaker is enabled.");
}
else
{
_logger.LogInformation(
"Delta port pool disabled (DeltaPortStart={Start}, DeltaPortEnd={End}). Using IP-based matching.",
"Delta Matchmaker is disabled (DeltaPortStart={Start}, DeltaPortEnd={End}). Using IP-based matching.",
_serverConfig.DeltaPortStart,
_serverConfig.DeltaPortEnd);
}
+8 -8
View File
@@ -60,17 +60,17 @@ public sealed class PortPoolService : IDisposable
if (skipped > 0)
{
_logger.LogWarning(
"[PortPool] Skipped {Count} port(s) overlapping with main listen port {ListenPort}",
"PortPool skipped {Count} port(s) overlapping with main listen port {ListenPort}",
skipped, _listenPort);
}
_logger.LogInformation(
"[PortPool] Initialized with {Count} ports ({Start}-{End})",
"PortPool initialized with {Count} ports ({Start}-{End})",
_availablePorts.Count, _deltaPortStart, _deltaPortEnd);
}
else
{
_logger.LogInformation("[PortPool] Disabled (DeltaPortStart={Start}, DeltaPortEnd={End})",
_logger.LogInformation("PortPool disabled (DeltaPortStart={Start}, DeltaPortEnd={End})",
_deltaPortStart, _deltaPortEnd);
}
}
@@ -87,7 +87,7 @@ public sealed class PortPoolService : IDisposable
if (!_availablePorts.TryTake(out var port))
{
_logger.LogWarning("[PortPool] Pool exhausted for PUID={Puid}", puid);
_logger.LogWarning("PortPool exhausted for PUID={Puid}", puid);
return 0;
}
@@ -105,7 +105,7 @@ public sealed class PortPoolService : IDisposable
_timeouts[port] = cts;
_ = TimeoutAsync(port, cts.Token);
_logger.LogDebug("[PortPool] Allocated port {Port} to PUID={Puid}", port, puid);
_logger.LogDebug("PortPool allocated port {Port} to PUID={Puid}", port, puid);
return port;
}
@@ -125,7 +125,7 @@ public sealed class PortPoolService : IDisposable
_activeLeases.TryRemove(port, out _);
_availablePorts.Add(port);
_logger.LogInformation("[PortPool] Returned port {Port} to pool", port);
_logger.LogInformation("PortPool returned port {Port} to pool", port);
OnPortReturned?.Invoke(port);
}
@@ -145,7 +145,7 @@ public sealed class PortPoolService : IDisposable
{
cts.Cancel();
cts.Dispose();
_logger.LogDebug("[PortPool] Port {Port} confirmed (timeout cancelled)", port);
_logger.LogDebug("PortPool port {Port} confirmed (timeout cancelled)", port);
}
}
@@ -161,7 +161,7 @@ public sealed class PortPoolService : IDisposable
await Task.Delay(TimeSpan.FromMinutes(5), ct);
// Timer fired — no connection came in
_logger.LogWarning("[PortPool] Port {Port} lease expired (no connection), returning to pool", port);
_logger.LogWarning("PortPool port {Port} lease expired (no connection), returning to pool", port);
ReturnPort(port);
}
catch (OperationCanceledException)
@@ -75,13 +75,13 @@ namespace Empostor.Server.Net.State
{
if (Character == null)
{
_logger.LogInformation("{0} - Player {1} spawn timed out, kicking.", Game.Code, Client.Id);
_logger.LogInformation("{Code} - Player {Id} spawn timed out, kicking.", Game.Code, Client.Id);
await KickAsync();
}
}
catch (Exception e)
{
_logger.LogError(e, "Exception caught while kicking player for spawn timeout.");
_logger.LogError(e, "{Code} - Exception while kicking player {Id} for spawn timeout", Game.Code, Client.Id);
}
finally
{
+5 -5
View File
@@ -87,7 +87,7 @@ namespace Empostor.Server.Net.State
var targetId = parent.ReadPackedInt32();
if (!TryGetPlayer(targetId, out target))
{
_logger.LogWarning("Player {0} tried to send GameData to unknown player {1}.", sender.Client.Id, targetId);
_logger.LogWarning("{Code} - Player {Id} sent GameData to unknown player {Target}", Code, sender.Client.Id, targetId);
return false;
}
@@ -110,7 +110,7 @@ namespace Empostor.Server.Net.State
}
else
{
_logger.LogWarning("Received DataFlag for unregistered NetId {0}.", netId);
_logger.LogWarning("{Code} - Received DataFlag for unregistered NetId {NetId}", Code, netId);
}
break;
@@ -129,7 +129,7 @@ namespace Empostor.Server.Net.State
}
else
{
_logger.LogWarning("Received RpcFlag for unregistered NetId {0}.", netId);
_logger.LogWarning("{Code} - Received RpcFlag for unregistered NetId {NetId}", Code, netId);
}
break;
@@ -315,7 +315,7 @@ namespace Empostor.Server.Net.State
default:
{
_logger.LogWarning("Bad GameData tag {0}", reader.Tag);
_logger.LogWarning("{Code} - Bad GameData tag {Tag}", Code, reader.Tag);
break;
}
}
@@ -513,7 +513,7 @@ namespace Empostor.Server.Net.State
if (!AddNetObject(playerInfo))
{
_logger.LogError("Couldn't spawn PlayerInfo for {Name} ({ClientId})", sender.Client.Name, sender.Client.Id);
_logger.LogError("{Code} - Could not spawn PlayerInfo for {Name} ({ClientId})", Code, sender.Client.Name, sender.Client.Id);
playerInfo.NetId = uint.MaxValue;
return;
}
+20 -5
View File
@@ -57,7 +57,7 @@ namespace Empostor.Server.Net.State
public async ValueTask HandleRemovePlayer(int playerId, DisconnectReason reason)
{
await PlayerRemove(playerId);
await PlayerRemove(playerId, reason: reason.ToString());
if (GameState == GameStates.Destroyed)
{
return;
@@ -70,14 +70,14 @@ namespace Empostor.Server.Net.State
public async ValueTask HandleKickPlayer(int playerId, bool isBan)
{
_logger.LogInformation("{0} - Player {1} has left.", Code, playerId);
_logger.LogInformation("{Code} - Kicking player {PlayerId} (Ban={IsBan})", Code, playerId, isBan);
using (var kickMsg = MessageWriter.Get(MessageType.Reliable))
{
WriteKickPlayerMessage(kickMsg, false, playerId, isBan);
await SendToAllAsync(kickMsg);
}
await PlayerRemove(playerId, isBan);
await PlayerRemove(playerId, reason: isBan ? "Ban" : "Kicked", isBan: isBan);
if (GameState == GameStates.Destroyed)
{
return;
@@ -118,7 +118,18 @@ namespace Empostor.Server.Net.State
private async ValueTask HandleJoinGameNew(ClientPlayer sender, bool isNew)
{
_logger.LogInformation("{0} - Player {1} ({2}) is joining.", Code, sender.Client.Name, sender.Client.Id);
var client = sender.Client;
var clientIp = client.Connection.EndPoint?.Address;
var ipStr = clientIp?.IsIPv4MappedToIPv6 == true ? clientIp.MapToIPv4().ToString() : clientIp?.ToString() ?? "?";
var remotePort = (client.Connection.EndPoint as System.Net.IPEndPoint)?.Port ?? 0;
var authority = client.GameVersion.HasDisableServerAuthorityFlag ? "true" : "false";
var version = client.GameVersion.ToString();
var hashPuid = client.ProductUserId?.Length >= 9 ? client.ProductUserId[..9] : client.ProductUserId ?? "0";
var deltaPort = client.DeltaPort;
_logger.LogInformation("{Code} - Player {Name} ({HashPuid}) ({Id}) is joining from ({Ip}:{RemotePort}) with v{Version}, Authority:{Authority}, port: {DeltaPort}",
Code, sender.Client.Name, hashPuid, sender.Client.Id, ipStr, remotePort, version, authority, deltaPort);
if (isNew)
{
await PlayerAdd(sender);
@@ -206,7 +217,10 @@ namespace Empostor.Server.Net.State
private async ValueTask HandleJoinGameNext(ClientPlayer sender, bool isNew)
{
_logger.LogInformation("{0} - Player {1} ({2}) is rejoining.", Code, sender.Client.Name, sender.Client.Id);
var authority = sender.Client.GameVersion.HasDisableServerAuthorityFlag ? "true" : "false";
_logger.LogInformation("{Code} - Player {Name} ({Id}) is rejoining. Player Authority : {Authority}, port: {DeltaPort}",
Code, sender.Client.Name, sender.Client.Id, authority, sender.Client.DeltaPort);
if (isNew)
{
await PlayerAdd(sender);
@@ -214,6 +228,7 @@ namespace Empostor.Server.Net.State
if (sender.Client.Id == HostId)
{
_logger.LogInformation("{Code} - Host {Name} ({Id}) is rejoining.", Code, sender.Client.Name, sender.Client.Id);
GameState = GameStates.NotStarted;
await HandleJoinGameNew(sender, false);
await CheckLimboPlayers();
+6 -4
View File
@@ -26,14 +26,16 @@ namespace Empostor.Server.Net.State
await _eventManager.CallAsync(new GamePlayerJoinedEvent(this, player));
}
private async ValueTask<bool> PlayerRemove(int playerId, bool isBan = false)
private async ValueTask<bool> PlayerRemove(int playerId, string reason = "", bool isBan = false)
{
if (!_players.TryRemove(playerId, out var player))
{
return false;
}
_logger.LogInformation("{0} - Player {1} ({2}) has left.", Code, player.Client.Name, playerId);
_logger.LogInformation("{Code} - Player {Name} ({Id}) has left for \"{Reason}\" hashpuid : {HashPuid}",
Code, player.Client.Name, playerId, reason,
player.Client.ProductUserId?.Length >= 9 ? player.Client.ProductUserId[..9] : player.Client.ProductUserId ?? "0");
if (GameState == GameStates.Starting || GameState == GameStates.Started || GameState == GameStates.NotStarted)
{
if (player.Character?.PlayerInfo != null)
@@ -69,7 +71,7 @@ namespace Empostor.Server.Net.State
await Task.Delay(_timeoutConfig.ConnectionTimeout);
if (player.Client.Connection.IsConnected && player.Client.Connection is HazelConnection hazel)
{
_logger.LogInformation("{0} - Player {1} ({2}) kept connection open after leaving, disposing.", Code, player.Client.Name, playerId);
_logger.LogInformation("{Code} - Player {Name} ({Id}) kept connection open after leaving, disposing.", Code, player.Client.Name, playerId);
await player.Client.DisconnectAsync(isBan ? DisconnectReason.Banned : DisconnectReason.Kicked);
}
});
@@ -101,7 +103,7 @@ namespace Empostor.Server.Net.State
}
HostId = host.Client.Id;
_logger.LogInformation("{0} - Assigned {1} ({2}) as new host.", Code, host.Client.Name, host.Client.Id);
_logger.LogInformation("{Code} - Assigned {Name} ({Id}) as new host.", Code, host.Client.Name, host.Client.Id);
if (GameState == GameStates.Ended && host.Limbo == LimboStates.WaitingForHost)
{
GameState = GameStates.NotStarted;
+5 -3
View File
@@ -53,10 +53,12 @@ namespace Empostor.Server
{
private static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateBootstrapLogger();
Log.Logger = new LoggerConfiguration()
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateBootstrapLogger();
try
{
Log.Information("Starting Empostor v{0}", DotnetUtils.Version);
Log.Information("Empostor v{Version} starting", DotnetUtils.Version);
CreateHostBuilder(args).Build().Run();
return 0;
}
@@ -246,7 +248,7 @@ namespace Empostor.Server
#endif
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File(
"Log/empostor-.log",
rollingInterval: RollingInterval.Day,
@@ -25,7 +25,7 @@ public sealed class BanEnforcementListener : IEventListener
// IP 封禁检查
if (ip != null && _bans.IsIpBanned(ip))
{
_logger.LogWarning("[Ban] Rejecting banned IP {Ip} ({Name})", ip, client.Name);
_logger.LogWarning("BanRejecting banned IP {Ip} ({Name})", ip, client.Name);
await client.DisconnectAsync(DisconnectReason.Banned, "You are banned from this server.");
return;
}
@@ -33,7 +33,7 @@ public sealed class BanEnforcementListener : IEventListener
// FriendCode 封禁检查
if (_bans.IsFriendCodeBanned(client.FriendCode))
{
_logger.LogWarning("[Ban] Rejecting banned FriendCode {FC} ({Name})", client.FriendCode, client.Name);
_logger.LogWarning("BanRejecting banned FriendCode {FC} ({Name})", client.FriendCode, client.Name);
await client.DisconnectAsync(DisconnectReason.Banned, "You are banned from this server.");
}
}
@@ -96,7 +96,7 @@ namespace Empostor.Server.Service.Admin.Ban
var data = new BanData { Ips = new(_ips), FriendCodes = new(_friendCodes) };
await File.WriteAllTextAsync(BanFile, JsonSerializer.Serialize(data, JsonOpts));
}
catch (Exception ex) { _logger.LogWarning(ex, "[BanStore] Failed to save bans.json"); }
catch (Exception ex) { _logger.LogWarning(ex, "BanStoreFailed to save bans.json"); }
finally { _saveLock.Release(); }
});
}
@@ -115,10 +115,10 @@ namespace Empostor.Server.Service.Admin.Ban
{
_ips = new(data.Ips ?? new());
_friendCodes = new(data.FriendCodes ?? new());
_logger.LogInformation("[BanStore] Loaded {I} IP bans + {F} FC bans", _ips.Count, _friendCodes.Count);
_logger.LogInformation("BanStoreLoaded {I} IP bans + {F} FC bans", _ips.Count, _friendCodes.Count);
}
}
catch (Exception ex) { _logger.LogWarning(ex, "[BanStore] Failed to load bans.json"); }
catch (Exception ex) { _logger.LogWarning(ex, "BanStoreFailed to load bans.json"); }
}
private static string Normalize(IPAddress ip)
@@ -41,7 +41,7 @@ namespace Empostor.Server.Service.Admin.Reactor
{
if (reader.Position < reader.Length)
{
_logger.LogTrace("[ReactorMods] No Reactor header found for {Name}", e.Connection.Client?.Name ?? "unknown");
_logger.LogTrace("ReactorModsNo Reactor header found for {Name}", e.Connection.Client?.Name ?? "unknown");
}
return;
@@ -60,7 +60,7 @@ namespace Empostor.Server.Service.Admin.Reactor
if (mods.Length > 0)
{
_logger.LogInformation(
"[ReactorMods] {Name} has {Count} mod(s) (protocol v{Proto}): {Mods}",
"ReactorMods{Name} has {Count} mod(s) (protocol v{Proto}): {Mods}",
e.Connection.Client?.Name ?? "unknown",
mods.Length,
protocolVersion,
@@ -72,7 +72,7 @@ namespace Empostor.Server.Service.Admin.Report
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Report] Failed to save reports");
_logger.LogWarning(ex, "ReportFailed to save reports");
}
finally
{
@@ -98,12 +98,12 @@ namespace Empostor.Server.Service.Admin.Report
_reports.AddRange(list.Take(Max));
}
_logger.LogInformation("[Report] Loaded {Count} report(s)", _reports.Count);
_logger.LogInformation("ReportLoaded {Count} report(s)", _reports.Count);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Report] Failed to load reports file");
_logger.LogWarning(ex, "ReportFailed to load reports file");
}
}
@@ -158,12 +158,12 @@ internal sealed class DiscordWebhookListener : IEventListener
var resp = await client.PostAsync(url, new StringContent(json, Encoding.UTF8, "application/json"));
if (!resp.IsSuccessStatusCode)
{
_logger.LogWarning("[Discord] Webhook returned {Status}", (int)resp.StatusCode);
_logger.LogWarning("DiscordWebhook returned {Status}", (int)resp.StatusCode);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Discord] Failed to send webhook");
_logger.LogWarning(ex, "DiscordFailed to send webhook");
}
}
}
@@ -36,13 +36,13 @@ public sealed class DiscordWebhookStore
NotifyOnReport = saved.NotifyOnReport;
NotifyOnPlayerJoin = saved.NotifyOnPlayerJoin;
NotifyOnGameEnded = saved.NotifyOnGameEnded;
_logger.LogInformation("[DiscordWebhook] Loaded from {File}", ConfigFile);
_logger.LogInformation("DiscordWebhookLoaded from {File}", ConfigFile);
return;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[DiscordWebhook] Failed to load {File}, using defaults", ConfigFile);
_logger.LogWarning(ex, "DiscordWebhookFailed to load {File}, using defaults", ConfigFile);
}
}
@@ -93,11 +93,11 @@ public sealed class DiscordWebhookStore
{
var json = JsonSerializer.Serialize(Snapshot, JsonOpts);
await File.WriteAllTextAsync(ConfigFile, json);
_logger.LogInformation("[DiscordWebhook] Saved to {File}", ConfigFile);
_logger.LogInformation("DiscordWebhookSaved to {File}", ConfigFile);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[DiscordWebhook] Failed to save {File}", ConfigFile);
_logger.LogWarning(ex, "DiscordWebhookFailed to save {File}", ConfigFile);
}
finally
{
@@ -63,7 +63,7 @@ public sealed class AuthCacheService : IDisposable
}
}
_logger.LogDebug("[Auth] Stored PUID={Puid} FC={FC}", productUserId, friendCode ?? "(none)");
_logger.LogDebug("AuthCache stored PUID={Puid} FC={FC}", productUserId, friendCode ?? "(none)");
}
public UserAuthInfo? FindByToken(string? matchmakerToken)
@@ -185,6 +185,10 @@ public sealed class AuthCacheService : IDisposable
_ipToPort.TryRemove(info.ClientIp, out _);
}
_logger.LogInformation(
"TokenUser {Name} {FriendCode} removed for inactivity timer. Port: {Port}",
info.Name, info.FriendCode, port);
OnPortExpired?.Invoke(port);
}
}
@@ -193,15 +197,22 @@ public sealed class AuthCacheService : IDisposable
var expiredIps = _byIpDirect.Where(kv => Expired(kv.Value)).Select(kv => kv.Key).ToList();
foreach (var ip in expiredIps)
{
_byIpDirect.TryRemove(ip, out _);
_ipToPort.TryRemove(ip, out _);
if (_byIpDirect.TryRemove(ip, out var info))
{
var port = _ipToPort.TryGetValue(ip, out var p) ? p : 0;
_ipToPort.TryRemove(ip, out _);
_logger.LogInformation(
"TokenUser {Name} {FriendCode} removed for inactivity timer. Port: {Port}",
info.Name, info.FriendCode, port);
}
}
var totalExpired = expired.Count + expiredPorts.Count + expiredIps.Count;
if (totalExpired > 0)
{
_logger.LogDebug("[Auth] Cleaned {Count} expired entries (token={T}, port={P}, ip={I})",
totalExpired, expired.Count, expiredPorts.Count, expiredIps.Count);
_logger.LogDebug("AuthCache cleaned {Count} expired entries",
totalExpired);
}
}
@@ -222,6 +233,8 @@ public sealed class UserAuthInfo
public string FriendCode { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string? ClientIp { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
@@ -54,17 +54,17 @@ public sealed class FirewalldFirewallService : IFirewallService
if (process.ExitCode != 0)
{
var stderr = await process.StandardError.ReadToEndAsync(ct);
_logger.LogWarning("[Firewall] firewall-cmd {Args} failed (exit={Code}): {Error}",
_logger.LogWarning("Firewallfirewall-cmd {Args} failed (exit={Code}): {Error}",
arguments, process.ExitCode, stderr.Trim());
}
else
{
_logger.LogInformation("[Firewall] firewall-cmd {Args} succeeded", arguments);
_logger.LogInformation("Firewallfirewall-cmd {Args} succeeded", arguments);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Firewall] Failed to run firewall-cmd {Args}", arguments);
_logger.LogWarning(ex, "FirewallFailed to run firewall-cmd {Args}", arguments);
}
}
}
@@ -18,13 +18,13 @@ public sealed class NoopFirewallService : IFirewallService
public ValueTask OpenPortAsync(ushort port, CancellationToken ct = default)
{
_logger.LogDebug("[Firewall] Noop: would open port {Port}/udp", port);
_logger.LogDebug("FirewallNoop: would open port {Port}/udp", port);
return ValueTask.CompletedTask;
}
public ValueTask ClosePortAsync(ushort port, CancellationToken ct = default)
{
_logger.LogDebug("[Firewall] Noop: would close port {Port}/udp", port);
_logger.LogDebug("FirewallNoop: would close port {Port}/udp", port);
return ValueTask.CompletedTask;
}
}
@@ -52,17 +52,17 @@ public sealed class UfwFirewallService : IFirewallService
if (process.ExitCode != 0)
{
var stderr = await process.StandardError.ReadToEndAsync(ct);
_logger.LogWarning("[Firewall] ufw {Args} failed (exit={Code}): {Error}",
_logger.LogWarning("Firewallufw {Args} failed (exit={Code}): {Error}",
arguments, process.ExitCode, stderr.Trim());
}
else
{
_logger.LogInformation("[Firewall] ufw {Args} succeeded", arguments);
_logger.LogInformation("Firewallufw {Args} succeeded", arguments);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[Firewall] Failed to run ufw {Args}", arguments);
_logger.LogWarning(ex, "FirewallFailed to run ufw {Args}", arguments);
}
}
}
@@ -109,7 +109,7 @@ public sealed class PlayerLogStore : IDisposable
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[PlayerLog] Failed to save logs");
_logger.LogWarning(ex, "PlayerLogFailed to save logs");
}
finally
{
@@ -142,12 +142,12 @@ public sealed class PlayerLogStore : IDisposable
Interlocked.Decrement(ref _count);
}
_logger.LogInformation("[PlayerLog] Loaded {Count} log(s)", _count);
_logger.LogInformation("PlayerLogLoaded {Count} log(s)", _count);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[PlayerLog] Failed to load logs file");
_logger.LogWarning(ex, "PlayerLogFailed to load logs file");
}
}
@@ -152,7 +152,7 @@ public sealed class PlayerStatsStore : IDisposable
var list = _stats.Values.ToList();
await File.WriteAllTextAsync(StatsFile, JsonSerializer.Serialize(list, JsonOpts));
}
catch (Exception ex) { _logger.LogWarning(ex, "[PlayerStats] Failed to save stats"); }
catch (Exception ex) { _logger.LogWarning(ex, "PlayerStatsFailed to save stats"); }
finally { _saveLock.Release(); }
});
}
@@ -161,7 +161,7 @@ public sealed class PlayerStatsStore : IDisposable
{
if (!File.Exists(StatsFile))
{
_logger.LogDebug("[PlayerStats] No stats file found, starting fresh");
_logger.LogDebug("PlayerStatsNo stats file found, starting fresh");
return;
}
@@ -172,10 +172,10 @@ public sealed class PlayerStatsStore : IDisposable
{
_stats = new ConcurrentDictionary<string, PlayerStatsEntry>(
list.ToDictionary(e => e.FriendCode, StringComparer.OrdinalIgnoreCase));
_logger.LogInformation("[PlayerStats] Loaded {Count} player stats", _stats.Count);
_logger.LogInformation("PlayerStatsLoaded {Count} player stats", _stats.Count);
}
}
catch (Exception ex) { _logger.LogWarning(ex, "[PlayerStats] Failed to load stats file"); }
catch (Exception ex) { _logger.LogWarning(ex, "PlayerStatsFailed to load stats file"); }
}
private static string Normalize(string friendCode)
@@ -37,16 +37,16 @@ public class ConsoleLogger : ILogger
public void WriteVerbose(string msg)
{
if (verbose) Console.WriteLine($"{DateTime.Now} [VERBOSE] {msg}");
if (verbose) Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [VRB] {msg}");
}
public void WriteError(string msg)
{
Console.WriteLine($"{DateTime.Now} [ERROR] {msg}");
Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [ERR] {msg}");
}
public void WriteInfo(string msg)
{
Console.WriteLine($"{DateTime.Now} [INFO] {msg}");
Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [INF] {msg}");
}
}