Facepunch.Steamworks/Facepunch.Steamworks/SteamNetworkingSockets.cs

261 lines
7.6 KiB
C#
Raw Normal View History

2019-05-02 16:58:44 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Steamworks.Data;
namespace Steamworks
{
public class SteamNetworkingSockets : SteamSharedClass<SteamNetworkingSockets>
2019-05-02 16:58:44 +01:00
{
internal static ISteamNetworkingSockets Internal => Interface as ISteamNetworkingSockets;
2020-02-22 20:23:19 +00:00
2020-09-01 10:30:42 +02:00
/// <summary>
/// Get the identity assigned to this interface.
/// E.g. on Steam, this is the user's SteamID, or for the gameserver interface, the SteamID assigned
/// to the gameserver. Returns false and sets the result to an invalid identity if we don't know
/// our identity yet. (E.g. GameServer has not logged in. On Steam, the user will know their SteamID
/// even if they are not signed into Steam.)
/// </summary>
public static NetIdentity Identity
{
get
{
NetIdentity identity = default;
Internal.GetIdentity( ref identity );
return identity;
}
}
2020-02-22 20:23:19 +00:00
internal override void InitializeInterface( bool server )
2019-05-02 16:58:44 +01:00
{
SetInterface( server, new ISteamNetworkingSockets( server ) );
InstallEvents( server );
2019-05-02 16:58:44 +01:00
}
2020-02-22 20:23:19 +00:00
#region SocketInterface
2019-05-07 17:41:36 +01:00
static readonly Dictionary<uint, SocketManager> SocketInterfaces = new Dictionary<uint, SocketManager>();
internal static SocketManager GetSocketManager( uint id )
{
if ( SocketInterfaces == null ) return null;
if ( id == 0 ) throw new System.ArgumentException( "Invalid Socket" );
if ( SocketInterfaces.TryGetValue( id, out var isocket ) )
return isocket;
return null;
}
internal static void SetSocketManager( uint id, SocketManager manager )
{
if ( id == 0 ) throw new System.ArgumentException( "Invalid Socket" );
SocketInterfaces[id] = manager;
}
2020-02-22 20:23:19 +00:00
#endregion
2020-02-22 20:23:19 +00:00
#region ConnectionInterface
static readonly Dictionary<uint, ConnectionManager> ConnectionInterfaces = new Dictionary<uint, ConnectionManager>();
internal static ConnectionManager GetConnectionManager( uint id )
{
if ( ConnectionInterfaces == null ) return null;
if ( id == 0 ) return null;
if ( ConnectionInterfaces.TryGetValue( id, out var iconnection ) )
return iconnection;
return null;
}
internal static void SetConnectionManager( uint id, ConnectionManager manager )
{
if ( id == 0 ) throw new System.ArgumentException( "Invalid Connection" );
ConnectionInterfaces[id] = manager;
}
2020-02-22 20:23:19 +00:00
#endregion
2019-05-02 16:58:44 +01:00
internal void InstallEvents( bool server )
2019-05-02 16:58:44 +01:00
{
2020-02-22 20:23:19 +00:00
Dispatch.Install<SteamNetConnectionStatusChangedCallback_t>( ConnectionStatusChanged, server );
2019-05-02 20:41:45 +01:00
}
2020-02-22 20:23:19 +00:00
private static void ConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t data )
2019-05-02 20:41:45 +01:00
{
//
// This is a message from/to a listen socket
//
if ( data.Nfo.listenSocket.Id > 0 )
2019-05-02 21:40:39 +01:00
{
var iface = GetSocketManager( data.Nfo.listenSocket.Id );
iface?.OnConnectionChanged( data.Conn, data.Nfo );
2019-05-02 21:40:39 +01:00
}
else
2019-05-02 21:40:39 +01:00
{
var iface = GetConnectionManager( data.Conn.Id );
iface?.OnConnectionChanged( data.Nfo );
2019-05-02 21:40:39 +01:00
}
OnConnectionStatusChanged?.Invoke( data.Conn, data.Nfo );
2019-05-02 17:45:10 +01:00
}
2019-05-02 16:58:44 +01:00
2019-05-06 13:34:41 +01:00
public static event Action<Connection, ConnectionInfo> OnConnectionStatusChanged;
2019-05-02 21:40:39 +01:00
2019-05-02 16:58:44 +01:00
/// <summary>
2019-05-02 17:45:10 +01:00
/// Creates a "server" socket that listens for clients to connect to by calling
/// Connect, over ordinary UDP (IPv4 or IPv6)
///
2021-10-21 03:40:56 -04:00
/// To use this derive a class from <see cref="SocketManager"/> and override as much as you want.
///
2019-05-02 16:58:44 +01:00
/// </summary>
public static T CreateNormalSocket<T>( NetAddress address ) where T : SocketManager, new()
2019-05-02 17:45:10 +01:00
{
var t = new T();
2020-02-24 14:11:27 +00:00
var options = Array.Empty<NetKeyValue>();
2020-02-22 20:23:19 +00:00
t.Socket = Internal.CreateListenSocketIP( ref address, options.Length, options );
t.Initialize();
SetSocketManager( t.Socket.Id, t );
return t;
}
/// <summary>
/// Creates a "server" socket that listens for clients to connect to by calling
/// Connect, over ordinary UDP (IPv4 or IPv6).
///
2021-10-21 03:40:56 -04:00
/// To use this you should pass a class that inherits <see cref="ISocketManager"/>. You can use
/// SocketManager to get connections and send messages, but the ISocketManager class
/// will received all the appropriate callbacks.
///
/// </summary>
public static SocketManager CreateNormalSocket( NetAddress address, ISocketManager intrface )
{
var options = Array.Empty<NetKeyValue>();
var socket = Internal.CreateListenSocketIP( ref address, options.Length, options );
var t = new SocketManager
{
Socket = socket,
Interface = intrface
};
t.Initialize();
SetSocketManager( t.Socket.Id, t );
return t;
2019-05-02 17:45:10 +01:00
}
2019-05-02 16:58:44 +01:00
/// <summary>
2021-10-21 03:40:56 -04:00
/// Connect to a socket created via <c>CreateListenSocketIP</c>.
2019-05-02 16:58:44 +01:00
/// </summary>
public static T ConnectNormal<T>( NetAddress address ) where T : ConnectionManager, new()
2019-05-02 16:58:44 +01:00
{
var t = new T();
2020-02-24 14:11:27 +00:00
var options = Array.Empty<NetKeyValue>();
2020-02-22 20:23:19 +00:00
t.Connection = Internal.ConnectByIPAddress( ref address, options.Length, options );
SetConnectionManager( t.Connection.Id, t );
return t;
}
/// <summary>
2021-10-21 03:40:56 -04:00
/// Connect to a socket created via <c>CreateListenSocketIP</c>.
/// </summary>
public static ConnectionManager ConnectNormal( NetAddress address, IConnectionManager iface )
{
var options = Array.Empty<NetKeyValue>();
var connection = Internal.ConnectByIPAddress( ref address, options.Length, options );
var t = new ConnectionManager
{
Connection = connection,
Interface = iface
};
SetConnectionManager( t.Connection.Id, t );
return t;
2019-05-02 16:58:44 +01:00
}
/// <summary>
2021-10-21 03:40:56 -04:00
/// Creates a server that will be relayed via Valve's network (hiding the IP and improving ping).
///
2021-10-21 03:40:56 -04:00
/// To use this derive a class from <see cref="SocketManager"/> and override as much as you want.
///
2019-05-02 16:58:44 +01:00
/// </summary>
public static T CreateRelaySocket<T>( int virtualport = 0 ) where T : SocketManager, new()
2019-05-02 16:58:44 +01:00
{
var t = new T();
2020-02-24 14:11:27 +00:00
var options = Array.Empty<NetKeyValue>();
2020-02-22 20:23:19 +00:00
t.Socket = Internal.CreateListenSocketP2P( virtualport, options.Length, options );
t.Initialize();
SetSocketManager( t.Socket.Id, t );
return t;
2019-05-02 16:58:44 +01:00
}
/// <summary>
2021-10-21 03:40:56 -04:00
/// Creates a server that will be relayed via Valve's network (hiding the IP and improving ping).
///
2021-10-21 03:40:56 -04:00
/// To use this you should pass a class that inherits <see cref="ISocketManager"/>. You can use
/// <see cref="SocketManager"/> to get connections and send messages, but the <see cref="ISocketManager"/> class
/// will received all the appropriate callbacks.
///
/// </summary>
public static SocketManager CreateRelaySocket( int virtualport, ISocketManager intrface )
{
var options = Array.Empty<NetKeyValue>();
var socket = Internal.CreateListenSocketP2P( virtualport, options.Length, options );
var t = new SocketManager
{
Socket = socket,
Interface = intrface
};
t.Initialize();
SetSocketManager( t.Socket.Id, t );
return t;
}
2019-05-02 16:58:44 +01:00
/// <summary>
2021-10-21 03:40:56 -04:00
/// Connect to a relay server.
2019-05-02 16:58:44 +01:00
/// </summary>
public static T ConnectRelay<T>( SteamId serverId, int virtualport = 0 ) where T : ConnectionManager, new()
2019-05-02 16:58:44 +01:00
{
var t = new T();
2019-05-06 13:34:41 +01:00
NetIdentity identity = serverId;
2020-02-24 14:11:27 +00:00
var options = Array.Empty<NetKeyValue>();
2020-02-22 20:23:19 +00:00
t.Connection = Internal.ConnectP2P( ref identity, virtualport, options.Length, options );
SetConnectionManager( t.Connection.Id, t );
return t;
2019-05-02 16:58:44 +01:00
}
/// <summary>
2021-10-21 03:40:56 -04:00
/// Connect to a relay server.
/// </summary>
public static ConnectionManager ConnectRelay( SteamId serverId, int virtualport, IConnectionManager iface )
{
NetIdentity identity = serverId;
var options = Array.Empty<NetKeyValue>();
var connection = Internal.ConnectP2P( ref identity, virtualport, options.Length, options );
var t = new ConnectionManager
{
Connection = connection,
Interface = iface
};
SetConnectionManager( t.Connection.Id, t );
return t;
}
2019-05-02 16:58:44 +01:00
}
2021-10-21 03:40:56 -04:00
}