diff --git a/Facepunch.Steamworks.Test/NetworkingSockets.cs b/Facepunch.Steamworks.Test/NetworkingSockets.cs index 16c1ea3..0acd7ba 100644 --- a/Facepunch.Steamworks.Test/NetworkingSockets.cs +++ b/Facepunch.Steamworks.Test/NetworkingSockets.cs @@ -14,10 +14,17 @@ namespace Steamworks [DeploymentItem( "steam_api.dll" )] public partial class NetworkingSocketsTest { + void DebugOutput( NetDebugOutput type, string text ) + { + Console.WriteLine( $"[NET:{type}]\t\t{text}" ); + } [TestMethod] public async Task CreateRelayServer() { + SteamNetworkingUtils.DebugLevel = NetDebugOutput.Everything; + SteamNetworkingUtils.OnDebugOutput += DebugOutput; + var si = SteamNetworkingSockets.CreateRelaySocket(); Console.WriteLine( $"Created Socket: {si}" ); @@ -31,6 +38,9 @@ namespace Steamworks [TestMethod] public async Task CreateNormalServer() { + SteamNetworkingUtils.DebugLevel = NetDebugOutput.Everything; + SteamNetworkingUtils.OnDebugOutput += DebugOutput; + var si = SteamNetworkingSockets.CreateNormalSocket( Data.NetAddress.AnyIp( 21893 ) ); Console.WriteLine( $"Created Socket: {si}" ); @@ -45,6 +55,8 @@ namespace Steamworks public async Task RelayEndtoEnd() { SteamNetworkingUtils.InitRelayNetworkAccess(); + SteamNetworkingUtils.DebugLevel = NetDebugOutput.Warning; + SteamNetworkingUtils.OnDebugOutput += DebugOutput; // For some reason giving steam a couple of seconds here // seems to prevent it returning null connections from ConnectNormal @@ -66,6 +78,9 @@ namespace Steamworks [TestMethod] public async Task NormalEndtoEnd() { + SteamNetworkingUtils.DebugLevel = NetDebugOutput.Everything; + SteamNetworkingUtils.OnDebugOutput += DebugOutput; + // For some reason giving steam a couple of seconds here // seems to prevent it returning null connections from ConnectNormal await Task.Delay( 2000 ); diff --git a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs index d16453d..eeafe9b 100644 --- a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs +++ b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestConnectionInterface.cs @@ -47,6 +47,7 @@ namespace Steamworks var sw = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine( "[Connection] Connecting" ); while ( Connecting ) { await Task.Delay( 10 ); @@ -88,14 +89,18 @@ namespace Steamworks if ( str.Contains( "Hello" ) ) { + Console.WriteLine( $"[Connection][{messageNum}][{recvTime}][{channel}] Sending: Hello, How are you!?" ); Connection.SendMessage( "Hello, How are you!?" ); + Console.WriteLine( $"[Connection][{messageNum}][{recvTime}][{channel}] Sending: How do you like 20 messages in a row?" ); Connection.SendMessage( "How do you like 20 messages in a row?" ); for ( int i=0; i<20; i++ ) { Connection.SendMessage( $"BLAMMO!" ); } + + Connection.Flush(); } if ( str.Contains( "status" )) diff --git a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs index 8941fcb..9e5c6c9 100644 --- a/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs +++ b/Facepunch.Steamworks.Test/NetworkingSocketsTest.TestSocketInterface.cs @@ -77,18 +77,23 @@ namespace Steamworks sw = System.Diagnostics.Stopwatch.StartNew(); + Console.WriteLine( $"Socket: Listening" ); + while ( Connected.Contains( singleClient ) ) { Receive(); await Task.Delay( 100 ); - if ( sw.Elapsed.TotalSeconds > 10 ) + if ( sw.Elapsed.TotalSeconds > 5 ) { + Console.WriteLine( "Socket: This all took too long - throwing an exception" ); Assert.Fail( "Socket Took Too Long" ); break; } } + Console.WriteLine( $"Socket: Closing connection because {Connected.Count()} Connected" ); + await Task.Delay( 1000 ); Close(); diff --git a/Facepunch.Steamworks/Classes/Dispatch.cs b/Facepunch.Steamworks/Classes/Dispatch.cs index 3755279..a35920f 100644 --- a/Facepunch.Steamworks/Classes/Dispatch.cs +++ b/Facepunch.Steamworks/Classes/Dispatch.cs @@ -58,6 +58,7 @@ namespace Steamworks public static void Frame( HSteamPipe pipe ) { SteamAPI_ManualDispatch_RunFrame( pipe ); + SteamNetworkingUtils.OutputDebugMessages(); CallbackMsg_t msg = default; diff --git a/Facepunch.Steamworks/Enum/DebugOutputType.cs b/Facepunch.Steamworks/Enum/DebugOutputType.cs deleted file mode 100644 index 5f36bbd..0000000 --- a/Facepunch.Steamworks/Enum/DebugOutputType.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Steamworks.Data -{ - enum DebugOutputType : int - { - None = 0, - Bug = 1, // You used the API incorrectly, or an internal error happened - Error = 2, // Run-time error condition that isn't the result of a bug. (E.g. we are offline, cannot bind a port, etc) - Important = 3, // Nothing is wrong, but this is an important notification - Warning = 4, - Msg = 5, // Recommended amount - Verbose = 6, // Quite a bit - Debug = 7, // Practically everything - Everything = 8, // Wall of text, detailed packet contents breakdown, etc - - Force32Bit = 0x7fffffff - }; -} diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingUtils.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingUtils.cs index 6c65ae3..c08abff 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingUtils.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworkingUtils.cs @@ -178,10 +178,10 @@ namespace Steamworks #region FunctionMeta [DllImport( Platform.LibraryName, EntryPoint = "SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction", CallingConvention = Platform.CC)] - private static extern void _SetDebugOutputFunction( IntPtr self, DebugOutputType eDetailLevel, NetDebugFunc pfnFunc ); + private static extern void _SetDebugOutputFunction( IntPtr self, NetDebugOutput eDetailLevel, NetDebugFunc pfnFunc ); #endregion - internal void SetDebugOutputFunction( DebugOutputType eDetailLevel, NetDebugFunc pfnFunc ) + internal void SetDebugOutputFunction( NetDebugOutput eDetailLevel, NetDebugFunc pfnFunc ) { _SetDebugOutputFunction( Self, eDetailLevel, pfnFunc ); } diff --git a/Facepunch.Steamworks/Networking/NetDebugFunc.cs b/Facepunch.Steamworks/Networking/NetDebugFunc.cs index 9c47c8b..85e7aaa 100644 --- a/Facepunch.Steamworks/Networking/NetDebugFunc.cs +++ b/Facepunch.Steamworks/Networking/NetDebugFunc.cs @@ -4,5 +4,5 @@ using System.Runtime.InteropServices; namespace Steamworks.Data { - delegate void NetDebugFunc( DebugOutputType nType, string pszMsg ); + delegate void NetDebugFunc( NetDebugOutput nType, string pszMsg ); } \ No newline at end of file diff --git a/Facepunch.Steamworks/SteamNetworkingUtils.cs b/Facepunch.Steamworks/SteamNetworkingUtils.cs index b6899ef..ff6d06a 100644 --- a/Facepunch.Steamworks/SteamNetworkingUtils.cs +++ b/Facepunch.Steamworks/SteamNetworkingUtils.cs @@ -28,6 +28,20 @@ namespace Steamworks }, server ); } + /// + /// A function to receive debug network information on. This will do nothing + /// unless you set DebugLevel to something other than None. + /// + /// You should set this to an appropriate level instead of setting it to the highest + /// and then filtering it by hand because a lot of energy is used by creating the strings + /// and your frame rate will tank and you won't know why. + /// + + public static event Action OnDebugOutput; + + /// + /// The latest available status gathered from the SteamRelayNetworkStatus callback + /// public static SteamNetworkingAvailability Status { get; private set; } /// @@ -145,7 +159,66 @@ namespace Steamworks set => SetConfigFloat( NetConfig.FakePacketLag_Recv, value ); } -#region Config Internals + + + /// + /// Get Debug Information via OnDebugOutput event + /// + /// Except when debugging, you should only use NetDebugOutput.Msg + /// or NetDebugOutput.Warning. For best performance, do NOT + /// request a high detail level and then filter out messages in the callback. + /// + /// This incurs all of the expense of formatting the messages, which are then discarded. + /// Setting a high priority value (low numeric value) here allows the library to avoid + /// doing this work. + /// + public static NetDebugOutput DebugLevel + { + get => _debugLevel; + set + { + _debugLevel = value; + Internal.SetDebugOutputFunction( value, OnDebugMessage ); + } + } + + /// + /// So we can remember and provide a Get for DebugLEvel + /// + private static NetDebugOutput _debugLevel; + + struct DebugMessage + { + public NetDebugOutput Type; + public string Msg; + } + + private static System.Collections.Concurrent.ConcurrentQueue debugMessages = new System.Collections.Concurrent.ConcurrentQueue(); + + /// + /// This can be called from other threads - so we're going to queue these up and process them in a safe place. + /// + private static void OnDebugMessage( NetDebugOutput nType, string pszMsg ) + { + debugMessages.Enqueue( new DebugMessage { Type = nType, Msg = pszMsg } ); + } + + /// + /// Called regularly from the Dispatch loop so we can provide a timely + /// stream of messages. + /// + internal static void OutputDebugMessages() + { + if ( debugMessages.IsEmpty ) + return; + + while ( debugMessages.TryDequeue( out var result ) ) + { + OnDebugOutput?.Invoke( result.Type, result.Msg ); + } + } + + #region Config Internals internal unsafe static bool GetConfigInt( NetConfig type, int value ) { diff --git a/Generator/Cleanup.cs b/Generator/Cleanup.cs index 88a05c3..024b3d2 100644 --- a/Generator/Cleanup.cs +++ b/Generator/Cleanup.cs @@ -47,7 +47,7 @@ public static class Cleanup type = type.Replace( "SteamNetConnectionInfo_t", "ConnectionInfo" ); type = type.Replace( "SteamNetworkingConnectionState", "ConnectionState" ); type = type.Replace( "SteamNetworkingMicroseconds", "long" ); - type = type.Replace( "SteamNetworkingSocketsDebugOutputType", "DebugOutputType" ); + type = type.Replace( "SteamNetworkingSocketsDebugOutputType", "NetDebugOutput" ); type = type.Replace( "SteamNetworkingGetConfigValueResult", "NetConfigResult" ); type = type.Replace( "SteamInputType", "InputType" ); type = type.Replace( "InputDigitalActionData_t", "DigitalState" ); @@ -136,6 +136,7 @@ public static class Cleanup if ( name == "NetConnectionEnd" ) return "public"; if ( name == "NetIdentity" ) return "public"; if ( name == "NetAddress" ) return "public"; + if ( name == "NetDebugOutput" ) return "public"; return "internal"; }