From 28effd140b8ea27cde3c2f01a8739277447ecc75 Mon Sep 17 00:00:00 2001 From: Rohan Singh Date: Tue, 19 Jan 2021 17:04:48 -0500 Subject: [PATCH] Pass results back, optionally --- ...kingSocketsTest.TestConnectionInterface.cs | 5 +- ...tworkingSocketsTest.TestSocketInterface.cs | 2 +- .../Interfaces/ISteamNetworkingSockets.cs | 4 +- .../Networking/BroadcastBufferManager.cs | 11 ++-- .../Networking/ConnectionManager.cs | 64 +++++++++++++------ Generator/Types/BaseType.cs | 23 +++++-- Generator/Types/StructType.cs | 4 +- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs index efbf3cb..03661cd 100644 --- a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs +++ b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Text; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -96,10 +97,12 @@ public override unsafe void OnMessage( IntPtr data, int size, long messageNum, l Connection.SendMessage( "How do you like 20 messages in a row?" ); var connections = new[] { Connection }; + var results = new Result[1]; for ( int i=0; i<20; i++ ) { Console.WriteLine( $"[Connection][{messageNum}][{recvTime}][{channel}] Sending: BLAMMO {i}!" ); - Broadcast( connections, connections.Length, $"BLAMMO {i}!" ); + SendMessages( connections, connections.Length, $"BLAMMO {i}!", results: results ); + Assert.AreEqual( Result.OK, results[0] ); } Connection.Flush(); diff --git a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs index aff919e..ed5b9bd 100644 --- a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs +++ b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs @@ -97,7 +97,7 @@ internal async Task RunAsync() Receive(); await Task.Delay( 100 ); - if ( sw.Elapsed.TotalSeconds > 100 ) + if ( sw.Elapsed.TotalSeconds > 30 ) { Console.WriteLine( "Socket: This all took too long - throwing an exception" ); Assert.Fail( "Socket Took Too Long" ); diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingSockets.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingSockets.cs index 46f0d23..61e402e 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingSockets.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingSockets.cs @@ -162,10 +162,10 @@ internal Result SendMessageToConnection( Connection hConn, IntPtr pData, uint cb #region FunctionMeta [DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ISteamNetworkingSockets_SendMessages", CallingConvention = Platform.CC)] - private static extern void _SendMessages( IntPtr self, int nMessages, NetMsg** pMessages, [In,Out] long[] pOutMessageNumberOrResult ); + private static extern void _SendMessages( IntPtr self, int nMessages, NetMsg** pMessages, long* pOutMessageNumberOrResult ); #endregion - internal void SendMessages( int nMessages, NetMsg** pMessages, [In,Out] long[] pOutMessageNumberOrResult ) + internal void SendMessages( int nMessages, NetMsg** pMessages, long* pOutMessageNumberOrResult ) { _SendMessages( Self, nMessages, pMessages, pOutMessageNumberOrResult ); } diff --git a/Facepunch.Steamworks/Networking/BroadcastBufferManager.cs b/Facepunch.Steamworks/Networking/BroadcastBufferManager.cs index cb2a0d2..a6e63b5 100644 --- a/Facepunch.Steamworks/Networking/BroadcastBufferManager.cs +++ b/Facepunch.Steamworks/Networking/BroadcastBufferManager.cs @@ -245,7 +245,8 @@ private static void FreeBuffer( IntPtr ptr, int size ) #endif } } - + + private const int Bucket512 = 512; private const int Bucket1Kb = 1 * 1024; private const int Bucket4Kb = 4 * 1024; private const int Bucket16Kb = 16 * 1024; @@ -253,7 +254,8 @@ private static void FreeBuffer( IntPtr ptr, int size ) private const int Bucket256Kb = 256 * 1024; private static int GetBucketSize( int size ) - { + { + if ( size <= Bucket512 ) return Bucket512; if ( size <= Bucket1Kb ) return Bucket1Kb; if ( size <= Bucket4Kb ) return Bucket4Kb; if ( size <= Bucket16Kb ) return Bucket16Kb; @@ -265,8 +267,9 @@ private static int GetBucketSize( int size ) private static int GetBucketLimit( int size ) { - if ( size <= Bucket1Kb ) return 256; - if ( size <= Bucket4Kb ) return 64; + if ( size <= Bucket512 ) return 1024; + if ( size <= Bucket1Kb ) return 512; + if ( size <= Bucket4Kb ) return 128; if ( size <= Bucket16Kb ) return 32; if ( size <= Bucket64Kb ) return 16; if ( size <= Bucket256Kb ) return 8; diff --git a/Facepunch.Steamworks/Networking/ConnectionManager.cs b/Facepunch.Steamworks/Networking/ConnectionManager.cs index 66f5a59..7e0c923 100644 --- a/Facepunch.Steamworks/Networking/ConnectionManager.cs +++ b/Facepunch.Steamworks/Networking/ConnectionManager.cs @@ -151,18 +151,29 @@ public unsafe int Receive( int bufferSize = 32, bool receiveToEnd = true ) return totalProcessed; } - public unsafe void Broadcast( Connection[] connections, int connectionCount, IntPtr ptr, int size, SendType sendType = SendType.Reliable ) + /// + /// Sends a message to multiple connections. + /// + /// The connections to send the message to. + /// The number of connections to send the message to, to allow reusing the connections array. + /// Pointer to the message data. + /// Size of the message data. + /// Flags to control delivery of the message. + /// An optional array to hold the results of sending the messages for each connection. + 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( nameof( connectionCount ) ); - if ( connectionCount > 1024 ) + 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( nameof( size ) ); + throw new ArgumentException( "`size` cannot be zero", nameof( size ) ); if ( connectionCount == 0 ) return; @@ -175,6 +186,8 @@ public unsafe void Broadcast( Connection[] connections, int connectionCount, Int 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(); @@ -185,18 +198,21 @@ public unsafe void Broadcast( Connection[] connections, int connectionCount, Int messages[i]->FreeDataPtr = BroadcastBufferManager.FreeFunctionPointer; } - SteamNetworkingSockets.Internal.SendMessages( connectionCount, messages, null ); - } + SteamNetworkingSockets.Internal.SendMessages( connectionCount, messages, messageNumberOrResults ); - /// - /// 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()) - /// - public unsafe void Broadcast( Connection[] connections, int connectionCount, byte[] data, SendType sendType = SendType.Reliable ) - { - fixed ( byte* ptr = data ) + if (results == null) + return; + + for ( var i = 0; i < connectionCount; i++ ) { - Broadcast( connections, connectionCount, (IntPtr)ptr, data.Length, sendType ); + if ( messageNumberOrResults[i] < 0 ) + { + results[i] = (Result)( -messageNumberOrResults[i] ); + } + else + { + results[i] = Result.OK; + } } } @@ -204,21 +220,33 @@ public unsafe void Broadcast( Connection[] connections, int connectionCount, byt /// 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()) /// - public unsafe void Broadcast( Connection[] connections, int connectionCount, byte[] data, int offset, int length, SendType sendType = SendType.Reliable ) + public unsafe void SendMessages( Connection[] connections, int connectionCount, byte[] data, SendType sendType = SendType.Reliable, Result[] results = null ) { fixed ( byte* ptr = data ) { - Broadcast( connections, connectionCount, (IntPtr)ptr + offset, length, sendType ); + SendMessages( connections, connectionCount, (IntPtr)ptr, data.Length, sendType, results ); + } + } + + /// + /// 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()) + /// + 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 ); } } /// /// This creates a ton of garbage - so don't do anything with this beyond testing! /// - public void Broadcast( Connection[] connections, int connectionCount, string str, SendType sendType = SendType.Reliable ) + public void SendMessages( Connection[] connections, int connectionCount, string str, SendType sendType = SendType.Reliable, Result[] results = null ) { var bytes = System.Text.Encoding.UTF8.GetBytes( str ); - Broadcast( connections, connectionCount, bytes, sendType ); + SendMessages( connections, connectionCount, bytes, sendType, results ); } internal unsafe void ReceiveMessage( ref NetMsg* msg ) diff --git a/Generator/Types/BaseType.cs b/Generator/Types/BaseType.cs index ff51c88..35047ea 100644 --- a/Generator/Types/BaseType.cs +++ b/Generator/Types/BaseType.cs @@ -76,19 +76,33 @@ public static BaseType Parse( string type, string varname = null, string callres public virtual bool ShouldSkipAsArgument => false; public virtual string AsNativeArgument() => AsArgument(); - public virtual string AsArgument() => IsVector ? $"[In,Out] {Ref}{TypeName.Trim( '*', ' ', '&' )}[] {VarName}" : $"{Ref}{TypeName.Trim( '*', ' ', '&' )} {VarName}"; - public virtual string AsCallArgument() => $"{Ref}{VarName}"; + public virtual string AsArgument() + { + if (IsVector) + { + return $"[In,Out] {Ref}{TypeName.Trim('*', ' ', '&')}[] {VarName}"; + } + + return TreatAsPointer + ? $"{Ref}{TypeName}{new string('*', NativeType.Count(c => c == '*'))} {VarName}" + : $"{Ref}{TypeName.Trim('*', ' ', '&')} {VarName}"; + } + + public virtual string AsCallArgument() => $"{Ref}{VarName}"; public virtual string Return( string varname ) => $"return {varname};"; public virtual string ReturnAttribute => null; public virtual string ReturnType => TypeName; - public virtual string Ref => !IsVector && NativeType.EndsWith( "*" ) || NativeType.EndsWith( "**" ) || NativeType.Contains( "&" ) ? "ref " : ""; + public virtual string Ref => !TreatAsPointer && !IsVector && NativeType.EndsWith( "*" ) || NativeType.EndsWith( "**" ) || NativeType.Contains( "&" ) ? "ref " : ""; + public virtual bool IsVector { get - { + { + if ( TreatAsPointer ) return false; + if ( Func == "ReadP2PPacket" ) return false; if ( Func == "SendP2PPacket" ) return false; if ( VarName == "pOutMessageNumber" ) return false; @@ -124,6 +138,7 @@ public virtual bool IsVector } } + public virtual bool TreatAsPointer => VarName == "pOutMessageNumberOrResult"; public virtual bool IsVoid => false; } diff --git a/Generator/Types/StructType.cs b/Generator/Types/StructType.cs index 9e5a616..d694f0d 100644 --- a/Generator/Types/StructType.cs +++ b/Generator/Types/StructType.cs @@ -23,9 +23,9 @@ internal class StructType : BaseType public override string AsCallArgument() => IsPointer && TreatAsPointer ? VarName : base.AsCallArgument(); - public bool IsPointer => NativeType.EndsWith( "*" ); + public override bool TreatAsPointer => StructName == "NetMsg"; - public bool TreatAsPointer => StructName == "NetMsg"; + public bool IsPointer => NativeType.EndsWith( "*" ); public override string Return( string varname ) {