Code Monkey home page Code Monkey logo

valvesockets-csharp's Introduction

alt logo

GitHub release

This repository provides a managed C# abstraction of GameNetworkingSockets library which is created and maintained by Valve Software. You will need to build the native library with all required dependencies before you get started.

The project is updating in accordance with the releases of the native library.

Building

A managed assembly can be built using any available compiling platform that supports C# 3.0 or higher.

Define VALVESOCKETS_SPAN to enable support for Span. Please, follow these steps to enable fast access to native memory blocks and improve performance.

Usage

Before starting to work, the library should be initialized using Valve.Sockets.Library.Initialize(); function.

After the work is done, deinitialize the library using Valve.Sockets.Library.Deinitialize(); function.

.NET environment

Start a new server
NetworkingSockets server = new NetworkingSockets();

uint pollGroup = server.CreatePollGroup();

StatusCallback status = (ref StatusInfo info) => {
	switch (info.connectionInfo.state) {
		case ConnectionState.None:
			break;

		case ConnectionState.Connecting:
			server.AcceptConnection(info.connection);
			server.SetConnectionPollGroup(pollGroup, info.connection);
			break;

		case ConnectionState.Connected:
			Console.WriteLine("Client connected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;

		case ConnectionState.ClosedByPeer:
		case ConnectionState.ProblemDetectedLocally:
			server.CloseConnection(info.connection);
			Console.WriteLine("Client disconnected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;
	}
};

utils.SetStatusCallback(status);

Address address = new Address();

address.SetAddress("::0", port);

uint listenSocket = server.CreateListenSocket(ref address);

#if VALVESOCKETS_SPAN
	MessageCallback message = (in NetworkingMessage netMessage) => {
		Console.WriteLine("Message received from - ID: " + netMessage.connection + ", Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
	};
#else
	const int maxMessages = 20;

	NetworkingMessage[] netMessages = new NetworkingMessage[maxMessages];
#endif

while (!Console.KeyAvailable) {
	server.RunCallbacks();

	#if VALVESOCKETS_SPAN
		server.ReceiveMessagesOnPollGroup(pollGroup, message, 20);
	#else
		int netMessagesCount = server.ReceiveMessagesOnPollGroup(pollGroup, netMessages, maxMessages);

		if (netMessagesCount > 0) {
			for (int i = 0; i < netMessagesCount; i++) {
				ref NetworkingMessage netMessage = ref netMessages[i];

				Console.WriteLine("Message received from - ID: " + netMessage.connection + ", Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);

				netMessage.Destroy();
			}
		}
	#endif

	Thread.Sleep(15);
}

server.DestroyPollGroup(pollGroup);
Start a new client
NetworkingSockets client = new NetworkingSockets();

uint connection = 0;

StatusCallback status = (ref StatusInfo info) => {
	switch (info.connectionInfo.state) {
		case ConnectionState.None:
			break;

		case ConnectionState.Connected:
			Console.WriteLine("Client connected to server - ID: " + connection);
			break;

		case ConnectionState.ClosedByPeer:
		case ConnectionState.ProblemDetectedLocally:
			client.CloseConnection(connection);
			Console.WriteLine("Client disconnected from server");
			break;
	}
};

utils.SetStatusCallback(status);

Address address = new Address();

address.SetAddress("::1", port);

connection = client.Connect(ref address);

#if VALVESOCKETS_SPAN
	MessageCallback message = (in NetworkingMessage netMessage) => {
		Console.WriteLine("Message received from server - Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
	};
#else
	const int maxMessages = 20;

	NetworkingMessage[] netMessages = new NetworkingMessage[maxMessages];
#endif

while (!Console.KeyAvailable) {
	client.RunCallbacks();

	#if VALVESOCKETS_SPAN
		client.ReceiveMessagesOnConnection(connection, message, 20);
	#else
		int netMessagesCount = client.ReceiveMessagesOnConnection(connection, netMessages, maxMessages);

		if (netMessagesCount > 0) {
			for (int i = 0; i < netMessagesCount; i++) {
				ref NetworkingMessage netMessage = ref netMessages[i];

				Console.WriteLine("Message received from server - Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);

				netMessage.Destroy();
			}
		}
	#endif

	Thread.Sleep(15);
}
Create and send a new message
byte[] data = new byte[64];

sockets.SendMessageToConnection(connection, data);
Copy payload from a message
byte[] buffer = new byte[1024];

netMessage.CopyTo(buffer);
Set a hook for debug information
DebugCallback debug = (type, message) => {
	Console.WriteLine("Debug - Type: " + type + ", Message: " + message);
};

NetworkingUtils utils = new NetworkingUtils();

utils.SetDebugCallback(DebugType.Everything, debug);

Unity

Usage is almost the same as in the .NET environment, except that the console functions must be replaced with functions provided by Unity. If the NetworkingSockets.RunCallbacks() will be called in a game loop, then keep Unity run in background by enabling the appropriate option in the player settings.

API reference

Enumerations

SendFlags

Definitions of a flags for NetworkingSockets.SendMessageToConnection() function:

SendFlags.Unreliable unreliable, delivery of message is not guaranteed, the message may be delivered out of order.

SendFlags.Reliable reliable ordered, a message must be received by the target connection and resend attempts should be made until the message is delivered.

SendFlags.NoNagle a message will not be grouped with other messages within a timer.

SendFlags.NoDelay a message will not be buffered if it can't be sent relatively quickly.

IdentityType

Definitions of identity type for NetworkingIdentity structure:

IdentityType.Invalid unknown or invalid.

IdentityType.SteamID Steam identifier.

IdentityType.IPAddress IPv4/IPv6 address.

ConnectionState

Definitions of connection states for ConnectionInfo.state field:

ConnectionState.None dummy state, the connection doesn't exist or has already been closed.

ConnectionState.Connecting in-progress of establishing a connection initiated by NetworkingSockets.Connect() function.

ConnectionState.FindingRoute if the server accepts the connection, then this connection switch into the rendezvous state, but the end-to-end route is still have not yet established (through the relay network).

ConnectionState.Connected a connection request initiated by NetworkingSockets.Connect() function has completed.

ConnectionState.ClosedByPeer a connection has been closed by the peer, but not closed locally. If there are any messages in the inbound queue, they can be retrieved. Otherwise, nothing may be done with the connection except to close it using NetworkingSockets.CloseConnection() function. The connection still exists from an API perspective and must be closed to free up resources.

ConnectionState.ProblemDetectedLocally a disruption in the connection has been detected locally. Attempts to send further messages will fail. Any remaining received messages in the queue are available. The connection still exists from an API perspective and must be closed to free up resources.

ConfigurationScope

Definitions of configuration scopes:

ConfigurationScope.Global

ConfigurationScope.SocketsInterface

ConfigurationScope.ListenSocket

ConfigurationScope.Connection

ConfigurationDataType

Definitions of configuration data types:

ConfigurationDataType.Int32

ConfigurationDataType.Int64

ConfigurationDataType.Float

ConfigurationDataType.String

ConfigurationDataType.FunctionPtr

ConfigurationValue

Definitions of configuration values:

ConfigurationValue.Invalid

ConfigurationValue.FakePacketLossSend

ConfigurationValue.FakePacketLossRecv

ConfigurationValue.FakePacketLagSend

ConfigurationValue.FakePacketLagRecv

ConfigurationValue.FakePacketReorderSend

ConfigurationValue.FakePacketReorderRecv

ConfigurationValue.FakePacketReorderTime

ConfigurationValue.FakePacketDupSend

ConfigurationValue.FakePacketDupRecv

ConfigurationValue.FakePacketDupTimeMax

ConfigurationValue.TimeoutInitial

ConfigurationValue.TimeoutConnected

ConfigurationValue.SendBufferSize

ConfigurationValue.SendRateMin

ConfigurationValue.SendRateMax

ConfigurationValue.NagleTime

ConfigurationValue.IPAllowWithoutAuth

ConfigurationValue.MTUPacketSize

ConfigurationValue.MTUDataSize

ConfigurationValue.Unencrypted

ConfigurationValue.EnumerateDevVars

ConfigurationValue.SymmetricConnect

ConfigurationValue.LocalVirtualPort

ConfigurationValue.ConnectionStatusChanged

ConfigurationValue.AuthStatusChanged

ConfigurationValue.RelayNetworkStatusChanged

ConfigurationValue.MessagesSessionRequest

ConfigurationValue.MessagesSessionFailed

ConfigurationValue.P2PSTUNServerList

ConfigurationValue.P2PTransportICEEnable

ConfigurationValue.P2PTransportICEPenalty

ConfigurationValue.P2PTransportSDRPenalty

ConfigurationValue.SDRClientConsecutitivePingTimeoutsFailInitial

ConfigurationValue.SDRClientConsecutitivePingTimeoutsFail

ConfigurationValue.SDRClientMinPingsBeforePingAccurate

ConfigurationValue.SDRClientSingleSocket

ConfigurationValue.SDRClientForceRelayCluster

ConfigurationValue.SDRClientDebugTicketAddress

ConfigurationValue.SDRClientForceProxyAddr

ConfigurationValue.SDRClientFakeClusterPing

ConfigurationValue.LogLevelAckRTT

ConfigurationValue.LogLevelPacketDecode

ConfigurationValue.LogLevelMessage

ConfigurationValue.LogLevelPacketGaps

ConfigurationValue.LogLevelP2PRendezvous

ConfigurationValue.LogLevelSDRRelayPings

ConfigurationValueResult

Definitions of configuration value results:

ConfigurationValueResult.BadValue

ConfigurationValueResult.BadScopeObject

ConfigurationValueResult.BufferTooSmall

ConfigurationValueResult.OK

ConfigurationValueResult.OKInherited

DebugType

Definitions of debug types:

DebugType.None

DebugType.Bug

DebugType.Error

DebugType.Important

DebugType.Warning

DebugType.Message

DebugType.Verbose

DebugType.Debug

DebugType.Everything

Result

Definitions of operation result:

Result.OK success.

Result.Fail generic failure.

Result.NoConnection failed network connection.

Result.InvalidParam a parameter is incorrect.

Result.InvalidState called object was in an invalid state.

Result.Ignored target is ignoring a sender.

Delegates

Socket callbacks

Provides per socket events.

StatusCallback(ref StatusInfo info) notifies when dispatch mechanism on the listen socket returns a connection state. A reference to the delegate should be preserved from being garbage collected.

Library callbacks

Provides per application events.

DebugCallback(DebugType type, string message) notifies when debug information with the desired verbosity come up. A reference to the delegate should be preserved from being garbage collected.

Structures

Address

Contains marshalled data with an IP address and port number.

Address.ip IP address in bytes.

Address.port port number.

Address.IsLocalHost checks if identity is localhost.

Address.GetIP() gets an IP address in a printable form.

Address.SetLocalHost(ushort port) sets localhost with a specified port.

Address.SetAddress(string ip, ushort port) sets an IP address (IPv4/IPv6) with a specified port.

Address.Equals(Address other) determines equality of addresses.

Configuration

Contains marshalled data with configuration.

Configuration.value a type of the value described in the ConfigurationValue enumeration.

Configuration.dataType a type of data described in the ConfigurationDataType enumeration.

Configuration.data a union of configuration data.

StatusInfo

Contains marshalled data with connection state.

StatusInfo.connection connection ID.

StatusInfo.connectionInfo essentially ConnectionInfo structure with marshalled data.

ConnectionInfo

Contains marshalled data with connection info.

ConnectionInfo.identity identifier of an endpoint.

ConnectionInfo.userData user-supplied data that set using NetworkingSockets.SetConnectionUserData() function.

ConnectionInfo.listenSocket listen socket for this connection.

ConnectionInfo.address remote address of an endpoint.

ConnectionInfo.state high-level state of the connection described in the ConnectionState enumeration.

ConnectionInfo.endReason basic cause of the connection termination or problem.

ConnectionInfo.endDebug explanation in a human-readable form for connection termination or problem. This is intended for debugging diagnostic purposes only, not for displaying to users. It might have some details specific to the issue.

ConnectionInfo.connectionDescription debug description includes the connection handle, connection type, and peer information.

ConnectionStatus

Contains marshalled data with connection status for frequent requests.

ConnectionStatus.state high-level state of the connection described in the ConnectionState enumeration.

ConnectionStatus.ping current ping in milliseconds.

ConnectionStatus.connectionQualityLocal connection quality measured locally (percentage of packets delivered end-to-end in order).

ConnectionStatus.connectionQualityRemote packet delivery success rate as observed from the remote host.

ConnectionStatus.outPacketsPerSecond current outbound packet rates from recent history.

ConnectionStatus.outBytesPerSecond current outbound data rates from recent history.

ConnectionStatus.inPacketsPerSecond current inbound packet rates from recent history.

ConnectionStatus.inBytesPerSecond current inbound data rates from recent history.

ConnectionStatus.sendRateBytesPerSecond estimated rate at which data can be sent to a peer. It could be significantly higher than ConnectionStatus.outBytesPerSecond, meaning the capacity of the channel is higher than the sent data.

ConnectionStatus.pendingUnreliable number of bytes pending to be sent unreliably. This is data that recently requested to be sent but has not yet actually been put on the wire.

ConnectionStatus.pendingReliable number of bytes pending to be sent reliably. The reliable number also includes data that was previously placed on the wire but has now been scheduled for re-transmission. Thus, it's possible to observe increasing of the bytes between two checks, even if no calls were made to send reliable data between the checks. Data that is awaiting the Nagle delay will appear in these numbers.

ConnectionStatus.sentUnackedReliable number of bytes of reliable data that has been placed the wire, but for which not yet received an acknowledgment, and thus might have to be re-transmitted.

NetworkingIdentity

Contains marshalled data of networking identity.

NetworkingIdentity.type description of a networking identity.

NetworkingIdentity.IsInvalid checks if identity has the invalid type.

NetworkingIdentity.GetSteamID() gets Steam ID.

NetworkingIdentity.SetSteamID(ulong steamID) sets Steam ID.

NetworkingMessage

Contains marshalled data of networking message.

NetworkingMessage.identity identifier of a sender.

NetworkingMessage.connectionUserData user-supplied connection data that set using NetworkingSockets.SetConnectionUserData() function.

NetworkingMessage.timeReceived local timestamp when the message was received.

NetworkingMessage.messageNumber message number assigned by a sender.

NetworkingMessage.data payload of a message.

NetworkingMessage.length length of the payload.

NetworkingMessage.connection connection ID from which the message came from.

NetworkingMessage.channel channel number the message was received on.

NetworkingMessage.flags flags that were used to send the message.

NetworkingMessage.CopyTo(byte[] destination) copies payload from the message to the destination array.

NetworkingMessage.Destroy() destroys the message. Should be called only when the messages are obtained from sockets.

Classes

NetworkingSockets

Contains a managed pointer to the sockets.

NetworkingSockets.CreateListenSocket(ref Address address, Configuration[] configurations) creates a socket with optional configurations and returns a socket ID that listens for incoming connections which initiated by NetworkingSockets.Connect() function.

NetworkingSockets.Connect(ref Address address, Configuration[] configurations) initiates a connection to a foreign host with optional configurations. Returns a local connection ID.

NetworkingSockets.AcceptConnection(Connection connection) accepts an incoming connection that has received on a listen socket. When a connection attempt is received (perhaps after a few basic handshake packets have been exchanged to prevent trivial spoofing), a connection interface object is created in the ConnectionState.Connecting state and a StatusCallback() is called. Returns a result described in the Result enumeration.

NetworkingSockets.CloseConnection(Connection connection, int reason, string debug, bool enableLinger) disconnects from the host and invalidates the connection handle. Any unread data on the connection is discarded. The reason parameter is an optional user-supplied code that will be received on the other end and recorded (when possible) in backend analytics. Debug logging might indicate an error if the reason code out of acceptable range. The debug parameter is an optional human-readable diagnostic string that will be received on the other end and recorded (when possible) in backend analytics. If the user wishes to put the socket into a lingering state, where an attempt is made to flush any remaining sent data, the linger parameter should be enabled, otherwise reliable data is not flushed. If the connection has already ended, the reason code, debug string and linger parameter is ignored. Returns true on success or false on failure.

NetworkingSockets.CloseListenSocket(ListenSocket socket, string remoteReason) destroys the listen socket, and all the client sockets generated by accepting connections on the listen socket. The remote reason determines what cleanup actions are performed on the client sockets being destroyed. If cleanup is requested and the user has requested the listen socket bound to a particular local port to facilitate direct IPv4 connections, then the underlying UDP socket must remain open until all clients have been cleaned up. Returns true on success or false on failure.

NetworkingSockets.SetConnectionUserData(Connection peer, long userData) sets a user-supplied data for the connection. Returns true on success or false on failure.

NetworkingSockets.GetConnectionUserData(Connection peer) returns a user-supplied data or -1 if a handle is invalid or if any data has not be set for the connection.

NetworkingSockets.SetConnectionName(Connection peer, string name) sets a name for the connection, used mostly for debugging.

NetworkingSockets.GetConnectionName(Connection peer, StringBuilder name, int maxLength) fetches connection name to the mutable string. Returns true on success or false on failure.

NetworkingSockets.SendMessageToConnection(Connection connection, byte[] data, int length, SendFlags flags) sends a message to the host on the connected socket. The length and send type parameters are optional. Multiple flags can be specified at once. Returns a result described in the Result enumeration. Pointer IntPtr to a native buffer can be used instead of a reference to a byte array.

NetworkingSockets.FlushMessagesOnConnection(Connection connection) if the Nagle is enabled (it's enabled by default) then the message will be queued up the Nagle time before being sent, to merge small messages into the same packet. Call this function to flush any queued messages and send them immediately on the next transmission time. Returns a result described in the Result enumeration.

NetworkingSockets.ReceiveMessagesOnConnection(Connection connection, NetworkingMessage[] messages, int maxMessages) fetches the next available messages from the socket for a connection. Returns a number of messages or -1 if the connection handle is invalid. The order of the messages returned in the array is relevant. Reliable messages will be received in the order they were sent. If any messages are obtained, message.Destroy() should be called for each of them to free up resources.

NetworkingSockets.GetConnectionInfo(Connection connection, ref ConnectionInfo info) gets information about the specified connection. Returns true on success or false on failure.

NetworkingSockets.GetQuickConnectionStatus(Connection connection, ref ConnectionStatus status) gets a brief set of connection status that can be displayed to the user in-game. Returns true on success or false on failure.

NetworkingSockets.GetDetailedConnectionStatus(Connection connection, StringBuilder status, int statusLength) gets detailed connection stats in a printable form. Returns 0 on success, -1 on failure, or > 0 if a capacity of the mutable string is not enough.

NetworkingSockets.GetListenSocketAddress(ListenSocket socket, ref Address address) gets local IP and port number of a listen socket. Returns true on success or false on failure.

NetworkingSockets.CreateSocketPair(Connection connectionLeft, Connection connectionRight, bool useNetworkLoopback, ref NetworkingIdentity identityLeft, ref NetworkingIdentity identityRight) creates a pair of connections that are talking to each other e.g. a loopback communication. The two connections will be immediately placed into the connected state, and no callbacks will be called. After this, if either connection is closed, the other connection will receive a callback, exactly as if they were communicating over the network. By default, internal buffers are used, completely bypassing the network, the chopping up of messages into packets, encryption, copying the payload, etc. This means that loopback packets, by default, will not simulate lag or loss. Enabled network loopback parameter will cause the socket pair to send packets through the local network loopback device on ephemeral ports. Fake lag and loss are supported in this case, and CPU time is expended to encrypt and decrypt.

NetworkingSockets.GetIdentity() gets an identity associated with sockets.

NetworkingSockets.CreatePollGroup() creates a new poll group for connections. Returns the poll group handle.

NetworkingSockets.DestroyPollGroup(PollGroup pollGroup) destroys a poll group. If there are any connections in the poll group, they are removed from the group and left in a state where they are not part of any poll group. Returns false if passed an invalid poll group handle.

NetworkingSockets.SetConnectionPollGroup(PollGroup pollGroup, Connection connection) assigns a connection to a poll group. A connection may only belong to a single poll group. Adding a connection to a poll group implicitly removes it from any other poll group. You can pass zero value to the poll group parameter to remove a connection from its current poll group. If there are received messages currently pending on the connection, an attempt is made to add them to the queue of messages for the poll group in approximately the order that would have applied if the connection was already part of the poll group at the time that the messages were received. Returns false if the connection handle is invalid or if the poll group handle is invalid.

NetworkingSockets.ReceiveMessagesOnPollGroup() fetches the next available messages from the socket on any connection in the poll group. Examine NetworkingMessage.connection to identify connection. Delivery order of messages among different connections will usually match the order that the last packet was received which completed the message. But this is not a strong guarantee, especially for packets received right as a connection is being assigned to poll group. Delivery order of messages on the same connection is well defined and the same guarantees are present. Messages are not grouped by connection, so they will not necessarily appear consecutively in the list, they may be interleaved with messages for other connections. Returns a number of messages or -1 if the poll group handle is invalid.

NetworkingSockets.RunCallbacks() dispatches callbacks if available.

NetworkingUtils

NetworkingUtils.Dispose() destroys the networking utils and cleanups unmanaged resources.

NetworkingUtils.Time returns a current local monotonic time in microseconds. It never reset while the application remains alive.

NetworkingUtils.FirstConfigurationValue gets the lowest numbered configuration value available in the current environment.

NetworkingUtils.SetStatusCallback(StatusCallback callback) sets a callback for connection status updates. Returns true on success or false on failure.

NetworkingUtils.SetDebugCallback(DebugType detailLevel, DebugCallback callback) sets a callback for debug output.

NetworkingUtils.SetConfigurationValue(ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ConfigurationDataType dataType, IntPtr value) sets a configuration value according to ConfigurationValue, ConfigurationScope, and ConfigurationDataType enumerations. The value parameter should be a reference to the actual value.

NetworkingUtils.SetConfigurationValue(Configuration configuration, ConfigurationScope configurationScope, IntPtr scopeObject) sets a configuration using Configuration structure according to ConfigurationScope enumeration.

NetworkingUtils.GetConfigurationValue(ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ref ConfigurationDataType dataType, ref IntPtr result, ref IntPtr resultLength) gets a configuration value according to ConfigurationValue, ConfigurationScope, and ConfigurationDataType enumerations.

Library

Contains constant fields.

Library.maxCloseMessageLength the maximum length of the reason string in bytes when a connection is closed.

Library.maxMessageSize the maximum size of a single message that can be sent.

Library.Initialize(ref NetworkingIdentity identity, StringBuilder errorMessage) initializes the native library with optional identity that will be associated with sockets. Error message parameter is optional and should be used to determine error during initialization. The capacity of a mutable string for an error message must be equal to Library.maxErrorMessageLength.

Library.Deinitialize() deinitializes the native library. Should be called after the work is done.

valvesockets-csharp's People

Contributors

imerr avatar nxrighthere avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

valvesockets-csharp's Issues

ValveSockets.cs with DynDllImports

Not an actual issue, but I wanted to post this here in case anyone else ran into the same problem so they don't have to do the work of converting it themselves.

https://github.com/PhantomGamers/ValveSockets-CSharp/blob/monomod-dyndll/ValveSockets.cs

has the [DllImport] lines switched to [DynDllImport] which makes it compatible to load from a BepInEx plugin

(This requires MonoMod.Utils, or the BepInEx.Core package which has it included)

(credit to @Yamashi for figuring out the entrypoint bit for overloads)

Question about performance

Hey there,
I am a big fan of your benchmark tests, I went to take a look to see if you happened to add this one in the mix but didn't see it. Did you ever get around to running your usual tests against this as well? I am interested to see how it stacks up against the usuals.

Thanks!
-MH

Error - Access Violation

I'm just setting everything up to use the library.
I've got a the simple example server -

using System;
using System.Threading;
using Valve.Sockets;


class Program
{
    static void Main(string[] args)
    {
        NetworkingSockets server = new NetworkingSockets();
        Address address = new Address();

        address.SetAddress("::0", 8030);

        uint listenSocket = server.CreateListenSocket(ref address);

        StatusCallback status = (info, context) => {
            switch (info.connectionInfo.state)
            {
                case ConnectionState.None:
                    break;

                case ConnectionState.Connecting:
                    server.AcceptConnection(info.connection);
                    break;

                case ConnectionState.Connected:
                    Console.WriteLine("Client connected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
                    break;

                case ConnectionState.ClosedByPeer:
                    server.CloseConnection(info.connection);
                    Console.WriteLine("Client disconnected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
                    break;
            }
        };

        MessageCallback message = (in NetworkingMessage netMessage) => {
            Console.WriteLine("Message received from - ID: " + netMessage.connection + ", Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
        };

        while (!Console.KeyAvailable)
        {
            server.DispatchCallback(status);
            server.ReceiveMessagesOnListenSocket(listenSocket, message, 20);
            Thread.Sleep(15);
        }
    }
}

However after running it in debugging for couple of seconds it crashes with error (i'll just include the full console output) -

'dotnet.exe' (CoreCLR: DefaultDomain): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Users\Marcel\Documents\Github2\Hedark2\test4\bin\Debug\netcoreapp2.1\test4.dll'. Symbols loaded.
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\System.Runtime.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\System.Console.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\System.Threading.Thread.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Step into: Stepping over non-user code 'Program.<>c__DisplayClass0_0..ctor'
'dotnet.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\System.Runtime.InteropServices.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
The program '[1364] dotnet.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.

Any help would be appreciated very much!
Thanks

Support for 1.4.0 version

Hey,
I'm currently in the process of evaluating using GNS as a network backend
Your wrapper works well (thanks!), but we're having some issues getting the whole thing to run on linux and I think I've tracked it down to a 1.3.0 compatibility issue. Seems to work perfectly with 1.2.0

The issue presents itself as follows:
1.3.0:

$ mono GNSTest.exe
Client 65879239 -> None
Client 65879239 -> 5003

(5003 is a new server timeout status)

1.2.0:

$ mono GNSTest.exe
Client 1015838903 -> Connecting
Client 1015838903 -> Connected
Client connected - ID: 1015838903, IP: 192.168.0.x
[...]
  • Connecting to a windows-based server, either localhost or a different machine on lan works fine (WAN likely too)
  • Connecting to a linux-based server (as a different machine on LAN) does not work, the server gets/initialized the connection in the "None" state and then times out after the x second connection timeout
  • Connecting to the "example_chat" server running on the same linux machine works
  • Tried 1.3.0 libraries built on the same linux machine and ci-built ones, with dependencies from the os package manager (apt) and ones built from source

I've had a browse through the release notes & changes, but there isn't anything obvious I could spot to cause the issue. I'm just using the example server code from the readme (with/without span) to reproduce it

Any chance you could have a look at this or point me towards how to investigate this further?

Non-global connection callbacks

Hi!

Is there a way to set a connection status handler callback for a specific NetworkingSockets instance?

Currently, it's recommended to use NetworkingUtils.SetStatusCallback. However, as far as I see, this sets a global per application callback, which doesn't allow to create both client and server in a single app.

Thanks!

Issue with basic server example for Unity

Hey there!

I'm trying to put together a basic Unity package with some niceties for people that want to use this library. You can find the starting point here. However, I'm trying to port your simple server example to more idiomatic Unity, but it's currently crashing on play here:

Application Specific Information:
libGameNetworkingSockets.dylib
abort() called
terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument

Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x00007fff5e783b66 __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff5e94e080 pthread_kill + 333
2   libsystem_c.dylib             	0x00007fff5e6df1ae abort + 127
3   libmonobdwgc-2.0.dylib        	0x000000013e5aa4b2 mono_handle_native_crash + 585
4   libsystem_platform.dylib      	0x00007fff5e941f5a _sigtramp + 26
5   com.unity3d.UnityEditor5.x    	0x0000000100020008 floor1_encode + 696
6   libsystem_c.dylib             	0x00007fff5e6df1ae abort + 127
7   libc++abi.dylib               	0x00007fff5c5d9f8f abort_message + 245
8   libc++abi.dylib               	0x00007fff5c5da113 default_terminate_handler() + 241
9   libobjc.A.dylib               	0x00007fff5da1beab _objc_terminate() + 105
10  libc++abi.dylib               	0x00007fff5c5f57c9 std::__terminate(void (*)()) + 8
11  libc++abi.dylib               	0x00007fff5c5f526f __cxa_throw + 121
12  libc++.1.dylib                	0x00007fff5c5c87af std::__1::__throw_system_error(int, char const*) + 77
13  libc++.1.dylib                	0x00007fff5c5bac93 std::__1::mutex::lock() + 29
14  libc++.1.dylib                	0x00007fff5c5bb118 std::__1::recursive_timed_mutex::lock() + 42
15  libGameNetworkingSockets.dylib	0x0000000120635a40 SteamNetworkingSocketsLib::SteamDatagramTransportLock::Lock() + 16 (steamnetworkingsockets_lowlevel.cpp:75)
16  libGameNetworkingSockets.dylib	0x0000000120626f95 SteamNetworkingSocketsLib::EnsureConfigValueTableInitted() + 53 (steamnetworkingsockets_lowlevel.h:354)
17  libGameNetworkingSockets.dylib	0x000000012062761f SteamNetworkingSocketsLib::CSteamNetworkingSockets::CSteamNetworkingSockets() + 447 (vector:1471)
18  libGameNetworkingSockets.dylib	0x000000012062cd48 _GLOBAL__sub_I_csteamnetworkingsockets.cpp + 2360 (csteamnetworkingsockets.cpp:1239)

Wondering if you have any insight into why this may be happening! Also, not sure if it would be an issue with the wrapper or the main lib. Worth nothing I'm working from a compiled dylib file on OSX, compiled with the latest master from the main repo.

Application didn't accept or close incoming connection in a reasonable amount of time

Hey. I am trying to include this Wrapper into my Unity Projects and as soon as I tried to connect to the server, I get the following messages:

Debug - Type: Bug, Message: E:\Extra\Tudor\Projects\MobileController\GameSockets\GameNetworkingSockets-1.2.0\vcpkg\buildtrees\gamenetworkingsockets\src\7a54b1e6c2-a58e0d55db.clean\src\steamnetworkingsockets\clientlib\steamnetworkingsockets_connections.cpp(3267): Application didn't accept or close incoming connection in a reasonable amount of time. This is probably a bug.
UnityEngine.MonoBehaviour:print (object)
Server/<>c:b__7_1 (Valve.Sockets.DebugType,string) (at Assets/Server.cs:53)

Debug - Type: Message, Message: [#2350480830 UDP [::1]:57469] problem detected locally (5003): App didn't accept or close incoming connection in time.
UnityEngine.MonoBehaviour:print (object)
Server/<>c:b__7_1 (Valve.Sockets.DebugType,string) (at Assets/Server.cs:53)

Debug - Type: Bug, Message: [#2350480830 UDP [::1]:57469] We are in state 5 and have been waiting 20.0s to be cleaned up. Did you forget to call CloseConnection()?
UnityEngine.MonoBehaviour:print (object)
Server/<>c:b__7_1 (Valve.Sockets.DebugType,string) (at Assets/Server.cs:53)

Do you have any idea how to solve this?

I have attached the source code for both the client and server.
client.docx
server.docx

P.S. The two project are running on the same machine.

Handling case k_ESteamNetworkingConnectionState_ProblemDetectedLocally: is missing

Hey,

Thanks for the binding class of GNS. It is helpful.

What i noticed is, case " k_ESteamNetworkingConnectionState_ProblemDetectedLocally:" is not handled on below sample server application.

StatusCallback status = (info, context) => {
	switch (info.connectionInfo.state) {
		case ConnectionState.None:
			break;

		case ConnectionState.Connecting:
			server.AcceptConnection(info.connection);
			server.SetConnectionPollGroup(pollGroup, info.connection);
			break;

		case ConnectionState.Connected:
			Console.WriteLine("Client connected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;

		case ConnectionState.ClosedByPeer:
			server.CloseConnection(info.connection);
			Console.WriteLine("Client disconnected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;
	}
};

So disconnected client resources on native side not removed (by not calling CloseConnection()).

That can be problematic when you have good amount of connect/disconnect use cases. like 16k clients connected to server for some time interval. After a while a new client becomes unable to connect, because of the duplicate data on containers on native side.

I address the problem at this issue and it is discovered that it is the binding class is missing the handling "k_ESteamNetworkingConnectionState_ProblemDetectedLocally".

So better to have case ConnectionState.ProblemDetectedLocally: to free the resources as below:

StatusCallback status = (info, context) => {
	switch (info.connectionInfo.state) {
		case ConnectionState.None:
			break;

		case ConnectionState.Connecting:
			server.AcceptConnection(info.connection);
			server.SetConnectionPollGroup(pollGroup, info.connection);
			break;

		case ConnectionState.Connected:
			Console.WriteLine("Client connected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;

		case ConnectionState.ClosedByPeer:
                case ConnectionState.ProblemDetectedLocally:
			server.CloseConnection(info.connection);
			Console.WriteLine("Client disconnected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
			break;
	}
};

Multiple problems when using with Unity/MacOS

Hi, I'm evaluating this library for some time now in Unity. I managed to import it into the project with some issues (for some reason it doesn't load the first time you run the game), however it doesn't work out of the box for me. I've compiled the library from 1.1.0 and took the same version of the bindings. Here are the problems I've encountered so far:

  1. client.DispatchCallback(status) is getting called with info structure containing garbage. It looks like there is a problem with marshalling. I was able to fix this with adding "ref" to the StatusCallback declaration:
    public delegate void StatusCallback(ref StatusInfo info, IntPtr context);
    I'm not an expert in c# marshalling and not sure this is a right fix and the system is now working as it supposed to, or is it going to break other platforms.

  2. Once StatusCallback is changed, the structure still seems to be off. It appears that some of the field values are shifted to neighbour fields. I was able to fix this by adding StructLayoutAttribute.Pack = 4 to StatusInfo structure declaration:
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct StatusInfo {
    ...
    as it looks like "connection" variable takes whole 8 bytes instead of 4. Not sure why Unity/Mono has a different default Pack setting, but I think this should fix the problem for Mono and not break other platforms.

  3. Just a suggestion to mention deinitialization procedure, especially if you set a debug callback like described in the "Usage":

Library.Initialize();
NetworkingUtils utils = new NetworkingUtils();
utils.SetDebugCallback(DebugType.Everything, debug);

you absolutely MUST set it to None when you're done:

utils.SetDebugCallback(DebugType.None, null);
Library.Deinitilize();

otherwise Unity will freeze on the next launch (probably because debug callback is now invalid and crashes silently somewhere inside).

Changed callback plumbing

FYI, I've changed how callbacks are plumbed, and I'm sure that I just broke this library. The good news is that now it is possible to use the same mechanism either in Steamworks or the opensource version. Let me know if anything is unclear.

P2P API on C# side

Hello, first of all thanks for your efforts so far. It helped so much along the way.

I was wondering if you are planning to implement the P2P callbacks and function calls on the C# side. Especially on Signalling implementation.

CloseConnection reason value check seems is not sync with native side.

Hey,

binding class has below method:

public bool CloseConnection(Connection connection, int reason, string debug, bool enableLinger) {
if (reason > Library.maxCloseReasonValue)
	throw new ArgumentOutOfRangeException("reason");

if (debug.Length > Library.maxCloseMessageLength)
	throw new ArgumentOutOfRangeException("debug");

return Native.SteamAPI_ISteamNetworkingSockets_CloseConnection(nativeSockets, connection, reason, debug, enableLinger);
		}

with maxCloseReasonValue is set to 999.
But on native side things are quite different on APICloseConnection api.

if ( nReason == 0 )
{
	nReason = k_ESteamNetConnectionEnd_App_Generic;
}
else if ( nReason < k_ESteamNetConnectionEnd_App_Min || nReason > k_ESteamNetConnectionEnd_AppException_Max )
{
	// Use a special value so that we can detect if people have this bug in our analytics
	nReason = k_ESteamNetConnectionEnd_App_Max;
	pszDebug = "Invalid numeric reason code";
}		

and steamnetworkingtypes.h tells:

// 1xxx: Application ended the connection in a "usual" manner.
// E.g.: user intentionally disconnected from the server,
// gameplay ended normally, etc
k_ESteamNetConnectionEnd_App_Min = 1000,
k_ESteamNetConnectionEnd_App_Generic = k_ESteamNetConnectionEnd_App_Min,
// Use codes in this range for "normal" disconnection
k_ESteamNetConnectionEnd_App_Max = 1999,

// 2xxx: Application ended the connection in some sort of exceptional
// or unusual manner that might indicate a bug or configuration
// issue.
//
k_ESteamNetConnectionEnd_AppException_Min = 2000,
k_ESteamNetConnectionEnd_AppException_Generic = k_ESteamNetConnectionEnd_AppException_Min,
// Use codes in this range for "unusual" disconnection
k_ESteamNetConnectionEnd_AppException_Max = 2999

which makes the reason code expected between 1000 and 2999. As long as binding class expect below 999, otherwise it will give exception. If you give below 999, you may get "invalid numeric reason code" error on native side. In other words it seems native and binding sides expecting different values.

Unity, DllNotFoundException

Hi,
Im pretty excited to use this Wrapper but i dont rly know how to start.
I created a new Project, add a Plugins Folder and copied the GameNetworkingSockets into this Folder. Tryed to start and got this Error Message "DllNotFoundException: GameNetworkingSockets".

Any hints on this ?

GameNetworkingSockets performance question

Hi, i am going to start by saying that i am using facepunch.steamworks for sockets, not this. However, im considering the switch to this for one reason, and im wondering if something is wrong. I implimented my own netcode using system.net.sockets, with tcp and udp support. I didnt want players to have to port forward to play with one another, so i implimented steam networking sockets, sending reliable packets to replace tcp and unreliable packets to replace udp (makes sense, right?). the issue that im having is that vs my own solution, my game is so slow its unplayable. the ping is just super high for clients, like 240 from USE to UK. I did some testing with a ping pong packet, and it turns out that both unreliable and reliable messages have the exact same ping time, which doesnt make sense to me. what is the point of an unreliable packet if its the same speed as a reliable one? is this an issue with facepunch.steamworks? what kind of performance do you get using steamnetworkingsockets?

IL2CPP callbacks compatibility

it seems that this code doesn't support unity IL2CPP because of

: IL2CPP does not support marshaling delegates that point to instance methods to native code

do you have any suggestions about it?

Unity Editor crashes when entering play mode for second time

Hi,

I'm encountering an issue where the Unity Editor crashes when I enter play mode for the second time.
Error flow:

Press play,
Library initializes (OnAwake).
.. use library (all works fine) ..
Library Deinitialize (OnApplicationQuit)
Exit Playmode
Press Play again... crash...

I'm running on Windows using 1.2 release for both ValveSockets-CSharp and GameNetworkingSockets.

Any other info can I provide you with?

Thanks

Unity crash !

Hello!

When I try to connect the client with the client.Connect() function, Unity crash without error message. I have no problem when I start the server. This problem only appears for the client connection. Do you have this problem too? If yes or if you already had it, do you know how to solve it?

Thank you in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.