mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-06 17:58:05 +02:00
* Some stuff for auth * Holy crap auth works * Enable encryption even if no auth token is provided. It's still possible that the public key was retrieved over HTTPS via the status API, in which case it will be secure. * Fix integration test compile. * Secure CVar API. * Literally rewrite the auth protocol to be minecraft's. * Better exception tolerance in server handshake. * Auth works from launcher. * Fix some usages of UserID instead of UserName * Fix auth.server CVar * Kick existing connection if same account connects twice. * Username assignment, guest session distinguishing. * Necessary work to make bans work. * Expose LoginType to OnConnecting. * Fixing tests and warnings.
203 lines
7.1 KiB
C#
203 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Robust.Server.Interfaces.GameObjects;
|
|
using Robust.Server.Interfaces.Player;
|
|
using Robust.Server.Player;
|
|
using Robust.Shared.Enums;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Interfaces.Configuration;
|
|
using Robust.Shared.Interfaces.GameObjects;
|
|
using Robust.Shared.Interfaces.Network;
|
|
using Robust.Shared.Interfaces.Timing;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Network.Messages;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Robust.Server.GameObjects
|
|
{
|
|
/// <summary>
|
|
/// The server implementation of the Entity Network Manager.
|
|
/// </summary>
|
|
public class ServerEntityNetworkManager : IServerEntityNetworkManager, IPostInjectInit
|
|
{
|
|
[Dependency] private readonly IServerNetManager _networkManager = default!;
|
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<NetworkComponentMessage>? ReceivedComponentMessage;
|
|
|
|
/// <inheritdoc />
|
|
public event EventHandler<object>? ReceivedSystemMessage;
|
|
|
|
private readonly PriorityQueue<MsgEntity> _queue = new PriorityQueue<MsgEntity>(new MessageSequenceComparer());
|
|
|
|
private readonly Dictionary<IPlayerSession, uint> _lastProcessedSequencesCmd =
|
|
new Dictionary<IPlayerSession, uint>();
|
|
|
|
private bool _logLateMsgs;
|
|
|
|
/// <inheritdoc />
|
|
public void SetupNetworking()
|
|
{
|
|
_networkManager.RegisterNetMessage<MsgEntity>(MsgEntity.NAME, HandleEntityNetworkMessage);
|
|
|
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
|
|
|
_logLateMsgs = _configurationManager.GetCVar<bool>("net.log_late_msg");
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
while (_queue.Count != 0 && _queue.Peek().SourceTick <= _gameTiming.CurTick)
|
|
{
|
|
DispatchEntityNetworkMessage(_queue.Take());
|
|
}
|
|
}
|
|
|
|
public uint GetLastMessageSequence(IPlayerSession session)
|
|
{
|
|
return _lastProcessedSequencesCmd[session];
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SendComponentNetworkMessage(INetChannel? channel, IEntity entity, IComponent component,
|
|
ComponentMessage message)
|
|
{
|
|
if (_networkManager.IsClient)
|
|
return;
|
|
|
|
if (!component.NetID.HasValue)
|
|
throw new ArgumentException($"Component {component.Name} does not have a NetID.", nameof(component));
|
|
|
|
var msg = _networkManager.CreateNetMessage<MsgEntity>();
|
|
msg.Type = EntityMessageType.ComponentMessage;
|
|
msg.EntityUid = entity.Uid;
|
|
msg.NetId = component.NetID.Value;
|
|
msg.ComponentMessage = message;
|
|
msg.SourceTick = _gameTiming.CurTick;
|
|
|
|
// Logger.DebugS("net.ent", "Sending: {0}", msg);
|
|
|
|
//Send the message
|
|
if (channel == null)
|
|
_networkManager.ServerSendToAll(msg);
|
|
else
|
|
_networkManager.ServerSendMessage(msg, channel);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SendSystemNetworkMessage(EntitySystemMessage message)
|
|
{
|
|
var newMsg = _networkManager.CreateNetMessage<MsgEntity>();
|
|
newMsg.Type = EntityMessageType.SystemMessage;
|
|
newMsg.SystemMessage = message;
|
|
newMsg.SourceTick = _gameTiming.CurTick;
|
|
|
|
_networkManager.ServerSendToAll(newMsg);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void SendSystemNetworkMessage(EntitySystemMessage message, INetChannel targetConnection)
|
|
{
|
|
var newMsg = _networkManager.CreateNetMessage<MsgEntity>();
|
|
newMsg.Type = EntityMessageType.SystemMessage;
|
|
newMsg.SystemMessage = message;
|
|
newMsg.SourceTick = _gameTiming.CurTick;
|
|
|
|
_networkManager.ServerSendMessage(newMsg, targetConnection);
|
|
}
|
|
|
|
private void HandleEntityNetworkMessage(MsgEntity message)
|
|
{
|
|
var msgT = message.SourceTick;
|
|
var cT = _gameTiming.CurTick;
|
|
|
|
if (msgT <= cT)
|
|
{
|
|
if (msgT < cT && _logLateMsgs)
|
|
{
|
|
Logger.WarningS("net.ent", "Got late MsgEntity! Diff: {0}, msgT: {2}, cT: {3}, player: {1}",
|
|
(int) msgT.Value - (int) cT.Value, message.MsgChannel.UserName, msgT, cT);
|
|
}
|
|
|
|
DispatchEntityNetworkMessage(message);
|
|
return;
|
|
}
|
|
|
|
_queue.Add(message);
|
|
}
|
|
|
|
private void DispatchEntityNetworkMessage(MsgEntity message)
|
|
{
|
|
// Don't try to retrieve the session if the client disconnected
|
|
if (!message.MsgChannel.IsConnected)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var player = _playerManager.GetSessionByChannel(message.MsgChannel);
|
|
|
|
if (message.Sequence != 0)
|
|
{
|
|
if (_lastProcessedSequencesCmd[player] < message.Sequence)
|
|
{
|
|
_lastProcessedSequencesCmd[player] = message.Sequence;
|
|
}
|
|
}
|
|
|
|
switch (message.Type)
|
|
{
|
|
case EntityMessageType.ComponentMessage:
|
|
ReceivedComponentMessage?.Invoke(this, new NetworkComponentMessage(message, player));
|
|
return;
|
|
|
|
case EntityMessageType.SystemMessage:
|
|
var msg = message.SystemMessage;
|
|
var sessionType = typeof(EntitySessionMessage<>).MakeGenericType(msg.GetType());
|
|
var sessionMsg = Activator.CreateInstance(sessionType, new EntitySessionEventArgs(player), msg)!;
|
|
ReceivedSystemMessage?.Invoke(this, sessionMsg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
|
{
|
|
switch (args.NewStatus)
|
|
{
|
|
case SessionStatus.Connected:
|
|
_lastProcessedSequencesCmd.Add(args.Session, 0);
|
|
break;
|
|
|
|
case SessionStatus.Disconnected:
|
|
_lastProcessedSequencesCmd.Remove(args.Session);
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal sealed class MessageSequenceComparer : IComparer<MsgEntity>
|
|
{
|
|
public int Compare(MsgEntity? x, MsgEntity? y)
|
|
{
|
|
DebugTools.AssertNotNull(x);
|
|
DebugTools.AssertNotNull(y);
|
|
|
|
var cmp = y!.SourceTick.CompareTo(x!.SourceTick);
|
|
if (cmp != 0)
|
|
{
|
|
return cmp;
|
|
}
|
|
|
|
return y.Sequence.CompareTo(x.Sequence);
|
|
}
|
|
}
|
|
|
|
void IPostInjectInit.PostInject()
|
|
{
|
|
_configurationManager.RegisterCVar("net.log_late_msg", true, onValueChanged: b => _logLateMsgs = b);
|
|
}
|
|
}
|
|
}
|