Unstable 1.1.14.0
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using Steamworks.Data;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Steamworks
|
||||
{
|
||||
@@ -36,7 +35,10 @@ namespace Steamworks
|
||||
set => Connection.UserData = value;
|
||||
}
|
||||
|
||||
public void Close() => Connection.Close();
|
||||
public void Close( bool linger = false, int reasonCode = 0, string debugString = "Closing Connection" )
|
||||
{
|
||||
Connection.Close( linger, reasonCode, debugString );
|
||||
}
|
||||
|
||||
public override string ToString() => Connection.ToString();
|
||||
|
||||
@@ -44,18 +46,40 @@ namespace Steamworks
|
||||
{
|
||||
ConnectionInfo = info;
|
||||
|
||||
//
|
||||
// Some notes:
|
||||
// - Update state before the callbacks, in case an exception is thrown
|
||||
// - ConnectionState.None happens when a connection is destroyed, even if it was already disconnected (ClosedByPeer / ProblemDetectedLocally)
|
||||
//
|
||||
switch ( info.State )
|
||||
{
|
||||
case ConnectionState.Connecting:
|
||||
OnConnecting( info );
|
||||
if ( !Connecting && !Connected )
|
||||
{
|
||||
Connecting = true;
|
||||
|
||||
OnConnecting( info );
|
||||
}
|
||||
break;
|
||||
case ConnectionState.Connected:
|
||||
OnConnected( info );
|
||||
if ( Connecting && !Connected )
|
||||
{
|
||||
Connecting = false;
|
||||
Connected = true;
|
||||
|
||||
OnConnected( info );
|
||||
}
|
||||
break;
|
||||
case ConnectionState.ClosedByPeer:
|
||||
case ConnectionState.ProblemDetectedLocally:
|
||||
case ConnectionState.None:
|
||||
OnDisconnected( info );
|
||||
if ( Connecting || Connected )
|
||||
{
|
||||
Connecting = false;
|
||||
Connected = false;
|
||||
|
||||
OnDisconnected( info );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -66,8 +90,6 @@ namespace Steamworks
|
||||
public virtual void OnConnecting( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnConnecting( info );
|
||||
|
||||
Connecting = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,9 +98,6 @@ namespace Steamworks
|
||||
public virtual void OnConnected( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnConnected( info );
|
||||
|
||||
Connected = true;
|
||||
Connecting = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,52 +106,166 @@ namespace Steamworks
|
||||
public virtual void OnDisconnected( ConnectionInfo info )
|
||||
{
|
||||
Interface?.OnDisconnected( info );
|
||||
|
||||
Connected = false;
|
||||
Connecting = false;
|
||||
}
|
||||
|
||||
public void Receive( int bufferSize = 32 )
|
||||
public unsafe int Receive( int bufferSize = 32, bool receiveToEnd = true )
|
||||
{
|
||||
if (SteamNetworkingSockets.Internal is null) { return; }
|
||||
if (SteamNetworkingSockets.Internal is null) { return 0; }
|
||||
|
||||
if ( bufferSize < 1 || bufferSize > 256 ) throw new ArgumentOutOfRangeException( nameof( bufferSize ) );
|
||||
|
||||
int totalProcessed = 0;
|
||||
NetMsg** messageBuffer = stackalloc NetMsg*[bufferSize];
|
||||
|
||||
int processed = 0;
|
||||
IntPtr messageBuffer = Marshal.AllocHGlobal( IntPtr.Size * bufferSize );
|
||||
|
||||
try
|
||||
while ( true )
|
||||
{
|
||||
processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( Connection, messageBuffer, bufferSize );
|
||||
int processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( Connection, new IntPtr( &messageBuffer[0] ), bufferSize );
|
||||
totalProcessed += processed;
|
||||
|
||||
for ( int i = 0; i < processed; i++ )
|
||||
try
|
||||
{
|
||||
ReceiveMessage( Marshal.ReadIntPtr( messageBuffer, i * IntPtr.Size ) );
|
||||
for ( int i = 0; i < processed; i++ )
|
||||
{
|
||||
ReceiveMessage( ref messageBuffer[i] );
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
for ( int i = 0; i < processed; i++ )
|
||||
{
|
||||
if ( messageBuffer[i] != null )
|
||||
{
|
||||
NetMsg.InternalRelease( messageBuffer[i] );
|
||||
}
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Keep going if receiveToEnd and we filled the buffer
|
||||
//
|
||||
if ( !receiveToEnd || processed < bufferSize )
|
||||
break;
|
||||
}
|
||||
|
||||
return totalProcessed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to multiple connections.
|
||||
/// </summary>
|
||||
/// <param name="connections">The connections to send the message to.</param>
|
||||
/// <param name="connectionCount">The number of connections to send the message to, to allow reusing the connections array.</param>
|
||||
/// <param name="ptr">Pointer to the message data.</param>
|
||||
/// <param name="size">Size of the message data.</param>
|
||||
/// <param name="sendType">Flags to control delivery of the message.</param>
|
||||
/// <param name="results">An optional array to hold the results of sending the messages for each connection.</param>
|
||||
public unsafe void SendMessages( Connection[] connections, int connectionCount, IntPtr ptr, int size, SendType sendType = SendType.Reliable, Result[]? results = null )
|
||||
{
|
||||
if ( connections == null )
|
||||
throw new ArgumentNullException( nameof( connections ) );
|
||||
if ( connectionCount < 0 || connectionCount > connections.Length )
|
||||
throw new ArgumentException( "`connectionCount` must be between 0 and `connections.Length`", nameof( connectionCount ) );
|
||||
if ( results != null && connectionCount > results.Length )
|
||||
throw new ArgumentException( "`results` must have at least `connectionCount` entries", nameof( results ) );
|
||||
if ( connectionCount > 1024 ) // restricting this because we stack allocate based on this value
|
||||
throw new ArgumentOutOfRangeException( nameof( connectionCount ) );
|
||||
if ( ptr == IntPtr.Zero )
|
||||
throw new ArgumentNullException( nameof( ptr ) );
|
||||
if ( size == 0 )
|
||||
throw new ArgumentException( "`size` cannot be zero", nameof( size ) );
|
||||
|
||||
if ( SteamNetworkingSockets.Internal is null )
|
||||
return;
|
||||
if ( connectionCount == 0 )
|
||||
return;
|
||||
|
||||
// SendMessages does not make a copy of the data. We will need to copy because we don't want to force the caller to keep the pointer valid.
|
||||
// 1. We don't want a copy per message. They all refer to the same data. This is the benefit of using Broadcast vs. many sends.
|
||||
// 2. We need to use unmanaged memory. Managed memory may move around and invalidate pointers so it's not an option.
|
||||
// 3. We'll use a reference counter and custom free() function to release this unmanaged memory.
|
||||
var copyPtr = BufferManager.Get( size, connectionCount );
|
||||
Buffer.MemoryCopy( (void*)ptr, (void*)copyPtr, size, size );
|
||||
|
||||
var messages = stackalloc NetMsg*[connectionCount];
|
||||
var messageNumberOrResults = stackalloc long[results != null ? connectionCount : 0];
|
||||
|
||||
for ( var i = 0; i < connectionCount; i++ )
|
||||
{
|
||||
messages[i] = SteamNetworkingUtils.AllocateMessage();
|
||||
messages[i]->Connection = connections[i];
|
||||
messages[i]->Flags = sendType;
|
||||
messages[i]->DataPtr = copyPtr;
|
||||
messages[i]->DataSize = size;
|
||||
messages[i]->FreeDataPtr = BufferManager.FreeFunctionPointer;
|
||||
}
|
||||
|
||||
SteamNetworkingSockets.Internal.SendMessages( connectionCount, messages, messageNumberOrResults );
|
||||
|
||||
if (results == null)
|
||||
return;
|
||||
|
||||
for ( var i = 0; i < connectionCount; i++ )
|
||||
{
|
||||
if ( messageNumberOrResults[i] < 0 )
|
||||
{
|
||||
results[i] = (Result)( -messageNumberOrResults[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
results[i] = Result.OK;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal( messageBuffer );
|
||||
}
|
||||
|
||||
//
|
||||
// Overwhelmed our buffer, keep going
|
||||
//
|
||||
if ( processed == bufferSize )
|
||||
Receive( bufferSize );
|
||||
}
|
||||
|
||||
internal unsafe void ReceiveMessage( IntPtr msgPtr )
|
||||
/// <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 void SendMessages( Connection[] connections, int connectionCount, byte[] data, SendType sendType = SendType.Reliable, Result[]? results = null )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
SendMessages( connections, connectionCount, (IntPtr)ptr, data.Length, sendType, results );
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 void SendMessages( Connection[] connections, int connectionCount, byte[] data, int offset, int length, SendType sendType = SendType.Reliable, Result[]? results = null )
|
||||
{
|
||||
fixed ( byte* ptr = data )
|
||||
{
|
||||
SendMessages( connections, connectionCount, (IntPtr)ptr + offset, length, sendType, results );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This creates a ton of garbage - so don't do anything with this beyond testing!
|
||||
/// </summary>
|
||||
public void SendMessages( Connection[] connections, int connectionCount, string str, SendType sendType = SendType.Reliable, Result[]? results = null )
|
||||
{
|
||||
var bytes = System.Text.Encoding.UTF8.GetBytes( str );
|
||||
SendMessages( connections, connectionCount, bytes, sendType, results );
|
||||
}
|
||||
|
||||
internal unsafe void ReceiveMessage( ref NetMsg* msg )
|
||||
{
|
||||
var msg = Marshal.PtrToStructure<NetMsg>( msgPtr );
|
||||
try
|
||||
{
|
||||
OnMessage( msg.DataPtr, msg.DataSize, msg.RecvTime, msg.MessageNumber, msg.Channel );
|
||||
OnMessage( msg->DataPtr, msg->DataSize, msg->RecvTime, msg->MessageNumber, msg->Channel );
|
||||
}
|
||||
finally
|
||||
{
|
||||
//
|
||||
// Releases the message
|
||||
//
|
||||
NetMsg.InternalRelease( (NetMsg*) msgPtr );
|
||||
NetMsg.InternalRelease( msg );
|
||||
msg = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,4 +274,4 @@ namespace Steamworks
|
||||
Interface?.OnMessage( data, size, messageNum, recvTime, channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user