Connection basics

This commit is contained in:
Garry Newman 2019-05-02 17:45:10 +01:00
parent 1c5eeedf40
commit 6c41ef2e51
6 changed files with 238 additions and 129 deletions

View File

@ -57,11 +57,11 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate HSteamNetConnection FConnectByIPAddress( IntPtr self, ref SteamNetworkingIPAddr address );
private delegate NetConnection FConnectByIPAddress( IntPtr self, ref SteamNetworkingIPAddr address );
private FConnectByIPAddress _ConnectByIPAddress;
#endregion
internal HSteamNetConnection ConnectByIPAddress( ref SteamNetworkingIPAddr address )
internal NetConnection ConnectByIPAddress( ref SteamNetworkingIPAddr address )
{
return _ConnectByIPAddress( Self, ref address );
}
@ -79,22 +79,22 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate HSteamNetConnection FConnectP2P( IntPtr self, ref SteamNetworkingIdentity identityRemote, int nVirtualPort );
private delegate NetConnection FConnectP2P( IntPtr self, ref SteamNetworkingIdentity identityRemote, int nVirtualPort );
private FConnectP2P _ConnectP2P;
#endregion
internal HSteamNetConnection ConnectP2P( ref SteamNetworkingIdentity identityRemote, int nVirtualPort )
internal NetConnection ConnectP2P( ref SteamNetworkingIdentity identityRemote, int nVirtualPort )
{
return _ConnectP2P( Self, ref identityRemote, nVirtualPort );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate Result FAcceptConnection( IntPtr self, HSteamNetConnection hConn );
private delegate Result FAcceptConnection( IntPtr self, NetConnection hConn );
private FAcceptConnection _AcceptConnection;
#endregion
internal Result AcceptConnection( HSteamNetConnection hConn )
internal Result AcceptConnection( NetConnection hConn )
{
return _AcceptConnection( Self, hConn );
}
@ -102,11 +102,11 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FCloseConnection( IntPtr self, HSteamNetConnection hPeer, int nReason, string pszDebug, [MarshalAs( UnmanagedType.U1 )] bool bEnableLinger );
private delegate bool FCloseConnection( IntPtr self, NetConnection hPeer, int nReason, string pszDebug, [MarshalAs( UnmanagedType.U1 )] bool bEnableLinger );
private FCloseConnection _CloseConnection;
#endregion
internal bool CloseConnection( HSteamNetConnection hPeer, int nReason, string pszDebug, [MarshalAs( UnmanagedType.U1 )] bool bEnableLinger )
internal bool CloseConnection( NetConnection hPeer, int nReason, string pszDebug, [MarshalAs( UnmanagedType.U1 )] bool bEnableLinger )
{
return _CloseConnection( Self, hPeer, nReason, pszDebug, bEnableLinger );
}
@ -126,33 +126,33 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FSetConnectionUserData( IntPtr self, HSteamNetConnection hPeer, long nUserData );
private delegate bool FSetConnectionUserData( IntPtr self, NetConnection hPeer, long nUserData );
private FSetConnectionUserData _SetConnectionUserData;
#endregion
internal bool SetConnectionUserData( HSteamNetConnection hPeer, long nUserData )
internal bool SetConnectionUserData( NetConnection hPeer, long nUserData )
{
return _SetConnectionUserData( Self, hPeer, nUserData );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate long FGetConnectionUserData( IntPtr self, HSteamNetConnection hPeer );
private delegate long FGetConnectionUserData( IntPtr self, NetConnection hPeer );
private FGetConnectionUserData _GetConnectionUserData;
#endregion
internal long GetConnectionUserData( HSteamNetConnection hPeer )
internal long GetConnectionUserData( NetConnection hPeer )
{
return _GetConnectionUserData( Self, hPeer );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate void FSetConnectionName( IntPtr self, HSteamNetConnection hPeer, string pszName );
private delegate void FSetConnectionName( IntPtr self, NetConnection hPeer, string pszName );
private FSetConnectionName _SetConnectionName;
#endregion
internal void SetConnectionName( HSteamNetConnection hPeer, string pszName )
internal void SetConnectionName( NetConnection hPeer, string pszName )
{
_SetConnectionName( Self, hPeer, pszName );
}
@ -160,44 +160,44 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FGetConnectionName( IntPtr self, HSteamNetConnection hPeer, StringBuilder pszName, int nMaxLen );
private delegate bool FGetConnectionName( IntPtr self, NetConnection hPeer, StringBuilder pszName, int nMaxLen );
private FGetConnectionName _GetConnectionName;
#endregion
internal bool GetConnectionName( HSteamNetConnection hPeer, StringBuilder pszName, int nMaxLen )
internal bool GetConnectionName( NetConnection hPeer, StringBuilder pszName, int nMaxLen )
{
return _GetConnectionName( Self, hPeer, pszName, nMaxLen );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate Result FSendMessageToConnection( IntPtr self, HSteamNetConnection hConn, IntPtr pData, uint cbData, int nSendFlags );
private delegate Result FSendMessageToConnection( IntPtr self, NetConnection hConn, IntPtr pData, uint cbData, int nSendFlags );
private FSendMessageToConnection _SendMessageToConnection;
#endregion
internal Result SendMessageToConnection( HSteamNetConnection hConn, IntPtr pData, uint cbData, int nSendFlags )
internal Result SendMessageToConnection( NetConnection hConn, IntPtr pData, uint cbData, int nSendFlags )
{
return _SendMessageToConnection( Self, hConn, pData, cbData, nSendFlags );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate Result FFlushMessagesOnConnection( IntPtr self, HSteamNetConnection hConn );
private delegate Result FFlushMessagesOnConnection( IntPtr self, NetConnection hConn );
private FFlushMessagesOnConnection _FlushMessagesOnConnection;
#endregion
internal Result FlushMessagesOnConnection( HSteamNetConnection hConn )
internal Result FlushMessagesOnConnection( NetConnection hConn )
{
return _FlushMessagesOnConnection( Self, hConn );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate int FReceiveMessagesOnConnection( IntPtr self, HSteamNetConnection hConn, [In,Out] ref SteamNetworkingMessage_t[] ppOutMessages, int nMaxMessages );
private delegate int FReceiveMessagesOnConnection( IntPtr self, NetConnection hConn, [In,Out] ref SteamNetworkingMessage_t[] ppOutMessages, int nMaxMessages );
private FReceiveMessagesOnConnection _ReceiveMessagesOnConnection;
#endregion
internal int ReceiveMessagesOnConnection( HSteamNetConnection hConn, [In,Out] ref SteamNetworkingMessage_t[] ppOutMessages, int nMaxMessages )
internal int ReceiveMessagesOnConnection( NetConnection hConn, [In,Out] ref SteamNetworkingMessage_t[] ppOutMessages, int nMaxMessages )
{
return _ReceiveMessagesOnConnection( Self, hConn, ref ppOutMessages, nMaxMessages );
}
@ -216,11 +216,11 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FGetConnectionInfo( IntPtr self, HSteamNetConnection hConn, ref SteamNetConnectionInfo_t pInfo );
private delegate bool FGetConnectionInfo( IntPtr self, NetConnection hConn, ref SteamNetConnectionInfo_t pInfo );
private FGetConnectionInfo _GetConnectionInfo;
#endregion
internal bool GetConnectionInfo( HSteamNetConnection hConn, ref SteamNetConnectionInfo_t pInfo )
internal bool GetConnectionInfo( NetConnection hConn, ref SteamNetConnectionInfo_t pInfo )
{
return _GetConnectionInfo( Self, hConn, ref pInfo );
}
@ -228,22 +228,22 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FGetQuickConnectionStatus( IntPtr self, HSteamNetConnection hConn, ref SteamNetworkingQuickConnectionStatus pStats );
private delegate bool FGetQuickConnectionStatus( IntPtr self, NetConnection hConn, ref SteamNetworkingQuickConnectionStatus pStats );
private FGetQuickConnectionStatus _GetQuickConnectionStatus;
#endregion
internal bool GetQuickConnectionStatus( HSteamNetConnection hConn, ref SteamNetworkingQuickConnectionStatus pStats )
internal bool GetQuickConnectionStatus( NetConnection hConn, ref SteamNetworkingQuickConnectionStatus pStats )
{
return _GetQuickConnectionStatus( Self, hConn, ref pStats );
}
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate int FGetDetailedConnectionStatus( IntPtr self, HSteamNetConnection hConn, StringBuilder pszBuf, int cbBuf );
private delegate int FGetDetailedConnectionStatus( IntPtr self, NetConnection hConn, StringBuilder pszBuf, int cbBuf );
private FGetDetailedConnectionStatus _GetDetailedConnectionStatus;
#endregion
internal int GetDetailedConnectionStatus( HSteamNetConnection hConn, StringBuilder pszBuf, int cbBuf )
internal int GetDetailedConnectionStatus( NetConnection hConn, StringBuilder pszBuf, int cbBuf )
{
return _GetDetailedConnectionStatus( Self, hConn, pszBuf, cbBuf );
}
@ -263,11 +263,11 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
[return: MarshalAs( UnmanagedType.I1 )]
private delegate bool FCreateSocketPair( IntPtr self, [In,Out] HSteamNetConnection[] pOutConnection1, [In,Out] HSteamNetConnection[] pOutConnection2, [MarshalAs( UnmanagedType.U1 )] bool bUseNetworkLoopback, ref SteamNetworkingIdentity pIdentity1, ref SteamNetworkingIdentity pIdentity2 );
private delegate bool FCreateSocketPair( IntPtr self, [In,Out] NetConnection[] pOutConnection1, [In,Out] NetConnection[] pOutConnection2, [MarshalAs( UnmanagedType.U1 )] bool bUseNetworkLoopback, ref SteamNetworkingIdentity pIdentity1, ref SteamNetworkingIdentity pIdentity2 );
private FCreateSocketPair _CreateSocketPair;
#endregion
internal bool CreateSocketPair( [In,Out] HSteamNetConnection[] pOutConnection1, [In,Out] HSteamNetConnection[] pOutConnection2, [MarshalAs( UnmanagedType.U1 )] bool bUseNetworkLoopback, ref SteamNetworkingIdentity pIdentity1, ref SteamNetworkingIdentity pIdentity2 )
internal bool CreateSocketPair( [In,Out] NetConnection[] pOutConnection1, [In,Out] NetConnection[] pOutConnection2, [MarshalAs( UnmanagedType.U1 )] bool bUseNetworkLoopback, ref SteamNetworkingIdentity pIdentity1, ref SteamNetworkingIdentity pIdentity2 )
{
return _CreateSocketPair( Self, pOutConnection1, pOutConnection2, bUseNetworkLoopback, ref pIdentity1, ref pIdentity2 );
}
@ -309,11 +309,11 @@ namespace Steamworks
#region FunctionMeta
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
private delegate HSteamNetConnection FConnectToHostedDedicatedServer( IntPtr self, ref SteamNetworkingIdentity identityTarget, int nVirtualPort );
private delegate NetConnection FConnectToHostedDedicatedServer( IntPtr self, ref SteamNetworkingIdentity identityTarget, int nVirtualPort );
private FConnectToHostedDedicatedServer _ConnectToHostedDedicatedServer;
#endregion
internal HSteamNetConnection ConnectToHostedDedicatedServer( ref SteamNetworkingIdentity identityTarget, int nVirtualPort )
internal NetConnection ConnectToHostedDedicatedServer( ref SteamNetworkingIdentity identityTarget, int nVirtualPort )
{
return _ConnectToHostedDedicatedServer( Self, ref identityTarget, nVirtualPort );
}

View File

@ -8,17 +8,17 @@ using Steamworks.Data;
namespace Steamworks
{
public static class SteamNetworkingSockets
public static class SteamNetworking
{
static ISteamNetworkingSockets _internal;
internal static ISteamNetworkingSockets Internal
static ISteamNetworking _internal;
internal static ISteamNetworking Internal
{
get
{
if ( _internal == null )
{
_internal = new ISteamNetworkingSockets();
_internal.InitClient();
_internal = new ISteamNetworking();
_internal.InitUserless();
}
return _internal;
@ -32,7 +32,90 @@ namespace Steamworks
internal static void InstallEvents()
{
P2PSessionRequest_t.Install( x => OnP2PSessionRequest?.Invoke( x.SteamIDRemote ) );
P2PSessionConnectFail_t.Install( x => OnP2PConnectionFailed?.Invoke( x.SteamIDRemote ) );
}
/// <summary>
/// This SteamId wants to send you a message. You should respond by calling AcceptP2PSessionWithUser
/// if you want to recieve their messages
/// </summary>
public static Action<SteamId> OnP2PSessionRequest;
/// <summary>
/// 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).
/// </summary>
public static Action<SteamId> OnP2PConnectionFailed;
/// <summary>
/// This should be called in response to a OnP2PSessionRequest
/// </summary>
public static bool AcceptP2PSessionWithUser( SteamId user ) => Internal.AcceptP2PSessionWithUser( user );
/// <summary>
/// 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
/// </summary>
public static bool CloseP2PSessionWithUser( SteamId user ) => Internal.CloseP2PSessionWithUser( user );
/// <summary>
/// Checks if a P2P packet is available to read, and gets the size of the message if there is one.
/// </summary>
public static bool IsP2PPacketAvailable( int channel = 0 )
{
uint _ = 0;
return Internal.IsP2PPacketAvailable( ref _, channel );
}
/// <summary>
/// Reads in a packet that has been sent from another user via SendP2PPacket..
/// </summary>
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
};
}
}
/// <summary>
/// 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.
/// </summary>
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 );
}
}
}
}

View File

@ -8,17 +8,17 @@ using Steamworks.Data;
namespace Steamworks
{
public static class SteamNetworking
public static class SteamNetworkingSockets
{
static ISteamNetworking _internal;
internal static ISteamNetworking Internal
static ISteamNetworkingSockets _internal;
internal static ISteamNetworkingSockets Internal
{
get
{
if ( _internal == null )
{
_internal = new ISteamNetworking();
_internal.InitClient();
_internal = new ISteamNetworkingSockets();
_internal.InitUserless();
}
return _internal;
@ -32,90 +32,40 @@ namespace Steamworks
internal static void InstallEvents()
{
P2PSessionRequest_t.Install( x => OnP2PSessionRequest?.Invoke( x.SteamIDRemote ) );
P2PSessionConnectFail_t.Install( x => OnP2PConnectionFailed?.Invoke( x.SteamIDRemote ) );
}
/// <summary>
/// This SteamId wants to send you a message. You should respond by calling AcceptP2PSessionWithUser
/// if you want to recieve their messages
/// Creates a "server" socket that listens for clients to connect to by calling
/// Connect, over ordinary UDP (IPv4 or IPv6)
/// </summary>
public static Action<SteamId> OnP2PSessionRequest;
/// <summary>
/// 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).
/// </summary>
public static Action<SteamId> OnP2PConnectionFailed;
/// <summary>
/// This should be called in response to a OnP2PSessionRequest
/// </summary>
public static bool AcceptP2PSessionWithUser( SteamId user ) => Internal.AcceptP2PSessionWithUser( user );
/// <summary>
/// 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
/// </summary>
public static bool CloseP2PSessionWithUser( SteamId user ) => Internal.CloseP2PSessionWithUser( user );
/// <summary>
/// Checks if a P2P packet is available to read, and gets the size of the message if there is one.
/// </summary>
public static bool IsP2PPacketAvailable( int channel = 0 )
public static HSteamListenSocket CreateExposedSocket( SteamNetworkingIPAddr address )
{
uint _ = 0;
return Internal.IsP2PPacketAvailable( ref _, channel );
return Internal.CreateListenSocketIP( ref address );
}
/// <summary>
/// Reads in a packet that has been sent from another user via SendP2PPacket..
/// Connect to a socket created via <method>CreateListenSocketIP</method>
/// </summary>
public unsafe static P2Packet? ReadP2PPacket( int channel = 0 )
public static NetConnection ConnectExposed( SteamNetworkingIPAddr address )
{
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
};
}
return Internal.ConnectByIPAddress( ref address );
}
/// <summary>
/// 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.
/// Creates a server that will be relayed via Valve's network (hiding the IP and improving ping)
/// </summary>
public static unsafe bool SendP2PPacket( SteamId steamid, byte[] data, int length = -1, int nChannel = 0, P2PSend sendType = P2PSend.Reliable )
public static HSteamListenSocket CreateSocket( int virtualport = 0 )
{
if ( length <= 0 )
length = data.Length;
fixed ( byte* p = data )
{
return Internal.SendP2PPacket( steamid, (IntPtr)p, (uint)length, (P2PSend)sendType, nChannel );
}
return Internal.CreateListenSocketP2P( virtualport );
}
/// <summary>
/// Connect to a relay server
/// </summary>
public static NetConnection Connect( SteamNetworkingIdentity identity, int virtualport = 0 )
{
return Internal.ConnectP2P( ref identity, virtualport );
}
}
}

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
namespace Steamworks.Data
{
public struct NetConnection
{
uint Id;
public static implicit operator NetConnection( uint value )
{
return new NetConnection { Id = value };
}
public static implicit operator uint( NetConnection value )
{
return value.Id;
}
public override string ToString() => Id.ToString();
/// <summary>
/// Accept an incoming connection that has been received on a listen socket.
/// </summary>
public Result Accept()
{
return SteamNetworkingSockets.Internal.AcceptConnection( this );
}
/// <summary>
/// Disconnects from the remote host and invalidates the connection handle. Any unread data on the connection is discarded..
/// reasonCode is defined and used by you.
/// </summary>
public bool Close( bool linger = false, int reasonCode = 0, string debugString = "Closing Connection" )
{
return SteamNetworkingSockets.Internal.CloseConnection( this, reasonCode, debugString, linger );
}
/// <summary>
/// Get/Set connection user data
/// </summary>
public long UserData
{
get => SteamNetworkingSockets.Internal.GetConnectionUserData( this );
set => SteamNetworkingSockets.Internal.SetConnectionUserData( this, value );
}
/// <summary>
/// A name for the connection, used mostly for debugging
/// </summary>
public string ConnectionName
{
get
{
var sb = Helpers.TakeStringBuilder();
if ( !SteamNetworkingSockets.Internal.GetConnectionName( this, sb, sb.Capacity ) )
return "ERROR";
return sb.ToString();
}
set => SteamNetworkingSockets.Internal.SetConnectionName( this, value );
}
/// <summary>
/// Flush any messages waiting on the Nagle timer and send them at the next transmission opportunity (often that means right now).
/// </summary>
public Result Flush() => SteamNetworkingSockets.Internal.FlushMessagesOnConnection( this );
/*
[ThreadStatic]
private static SteamNetworkingMessage_t[] messageBuffer;
public IEnumerable<SteamNetworkingMessage_t> Messages
{
get
{
if ( messageBuffer == null )
messageBuffer = new SteamNetworkingMessage_t[128];
var num = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( this, ref messageBuffer, messageBuffer.Length );
for ( int i = 0; i < num; i++)
{
yield return messageBuffer[i];
messageBuffer[i].Release();
}
}
}*/
}
}

View File

@ -58,23 +58,6 @@ namespace Steamworks.Data
public override string ToString() => Value.ToString();
}
public struct HSteamNetConnection
{
public uint Value;
public static implicit operator HSteamNetConnection( uint value )
{
return new HSteamNetConnection { Value = value };
}
public static implicit operator uint( HSteamNetConnection value )
{
return value.Value;
}
public override string ToString() => Value.ToString();
}
public enum IdentityType
{
Invalid = 0,
@ -153,7 +136,7 @@ namespace Steamworks.Data
{
public IntPtr data;
public int length;
public HSteamNetConnection connection;
public NetConnection connection;
public SteamNetworkingIdentity identity;
public long userData;
public SteamNetworkingMicroseconds timeReceived;

View File

@ -30,6 +30,7 @@ public static class Cleanup
type = type.Replace( "SteamNetworkingConfigValue", "NetConfig" );
type = type.Replace( "SteamNetworkingConfigScope", "NetScope" );
type = type.Replace( "SteamNetworkingConfigDataType", "NetConfigType" );
type = type.Replace( "HSteamNetConnection", "NetConnection" );
return type;
}