Restructuring of the files
This commit is contained in:
125
Facepunch.Steamworks/Networking/Connection.cs
Normal file
125
Facepunch.Steamworks/Networking/Connection.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Used as a base to create your client connection. This creates a socket
|
||||
/// to a single connection.
|
||||
///
|
||||
/// You can override all the virtual functions to turn it into what you
|
||||
/// want it to do.
|
||||
/// </summary>
|
||||
public struct Connection
|
||||
{
|
||||
public uint Id { get; set; }
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
public static implicit operator Connection( uint value ) => new Connection() { Id = value };
|
||||
public static implicit operator uint( Connection value ) => value.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Accept an incoming connection that has been received on a listen socket.
|
||||
/// </summary>
|
||||
public Result Accept()
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.AcceptConnection( this );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the remote host and invalidates the connection handle. Any unread data on the connection is discarded..
|
||||
/// reasonCode is defined and used by you.
|
||||
/// </summary>
|
||||
public bool Close( bool linger = false, int reasonCode = 0, string debugString = "Closing Connection" )
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.CloseConnection( this, reasonCode, debugString, linger );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set connection user data
|
||||
/// </summary>
|
||||
public long UserData
|
||||
{
|
||||
get => SteamNetworkingSockets.Internal.GetConnectionUserData( this );
|
||||
set => SteamNetworkingSockets.Internal.SetConnectionUserData( this, value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A name for the connection, used mostly for debugging
|
||||
/// </summary>
|
||||
public string ConnectionName
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( !SteamNetworkingSockets.Internal.GetConnectionName( this, out var strVal ) )
|
||||
return "ERROR";
|
||||
|
||||
return strVal;
|
||||
}
|
||||
|
||||
set => SteamNetworkingSockets.Internal.SetConnectionName( this, value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the best version to use.
|
||||
/// </summary>
|
||||
public Result SendMessage( IntPtr ptr, int size, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
long messageNumber = 0;
|
||||
return SteamNetworkingSockets.Internal.SendMessageToConnection( this, ptr, (uint) size, (int)sendType, ref messageNumber );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ideally should be using an IntPtr version unless you're being really careful with the byte[] array and
|
||||
/// you're not creating a new one every frame (like using .ToArray())
|
||||
/// </summary>
|
||||
public unsafe Result SendMessage( byte[] data, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
return SendMessage( (IntPtr)ptr, data.Length, sendType );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ideally should be using an IntPtr version unless you're being really careful with the byte[] array and
|
||||
/// you're not creating a new one every frame (like using .ToArray())
|
||||
/// </summary>
|
||||
public unsafe Result SendMessage( byte[] data, int offset, int length, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
return SendMessage( (IntPtr)ptr + offset, length, sendType );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This creates a ton of garbage - so don't do anything with this beyond testing!
|
||||
/// </summary>
|
||||
public unsafe Result SendMessage( string str, SendType sendType = SendType.Reliable )
|
||||
{
|
||||
var bytes = System.Text.Encoding.UTF8.GetBytes( str );
|
||||
return SendMessage( bytes, sendType );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush any messages waiting on the Nagle timer and send them at the next transmission
|
||||
/// opportunity (often that means right now).
|
||||
/// </summary>
|
||||
public Result Flush() => SteamNetworkingSockets.Internal.FlushMessagesOnConnection( this );
|
||||
|
||||
/// <summary>
|
||||
/// Returns detailed connection stats in text format. Useful
|
||||
/// for dumping to a log, etc.
|
||||
/// </summary>
|
||||
/// <returns>Plain text connection info</returns>
|
||||
public string DetailedStatus()
|
||||
{
|
||||
if ( SteamNetworkingSockets.Internal.GetDetailedConnectionStatus( this, out var strVal ) != 0 )
|
||||
return null;
|
||||
|
||||
return strVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Facepunch.Steamworks/Networking/ConnectionInfo.cs
Normal file
45
Facepunch.Steamworks/Networking/ConnectionInfo.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Describe the state of a connection
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Sequential, Size = 696 )]
|
||||
public struct ConnectionInfo
|
||||
{
|
||||
internal NetIdentity identity;
|
||||
internal long userData;
|
||||
internal Socket listenSocket;
|
||||
internal NetAddress address;
|
||||
internal ushort pad;
|
||||
internal SteamNetworkingPOPID popRemote;
|
||||
internal SteamNetworkingPOPID popRelay;
|
||||
internal ConnectionState state;
|
||||
internal int endReason;
|
||||
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
|
||||
internal string endDebug;
|
||||
[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 128 )]
|
||||
internal string connectionDescription;
|
||||
|
||||
/// <summary>
|
||||
/// High level state of the connection
|
||||
/// </summary>
|
||||
public ConnectionState State => state;
|
||||
|
||||
/// <summary>
|
||||
/// Remote address. Might be all 0's if we don't know it, or if this is N/A.
|
||||
/// </summary>
|
||||
public NetAddress Address => address;
|
||||
|
||||
/// <summary>
|
||||
/// Who is on the other end? Depending on the connection type and phase of the connection, we might not know
|
||||
/// </summary>
|
||||
public NetIdentity Identity => identity;
|
||||
|
||||
/// <summary>
|
||||
/// Basic cause of the connection termination or problem.
|
||||
/// </summary>
|
||||
public NetConnectionEnd EndReason => (NetConnectionEnd)endReason;
|
||||
}
|
||||
}
|
||||
142
Facepunch.Steamworks/Networking/ConnectionManager.cs
Normal file
142
Facepunch.Steamworks/Networking/ConnectionManager.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Facepunch.Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
public class ConnectionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// An optional interface to use instead of deriving
|
||||
/// </summary>
|
||||
public IConnectionManager Interface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual connection we're managing
|
||||
/// </summary>
|
||||
public Connection Connection;
|
||||
|
||||
/// <summary>
|
||||
/// The last received ConnectionInfo
|
||||
/// </summary>
|
||||
public ConnectionInfo ConnectionInfo { get; internal set; }
|
||||
|
||||
public bool Connected = false;
|
||||
public bool Connecting = true;
|
||||
|
||||
public string ConnectionName
|
||||
{
|
||||
get => Connection.ConnectionName;
|
||||
set => Connection.ConnectionName = value;
|
||||
}
|
||||
|
||||
public long UserData
|
||||
{
|
||||
get => Connection.UserData;
|
||||
set => Connection.UserData = value;
|
||||
}
|
||||
|
||||
public void Close() => Connection.Close();
|
||||
|
||||
public override string ToString() => Connection.ToString();
|
||||
|
||||
public virtual void OnConnectionChanged( ConnectionInfo info )
|
||||
{
|
||||
ConnectionInfo = info;
|
||||
|
||||
switch ( info.State )
|
||||
{
|
||||
case ConnectionState.Connecting:
|
||||
OnConnecting( info );
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
OnConnected( info );
|
||||
break;
|
||||
case ConnectionState.ClosedByPeer:
|
||||
case ConnectionState.ProblemDetectedLocally:
|
||||
case ConnectionState.None:
|
||||
OnDisconnected( info );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We're trying to connect!
|
||||
/// </summary>
|
||||
public virtual void OnConnecting( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnConnecting( info );
|
||||
|
||||
Connecting = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client is connected. They move from connecting to Connections
|
||||
/// </summary>
|
||||
public virtual void OnConnected( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnConnected( info );
|
||||
|
||||
Connected = true;
|
||||
Connecting = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
|
||||
/// </summary>
|
||||
public virtual void OnDisconnected( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnDisconnected( info );
|
||||
|
||||
Connected = false;
|
||||
Connecting = false;
|
||||
}
|
||||
|
||||
public void Receive( int bufferSize = 32 )
|
||||
{
|
||||
int processed = 0;
|
||||
IntPtr messageBuffer = Marshal.AllocHGlobal( IntPtr.Size * bufferSize );
|
||||
|
||||
try
|
||||
{
|
||||
processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( Connection, messageBuffer, bufferSize );
|
||||
|
||||
for ( int i = 0; i < processed; i++ )
|
||||
{
|
||||
ReceiveMessage( Marshal.ReadIntPtr( messageBuffer, i * IntPtr.Size ) );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal( messageBuffer );
|
||||
}
|
||||
|
||||
//
|
||||
// Overwhelmed our buffer, keep going
|
||||
//
|
||||
if ( processed == bufferSize )
|
||||
Receive( bufferSize );
|
||||
}
|
||||
|
||||
internal unsafe void ReceiveMessage( IntPtr msgPtr )
|
||||
{
|
||||
var msg = Marshal.PtrToStructure<NetMsg>( msgPtr );
|
||||
try
|
||||
{
|
||||
OnMessage( msg.DataPtr, msg.DataSize, msg.RecvTime, msg.MessageNumber, msg.Channel );
|
||||
}
|
||||
finally
|
||||
{
|
||||
//
|
||||
// Releases the message
|
||||
//
|
||||
NetMsg.InternalRelease( (NetMsg*) msgPtr );
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnMessage( IntPtr data, int size, long messageNum, long recvTime, int channel )
|
||||
{
|
||||
Interface?.OnMessage( data, size, messageNum, recvTime, channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Facepunch.Steamworks/Networking/IConnectionManager.cs
Normal file
28
Facepunch.Steamworks/Networking/IConnectionManager.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
public interface IConnectionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// We started connecting to this guy
|
||||
/// </summary>
|
||||
void OnConnecting( ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// Called when the connection is fully connected and can start being communicated with
|
||||
/// </summary>
|
||||
void OnConnected( ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// We got disconnected
|
||||
/// </summary>
|
||||
void OnDisconnected( ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// Received a message
|
||||
/// </summary>
|
||||
void OnMessage( IntPtr data, int size, long messageNum, long recvTime, int channel );
|
||||
}
|
||||
}
|
||||
28
Facepunch.Steamworks/Networking/ISocketManager.cs
Normal file
28
Facepunch.Steamworks/Networking/ISocketManager.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
public interface ISocketManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Must call Accept or Close on the connection within a second or so
|
||||
/// </summary>
|
||||
void OnConnecting( Connection connection, ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// Called when the connection is fully connected and can start being communicated with
|
||||
/// </summary>
|
||||
void OnConnected( Connection connection, ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// Called when the connection leaves
|
||||
/// </summary>
|
||||
void OnDisconnected( Connection connection, ConnectionInfo info );
|
||||
|
||||
/// <summary>
|
||||
/// Received a message from a connection
|
||||
/// </summary>
|
||||
void OnMessage( Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel );
|
||||
}
|
||||
}
|
||||
156
Facepunch.Steamworks/Networking/NetAddress.cs
Normal file
156
Facepunch.Steamworks/Networking/NetAddress.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Size = 18, Pack = 1 )]
|
||||
public partial struct NetAddress
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
internal IPV4 ip;
|
||||
|
||||
[FieldOffset( 16 )]
|
||||
internal ushort port;
|
||||
|
||||
internal struct IPV4
|
||||
{
|
||||
internal ulong m_8zeros;
|
||||
internal ushort m_0000;
|
||||
internal ushort m_ffff;
|
||||
internal byte ip0;
|
||||
internal byte ip1;
|
||||
internal byte ip2;
|
||||
internal byte ip3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Port. This is redundant documentation.
|
||||
/// </summary>
|
||||
public ushort Port => port;
|
||||
|
||||
/// <summary>
|
||||
/// Any IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress AnyIp( ushort port )
|
||||
{
|
||||
var addr = Cleared;
|
||||
addr.port = port;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Localhost IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress LocalHost( ushort port )
|
||||
{
|
||||
var local = Cleared;
|
||||
InternalSetIPv6LocalHost( ref local, port );
|
||||
return local;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress From( string addrStr, ushort port )
|
||||
{
|
||||
return From( IPAddress.Parse( addrStr ), port );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specific IP, specific port
|
||||
/// </summary>
|
||||
public static NetAddress From( IPAddress address, ushort port )
|
||||
{
|
||||
var addr = address.GetAddressBytes();
|
||||
|
||||
if ( address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork )
|
||||
{
|
||||
var local = Cleared;
|
||||
InternalSetIPv4( ref local, Utility.IpToInt32( address ), port );
|
||||
return local;
|
||||
}
|
||||
|
||||
throw new System.NotImplementedException( "Oops - no IPV6 support yet?" );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set everything to zero
|
||||
/// </summary>
|
||||
public static NetAddress Cleared
|
||||
{
|
||||
get
|
||||
{
|
||||
NetAddress self = default;
|
||||
InternalClear( ref self );
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the IP is ::0. (Doesn't check port.)
|
||||
/// </summary>
|
||||
public bool IsIPv6AllZeros
|
||||
{
|
||||
get
|
||||
{
|
||||
NetAddress self = this;
|
||||
return InternalIsIPv6AllZeros( ref self );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if IP is mapped IPv4
|
||||
/// </summary>
|
||||
public bool IsIPv4
|
||||
{
|
||||
get
|
||||
{
|
||||
NetAddress self = this;
|
||||
return InternalIsIPv4( ref self );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if this identity is localhost. (Either IPv6 ::1, or IPv4 127.0.0.1)
|
||||
/// </summary>
|
||||
public bool IsLocalHost
|
||||
{
|
||||
get
|
||||
{
|
||||
NetAddress self = this;
|
||||
return InternalIsLocalHost( ref self );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Address section
|
||||
/// </summary>
|
||||
public IPAddress Address
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( IsIPv4 )
|
||||
{
|
||||
NetAddress self = this;
|
||||
var ip = InternalGetIPv4( ref self );
|
||||
return Utility.Int32ToIp( ip );
|
||||
}
|
||||
|
||||
if ( IsIPv6AllZeros )
|
||||
{
|
||||
return IPAddress.IPv6Loopback;
|
||||
}
|
||||
|
||||
throw new System.NotImplementedException( "Oops - no IPV6 support yet?" );
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var ptr = Helpers.TakeMemory();
|
||||
var self = this;
|
||||
InternalToString( ref self, ptr, Helpers.MemoryBufferSize, true );
|
||||
return Helpers.MemoryToString( ptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Facepunch.Steamworks/Networking/NetDebugFunc.cs
Normal file
9
Facepunch.Steamworks/Networking/NetDebugFunc.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Facepunch.Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[UnmanagedFunctionPointer( Platform.CC )]
|
||||
delegate void NetDebugFunc( [In] NetDebugOutput nType, [In] IntPtr pszMsg );
|
||||
}
|
||||
10
Facepunch.Steamworks/Networking/NetErrorMessage.cs
Normal file
10
Facepunch.Steamworks/Networking/NetErrorMessage.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
internal unsafe struct NetErrorMessage
|
||||
{
|
||||
public fixed char Value[1024];
|
||||
}
|
||||
}
|
||||
126
Facepunch.Steamworks/Networking/NetIdentity.cs
Normal file
126
Facepunch.Steamworks/Networking/NetIdentity.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Size = 136, Pack = 1 )]
|
||||
public partial struct NetIdentity
|
||||
{
|
||||
[FieldOffset( 0 )]
|
||||
internal IdentityType type;
|
||||
|
||||
[FieldOffset( 4 )]
|
||||
internal int size;
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal ulong steamid;
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal NetAddress netaddress;
|
||||
|
||||
/// <summary>
|
||||
/// Return a NetIdentity that represents LocalHost
|
||||
/// </summary>
|
||||
public static NetIdentity LocalHost
|
||||
{
|
||||
get
|
||||
{
|
||||
NetIdentity id = default;
|
||||
InternalSetLocalHost( ref id );
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsSteamId => type == IdentityType.SteamID;
|
||||
public bool IsIpAddress => type == IdentityType.IPAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Return true if this identity is localhost
|
||||
/// </summary>
|
||||
public bool IsLocalHost
|
||||
{
|
||||
get
|
||||
{
|
||||
NetIdentity id = default;
|
||||
return InternalIsLocalHost( ref id );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert to a SteamId
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public static implicit operator NetIdentity( SteamId value )
|
||||
{
|
||||
NetIdentity id = default;
|
||||
InternalSetSteamID( ref id, value );
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the specified Address
|
||||
/// </summary>
|
||||
public static implicit operator NetIdentity( NetAddress address )
|
||||
{
|
||||
NetIdentity id = default;
|
||||
InternalSetIPAddr( ref id, ref address );
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically convert to a SteamId
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public static implicit operator SteamId( NetIdentity value )
|
||||
{
|
||||
return value.SteamId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns NULL if we're not a SteamId
|
||||
/// </summary>
|
||||
public SteamId SteamId
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( type != IdentityType.SteamID ) return default;
|
||||
var id = this;
|
||||
return InternalGetSteamID( ref id );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns NULL if we're not a NetAddress
|
||||
/// </summary>
|
||||
public NetAddress Address
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( type != IdentityType.IPAddress ) return default;
|
||||
var id = this;
|
||||
|
||||
var addrptr = InternalGetIPAddr( ref id );
|
||||
return addrptr.ToType<NetAddress>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We override tostring to provide a sensible representation
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
var id = this;
|
||||
SteamNetworkingUtils.Internal.SteamNetworkingIdentity_ToString( ref id, out var str );
|
||||
return str;
|
||||
}
|
||||
|
||||
internal enum IdentityType
|
||||
{
|
||||
Invalid = 0,
|
||||
IPAddress = 1,
|
||||
GenericString = 2,
|
||||
GenericBytes = 3,
|
||||
SteamID = 16
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Facepunch.Steamworks/Networking/NetKeyValue.cs
Normal file
31
Facepunch.Steamworks/Networking/NetKeyValue.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Facepunch.Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Explicit, Pack = Platform.StructPlatformPackSize )]
|
||||
internal struct NetKeyValue
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
internal NetConfig Value; // m_eValue ESteamNetworkingConfigValue
|
||||
|
||||
[FieldOffset( 4 )]
|
||||
internal NetConfigType DataType; // m_eDataType ESteamNetworkingConfigDataType
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal long Int64Value; // m_int64 int64_t
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal int Int32Value; // m_val_int32 int32_t
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal float FloatValue; // m_val_float float
|
||||
|
||||
[FieldOffset( 8 )]
|
||||
internal IntPtr PointerValue; // m_val_functionPtr void *
|
||||
|
||||
|
||||
// TODO - support strings, maybe
|
||||
}
|
||||
}
|
||||
21
Facepunch.Steamworks/Networking/NetMsg.cs
Normal file
21
Facepunch.Steamworks/Networking/NetMsg.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Facepunch.Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal partial struct NetMsg
|
||||
{
|
||||
internal IntPtr DataPtr;
|
||||
internal int DataSize;
|
||||
internal Connection Connection;
|
||||
internal NetIdentity Identity;
|
||||
internal long ConnectionUserData;
|
||||
internal long RecvTime;
|
||||
internal long MessageNumber;
|
||||
internal IntPtr FreeDataPtr;
|
||||
internal IntPtr ReleasePtr;
|
||||
internal int Channel;
|
||||
}
|
||||
}
|
||||
67
Facepunch.Steamworks/Networking/NetPingLocation.cs
Normal file
67
Facepunch.Steamworks/Networking/NetPingLocation.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Object that describes a "location" on the Internet with sufficient
|
||||
/// detail that we can reasonably estimate an upper bound on the ping between
|
||||
/// the two hosts, even if a direct route between the hosts is not possible,
|
||||
/// and the connection must be routed through the Steam Datagram Relay network.
|
||||
/// This does not contain any information that identifies the host. Indeed,
|
||||
/// if two hosts are in the same building or otherwise have nearly identical
|
||||
/// networking characteristics, then it's valid to use the same location
|
||||
/// object for both of them.
|
||||
///
|
||||
/// NOTE: This object should only be used in the same process! Do not serialize it,
|
||||
/// send it over the wire, or persist it in a file or database! If you need
|
||||
/// to do that, convert it to a string representation using the methods in
|
||||
/// ISteamNetworkingUtils().
|
||||
///
|
||||
/// </summary>
|
||||
[StructLayout( LayoutKind.Explicit, Size = 512 )]
|
||||
public struct NetPingLocation
|
||||
{
|
||||
public static NetPingLocation? TryParseFromString( string str )
|
||||
{
|
||||
var result = default( NetPingLocation );
|
||||
if ( !SteamNetworkingUtils.Internal.ParsePingLocationString( str, ref result ) )
|
||||
return null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
SteamNetworkingUtils.Internal.ConvertPingLocationToString( ref this, out var strVal );
|
||||
return strVal;
|
||||
}
|
||||
|
||||
/// Estimate the round-trip latency between two arbitrary locations, in
|
||||
/// milliseconds. This is a conservative estimate, based on routing through
|
||||
/// the relay network. For most basic relayed connections, this ping time
|
||||
/// will be pretty accurate, since it will be based on the route likely to
|
||||
/// be actually used.
|
||||
///
|
||||
/// If a direct IP route is used (perhaps via NAT traversal), then the route
|
||||
/// will be different, and the ping time might be better. Or it might actually
|
||||
/// be a bit worse! Standard IP routing is frequently suboptimal!
|
||||
///
|
||||
/// But even in this case, the estimate obtained using this method is a
|
||||
/// reasonable upper bound on the ping time. (Also it has the advantage
|
||||
/// of returning immediately and not sending any packets.)
|
||||
///
|
||||
/// In a few cases we might not able to estimate the route. In this case
|
||||
/// a negative value is returned. k_nSteamNetworkingPing_Failed means
|
||||
/// the reason was because of some networking difficulty. (Failure to
|
||||
/// ping, etc) k_nSteamNetworkingPing_Unknown is returned if we cannot
|
||||
/// currently answer the question for some other reason.
|
||||
///
|
||||
/// Do you need to be able to do this from a backend/matchmaking server?
|
||||
/// You are looking for the "ticketgen" library.
|
||||
public int EstimatePingTo( NetPingLocation target )
|
||||
{
|
||||
return SteamNetworkingUtils.Internal.EstimatePingTimeBetweenTwoLocations( ref this, ref target );
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Facepunch.Steamworks/Networking/Socket.cs
Normal file
29
Facepunch.Steamworks/Networking/Socket.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
public struct Socket
|
||||
{
|
||||
internal uint Id;
|
||||
public override string ToString() => Id.ToString();
|
||||
public static implicit operator Socket( uint value ) => new Socket() { Id = value };
|
||||
public static implicit operator uint( Socket value ) => value.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Destroy a listen socket. All the connections that were accepting on the listen
|
||||
/// socket are closed ungracefully.
|
||||
/// </summary>
|
||||
public bool Close()
|
||||
{
|
||||
return SteamNetworkingSockets.Internal.CloseListenSocket( Id );
|
||||
}
|
||||
|
||||
public SocketManager Manager
|
||||
{
|
||||
get => SteamNetworkingSockets.GetSocketManager( Id );
|
||||
set => SteamNetworkingSockets.SetSocketManager( Id, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Facepunch.Steamworks/Networking/SocketManager.cs
Normal file
165
Facepunch.Steamworks/Networking/SocketManager.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Facepunch.Steamworks.Data;
|
||||
|
||||
namespace Facepunch.Steamworks
|
||||
{
|
||||
/// <summary>
|
||||
/// Used as a base to create your networking server. This creates a socket
|
||||
/// and listens/communicates with multiple queries.
|
||||
///
|
||||
/// You can override all the virtual functions to turn it into what you
|
||||
/// want it to do.
|
||||
/// </summary>
|
||||
public partial class SocketManager
|
||||
{
|
||||
public ISocketManager Interface { get; set; }
|
||||
|
||||
public List<Connection> Connecting = new List<Connection>();
|
||||
public List<Connection> Connected = new List<Connection>();
|
||||
public Socket Socket { get; internal set; }
|
||||
|
||||
public override string ToString() => Socket.ToString();
|
||||
|
||||
internal HSteamNetPollGroup pollGroup;
|
||||
|
||||
internal void Initialize()
|
||||
{
|
||||
pollGroup = SteamNetworkingSockets.Internal.CreatePollGroup();
|
||||
}
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if ( SteamNetworkingSockets.Internal.IsValid )
|
||||
{
|
||||
SteamNetworkingSockets.Internal.DestroyPollGroup( pollGroup );
|
||||
Socket.Close();
|
||||
}
|
||||
|
||||
pollGroup = 0;
|
||||
Socket = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void OnConnectionChanged( Connection connection, ConnectionInfo info )
|
||||
{
|
||||
switch ( info.State )
|
||||
{
|
||||
case ConnectionState.Connecting:
|
||||
if ( !Connecting.Contains( connection ) )
|
||||
{
|
||||
Connecting.Add( connection );
|
||||
OnConnecting( connection, info );
|
||||
}
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
if ( !Connected.Contains( connection ) )
|
||||
{
|
||||
Connecting.Remove( connection );
|
||||
Connected.Add( connection );
|
||||
|
||||
OnConnected( connection, info );
|
||||
}
|
||||
break;
|
||||
case ConnectionState.ClosedByPeer:
|
||||
case ConnectionState.ProblemDetectedLocally:
|
||||
case ConnectionState.None:
|
||||
if ( Connecting.Contains( connection ) || Connected.Contains( connection ) )
|
||||
{
|
||||
OnDisconnected( connection, info );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default behaviour is to accept every connection
|
||||
/// </summary>
|
||||
public virtual void OnConnecting( Connection connection, ConnectionInfo info )
|
||||
{
|
||||
if ( Interface != null )
|
||||
{
|
||||
Interface.OnConnecting( connection, info );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.Accept();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client is connected. They move from connecting to Connections
|
||||
/// </summary>
|
||||
public virtual void OnConnected( Connection connection, ConnectionInfo info )
|
||||
{
|
||||
SteamNetworkingSockets.Internal.SetConnectionPollGroup( connection, pollGroup );
|
||||
|
||||
Interface?.OnConnected( connection, info );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
|
||||
/// </summary>
|
||||
public virtual void OnDisconnected( Connection connection, ConnectionInfo info )
|
||||
{
|
||||
SteamNetworkingSockets.Internal.SetConnectionPollGroup( connection, 0 );
|
||||
|
||||
connection.Close();
|
||||
|
||||
Connecting.Remove( connection );
|
||||
Connected.Remove( connection );
|
||||
|
||||
Interface?.OnDisconnected( connection, info );
|
||||
}
|
||||
|
||||
public void Receive( int bufferSize = 32 )
|
||||
{
|
||||
int processed = 0;
|
||||
IntPtr messageBuffer = Marshal.AllocHGlobal( IntPtr.Size * bufferSize );
|
||||
|
||||
try
|
||||
{
|
||||
processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnPollGroup( pollGroup, messageBuffer, bufferSize );
|
||||
|
||||
for ( int i = 0; i < processed; i++ )
|
||||
{
|
||||
ReceiveMessage( Marshal.ReadIntPtr( messageBuffer, i * IntPtr.Size ) );
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal( messageBuffer );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Overwhelmed our buffer, keep going
|
||||
//
|
||||
if ( processed == bufferSize )
|
||||
Receive( bufferSize );
|
||||
}
|
||||
|
||||
internal unsafe void ReceiveMessage( IntPtr msgPtr )
|
||||
{
|
||||
var msg = Marshal.PtrToStructure<NetMsg>( msgPtr );
|
||||
try
|
||||
{
|
||||
OnMessage( msg.Connection, msg.Identity, msg.DataPtr, msg.DataSize, msg.RecvTime, msg.MessageNumber, msg.Channel );
|
||||
}
|
||||
finally
|
||||
{
|
||||
//
|
||||
// Releases the message
|
||||
//
|
||||
NetMsg.InternalRelease( (NetMsg*) msgPtr );
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnMessage( Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel )
|
||||
{
|
||||
Interface?.OnMessage( connection, identity, data, size, messageNum, recvTime, channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Facepunch.Steamworks.Data
|
||||
{
|
||||
struct SteamDatagramRelayAuthTicket
|
||||
{
|
||||
// Not implemented, not used
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user