mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-01-07 13:58:25 -05:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
179 lines
4.7 KiB
C#
179 lines
4.7 KiB
C#
using Sandbox.Engine;
|
|
using Sandbox.Internal;
|
|
|
|
namespace Sandbox.Network;
|
|
|
|
internal partial class NetworkSystem
|
|
{
|
|
[SkipHotload]
|
|
private readonly HashSet<Connection> _connections = [];
|
|
|
|
[SkipHotload]
|
|
private readonly Dictionary<Guid, Connection> _connectionLookup = new();
|
|
|
|
public IEnumerable<Connection> Connections => _connections;
|
|
|
|
/// <summary>
|
|
/// If true then this host is sending assemblies and other files via network tables
|
|
/// and as such, does not need to load assemblies from the package (if it even exists).
|
|
/// </summary>
|
|
public bool IsDeveloperHost { get; set; }
|
|
|
|
/// <summary>
|
|
/// Get whether there are any connections still doing the handshake process.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
internal bool IsHandshaking()
|
|
{
|
|
return _connections.Count != 0 && _connections.Any( c => c.State != Connection.ChannelState.Connected );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find a connection by its unique id.
|
|
/// </summary>
|
|
/// <param name="id"></param>
|
|
/// <returns></returns>
|
|
internal Connection FindConnection( Guid id )
|
|
{
|
|
if ( Connection is not null && Connection.Id == id )
|
|
return Connection;
|
|
|
|
if ( _connectionLookup.TryGetValue( id, out var cached ) )
|
|
return cached;
|
|
|
|
foreach ( var c in _connections )
|
|
{
|
|
if ( c.Id == id )
|
|
{
|
|
_connectionLookup[id] = c;
|
|
return c;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal void OnConnected( Connection channel )
|
|
{
|
|
Log.Trace( $"{this}: On Connected {channel}" );
|
|
|
|
_connections.Add( channel );
|
|
|
|
channel.InitializeSystem( this );
|
|
|
|
if ( IsHost )
|
|
{
|
|
// If we're the host and have a new connection then start handshaking
|
|
channel.GenerateConnectionId();
|
|
StartHandshake( channel );
|
|
}
|
|
|
|
if ( channel.Id != Guid.Empty )
|
|
{
|
|
_connectionLookup[channel.Id] = channel;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start the handshaking process with the specified client <see cref="Connection"/>.
|
|
/// </summary>
|
|
/// <param name="channel"></param>
|
|
void StartHandshake( Connection channel )
|
|
{
|
|
channel.HandshakeId = Guid.NewGuid();
|
|
|
|
var hello = new ServerInfo
|
|
{
|
|
ServerName = Networking.ServerName,
|
|
ServerData = Networking.ServerData,
|
|
MaxPlayers = Networking.MaxPlayers,
|
|
MapName = Networking.MapName,
|
|
EngineVersion = 234,
|
|
GamePackage = Application.GamePackage?.GetIdent( false, true ) ?? "",
|
|
MapPackage = Application.MapPackage?.GetIdent( false, true ) ?? "",
|
|
Host = new ChannelInfo { Id = Connection.Local.Id },
|
|
Assigned = new ChannelInfo { Id = channel.Id },
|
|
IsDeveloperHost = IsDeveloperHost,
|
|
HandshakeId = channel.HandshakeId
|
|
};
|
|
|
|
channel.SendMessage( hello );
|
|
channel.State = Connection.ChannelState.LoadingServerInformation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restart the handshaking process. This could be used if the host changed
|
|
/// while we're connecting.
|
|
/// </summary>
|
|
internal void RestartHandshake()
|
|
{
|
|
var host = _connections.FirstOrDefault( c => c.IsHost );
|
|
if ( host is null )
|
|
return;
|
|
|
|
Connection.Local.State = Connection.ChannelState.Unconnected;
|
|
host.SendMessage( new RestartHandshakeMsg() );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called from the host to add a connection to the ConnectionInfo table
|
|
/// </summary>
|
|
internal void AddConnection( Connection source, UserInfo data )
|
|
{
|
|
var info = ConnectionInfo.Add( source );
|
|
info.Update( data );
|
|
OnConnectionInfoUpdated();
|
|
}
|
|
|
|
internal void OnDisconnected( Connection source )
|
|
{
|
|
if ( source.State >= Connection.ChannelState.Welcome )
|
|
{
|
|
// We only need to call this if we called OnConnected, which would only
|
|
// be the case if they got to at least the Welcome state during the handshake.
|
|
GameSystem?.OnLeave( source );
|
|
}
|
|
|
|
_connectionLookup.Remove( source.Id );
|
|
_connections.Remove( source );
|
|
|
|
source.State = Connection.ChannelState.Unconnected;
|
|
|
|
if ( !IsHost )
|
|
return;
|
|
|
|
Log.Info( $"{source.DisplayName} [{source.SteamId}] disconnected" );
|
|
|
|
ConnectionInfo.Remove( source.Id );
|
|
OnConnectionInfoUpdated();
|
|
}
|
|
|
|
/// <summary>
|
|
/// We were disconnected from the server. This will almost always be when we're on a dedicated server
|
|
/// and it has closed down.
|
|
/// </summary>
|
|
internal void OnServerDisconnection( int reasonCode, string reasonString )
|
|
{
|
|
if ( Connection.Local.State == Connection.ChannelState.Unconnected )
|
|
return;
|
|
|
|
IGameInstanceDll.Current.Disconnect();
|
|
IMenuSystem.ShowServerError( "Disconnected", reasonString );
|
|
Log.Warning( $"Disconnecting - {reasonString}" );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called any time we suspect the connection info might have changed, which
|
|
/// lets us tell the sockets/connections to update any information they hold.
|
|
/// </summary>
|
|
internal void OnConnectionInfoUpdated()
|
|
{
|
|
foreach ( var socket in sockets )
|
|
{
|
|
socket.OnConnectionInfoUpdated( this );
|
|
}
|
|
|
|
_connectionLookup.Clear();
|
|
}
|
|
}
|