mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-25 22:25:49 +03:00
P2P, rough cut
This commit is contained in:
parent
1014178db6
commit
19385ed951
40
Facepunch.Steamworks.Test/Client.Networking.cs
Normal file
40
Facepunch.Steamworks.Test/Client.Networking.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace Facepunch.Steamworks.Test
|
||||||
|
{
|
||||||
|
public partial class Client
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void PeerToPeerSend()
|
||||||
|
{
|
||||||
|
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
|
||||||
|
{
|
||||||
|
var TestString = "This string will be transformed to bytes, sent over the Steam P2P network, then converted back to a string.";
|
||||||
|
var OutputReceived = false;
|
||||||
|
var data = Encoding.UTF8.GetBytes( TestString );
|
||||||
|
|
||||||
|
client.Networking.OnP2PData = ( steamid, ms, channel ) =>
|
||||||
|
{
|
||||||
|
var str = Encoding.UTF8.GetString( ms.GetBuffer() );
|
||||||
|
Assert.AreEqual( str, TestString );
|
||||||
|
Assert.AreEqual( steamid, client.SteamId );
|
||||||
|
OutputReceived = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
client.Networking.SendP2PPacket( client.SteamId, data, data.Length );
|
||||||
|
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
|
||||||
|
if ( OutputReceived )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace Facepunch.Steamworks.Test
|
|||||||
[TestClass]
|
[TestClass]
|
||||||
[DeploymentItem( "FacepunchSteamworksApi.dll" )]
|
[DeploymentItem( "FacepunchSteamworksApi.dll" )]
|
||||||
[DeploymentItem( "steam_appid.txt" )]
|
[DeploymentItem( "steam_appid.txt" )]
|
||||||
public class Client
|
public partial class Client
|
||||||
{
|
{
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Init()
|
public void Init()
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
</Choose>
|
</Choose>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Client.cs" />
|
<Compile Include="Client.cs" />
|
||||||
|
<Compile Include="Client.Networking.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
146
Facepunch.Steamworks/Client.Networking.cs
Normal file
146
Facepunch.Steamworks/Client.Networking.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Valve.Steamworks;
|
||||||
|
|
||||||
|
namespace Facepunch.Steamworks
|
||||||
|
{
|
||||||
|
public partial class Client : IDisposable
|
||||||
|
{
|
||||||
|
private Networking _net;
|
||||||
|
|
||||||
|
public Networking Networking
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ( _net == null )
|
||||||
|
_net = new Networking( this );
|
||||||
|
|
||||||
|
return _net;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Networking
|
||||||
|
{
|
||||||
|
public Action<ulong, MemoryStream, int> OnP2PData;
|
||||||
|
|
||||||
|
internal Client client;
|
||||||
|
|
||||||
|
internal class Callback
|
||||||
|
{
|
||||||
|
internal delegate void P2PSessionRequest( P2PSessionRequest_t a );
|
||||||
|
internal delegate void P2PSessionConnectFail( P2PSessionConnectFail_t a );
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Networking( Client c )
|
||||||
|
{
|
||||||
|
client = c;
|
||||||
|
|
||||||
|
{
|
||||||
|
Callback.P2PSessionRequest cb = onP2PConnectionRequest;
|
||||||
|
client.InstallCallback( Valve.Steamworks.SteamAPI.k_iSteamNetworkingCallbacks + 2, cb );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Callback.P2PSessionConnectFail cb = onP2PConnectionFailed;
|
||||||
|
client.InstallCallback( Valve.Steamworks.SteamAPI.k_iSteamNetworkingCallbacks + 2, cb );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Update()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < 32; i++ )
|
||||||
|
{
|
||||||
|
// POOL ME
|
||||||
|
using ( var ms = new MemoryStream() )
|
||||||
|
{
|
||||||
|
while( ReadP2PPacket( ms, i ) )
|
||||||
|
{
|
||||||
|
// Nothing Here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onP2PConnectionRequest( P2PSessionRequest_t o )
|
||||||
|
{
|
||||||
|
Console.WriteLine( "onP2PConnectionRequest " + o.m_steamIDRemote );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onP2PConnectionFailed( P2PSessionConnectFail_t o )
|
||||||
|
{
|
||||||
|
Console.WriteLine( "onP2PConnectionFailed " + o.m_steamIDRemote );
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EP2PSend : int
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare).
|
||||||
|
/// The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or
|
||||||
|
/// there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
Unreliable = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first
|
||||||
|
/// packet sent to a remote host almost guarantees the packet will be dropped.
|
||||||
|
/// This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets
|
||||||
|
/// </summary>
|
||||||
|
UnreliableNoDelay = 1,
|
||||||
|
|
||||||
|
//// <summary>
|
||||||
|
/// Reliable message send. Can send up to 1MB of data in a single message.
|
||||||
|
/// Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data.
|
||||||
|
/// </summary>
|
||||||
|
Reliable = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// As above, but applies the Nagle algorithm to the send - sends will accumulate
|
||||||
|
/// until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm).
|
||||||
|
/// Useful if you want to send a set of smaller messages but have the coalesced into a single packet
|
||||||
|
/// Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then
|
||||||
|
/// do a normal k_EP2PSendReliable to force all the buffered data to be sent.
|
||||||
|
/// </summary>
|
||||||
|
ReliableWithBuffering = 3,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe bool SendP2PPacket( ulong steamid, byte[] data, int length, EP2PSend eP2PSendType = EP2PSend.Reliable, int nChannel = 0 )
|
||||||
|
{
|
||||||
|
fixed ( byte* p = data )
|
||||||
|
{
|
||||||
|
return client._networking.SendP2PPacket( steamid, (IntPtr) p, (uint)length, (uint)eP2PSendType, nChannel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe bool ReadP2PPacket( MemoryStream ms, int channel = 0 )
|
||||||
|
{
|
||||||
|
uint DataAvailable = 0;
|
||||||
|
|
||||||
|
if ( !client._networking.IsP2PPacketAvailable( ref DataAvailable, channel ) || DataAvailable == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ms.Capacity < DataAvailable )
|
||||||
|
ms.Capacity = (int) DataAvailable;
|
||||||
|
|
||||||
|
ms.Position = 0;
|
||||||
|
ms.SetLength( DataAvailable );
|
||||||
|
|
||||||
|
fixed ( byte* p = ms.GetBuffer() )
|
||||||
|
{
|
||||||
|
ulong steamid = 1;
|
||||||
|
if ( !client._networking.ReadP2PPacket( (IntPtr)p, (uint)DataAvailable, ref DataAvailable, ref steamid, channel ) || DataAvailable == 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ms.SetLength( DataAvailable );
|
||||||
|
|
||||||
|
OnP2PData?.Invoke( steamid, ms, channel );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ public partial class Client : IDisposable
|
|||||||
internal Valve.Steamworks.ISteamFriends _friends;
|
internal Valve.Steamworks.ISteamFriends _friends;
|
||||||
internal Valve.Steamworks.ISteamMatchmakingServers _servers;
|
internal Valve.Steamworks.ISteamMatchmakingServers _servers;
|
||||||
internal Valve.Steamworks.ISteamInventory _inventory;
|
internal Valve.Steamworks.ISteamInventory _inventory;
|
||||||
|
internal Valve.Steamworks.ISteamNetworking _networking;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current running program's AppId
|
/// Current running program's AppId
|
||||||
@ -62,6 +63,7 @@ public Client( uint appId )
|
|||||||
_user = _client.GetISteamUser( _huser, _hpipe, "SteamUser019" );
|
_user = _client.GetISteamUser( _huser, _hpipe, "SteamUser019" );
|
||||||
_servers = _client.GetISteamMatchmakingServers( _huser, _hpipe, "SteamMatchMakingServers002" );
|
_servers = _client.GetISteamMatchmakingServers( _huser, _hpipe, "SteamMatchMakingServers002" );
|
||||||
_inventory = _client.GetISteamInventory( _huser, _hpipe, "STEAMINVENTORY_INTERFACE_V001" );
|
_inventory = _client.GetISteamInventory( _huser, _hpipe, "STEAMINVENTORY_INTERFACE_V001" );
|
||||||
|
_networking = _client.GetISteamNetworking( _huser, _hpipe, "SteamNetworking005" );
|
||||||
|
|
||||||
AppId = appId;
|
AppId = appId;
|
||||||
Username = _friends.GetPersonaName();
|
Username = _friends.GetPersonaName();
|
||||||
@ -106,6 +108,7 @@ public void Update()
|
|||||||
Valve.Steamworks.SteamAPI.RunCallbacks();
|
Valve.Steamworks.SteamAPI.RunCallbacks();
|
||||||
Voice.Update();
|
Voice.Update();
|
||||||
Inventory.Update();
|
Inventory.Update();
|
||||||
|
Networking.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Valid
|
public bool Valid
|
||||||
@ -113,7 +116,7 @@ public bool Valid
|
|||||||
get { return _client != null; }
|
get { return _client != null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Action InstallCallback<T>( int type, Action<T> action )
|
internal Action InstallCallback( int type, Delegate action )
|
||||||
{
|
{
|
||||||
var ptr = Marshal.GetFunctionPointerForDelegate( action );
|
var ptr = Marshal.GetFunctionPointerForDelegate( action );
|
||||||
Valve.Steamworks.SteamAPI.RegisterCallback( ptr, type );
|
Valve.Steamworks.SteamAPI.RegisterCallback( ptr, type );
|
||||||
|
@ -113,6 +113,7 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Client.Networking.cs" />
|
||||||
<Compile Include="Client.Overlay.cs" />
|
<Compile Include="Client.Overlay.cs" />
|
||||||
<Compile Include="Client.ServerList.cs" />
|
<Compile Include="Client.ServerList.cs" />
|
||||||
<Compile Include="Client.ServerList.Request.cs" />
|
<Compile Include="Client.ServerList.Request.cs" />
|
||||||
|
@ -710,7 +710,7 @@ internal class NativeEntrypoints
|
|||||||
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_IsP2PPacketAvailable" )]
|
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_IsP2PPacketAvailable" )]
|
||||||
internal static extern bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable( IntPtr instancePtr, ref uint pcubMsgSize, int nChannel );
|
internal static extern bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable( IntPtr instancePtr, ref uint pcubMsgSize, int nChannel );
|
||||||
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_ReadP2PPacket" )]
|
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_ReadP2PPacket" )]
|
||||||
internal static extern bool SteamAPI_ISteamNetworking_ReadP2PPacket( IntPtr instancePtr, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref CSteamID psteamIDRemote, int nChannel );
|
internal static extern bool SteamAPI_ISteamNetworking_ReadP2PPacket( IntPtr instancePtr, IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref ulong psteamIDRemote, int nChannel );
|
||||||
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser" )]
|
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser" )]
|
||||||
internal static extern bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser( IntPtr instancePtr, ulong steamIDRemote );
|
internal static extern bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser( IntPtr instancePtr, ulong steamIDRemote );
|
||||||
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_CloseP2PSessionWithUser" )]
|
[DllImportAttribute( "FacepunchSteamworksApi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamNetworking_CloseP2PSessionWithUser" )]
|
||||||
@ -1982,7 +1982,7 @@ internal abstract class ISteamNetworking
|
|||||||
internal abstract IntPtr GetIntPtr();
|
internal abstract IntPtr GetIntPtr();
|
||||||
internal abstract bool SendP2PPacket( ulong steamIDRemote, IntPtr pubData, uint cubData, uint eP2PSendType, int nChannel );
|
internal abstract bool SendP2PPacket( ulong steamIDRemote, IntPtr pubData, uint cubData, uint eP2PSendType, int nChannel );
|
||||||
internal abstract bool IsP2PPacketAvailable( ref uint pcubMsgSize, int nChannel );
|
internal abstract bool IsP2PPacketAvailable( ref uint pcubMsgSize, int nChannel );
|
||||||
internal abstract bool ReadP2PPacket( IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref CSteamID psteamIDRemote, int nChannel );
|
internal abstract bool ReadP2PPacket( IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref ulong psteamIDRemote, int nChannel );
|
||||||
internal abstract bool AcceptP2PSessionWithUser( ulong steamIDRemote );
|
internal abstract bool AcceptP2PSessionWithUser( ulong steamIDRemote );
|
||||||
internal abstract bool CloseP2PSessionWithUser( ulong steamIDRemote );
|
internal abstract bool CloseP2PSessionWithUser( ulong steamIDRemote );
|
||||||
internal abstract bool CloseP2PChannelWithUser( ulong steamIDRemote, int nChannel );
|
internal abstract bool CloseP2PChannelWithUser( ulong steamIDRemote, int nChannel );
|
||||||
@ -2475,7 +2475,7 @@ internal override ISteamNetworking GetISteamNetworking( uint hSteamUser, uint hS
|
|||||||
{
|
{
|
||||||
CheckIfUsable();
|
CheckIfUsable();
|
||||||
IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamNetworking(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion);
|
IntPtr result = NativeEntrypoints.SteamAPI_ISteamClient_GetISteamNetworking(m_pSteamClient,hSteamUser,hSteamPipe,pchVersion);
|
||||||
return (ISteamNetworking)Marshal.PtrToStructure( result, typeof( ISteamNetworking ) );
|
return new CSteamNetworking( result );
|
||||||
}
|
}
|
||||||
internal override ISteamRemoteStorage GetISteamRemoteStorage( uint hSteamuser, uint hSteamPipe, string pchVersion )
|
internal override ISteamRemoteStorage GetISteamRemoteStorage( uint hSteamuser, uint hSteamPipe, string pchVersion )
|
||||||
{
|
{
|
||||||
@ -4730,7 +4730,7 @@ internal override bool IsP2PPacketAvailable( ref uint pcubMsgSize, int nChannel
|
|||||||
bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_IsP2PPacketAvailable(m_pSteamNetworking,ref pcubMsgSize,nChannel);
|
bool result = NativeEntrypoints.SteamAPI_ISteamNetworking_IsP2PPacketAvailable(m_pSteamNetworking,ref pcubMsgSize,nChannel);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
internal override bool ReadP2PPacket( IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref CSteamID psteamIDRemote, int nChannel )
|
internal override bool ReadP2PPacket( IntPtr pubDest, uint cubDest, ref uint pcubMsgSize, ref ulong psteamIDRemote, int nChannel )
|
||||||
{
|
{
|
||||||
CheckIfUsable();
|
CheckIfUsable();
|
||||||
pcubMsgSize = 0;
|
pcubMsgSize = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user