diff --git a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworking.cs b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworking.cs index 794851a..049c3cf 100644 --- a/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworking.cs +++ b/Facepunch.Steamworks/Generated/Interfaces/ISteamNetworking.cs @@ -44,11 +44,11 @@ public override void InitInternals() #region FunctionMeta [UnmanagedFunctionPointer( CallingConvention.ThisCall )] [return: MarshalAs( UnmanagedType.I1 )] - private delegate bool FSendP2PPacket( IntPtr self, SteamId steamIDRemote, [In,Out] IntPtr[] pubData, uint cubData, P2PSend eP2PSendType, int nChannel ); + private delegate bool FSendP2PPacket( IntPtr self, SteamId steamIDRemote, IntPtr pubData, uint cubData, P2PSend eP2PSendType, int nChannel ); private FSendP2PPacket _SendP2PPacket; #endregion - internal bool SendP2PPacket( SteamId steamIDRemote, [In,Out] IntPtr[] pubData, uint cubData, P2PSend eP2PSendType, int nChannel ) + internal bool SendP2PPacket( SteamId steamIDRemote, IntPtr pubData, uint cubData, P2PSend eP2PSendType, int nChannel ) { return _SendP2PPacket( Self, steamIDRemote, pubData, cubData, eP2PSendType, nChannel ); } @@ -68,11 +68,11 @@ internal bool IsP2PPacketAvailable( ref uint pcubMsgSize, int nChannel ) #region FunctionMeta [UnmanagedFunctionPointer( CallingConvention.ThisCall )] [return: MarshalAs( UnmanagedType.I1 )] - private delegate bool FReadP2PPacket( IntPtr self, [In,Out] IntPtr[] pubDest, uint cubDest, ref uint pcubMsgSize, ref SteamId psteamIDRemote, int nChannel ); + private delegate bool FReadP2PPacket( IntPtr self, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref SteamId psteamIDRemote, int nChannel ); private FReadP2PPacket _ReadP2PPacket; #endregion - internal bool ReadP2PPacket( [In,Out] IntPtr[] pubDest, uint cubDest, ref uint pcubMsgSize, ref SteamId psteamIDRemote, int nChannel ) + internal bool ReadP2PPacket( IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref SteamId psteamIDRemote, int nChannel ) { return _ReadP2PPacket( Self, pubDest, cubDest, ref pcubMsgSize, ref psteamIDRemote, nChannel ); } diff --git a/Facepunch.Steamworks/Generated/SteamEnums.cs b/Facepunch.Steamworks/Generated/SteamEnums.cs index 69b336e..ddf03bf 100644 --- a/Facepunch.Steamworks/Generated/SteamEnums.cs +++ b/Facepunch.Steamworks/Generated/SteamEnums.cs @@ -946,7 +946,7 @@ internal enum P2PSessionError : int // // EP2PSend // - internal enum P2PSend : int + public enum P2PSend : int { Unreliable = 0, UnreliableNoDelay = 1, diff --git a/Facepunch.Steamworks/SteamClient.cs b/Facepunch.Steamworks/SteamClient.cs index 550eb71..abed587 100644 --- a/Facepunch.Steamworks/SteamClient.cs +++ b/Facepunch.Steamworks/SteamClient.cs @@ -40,6 +40,7 @@ public static void Init( uint appid ) SteamScreenshots.InstallEvents(); SteamUserStats.InstallEvents(); SteamInventory.InstallEvents(); + SteamNetworking.InstallEvents(); RunCallbacksAsync(); } diff --git a/Facepunch.Steamworks/SteamNetworking.cs b/Facepunch.Steamworks/SteamNetworking.cs new file mode 100644 index 0000000..a5db69a --- /dev/null +++ b/Facepunch.Steamworks/SteamNetworking.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Steamworks.Data; + +namespace Steamworks +{ + public static class SteamNetworking + { + static ISteamNetworking _internal; + internal static ISteamNetworking Internal + { + get + { + if ( _internal == null ) + _internal = new ISteamNetworking(); + + return _internal; + } + } + + internal static void InstallEvents() + { + P2PSessionRequest_t.Install( x => OnP2PSessionRequest?.Invoke( x.SteamIDRemote ) ); + P2PSessionConnectFail_t.Install( x => OnP2PConnectionFailed?.Invoke( x.SteamIDRemote ) ); + } + + /// + /// This SteamId wants to send you a message. You should respond by calling AcceptP2PSessionWithUser + /// if you want to recieve their messages + /// + public static Action OnP2PSessionRequest; + + /// + /// Called when packets can't get through to the specified user. + /// All queued packets unsent at this point will be dropped, further attempts + /// to send will retry making the connection (but will be dropped if we fail again). + /// + public static Action OnP2PConnectionFailed; + + /// + /// This should be called in response to a OnP2PSessionRequest + /// + public static bool AcceptP2PSessionWithUser( SteamId user ) => Internal.AcceptP2PSessionWithUser( user ); + + /// + /// This should be called when you're done communicating with a user, as this will + /// free up all of the resources allocated for the connection under-the-hood. + /// If the remote user tries to send data to you again, a new OnP2PSessionRequest + /// callback will be posted + /// + public static bool CloseP2PSessionWithUser( SteamId user ) => Internal.CloseP2PSessionWithUser( user ); + + /// + /// Checks if a P2P packet is available to read, and gets the size of the message if there is one. + /// + public static bool IsP2PPacketAvailable( int channel = 0 ) + { + uint _ = 0; + return Internal.IsP2PPacketAvailable( ref _, channel ); + } + + /// + /// Reads in a packet that has been sent from another user via SendP2PPacket.. + /// + public unsafe static P2Packet? ReadP2PPacket( int channel = 0 ) + { + uint size = 0; + + if ( !Internal.IsP2PPacketAvailable( ref size, channel ) ) + return null; + + var buffer = Helpers.TakeBuffer( (int) size ); + + fixed ( byte* p = buffer ) + { + SteamId steamid = 1; + if ( !Internal.ReadP2PPacket( (IntPtr)p, (uint) buffer.Length, ref size, ref steamid, channel ) || size == 0 ) + return null; + + var data = new byte[size]; + Array.Copy( buffer, 0, data, 0, size ); + + return new P2Packet + { + SteamId = steamid, + Data = data + }; + } + } + + /// + /// Sends a P2P packet to the specified user. + /// This is a session-less API which automatically establishes NAT-traversing or Steam relay server connections. + /// NOTE: The first packet send may be delayed as the NAT-traversal code runs. + /// + public static unsafe bool SendP2PPacket( SteamId steamid, byte[] data, int length = -1, int nChannel = 0, P2PSend sendType = P2PSend.Reliable ) + { + if ( length <= 0 ) + length = data.Length; + + fixed ( byte* p = data ) + { + return Internal.SendP2PPacket( steamid, (IntPtr)p, (uint)length, (P2PSend)sendType, nChannel ); + } + } + + + } +} \ No newline at end of file diff --git a/Facepunch.Steamworks/Structs/P2Packet.cs b/Facepunch.Steamworks/Structs/P2Packet.cs new file mode 100644 index 0000000..ca85773 --- /dev/null +++ b/Facepunch.Steamworks/Structs/P2Packet.cs @@ -0,0 +1,8 @@ +namespace Steamworks.Data +{ + public struct P2Packet + { + public SteamId SteamId; + public byte[] Data; + } +} \ No newline at end of file diff --git a/Generator/Cleanup.cs b/Generator/Cleanup.cs index e4cf013..915bce5 100644 --- a/Generator/Cleanup.cs +++ b/Generator/Cleanup.cs @@ -58,6 +58,7 @@ internal static string Expose( string name ) if ( name == "UgcType" ) return "public"; if ( name == "InventoryItemId" ) return "public"; if ( name == "InventoryDefId" ) return "public"; + if ( name == "P2PSend" ) return "public"; return "internal"; } diff --git a/Generator/CodeWriter/Types/BaseType.cs b/Generator/CodeWriter/Types/BaseType.cs index 6076e8c..8d3ebac 100644 --- a/Generator/CodeWriter/Types/BaseType.cs +++ b/Generator/CodeWriter/Types/BaseType.cs @@ -60,6 +60,9 @@ public virtual bool IsVector { get { + if ( Func == "ReadP2PPacket" ) return false; + if ( Func == "SendP2PPacket" ) return false; + if ( VarName == "pOut" ) return false; if ( VarName == "pOutBuffer" ) return false; if ( VarName == "pubRGB" ) return false;