| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- using System.Text.Json;
- using System.Text.Json.Serialization;
- using Content.Server.Database;
- using Content.Shared.CCVar;
- using Robust.Server.Player;
- using Robust.Shared.Asynchronous;
- using Robust.Shared.Configuration;
- using Robust.Shared.Enums;
- using Robust.Shared.Network;
- using Robust.Shared.Player;
- namespace Content.Server.Administration.Managers;
- /// <summary>
- /// Handles kicking people that connect to multiple servers on the same DB at once.
- /// </summary>
- /// <seealso cref="CCVars.AdminAllowMultiServerPlay"/>
- public sealed class MultiServerKickManager
- {
- public const string NotificationChannel = "multi_server_kick";
- [Dependency] private readonly IPlayerManager _playerManager = null!;
- [Dependency] private readonly IServerDbManager _dbManager = null!;
- [Dependency] private readonly ILogManager _logManager = null!;
- [Dependency] private readonly IConfigurationManager _cfg = null!;
- [Dependency] private readonly IAdminManager _adminManager = null!;
- [Dependency] private readonly ITaskManager _taskManager = null!;
- [Dependency] private readonly IServerNetManager _netManager = null!;
- [Dependency] private readonly ILocalizationManager _loc = null!;
- [Dependency] private readonly ServerDbEntryManager _serverDbEntry = null!;
- private ISawmill _sawmill = null!;
- private bool _allowed;
- public void Initialize()
- {
- _sawmill = _logManager.GetSawmill("multi_server_kick");
- _playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
- _cfg.OnValueChanged(CCVars.AdminAllowMultiServerPlay, b => _allowed = b, true);
- _dbManager.SubscribeToJsonNotification<NotificationData>(
- _taskManager,
- _sawmill,
- NotificationChannel,
- OnNotification,
- OnNotificationEarlyFilter
- );
- }
- // ReSharper disable once AsyncVoidMethod
- private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
- {
- if (_allowed)
- return;
- if (e.NewStatus != SessionStatus.InGame)
- return;
- // Send notification to other servers so they can kick this player that just connected.
- try
- {
- await _dbManager.SendNotification(new DatabaseNotification
- {
- Channel = NotificationChannel,
- Payload = JsonSerializer.Serialize(new NotificationData
- {
- PlayerId = e.Session.UserId,
- ServerId = (await _serverDbEntry.ServerEntity).Id,
- }),
- });
- }
- catch (Exception ex)
- {
- _sawmill.Error($"Failed to send notification for multi server kick: {ex}");
- }
- }
- private bool OnNotificationEarlyFilter()
- {
- if (_allowed)
- {
- _sawmill.Verbose("Received notification for player join, but multi server play is allowed on this server. Ignoring");
- return false;
- }
- return true;
- }
- // ReSharper disable once AsyncVoidMethod
- private async void OnNotification(NotificationData notification)
- {
- if (!_playerManager.TryGetSessionById(new NetUserId(notification.PlayerId), out var player))
- return;
- if (notification.ServerId == (await _serverDbEntry.ServerEntity).Id)
- return;
- if (_adminManager.IsAdmin(player, includeDeAdmin: true))
- return;
- _sawmill.Info($"Kicking {player} for connecting to another server. Multi-server play is not allowed.");
- _netManager.DisconnectChannel(player.Channel, _loc.GetString("multi-server-kick-reason"));
- }
- private sealed class NotificationData
- {
- [JsonPropertyName("player_id")]
- public Guid PlayerId { get; set; }
- [JsonPropertyName("server_id")]
- public int ServerId { get; set; }
- }
- }
|