using Facepunch.Steamworks.Data;
using System;
using System.Runtime.InteropServices;
namespace Facepunch.Steamworks
{
public class ConnectionManager
{
///
/// An optional interface to use instead of deriving
///
public IConnectionManager Interface { get; set; }
///
/// The actual connection we're managing
///
public Connection Connection;
///
/// The last received ConnectionInfo
///
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;
}
}
///
/// We're trying to connect!
///
public virtual void OnConnecting( ConnectionInfo info )
{
Interface?.OnConnecting( info );
Connecting = true;
}
///
/// Client is connected. They move from connecting to Connections
///
public virtual void OnConnected( ConnectionInfo info )
{
Interface?.OnConnected( info );
Connected = true;
Connecting = false;
}
///
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
///
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( 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 );
}
}
}