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 { /// /// Class for utilizing the Steam Network API. /// public class SteamNetworking : SteamSharedClass { internal static ISteamNetworking? Internal => Interface as ISteamNetworking; internal override bool InitializeInterface( bool server ) { SetInterface( server, new ISteamNetworking( server ) ); if ( Interface is null || Interface.Self == IntPtr.Zero ) return false; InstallEvents( server ); return true; } internal static void InstallEvents( bool server ) { Dispatch.Install( x => OnP2PSessionRequest?.Invoke( x.SteamIDRemote ), server ); Dispatch.Install( x => OnP2PConnectionFailed?.Invoke( x.SteamIDRemote, (P2PSessionError) x.P2PSessionError ), server ); } public static void ResetActions() { OnP2PSessionRequest = null; OnP2PConnectionFailed = null; } /// /// Invoked when a wants to send the current user a message. You should respond by calling /// if you want to recieve their messages. /// public static Action? OnP2PSessionRequest; /// /// Invoked 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 . /// public static bool AcceptP2PSessionWithUser( SteamId user ) => Internal != null && Internal.AcceptP2PSessionWithUser( user ); /// /// Allow or disallow P2P connects to fall back on Steam server relay if direct /// connection or NAT traversal can't be established. Applies to connections /// created after setting or old connections that need to reconnect. /// public static bool AllowP2PPacketRelay( bool allow ) => Internal != null && Internal.AllowP2PPacketRelay( allow ); /// /// 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 /// callback will be posted /// public static bool CloseP2PSessionWithUser( SteamId user ) => Internal != null && Internal.CloseP2PSessionWithUser( user ); /// /// Checks if a P2P packet is available to read. /// public static bool IsP2PPacketAvailable( int channel = 0 ) { uint _ = 0; return Internal != null && Internal.IsP2PPacketAvailable( ref _, channel ); } /// /// Checks if a P2P packet is available to read, and gets the size of the message if there is one. /// public static bool IsP2PPacketAvailable( out uint msgSize, int channel = 0 ) { msgSize = 0; return Internal != null && Internal.IsP2PPacketAvailable( ref msgSize, 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 is null || !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 }; } } /// /// Reads in a packet that has been sent from another user via SendP2PPacket. /// public unsafe static bool ReadP2PPacket( byte[] buffer, ref uint size, ref SteamId steamid, int channel = 0 ) { fixed (byte* p = buffer) { return Internal != null && Internal.ReadP2PPacket( (IntPtr)p, (uint)buffer.Length, ref size, ref steamid, channel ); } } /// /// Reads in a packet that has been sent from another user via SendP2PPacket. /// public unsafe static bool ReadP2PPacket( byte* buffer, uint cbuf, ref uint size, ref SteamId steamid, int channel = 0 ) { return Internal != null && Internal.ReadP2PPacket( (IntPtr)buffer, cbuf, ref size, ref steamid, channel ); } /// /// 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 != null && Internal.SendP2PPacket( steamid, (IntPtr)p, (uint)length, (P2PSend)sendType, nChannel ); } } /// /// 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, uint length, int nChannel = 1, P2PSend sendType = P2PSend.Reliable ) { return Internal != null && Internal.SendP2PPacket( steamid, (IntPtr)data, (uint)length, (P2PSend)sendType, nChannel ); } public static P2PSessionState? GetP2PSessionState( SteamId steamid ) { P2PSessionState_t state = new P2PSessionState_t(); if (Internal != null && Internal.GetP2PSessionState(steamid, ref state)) { return new P2PSessionState(state); } return null; } } }