-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'refs/remotes/wizards/master'
# Conflicts: # Content.Server/Administration/Systems/AdminSystem.cs # Content.Server/GameTicking/GameTicker.Spawning.cs # Content.Server/IoC/ServerContentIoC.cs # Resources/Locale/en-US/_strings/administration/multi-server-kick.ftl # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml
- Loading branch information
Showing
45 changed files
with
517 additions
and
156 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
Content.Server/Administration/Managers/MultiServerKickManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
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; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Text.Json; | ||
using Robust.Shared.Asynchronous; | ||
|
||
namespace Content.Server.Database; | ||
|
||
public static class ServerDbManagerExt | ||
{ | ||
/// <summary> | ||
/// Subscribe to a database notification on a specific channel, formatted as JSON. | ||
/// </summary> | ||
/// <param name="dbManager">The database manager to subscribe on.</param> | ||
/// <param name="taskManager">The task manager used to run the main callback on the main thread.</param> | ||
/// <param name="sawmill">Sawmill to log any errors to.</param> | ||
/// <param name="channel"> | ||
/// The notification channel to listen on. Only notifications on this channel will be handled. | ||
/// </param> | ||
/// <param name="action"> | ||
/// The action to run on the notification data. | ||
/// This runs on the main thread. | ||
/// </param> | ||
/// <param name="earlyFilter"> | ||
/// An early filter callback that runs before the JSON message is deserialized. | ||
/// Return false to not handle the notification. | ||
/// This does not run on the main thread. | ||
/// </param> | ||
/// <param name="filter"> | ||
/// A filter callback that runs after the JSON message is deserialized. | ||
/// Return false to not handle the notification. | ||
/// This does not run on the main thread. | ||
/// </param> | ||
/// <typeparam name="TData">The type of JSON data to deserialize.</typeparam> | ||
public static void SubscribeToJsonNotification<TData>( | ||
this IServerDbManager dbManager, | ||
ITaskManager taskManager, | ||
ISawmill sawmill, | ||
string channel, | ||
Action<TData> action, | ||
Func<bool>? earlyFilter = null, | ||
Func<TData, bool>? filter = null) | ||
{ | ||
dbManager.SubscribeToNotifications(notification => | ||
{ | ||
if (notification.Channel != channel) | ||
return; | ||
|
||
if (notification.Payload == null) | ||
{ | ||
sawmill.Error($"Got {channel} notification with null payload!"); | ||
return; | ||
} | ||
|
||
if (earlyFilter != null && !earlyFilter()) | ||
return; | ||
|
||
TData data; | ||
try | ||
{ | ||
data = JsonSerializer.Deserialize<TData>(notification.Payload) | ||
?? throw new JsonException("Content is null"); | ||
} | ||
catch (JsonException e) | ||
{ | ||
sawmill.Error($"Got invalid JSON in {channel} notification: {e}"); | ||
return; | ||
} | ||
|
||
if (filter != null && !filter(data)) | ||
return; | ||
|
||
taskManager.RunOnMainThread(() => | ||
{ | ||
action(data); | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.