├── LICENSE
├── README.md
└── ValveSockets.cs
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Stanislav Denisov (nxrighthere@gmail.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [](https://github.com/nxrighthere/ValveSockets-CSharp/releases)
6 |
7 | This repository provides a managed C# abstraction of [GameNetworkingSockets](https://github.com/ValveSoftware/GameNetworkingSockets) library which is created and maintained by [Valve Software](https://www.valvesoftware.com). You will need to [build](https://github.com/ValveSoftware/GameNetworkingSockets#building) the native library with all required dependencies before you get started.
8 |
9 | The project is [updating](https://github.com/nxrighthere/ValveSockets-CSharp/issues/8#issuecomment-616596904) in accordance with the [releases](https://github.com/ValveSoftware/GameNetworkingSockets/releases) of the native library.
10 |
11 | Building
12 | --------
13 |
14 | A managed assembly can be built using any available compiling platform that supports C# 3.0 or higher.
15 |
16 | Define `VALVESOCKETS_SPAN` to enable support for Span. Please, follow [these steps](https://github.com/nxrighthere/ValveSockets-CSharp/issues/3#issuecomment-491916163) to enable fast access to native memory blocks and improve performance.
17 |
18 | Usage
19 | --------
20 | Before starting to work, the library should be initialized using `Valve.Sockets.Library.Initialize();` function.
21 |
22 | After the work is done, deinitialize the library using `Valve.Sockets.Library.Deinitialize();` function.
23 |
24 | ### .NET environment
25 | ##### Start a new server
26 | ```c#
27 | NetworkingSockets server = new NetworkingSockets();
28 |
29 | uint pollGroup = server.CreatePollGroup();
30 |
31 | StatusCallback status = (ref StatusInfo info) => {
32 | switch (info.connectionInfo.state) {
33 | case ConnectionState.None:
34 | break;
35 |
36 | case ConnectionState.Connecting:
37 | server.AcceptConnection(info.connection);
38 | server.SetConnectionPollGroup(pollGroup, info.connection);
39 | break;
40 |
41 | case ConnectionState.Connected:
42 | Console.WriteLine("Client connected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
43 | break;
44 |
45 | case ConnectionState.ClosedByPeer:
46 | case ConnectionState.ProblemDetectedLocally:
47 | server.CloseConnection(info.connection);
48 | Console.WriteLine("Client disconnected - ID: " + info.connection + ", IP: " + info.connectionInfo.address.GetIP());
49 | break;
50 | }
51 | };
52 |
53 | utils.SetStatusCallback(status);
54 |
55 | Address address = new Address();
56 |
57 | address.SetAddress("::0", port);
58 |
59 | uint listenSocket = server.CreateListenSocket(ref address);
60 |
61 | #if VALVESOCKETS_SPAN
62 | MessageCallback message = (in NetworkingMessage netMessage) => {
63 | Console.WriteLine("Message received from - ID: " + netMessage.connection + ", Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
64 | };
65 | #else
66 | const int maxMessages = 20;
67 |
68 | NetworkingMessage[] netMessages = new NetworkingMessage[maxMessages];
69 | #endif
70 |
71 | while (!Console.KeyAvailable) {
72 | server.RunCallbacks();
73 |
74 | #if VALVESOCKETS_SPAN
75 | server.ReceiveMessagesOnPollGroup(pollGroup, message, 20);
76 | #else
77 | int netMessagesCount = server.ReceiveMessagesOnPollGroup(pollGroup, netMessages, maxMessages);
78 |
79 | if (netMessagesCount > 0) {
80 | for (int i = 0; i < netMessagesCount; i++) {
81 | ref NetworkingMessage netMessage = ref netMessages[i];
82 |
83 | Console.WriteLine("Message received from - ID: " + netMessage.connection + ", Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
84 |
85 | netMessage.Destroy();
86 | }
87 | }
88 | #endif
89 |
90 | Thread.Sleep(15);
91 | }
92 |
93 | server.DestroyPollGroup(pollGroup);
94 | ```
95 |
96 | ##### Start a new client
97 | ```c#
98 | NetworkingSockets client = new NetworkingSockets();
99 |
100 | uint connection = 0;
101 |
102 | StatusCallback status = (ref StatusInfo info) => {
103 | switch (info.connectionInfo.state) {
104 | case ConnectionState.None:
105 | break;
106 |
107 | case ConnectionState.Connected:
108 | Console.WriteLine("Client connected to server - ID: " + connection);
109 | break;
110 |
111 | case ConnectionState.ClosedByPeer:
112 | case ConnectionState.ProblemDetectedLocally:
113 | client.CloseConnection(connection);
114 | Console.WriteLine("Client disconnected from server");
115 | break;
116 | }
117 | };
118 |
119 | utils.SetStatusCallback(status);
120 |
121 | Address address = new Address();
122 |
123 | address.SetAddress("::1", port);
124 |
125 | connection = client.Connect(ref address);
126 |
127 | #if VALVESOCKETS_SPAN
128 | MessageCallback message = (in NetworkingMessage netMessage) => {
129 | Console.WriteLine("Message received from server - Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
130 | };
131 | #else
132 | const int maxMessages = 20;
133 |
134 | NetworkingMessage[] netMessages = new NetworkingMessage[maxMessages];
135 | #endif
136 |
137 | while (!Console.KeyAvailable) {
138 | client.RunCallbacks();
139 |
140 | #if VALVESOCKETS_SPAN
141 | client.ReceiveMessagesOnConnection(connection, message, 20);
142 | #else
143 | int netMessagesCount = client.ReceiveMessagesOnConnection(connection, netMessages, maxMessages);
144 |
145 | if (netMessagesCount > 0) {
146 | for (int i = 0; i < netMessagesCount; i++) {
147 | ref NetworkingMessage netMessage = ref netMessages[i];
148 |
149 | Console.WriteLine("Message received from server - Channel ID: " + netMessage.channel + ", Data length: " + netMessage.length);
150 |
151 | netMessage.Destroy();
152 | }
153 | }
154 | #endif
155 |
156 | Thread.Sleep(15);
157 | }
158 | ```
159 |
160 | ##### Create and send a new message
161 | ```c#
162 | byte[] data = new byte[64];
163 |
164 | sockets.SendMessageToConnection(connection, data);
165 | ```
166 |
167 | ##### Copy payload from a message
168 | ```c#
169 | byte[] buffer = new byte[1024];
170 |
171 | netMessage.CopyTo(buffer);
172 | ```
173 |
174 | ##### Set a hook for debug information
175 | ```c#
176 | DebugCallback debug = (type, message) => {
177 | Console.WriteLine("Debug - Type: " + type + ", Message: " + message);
178 | };
179 |
180 | NetworkingUtils utils = new NetworkingUtils();
181 |
182 | utils.SetDebugCallback(DebugType.Everything, debug);
183 | ```
184 |
185 | ### Unity
186 | 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.
187 |
188 | API reference
189 | --------
190 | ### Enumerations
191 | #### SendFlags
192 | Definitions of a flags for `NetworkingSockets.SendMessageToConnection()` function:
193 |
194 | `SendFlags.Unreliable` unreliable, delivery of message is not guaranteed, the message may be delivered out of order.
195 |
196 | `SendFlags.Reliable` reliable ordered, a message must be received by the target connection and resend attempts should be made until the message is delivered.
197 |
198 | `SendFlags.NoNagle` a message will not be grouped with other messages within a timer.
199 |
200 | `SendFlags.NoDelay` a message will not be buffered if it can't be sent relatively quickly.
201 |
202 | #### IdentityType
203 | Definitions of identity type for `NetworkingIdentity` structure:
204 |
205 | `IdentityType.Invalid` unknown or invalid.
206 |
207 | `IdentityType.SteamID` Steam identifier.
208 |
209 | `IdentityType.IPAddress` IPv4/IPv6 address.
210 |
211 | #### ConnectionState
212 | Definitions of connection states for `ConnectionInfo.state` field:
213 |
214 | `ConnectionState.None` dummy state, the connection doesn't exist or has already been closed.
215 |
216 | `ConnectionState.Connecting` in-progress of establishing a connection initiated by `NetworkingSockets.Connect()` function.
217 |
218 | `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).
219 |
220 | `ConnectionState.Connected` a connection request initiated by `NetworkingSockets.Connect()` function has completed.
221 |
222 | `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.
223 |
224 | `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.
225 |
226 | #### ConfigurationScope
227 | Definitions of configuration scopes:
228 |
229 | `ConfigurationScope.Global`
230 |
231 | `ConfigurationScope.SocketsInterface`
232 |
233 | `ConfigurationScope.ListenSocket`
234 |
235 | `ConfigurationScope.Connection`
236 |
237 | #### ConfigurationDataType
238 | Definitions of configuration data types:
239 |
240 | `ConfigurationDataType.Int32`
241 |
242 | `ConfigurationDataType.Int64`
243 |
244 | `ConfigurationDataType.Float`
245 |
246 | `ConfigurationDataType.String`
247 |
248 | `ConfigurationDataType.FunctionPtr`
249 |
250 | #### ConfigurationValue
251 | Definitions of configuration values:
252 |
253 | `ConfigurationValue.Invalid`
254 |
255 | `ConfigurationValue.FakePacketLossSend`
256 |
257 | `ConfigurationValue.FakePacketLossRecv`
258 |
259 | `ConfigurationValue.FakePacketLagSend`
260 |
261 | `ConfigurationValue.FakePacketLagRecv`
262 |
263 | `ConfigurationValue.FakePacketReorderSend`
264 |
265 | `ConfigurationValue.FakePacketReorderRecv`
266 |
267 | `ConfigurationValue.FakePacketReorderTime`
268 |
269 | `ConfigurationValue.FakePacketDupSend`
270 |
271 | `ConfigurationValue.FakePacketDupRecv`
272 |
273 | `ConfigurationValue.FakePacketDupTimeMax`
274 |
275 | `ConfigurationValue.TimeoutInitial`
276 |
277 | `ConfigurationValue.TimeoutConnected`
278 |
279 | `ConfigurationValue.SendBufferSize`
280 |
281 | `ConfigurationValue.SendRateMin`
282 |
283 | `ConfigurationValue.SendRateMax`
284 |
285 | `ConfigurationValue.NagleTime`
286 |
287 | `ConfigurationValue.IPAllowWithoutAuth`
288 |
289 | `ConfigurationValue.MTUPacketSize`
290 |
291 | `ConfigurationValue.MTUDataSize`
292 |
293 | `ConfigurationValue.Unencrypted`
294 |
295 | `ConfigurationValue.EnumerateDevVars`
296 |
297 | `ConfigurationValue.SymmetricConnect`
298 |
299 | `ConfigurationValue.LocalVirtualPort`
300 |
301 | `ConfigurationValue.ConnectionStatusChanged`
302 |
303 | `ConfigurationValue.AuthStatusChanged`
304 |
305 | `ConfigurationValue.RelayNetworkStatusChanged`
306 |
307 | `ConfigurationValue.MessagesSessionRequest`
308 |
309 | `ConfigurationValue.MessagesSessionFailed`
310 |
311 | `ConfigurationValue.P2PSTUNServerList`
312 |
313 | `ConfigurationValue.P2PTransportICEEnable`
314 |
315 | `ConfigurationValue.P2PTransportICEPenalty`
316 |
317 | `ConfigurationValue.P2PTransportSDRPenalty`
318 |
319 | `ConfigurationValue.SDRClientConsecutitivePingTimeoutsFailInitial`
320 |
321 | `ConfigurationValue.SDRClientConsecutitivePingTimeoutsFail`
322 |
323 | `ConfigurationValue.SDRClientMinPingsBeforePingAccurate`
324 |
325 | `ConfigurationValue.SDRClientSingleSocket`
326 |
327 | `ConfigurationValue.SDRClientForceRelayCluster`
328 |
329 | `ConfigurationValue.SDRClientDebugTicketAddress`
330 |
331 | `ConfigurationValue.SDRClientForceProxyAddr`
332 |
333 | `ConfigurationValue.SDRClientFakeClusterPing`
334 |
335 | `ConfigurationValue.LogLevelAckRTT`
336 |
337 | `ConfigurationValue.LogLevelPacketDecode`
338 |
339 | `ConfigurationValue.LogLevelMessage`
340 |
341 | `ConfigurationValue.LogLevelPacketGaps`
342 |
343 | `ConfigurationValue.LogLevelP2PRendezvous`
344 |
345 | `ConfigurationValue.LogLevelSDRRelayPings`
346 |
347 | #### ConfigurationValueResult
348 | Definitions of configuration value results:
349 |
350 | `ConfigurationValueResult.BadValue`
351 |
352 | `ConfigurationValueResult.BadScopeObject`
353 |
354 | `ConfigurationValueResult.BufferTooSmall`
355 |
356 | `ConfigurationValueResult.OK`
357 |
358 | `ConfigurationValueResult.OKInherited`
359 |
360 | #### DebugType
361 | Definitions of debug types:
362 |
363 | `DebugType.None`
364 |
365 | `DebugType.Bug`
366 |
367 | `DebugType.Error`
368 |
369 | `DebugType.Important`
370 |
371 | `DebugType.Warning`
372 |
373 | `DebugType.Message`
374 |
375 | `DebugType.Verbose`
376 |
377 | `DebugType.Debug`
378 |
379 | `DebugType.Everything`
380 |
381 | #### Result
382 | Definitions of operation result:
383 |
384 | `Result.OK` success.
385 |
386 | `Result.Fail` generic failure.
387 |
388 | `Result.NoConnection` failed network connection.
389 |
390 | `Result.InvalidParam` a parameter is incorrect.
391 |
392 | `Result.InvalidState` called object was in an invalid state.
393 |
394 | `Result.Ignored` target is ignoring a sender.
395 |
396 | ### Delegates
397 | #### Socket callbacks
398 | Provides per socket events.
399 |
400 | `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.
401 |
402 | #### Library callbacks
403 | Provides per application events.
404 |
405 | `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.
406 |
407 | ### Structures
408 | #### Address
409 | Contains marshalled data with an IP address and port number.
410 |
411 | `Address.ip` IP address in bytes.
412 |
413 | `Address.port` port number.
414 |
415 | `Address.IsLocalHost` checks if identity is localhost.
416 |
417 | `Address.GetIP()` gets an IP address in a printable form.
418 |
419 | `Address.SetLocalHost(ushort port)` sets localhost with a specified port.
420 |
421 | `Address.SetAddress(string ip, ushort port)` sets an IP address (IPv4/IPv6) with a specified port.
422 |
423 | `Address.Equals(Address other)` determines equality of addresses.
424 |
425 | #### Configuration
426 | Contains marshalled data with configuration.
427 |
428 | `Configuration.value` a type of the value described in the `ConfigurationValue` enumeration.
429 |
430 | `Configuration.dataType` a type of data described in the `ConfigurationDataType` enumeration.
431 |
432 | `Configuration.data` a union of configuration data.
433 |
434 | #### StatusInfo
435 | Contains marshalled data with connection state.
436 |
437 | `StatusInfo.connection` connection ID.
438 |
439 | `StatusInfo.connectionInfo` essentially `ConnectionInfo` structure with marshalled data.
440 |
441 | #### ConnectionInfo
442 | Contains marshalled data with connection info.
443 |
444 | `ConnectionInfo.identity` identifier of an endpoint.
445 |
446 | `ConnectionInfo.userData` user-supplied data that set using `NetworkingSockets.SetConnectionUserData()` function.
447 |
448 | `ConnectionInfo.listenSocket` listen socket for this connection.
449 |
450 | `ConnectionInfo.address` remote address of an endpoint.
451 |
452 | `ConnectionInfo.state` high-level state of the connection described in the `ConnectionState` enumeration.
453 |
454 | `ConnectionInfo.endReason` basic cause of the connection termination or problem.
455 |
456 | `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.
457 |
458 | `ConnectionInfo.connectionDescription` debug description includes the connection handle, connection type, and peer information.
459 |
460 | #### ConnectionStatus
461 | Contains marshalled data with connection status for frequent requests.
462 |
463 | `ConnectionStatus.state` high-level state of the connection described in the `ConnectionState` enumeration.
464 |
465 | `ConnectionStatus.ping` current ping in milliseconds.
466 |
467 | `ConnectionStatus.connectionQualityLocal` connection quality measured locally (percentage of packets delivered end-to-end in order).
468 |
469 | `ConnectionStatus.connectionQualityRemote` packet delivery success rate as observed from the remote host.
470 |
471 | `ConnectionStatus.outPacketsPerSecond` current outbound packet rates from recent history.
472 |
473 | `ConnectionStatus.outBytesPerSecond` current outbound data rates from recent history.
474 |
475 | `ConnectionStatus.inPacketsPerSecond` current inbound packet rates from recent history.
476 |
477 | `ConnectionStatus.inBytesPerSecond` current inbound data rates from recent history.
478 |
479 | `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.
480 |
481 | `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.
482 |
483 | `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.
484 |
485 | `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.
486 |
487 | #### NetworkingIdentity
488 | Contains marshalled data of networking identity.
489 |
490 | `NetworkingIdentity.type` description of a networking identity.
491 |
492 | `NetworkingIdentity.IsInvalid` checks if identity has the invalid type.
493 |
494 | `NetworkingIdentity.GetSteamID()` gets Steam ID.
495 |
496 | `NetworkingIdentity.SetSteamID(ulong steamID)` sets Steam ID.
497 |
498 | #### NetworkingMessage
499 | Contains marshalled data of networking message.
500 |
501 | `NetworkingMessage.identity` identifier of a sender.
502 |
503 | `NetworkingMessage.connectionUserData` user-supplied connection data that set using `NetworkingSockets.SetConnectionUserData()` function.
504 |
505 | `NetworkingMessage.timeReceived` local timestamp when the message was received.
506 |
507 | `NetworkingMessage.messageNumber` message number assigned by a sender.
508 |
509 | `NetworkingMessage.data` payload of a message.
510 |
511 | `NetworkingMessage.length` length of the payload.
512 |
513 | `NetworkingMessage.connection` connection ID from which the message came from.
514 |
515 | `NetworkingMessage.channel` channel number the message was received on.
516 |
517 | `NetworkingMessage.flags` flags that were used to send the message.
518 |
519 | `NetworkingMessage.CopyTo(byte[] destination)` copies payload from the message to the destination array.
520 |
521 | `NetworkingMessage.Destroy()` destroys the message. Should be called only when the messages are obtained from sockets.
522 |
523 | ### Classes
524 | #### NetworkingSockets
525 | Contains a managed pointer to the sockets.
526 |
527 | `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.
528 |
529 | `NetworkingSockets.Connect(ref Address address, Configuration[] configurations)` initiates a connection to a foreign host with optional configurations. Returns a local connection ID.
530 |
531 | `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.
532 |
533 | `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.
534 |
535 | `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.
536 |
537 | `NetworkingSockets.SetConnectionUserData(Connection peer, long userData)` sets a user-supplied data for the connection. Returns true on success or false on failure.
538 |
539 | `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.
540 |
541 | `NetworkingSockets.SetConnectionName(Connection peer, string name)` sets a name for the connection, used mostly for debugging.
542 |
543 | `NetworkingSockets.GetConnectionName(Connection peer, StringBuilder name, int maxLength)` fetches connection name to the mutable string. Returns true on success or false on failure.
544 |
545 | `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.
546 |
547 | `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.
548 |
549 | `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.
550 |
551 | `NetworkingSockets.GetConnectionInfo(Connection connection, ref ConnectionInfo info)` gets information about the specified connection. Returns true on success or false on failure.
552 |
553 | `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.
554 |
555 | `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.
556 |
557 | `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.
558 |
559 | `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.
560 |
561 | `NetworkingSockets.GetIdentity()` gets an identity associated with sockets.
562 |
563 | `NetworkingSockets.CreatePollGroup()` creates a new poll group for connections. Returns the poll group handle.
564 |
565 | `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.
566 |
567 | `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.
568 |
569 | `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.
570 |
571 | `NetworkingSockets.RunCallbacks()` dispatches callbacks if available.
572 |
573 | #### NetworkingUtils
574 |
575 | `NetworkingUtils.Dispose()` destroys the networking utils and cleanups unmanaged resources.
576 |
577 | `NetworkingUtils.Time` returns a current local monotonic time in microseconds. It never reset while the application remains alive.
578 |
579 | `NetworkingUtils.FirstConfigurationValue` gets the lowest numbered configuration value available in the current environment.
580 |
581 | `NetworkingUtils.SetStatusCallback(StatusCallback callback)` sets a callback for connection status updates. Returns true on success or false on failure.
582 |
583 | `NetworkingUtils.SetDebugCallback(DebugType detailLevel, DebugCallback callback)` sets a callback for debug output.
584 |
585 | `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.
586 |
587 | `NetworkingUtils.SetConfigurationValue(Configuration configuration, ConfigurationScope configurationScope, IntPtr scopeObject)` sets a configuration using `Configuration` structure according to `ConfigurationScope` enumeration.
588 |
589 | `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.
590 |
591 | #### Library
592 | Contains constant fields.
593 |
594 | `Library.maxCloseMessageLength` the maximum length of the reason string in bytes when a connection is closed.
595 |
596 | `Library.maxMessageSize` the maximum size of a single message that can be sent.
597 |
598 | `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`.
599 |
600 | `Library.Deinitialize()` deinitializes the native library. Should be called after the work is done.
601 |
--------------------------------------------------------------------------------
/ValveSockets.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Managed C# wrapper for GameNetworkingSockets library by Valve Software
3 | * Copyright (c) 2018 Stanislav Denisov
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in all
13 | * copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | * SOFTWARE.
22 | */
23 |
24 | using System;
25 | using System.Net;
26 | using System.Net.Sockets;
27 | using System.Runtime.CompilerServices;
28 | using System.Runtime.InteropServices;
29 | using System.Security;
30 | using System.Text;
31 |
32 | namespace Valve.Sockets {
33 | using ListenSocket = UInt32;
34 | using Connection = UInt32;
35 | using PollGroup = UInt32;
36 | using Microseconds = Int64;
37 |
38 | [Flags]
39 | public enum SendFlags {
40 | Unreliable = 0,
41 | NoNagle = 1 << 0,
42 | NoDelay = 1 << 2,
43 | Reliable = 1 << 3
44 | }
45 |
46 | public enum IdentityType {
47 | Invalid = 0,
48 | SteamID = 16,
49 | IPAddress = 1,
50 | GenericString = 2,
51 | GenericBytes = 3
52 | }
53 |
54 | public enum ConnectionState {
55 | None = 0,
56 | Connecting = 1,
57 | FindingRoute = 2,
58 | Connected = 3,
59 | ClosedByPeer = 4,
60 | ProblemDetectedLocally = 5
61 | }
62 |
63 | public enum ConfigurationScope {
64 | Global = 1,
65 | SocketsInterface = 2,
66 | ListenSocket = 3,
67 | Connection = 4
68 | }
69 |
70 | public enum ConfigurationDataType {
71 | Int32 = 1,
72 | Int64 = 2,
73 | Float = 3,
74 | String = 4,
75 | FunctionPtr = 5
76 | }
77 |
78 | public enum ConfigurationValue {
79 | Invalid = 0,
80 | FakePacketLossSend = 2,
81 | FakePacketLossRecv = 3,
82 | FakePacketLagSend = 4,
83 | FakePacketLagRecv = 5,
84 | FakePacketReorderSend = 6,
85 | FakePacketReorderRecv = 7,
86 | FakePacketReorderTime = 8,
87 | FakePacketDupSend = 26,
88 | FakePacketDupRecv = 27,
89 | FakePacketDupTimeMax = 28,
90 | TimeoutInitial = 24,
91 | TimeoutConnected = 25,
92 | SendBufferSize = 9,
93 | SendRateMin = 10,
94 | SendRateMax = 11,
95 | NagleTime = 12,
96 | IPAllowWithoutAuth = 23,
97 | MTUPacketSize = 32,
98 | MTUDataSize = 33,
99 | Unencrypted = 34,
100 | EnumerateDevVars = 35,
101 | SymmetricConnect = 37,
102 | LocalVirtualPort = 38,
103 | ConnectionStatusChanged = 201,
104 | AuthStatusChanged = 202,
105 | RelayNetworkStatusChanged = 203,
106 | MessagesSessionRequest = 204,
107 | MessagesSessionFailed = 205,
108 | P2PSTUNServerList = 103,
109 | P2PTransportICEEnable = 104,
110 | P2PTransportICEPenalty = 105,
111 | P2PTransportSDRPenalty = 106,
112 | SDRClientConsecutitivePingTimeoutsFailInitial = 19,
113 | SDRClientConsecutitivePingTimeoutsFail = 20,
114 | SDRClientMinPingsBeforePingAccurate = 21,
115 | SDRClientSingleSocket = 22,
116 | SDRClientForceRelayCluster = 29,
117 | SDRClientDebugTicketAddress = 30,
118 | SDRClientForceProxyAddr = 31,
119 | SDRClientFakeClusterPing = 36,
120 | LogLevelAckRTT = 13,
121 | LogLevelPacketDecode = 14,
122 | LogLevelMessage = 15,
123 | LogLevelPacketGaps = 16,
124 | LogLevelP2PRendezvous = 17,
125 | LogLevelSDRRelayPings = 18
126 | }
127 |
128 | public enum ConfigurationValueResult {
129 | BadValue = -1,
130 | BadScopeObject = -2,
131 | BufferTooSmall = -3,
132 | OK = 1,
133 | OKInherited = 2
134 | }
135 |
136 | public enum DebugType {
137 | None = 0,
138 | Bug = 1,
139 | Error = 2,
140 | Important = 3,
141 | Warning = 4,
142 | Message = 5,
143 | Verbose = 6,
144 | Debug = 7,
145 | Everything = 8
146 | }
147 |
148 | public enum Result {
149 | OK = 1,
150 | Fail = 2,
151 | NoConnection = 3,
152 | InvalidPassword = 5,
153 | LoggedInElsewhere = 6,
154 | InvalidProtocolVer = 7,
155 | InvalidParam = 8,
156 | FileNotFound = 9,
157 | Busy = 10,
158 | InvalidState = 11,
159 | InvalidName = 12,
160 | InvalidEmail = 13,
161 | DuplicateName = 14,
162 | AccessDenied = 15,
163 | Timeout = 16,
164 | Banned = 17,
165 | AccountNotFound = 18,
166 | InvalidSteamID = 19,
167 | ServiceUnavailable = 20,
168 | NotLoggedOn = 21,
169 | Pending = 22,
170 | EncryptionFailure = 23,
171 | InsufficientPrivilege = 24,
172 | LimitExceeded = 25,
173 | Revoked = 26,
174 | Expired = 27,
175 | AlreadyRedeemed = 28,
176 | DuplicateRequest = 29,
177 | AlreadyOwned = 30,
178 | IPNotFound = 31,
179 | PersistFailed = 32,
180 | LockingFailed = 33,
181 | LogonSessionReplaced = 34,
182 | ConnectFailed = 35,
183 | HandshakeFailed = 36,
184 | IOFailure = 37,
185 | RemoteDisconnect = 38,
186 | ShoppingCartNotFound = 39,
187 | Blocked = 40,
188 | Ignored = 41,
189 | NoMatch = 42,
190 | AccountDisabled = 43,
191 | ServiceReadOnly = 44,
192 | AccountNotFeatured = 45,
193 | AdministratorOK = 46,
194 | ContentVersion = 47,
195 | TryAnotherCM = 48,
196 | PasswordRequiredToKickSession = 49,
197 | AlreadyLoggedInElsewhere = 50,
198 | Suspended = 51,
199 | Cancelled = 52,
200 | DataCorruption = 53,
201 | DiskFull = 54,
202 | RemoteCallFailed = 55,
203 | PasswordUnset = 56,
204 | ExternalAccountUnlinked = 57,
205 | PSNTicketInvalid = 58,
206 | ExternalAccountAlreadyLinked = 59,
207 | RemoteFileConflict = 60,
208 | IllegalPassword = 61,
209 | SameAsPreviousValue = 62,
210 | AccountLogonDenied = 63,
211 | CannotUseOldPassword = 64,
212 | InvalidLoginAuthCode = 65,
213 | AccountLogonDeniedNoMail = 66,
214 | HardwareNotCapableOfIPT = 67,
215 | IPTInitError = 68,
216 | ParentalControlRestricted = 69,
217 | FacebookQueryError = 70,
218 | ExpiredLoginAuthCode = 71,
219 | IPLoginRestrictionFailed = 72,
220 | AccountLockedDown = 73,
221 | AccountLogonDeniedVerifiedEmailRequired = 74,
222 | NoMatchingURL = 75,
223 | BadResponse = 76,
224 | RequirePasswordReEntry = 77,
225 | ValueOutOfRange = 78,
226 | UnexpectedError = 79,
227 | Disabled = 80,
228 | InvalidCEGSubmission = 81,
229 | RestrictedDevice = 82,
230 | RegionLocked = 83,
231 | RateLimitExceeded = 84,
232 | AccountLoginDeniedNeedTwoFactor = 85,
233 | ItemDeleted = 86,
234 | AccountLoginDeniedThrottle = 87,
235 | TwoFactorCodeMismatch = 88,
236 | TwoFactorActivationCodeMismatch = 89,
237 | AccountAssociatedToMultiplePartners = 90,
238 | NotModified = 91,
239 | NoMobileDevice = 92,
240 | TimeNotSynced = 93,
241 | SmsCodeFailed = 94,
242 | AccountLimitExceeded = 95,
243 | AccountActivityLimitExceeded = 96,
244 | PhoneActivityLimitExceeded = 97,
245 | RefundToWallet = 98,
246 | EmailSendFailure = 99,
247 | NotSettled = 100,
248 | NeedCaptcha = 101,
249 | GSLTDenied = 102,
250 | GSOwnerDenied = 103,
251 | InvalidItemType = 104,
252 | IPBanned = 105,
253 | GSLTExpired = 106,
254 | InsufficientFunds = 107,
255 | TooManyPending = 108,
256 | NoSiteLicensesFound = 109,
257 | WGNetworkSendExceeded = 110
258 | }
259 |
260 | [StructLayout(LayoutKind.Sequential)]
261 | public struct Address : IEquatable {
262 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
263 | public byte[] ip;
264 | public ushort port;
265 |
266 | public bool IsLocalHost {
267 | get {
268 | return Native.SteamAPI_SteamNetworkingIPAddr_IsLocalHost(ref this);
269 | }
270 | }
271 |
272 | public string GetIP() {
273 | return ip.ParseIP();
274 | }
275 |
276 | public void SetLocalHost(ushort port) {
277 | Native.SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost(ref this, port);
278 | }
279 |
280 | public void SetAddress(string ip, ushort port) {
281 | if (!ip.Contains(":"))
282 | Native.SteamAPI_SteamNetworkingIPAddr_SetIPv4(ref this, ip.ParseIPv4(), port);
283 | else
284 | Native.SteamAPI_SteamNetworkingIPAddr_SetIPv6(ref this, ip.ParseIPv6(), port);
285 | }
286 |
287 | public bool Equals(Address other) {
288 | return Native.SteamAPI_SteamNetworkingIPAddr_IsEqualTo(ref this, ref other);
289 | }
290 | }
291 |
292 | [StructLayout(LayoutKind.Sequential)]
293 | public struct Configuration {
294 | public ConfigurationValue value;
295 | public ConfigurationDataType dataType;
296 | public ConfigurationData data;
297 |
298 | [StructLayout(LayoutKind.Explicit)]
299 | public struct ConfigurationData {
300 | [FieldOffset(0)]
301 | public int Int32;
302 | [FieldOffset(0)]
303 | public long Int64;
304 | [FieldOffset(0)]
305 | public float Float;
306 | [FieldOffset(0)]
307 | public IntPtr String;
308 | [FieldOffset(0)]
309 | public IntPtr FunctionPtr;
310 | }
311 | }
312 |
313 | [StructLayout(LayoutKind.Sequential)]
314 | public struct StatusInfo {
315 | private const int callback = Library.socketsCallbacks + 1;
316 | public Connection connection;
317 | public ConnectionInfo connectionInfo;
318 | private ConnectionState oldState;
319 | }
320 |
321 | [StructLayout(LayoutKind.Sequential)]
322 | public struct ConnectionInfo {
323 | public NetworkingIdentity identity;
324 | public long userData;
325 | public ListenSocket listenSocket;
326 | public Address address;
327 | private ushort pad;
328 | private uint popRemote;
329 | private uint popRelay;
330 | public ConnectionState state;
331 | public int endReason;
332 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
333 | public string endDebug;
334 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
335 | public string connectionDescription;
336 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
337 | private uint[] reserved;
338 | }
339 |
340 | [StructLayout(LayoutKind.Sequential)]
341 | public struct ConnectionStatus {
342 | public ConnectionState state;
343 | public int ping;
344 | public float connectionQualityLocal;
345 | public float connectionQualityRemote;
346 | public float outPacketsPerSecond;
347 | public float outBytesPerSecond;
348 | public float inPacketsPerSecond;
349 | public float inBytesPerSecond;
350 | public int sendRateBytesPerSecond;
351 | public int pendingUnreliable;
352 | public int pendingReliable;
353 | public int sentUnackedReliable;
354 | public Microseconds queueTime;
355 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
356 | private uint[] reserved;
357 | }
358 |
359 | [StructLayout(LayoutKind.Explicit, Size = 136)]
360 | public struct NetworkingIdentity {
361 | [FieldOffset(0)]
362 | public IdentityType type;
363 |
364 | public bool IsInvalid {
365 | get {
366 | return Native.SteamAPI_SteamNetworkingIdentity_IsInvalid(ref this);
367 | }
368 | }
369 |
370 | public ulong GetSteamID() {
371 | return Native.SteamAPI_SteamNetworkingIdentity_GetSteamID64(ref this);
372 | }
373 |
374 | public void SetSteamID(ulong steamID) {
375 | Native.SteamAPI_SteamNetworkingIdentity_SetSteamID64(ref this, steamID);
376 | }
377 | }
378 |
379 | [StructLayout(LayoutKind.Sequential)]
380 | public struct NetworkingMessage {
381 | public IntPtr data;
382 | public int length;
383 | public Connection connection;
384 | public NetworkingIdentity identity;
385 | public long connectionUserData;
386 | public Microseconds timeReceived;
387 | public long messageNumber;
388 | internal IntPtr freeData;
389 | internal IntPtr release;
390 | public int channel;
391 | public int flags;
392 | public long userData;
393 |
394 | public void CopyTo(byte[] destination) {
395 | if (destination == null)
396 | throw new ArgumentNullException("destination");
397 |
398 | Marshal.Copy(data, destination, 0, length);
399 | }
400 |
401 | #if !VALVESOCKETS_SPAN
402 | public void Destroy() {
403 | if (release == IntPtr.Zero)
404 | throw new InvalidOperationException("Message not created");
405 |
406 | Native.SteamAPI_SteamNetworkingMessage_t_Release(release);
407 | }
408 | #endif
409 | }
410 |
411 | public delegate void StatusCallback(ref StatusInfo info);
412 | public delegate void DebugCallback(DebugType type, string message);
413 |
414 | #if VALVESOCKETS_SPAN
415 | public delegate void MessageCallback(in NetworkingMessage message);
416 | #endif
417 |
418 | internal static class ArrayPool {
419 | [ThreadStatic]
420 | private static IntPtr[] pointerBuffer;
421 |
422 | public static IntPtr[] GetPointerBuffer() {
423 | if (pointerBuffer == null)
424 | pointerBuffer = new IntPtr[Library.maxMessagesPerBatch];
425 |
426 | return pointerBuffer;
427 | }
428 | }
429 |
430 | public class NetworkingSockets {
431 | private IntPtr nativeSockets;
432 |
433 | public NetworkingSockets() {
434 | nativeSockets = Native.SteamAPI_SteamNetworkingSockets_v009();
435 |
436 | if (nativeSockets == IntPtr.Zero)
437 | throw new InvalidOperationException("Networking sockets not created");
438 | }
439 |
440 | public ListenSocket CreateListenSocket(ref Address address) {
441 | return Native.SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(nativeSockets, ref address, 0, IntPtr.Zero);
442 | }
443 |
444 | public ListenSocket CreateListenSocket(ref Address address, Configuration[] configurations) {
445 | if (configurations == null)
446 | throw new ArgumentNullException("configurations");
447 |
448 | return Native.SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(nativeSockets, ref address, configurations.Length, configurations);
449 | }
450 |
451 | public Connection Connect(ref Address address) {
452 | return Native.SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(nativeSockets, ref address, 0, IntPtr.Zero);
453 | }
454 |
455 | public Connection Connect(ref Address address, Configuration[] configurations) {
456 | if (configurations == null)
457 | throw new ArgumentNullException("configurations");
458 |
459 | return Native.SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(nativeSockets, ref address, configurations.Length, configurations);
460 | }
461 |
462 | public Result AcceptConnection(Connection connection) {
463 | return Native.SteamAPI_ISteamNetworkingSockets_AcceptConnection(nativeSockets, connection);
464 | }
465 |
466 | public bool CloseConnection(Connection connection) {
467 | return CloseConnection(connection, 0, String.Empty, false);
468 | }
469 |
470 | public bool CloseConnection(Connection connection, int reason, string debug, bool enableLinger) {
471 | if (debug.Length > Library.maxCloseMessageLength)
472 | throw new ArgumentOutOfRangeException("debug");
473 |
474 | return Native.SteamAPI_ISteamNetworkingSockets_CloseConnection(nativeSockets, connection, reason, debug, enableLinger);
475 | }
476 |
477 | public bool CloseListenSocket(ListenSocket socket) {
478 | return Native.SteamAPI_ISteamNetworkingSockets_CloseListenSocket(nativeSockets, socket);
479 | }
480 |
481 | public bool SetConnectionUserData(Connection peer, long userData) {
482 | return Native.SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(nativeSockets, peer, userData);
483 | }
484 |
485 | public long GetConnectionUserData(Connection peer) {
486 | return Native.SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(nativeSockets, peer);
487 | }
488 |
489 | public void SetConnectionName(Connection peer, string name) {
490 | Native.SteamAPI_ISteamNetworkingSockets_SetConnectionName(nativeSockets, peer, name);
491 | }
492 |
493 | public bool GetConnectionName(Connection peer, StringBuilder name, int maxLength) {
494 | return Native.SteamAPI_ISteamNetworkingSockets_GetConnectionName(nativeSockets, peer, name, maxLength);
495 | }
496 |
497 | public Result SendMessageToConnection(Connection connection, IntPtr data, uint length) {
498 | return SendMessageToConnection(connection, data, length, SendFlags.Unreliable);
499 | }
500 |
501 | public Result SendMessageToConnection(Connection connection, IntPtr data, uint length, SendFlags flags) {
502 | return Native.SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(nativeSockets, connection, data, length, flags, IntPtr.Zero);
503 | }
504 |
505 | public Result SendMessageToConnection(Connection connection, IntPtr data, int length, SendFlags flags) {
506 | return SendMessageToConnection(connection, data, (uint)length, flags);
507 | }
508 |
509 | public Result SendMessageToConnection(Connection connection, byte[] data) {
510 | if (data == null)
511 | throw new ArgumentNullException("data");
512 |
513 | return SendMessageToConnection(connection, data, data.Length, SendFlags.Unreliable);
514 | }
515 |
516 | public Result SendMessageToConnection(Connection connection, byte[] data, SendFlags flags) {
517 | if (data == null)
518 | throw new ArgumentNullException("data");
519 |
520 | return SendMessageToConnection(connection, data, data.Length, flags);
521 | }
522 |
523 | public Result SendMessageToConnection(Connection connection, byte[] data, int length, SendFlags flags) {
524 | if (data == null)
525 | throw new ArgumentNullException("data");
526 |
527 | return Native.SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(nativeSockets, connection, data, (uint)length, flags, IntPtr.Zero);
528 | }
529 |
530 | public Result FlushMessagesOnConnection(Connection connection) {
531 | return Native.SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection(nativeSockets, connection);
532 | }
533 |
534 | public bool GetConnectionInfo(Connection connection, ref ConnectionInfo info) {
535 | return Native.SteamAPI_ISteamNetworkingSockets_GetConnectionInfo(nativeSockets, connection, ref info);
536 | }
537 |
538 | public bool GetQuickConnectionStatus(Connection connection, ref ConnectionStatus status) {
539 | return Native.SteamAPI_ISteamNetworkingSockets_GetQuickConnectionStatus(nativeSockets, connection, ref status);
540 | }
541 |
542 | public int GetDetailedConnectionStatus(Connection connection, StringBuilder status, int statusLength) {
543 | return Native.SteamAPI_ISteamNetworkingSockets_GetDetailedConnectionStatus(nativeSockets, connection, status, statusLength);
544 | }
545 |
546 | public bool GetListenSocketAddress(ListenSocket socket, ref Address address) {
547 | return Native.SteamAPI_ISteamNetworkingSockets_GetListenSocketAddress(nativeSockets, socket, ref address);
548 | }
549 |
550 | public bool CreateSocketPair(Connection connectionLeft, Connection connectionRight, bool useNetworkLoopback, ref NetworkingIdentity identityLeft, ref NetworkingIdentity identityRight) {
551 | return Native.SteamAPI_ISteamNetworkingSockets_CreateSocketPair(nativeSockets, connectionLeft, connectionRight, useNetworkLoopback, ref identityLeft, ref identityRight);
552 | }
553 |
554 | public bool GetIdentity(ref NetworkingIdentity identity) {
555 | return Native.SteamAPI_ISteamNetworkingSockets_GetIdentity(nativeSockets, ref identity);
556 | }
557 |
558 | public PollGroup CreatePollGroup() {
559 | return Native.SteamAPI_ISteamNetworkingSockets_CreatePollGroup(nativeSockets);
560 | }
561 |
562 | public bool DestroyPollGroup(PollGroup pollGroup) {
563 | return Native.SteamAPI_ISteamNetworkingSockets_DestroyPollGroup(nativeSockets, pollGroup);
564 | }
565 |
566 | public bool SetConnectionPollGroup(PollGroup pollGroup, Connection connection) {
567 | return Native.SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(nativeSockets, connection, pollGroup);
568 | }
569 |
570 | public void RunCallbacks() {
571 | Native.SteamAPI_ISteamNetworkingSockets_RunCallbacks(nativeSockets);
572 | }
573 |
574 | #if VALVESOCKETS_SPAN
575 | [MethodImpl(256)]
576 | public void ReceiveMessagesOnConnection(Connection connection, MessageCallback callback, int maxMessages) {
577 | if (maxMessages > Library.maxMessagesPerBatch)
578 | throw new ArgumentOutOfRangeException("maxMessages");
579 |
580 | IntPtr[] nativeMessages = ArrayPool.GetPointerBuffer();
581 | int messagesCount = Native.SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(nativeSockets, connection, nativeMessages, maxMessages);
582 |
583 | for (int i = 0; i < messagesCount; i++) {
584 | Span message;
585 |
586 | unsafe {
587 | message = new Span((void*)nativeMessages[i], 1);
588 | }
589 |
590 | callback(in message[0]);
591 |
592 | Native.SteamAPI_SteamNetworkingMessage_t_Release(nativeMessages[i]);
593 | }
594 | }
595 |
596 | [MethodImpl(256)]
597 | public void ReceiveMessagesOnPollGroup(PollGroup pollGroup, MessageCallback callback, int maxMessages) {
598 | if (maxMessages > Library.maxMessagesPerBatch)
599 | throw new ArgumentOutOfRangeException("maxMessages");
600 |
601 | IntPtr[] nativeMessages = ArrayPool.GetPointerBuffer();
602 | int messagesCount = Native.SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(nativeSockets, pollGroup, nativeMessages, maxMessages);
603 |
604 | for (int i = 0; i < messagesCount; i++) {
605 | Span message;
606 |
607 | unsafe {
608 | message = new Span((void*)nativeMessages[i], 1);
609 | }
610 |
611 | callback(in message[0]);
612 |
613 | Native.SteamAPI_SteamNetworkingMessage_t_Release(nativeMessages[i]);
614 | }
615 | }
616 | #else
617 | [MethodImpl(256)]
618 | public int ReceiveMessagesOnConnection(Connection connection, NetworkingMessage[] messages, int maxMessages) {
619 | if (messages == null)
620 | throw new ArgumentNullException("messages");
621 |
622 | if (maxMessages > Library.maxMessagesPerBatch)
623 | throw new ArgumentOutOfRangeException("maxMessages");
624 |
625 | IntPtr[] nativeMessages = ArrayPool.GetPointerBuffer();
626 | int messagesCount = Native.SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(nativeSockets, connection, nativeMessages, maxMessages);
627 |
628 | for (int i = 0; i < messagesCount; i++) {
629 | messages[i] = (NetworkingMessage)Marshal.PtrToStructure(nativeMessages[i], typeof(NetworkingMessage));
630 | messages[i].release = nativeMessages[i];
631 | }
632 |
633 | return messagesCount;
634 | }
635 |
636 | [MethodImpl(256)]
637 | public int ReceiveMessagesOnPollGroup(PollGroup pollGroup, NetworkingMessage[] messages, int maxMessages) {
638 | if (messages == null)
639 | throw new ArgumentNullException("messages");
640 |
641 | if (maxMessages > Library.maxMessagesPerBatch)
642 | throw new ArgumentOutOfRangeException("maxMessages");
643 |
644 | IntPtr[] nativeMessages = ArrayPool.GetPointerBuffer();
645 | int messagesCount = Native.SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(nativeSockets, pollGroup, nativeMessages, maxMessages);
646 |
647 | for (int i = 0; i < messagesCount; i++) {
648 | messages[i] = (NetworkingMessage)Marshal.PtrToStructure(nativeMessages[i], typeof(NetworkingMessage));
649 | messages[i].release = nativeMessages[i];
650 | }
651 |
652 | return messagesCount;
653 | }
654 | #endif
655 | }
656 |
657 | public class NetworkingUtils : IDisposable {
658 | private IntPtr nativeUtils;
659 |
660 | public NetworkingUtils() {
661 | nativeUtils = Native.SteamAPI_SteamNetworkingUtils_v003();
662 |
663 | if (nativeUtils == IntPtr.Zero)
664 | throw new InvalidOperationException("Networking utils not created");
665 | }
666 |
667 | public void Dispose() {
668 | Dispose(true);
669 | GC.SuppressFinalize(this);
670 | }
671 |
672 | protected virtual void Dispose(bool disposing) {
673 | if (nativeUtils != IntPtr.Zero) {
674 | Native.SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged(nativeUtils, IntPtr.Zero);
675 | Native.SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction(nativeUtils, DebugType.None, IntPtr.Zero);
676 | nativeUtils = IntPtr.Zero;
677 | }
678 | }
679 |
680 | ~NetworkingUtils() {
681 | Dispose(false);
682 | }
683 |
684 | public Microseconds Time {
685 | get {
686 | return Native.SteamAPI_ISteamNetworkingUtils_GetLocalTimestamp(nativeUtils);
687 | }
688 | }
689 |
690 | public ConfigurationValue FirstConfigurationValue {
691 | get {
692 | return Native.SteamAPI_ISteamNetworkingUtils_GetFirstConfigValue(nativeUtils);
693 | }
694 | }
695 |
696 | public bool SetStatusCallback(StatusCallback callback) {
697 | return Native.SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged(nativeUtils, callback);
698 | }
699 |
700 | public void SetDebugCallback(DebugType detailLevel, DebugCallback callback) {
701 | Native.SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction(nativeUtils, detailLevel, callback);
702 | }
703 |
704 | public bool SetConfigurationValue(ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ConfigurationDataType dataType, IntPtr value) {
705 | return Native.SteamAPI_ISteamNetworkingUtils_SetConfigValue(nativeUtils, configurationValue, configurationScope, scopeObject, dataType, value);
706 | }
707 |
708 | public bool SetConfigurationValue(Configuration configuration, ConfigurationScope configurationScope, IntPtr scopeObject) {
709 | return Native.SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct(nativeUtils, configuration, configurationScope, scopeObject);
710 | }
711 |
712 | public ConfigurationValueResult GetConfigurationValue(ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ref ConfigurationDataType dataType, ref IntPtr result, ref IntPtr resultLength) {
713 | return Native.SteamAPI_ISteamNetworkingUtils_GetConfigValue(nativeUtils, configurationValue, configurationScope, scopeObject, ref dataType, ref result, ref resultLength);
714 | }
715 | }
716 |
717 | public static class Extensions {
718 | public static uint ParseIPv4(this string ip) {
719 | IPAddress address = default(IPAddress);
720 |
721 | if (IPAddress.TryParse(ip, out address)) {
722 | if (address.AddressFamily != AddressFamily.InterNetwork)
723 | throw new Exception("Incorrect format of an IPv4 address");
724 | }
725 |
726 | byte[] bytes = address.GetAddressBytes();
727 |
728 | Array.Reverse(bytes);
729 |
730 | return BitConverter.ToUInt32(bytes, 0);
731 | }
732 |
733 | public static byte[] ParseIPv6(this string ip) {
734 | IPAddress address = default(IPAddress);
735 |
736 | if (IPAddress.TryParse(ip, out address)) {
737 | if (address.AddressFamily != AddressFamily.InterNetworkV6)
738 | throw new Exception("Incorrect format of an IPv6 address");
739 | }
740 |
741 | return address.GetAddressBytes();
742 | }
743 |
744 | public static string ParseIP(this byte[] ip) {
745 | IPAddress address = new IPAddress(ip);
746 | string converted = address.ToString();
747 |
748 | if (converted.Length > 7 && converted.Remove(7) == "::ffff:") {
749 | Address ipv4 = default(Address);
750 |
751 | ipv4.ip = ip;
752 |
753 | byte[] bytes = BitConverter.GetBytes(Native.SteamAPI_SteamNetworkingIPAddr_GetIPv4(ref ipv4));
754 |
755 | Array.Reverse(bytes);
756 |
757 | address = new IPAddress(bytes);
758 | }
759 |
760 | return address.ToString();
761 | }
762 | }
763 |
764 | public static class Library {
765 | public const int maxCloseMessageLength = 128;
766 | public const int maxErrorMessageLength = 1024;
767 | public const int maxMessagesPerBatch = 256;
768 | public const int maxMessageSize = 512 * 1024;
769 | public const int socketsCallbacks = 1220;
770 |
771 | public static bool Initialize() {
772 | return Initialize(null);
773 | }
774 |
775 | public static bool Initialize(StringBuilder errorMessage) {
776 | if (errorMessage != null && errorMessage.Capacity != maxErrorMessageLength)
777 | throw new ArgumentOutOfRangeException("Capacity of the error message must be equal to " + maxErrorMessageLength);
778 |
779 | return Native.GameNetworkingSockets_Init(IntPtr.Zero, errorMessage);
780 | }
781 |
782 | public static bool Initialize(ref NetworkingIdentity identity, StringBuilder errorMessage) {
783 | if (errorMessage != null && errorMessage.Capacity != maxErrorMessageLength)
784 | throw new ArgumentOutOfRangeException("Capacity of the error message must be equal to " + maxErrorMessageLength);
785 |
786 | if (Object.Equals(identity, null))
787 | throw new ArgumentNullException("identity");
788 |
789 | return Native.GameNetworkingSockets_Init(ref identity, errorMessage);
790 | }
791 |
792 | public static void Deinitialize() {
793 | Native.GameNetworkingSockets_Kill();
794 | }
795 | }
796 |
797 | [SuppressUnmanagedCodeSecurity]
798 | internal static class Native {
799 | private const string nativeLibrary = "GameNetworkingSockets";
800 |
801 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
802 | internal static extern bool GameNetworkingSockets_Init(IntPtr identity, StringBuilder errorMessage);
803 |
804 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
805 | internal static extern bool GameNetworkingSockets_Init(ref NetworkingIdentity identity, StringBuilder errorMessage);
806 |
807 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
808 | internal static extern void GameNetworkingSockets_Kill();
809 |
810 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
811 | internal static extern IntPtr SteamAPI_SteamNetworkingSockets_v009();
812 |
813 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
814 | internal static extern IntPtr SteamAPI_SteamNetworkingUtils_v003();
815 |
816 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
817 | internal static extern ListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(IntPtr sockets, ref Address address, int configurationsCount, IntPtr configurations);
818 |
819 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
820 | internal static extern ListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(IntPtr sockets, ref Address address, int configurationsCount, Configuration[] configurations);
821 |
822 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
823 | internal static extern Connection SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(IntPtr sockets, ref Address address, int configurationsCount, IntPtr configurations);
824 |
825 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
826 | internal static extern Connection SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(IntPtr sockets, ref Address address, int configurationsCount, Configuration[] configurations);
827 |
828 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
829 | internal static extern Result SteamAPI_ISteamNetworkingSockets_AcceptConnection(IntPtr sockets, Connection connection);
830 |
831 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
832 | internal static extern bool SteamAPI_ISteamNetworkingSockets_CloseConnection(IntPtr sockets, Connection peer, int reason, string debug, bool enableLinger);
833 |
834 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
835 | internal static extern bool SteamAPI_ISteamNetworkingSockets_CloseListenSocket(IntPtr sockets, ListenSocket socket);
836 |
837 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
838 | internal static extern bool SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(IntPtr sockets, Connection peer, long userData);
839 |
840 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
841 | internal static extern long SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(IntPtr sockets, Connection peer);
842 |
843 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
844 | internal static extern void SteamAPI_ISteamNetworkingSockets_SetConnectionName(IntPtr sockets, Connection peer, string name);
845 |
846 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
847 | internal static extern bool SteamAPI_ISteamNetworkingSockets_GetConnectionName(IntPtr sockets, Connection peer, StringBuilder name, int maxLength);
848 |
849 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
850 | internal static extern Result SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(IntPtr sockets, Connection connection, IntPtr data, uint length, SendFlags flags, IntPtr outMessageNumber);
851 |
852 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
853 | internal static extern Result SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(IntPtr sockets, Connection connection, byte[] data, uint length, SendFlags flags, IntPtr outMessageNumber);
854 |
855 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
856 | internal static extern Result SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection(IntPtr sockets, Connection connection);
857 |
858 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
859 | internal static extern int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(IntPtr sockets, Connection connection, IntPtr[] messages, int maxMessages);
860 |
861 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
862 | internal static extern bool SteamAPI_ISteamNetworkingSockets_GetConnectionInfo(IntPtr sockets, Connection connection, ref ConnectionInfo info);
863 |
864 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
865 | internal static extern bool SteamAPI_ISteamNetworkingSockets_GetQuickConnectionStatus(IntPtr sockets, Connection connection, ref ConnectionStatus status);
866 |
867 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
868 | internal static extern int SteamAPI_ISteamNetworkingSockets_GetDetailedConnectionStatus(IntPtr sockets, Connection connection, StringBuilder status, int statusLength);
869 |
870 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
871 | internal static extern bool SteamAPI_ISteamNetworkingSockets_GetListenSocketAddress(IntPtr sockets, ListenSocket socket, ref Address address);
872 |
873 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
874 | internal static extern void SteamAPI_ISteamNetworkingSockets_RunCallbacks(IntPtr sockets);
875 |
876 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
877 | internal static extern bool SteamAPI_ISteamNetworkingSockets_CreateSocketPair(IntPtr sockets, Connection connectionLeft, Connection connectionRight, bool useNetworkLoopback, ref NetworkingIdentity identityLeft, ref NetworkingIdentity identityRight);
878 |
879 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
880 | internal static extern bool SteamAPI_ISteamNetworkingSockets_GetIdentity(IntPtr sockets, ref NetworkingIdentity identity);
881 |
882 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
883 | internal static extern PollGroup SteamAPI_ISteamNetworkingSockets_CreatePollGroup(IntPtr sockets);
884 |
885 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
886 | internal static extern bool SteamAPI_ISteamNetworkingSockets_DestroyPollGroup(IntPtr sockets, PollGroup pollGroup);
887 |
888 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
889 | internal static extern bool SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(IntPtr sockets, Connection connection, PollGroup pollGroup);
890 |
891 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
892 | internal static extern int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(IntPtr sockets, PollGroup pollGroup, IntPtr[] messages, int maxMessages);
893 |
894 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
895 | internal static extern void SteamAPI_SteamNetworkingIPAddr_SetIPv6(ref Address address, byte[] ip, ushort port);
896 |
897 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
898 | internal static extern void SteamAPI_SteamNetworkingIPAddr_SetIPv4(ref Address address, uint ip, ushort port);
899 |
900 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
901 | internal static extern uint SteamAPI_SteamNetworkingIPAddr_GetIPv4(ref Address address);
902 |
903 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
904 | internal static extern void SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost(ref Address address, ushort port);
905 |
906 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
907 | internal static extern bool SteamAPI_SteamNetworkingIPAddr_IsLocalHost(ref Address address);
908 |
909 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
910 | internal static extern bool SteamAPI_SteamNetworkingIPAddr_IsEqualTo(ref Address address, ref Address other);
911 |
912 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
913 | internal static extern bool SteamAPI_SteamNetworkingIdentity_IsInvalid(ref NetworkingIdentity identity);
914 |
915 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
916 | internal static extern void SteamAPI_SteamNetworkingIdentity_SetSteamID64(ref NetworkingIdentity identity, ulong steamID);
917 |
918 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
919 | internal static extern ulong SteamAPI_SteamNetworkingIdentity_GetSteamID64(ref NetworkingIdentity identity);
920 |
921 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
922 | internal static extern Microseconds SteamAPI_ISteamNetworkingUtils_GetLocalTimestamp(IntPtr utils);
923 |
924 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
925 | internal static extern bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged(IntPtr utils, IntPtr callback);
926 |
927 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
928 | internal static extern bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged(IntPtr utils, StatusCallback callback);
929 |
930 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
931 | internal static extern void SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction(IntPtr utils, DebugType detailLevel, IntPtr callback);
932 |
933 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
934 | internal static extern void SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction(IntPtr utils, DebugType detailLevel, DebugCallback callback);
935 |
936 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
937 | internal static extern bool SteamAPI_ISteamNetworkingUtils_SetConfigValue(IntPtr utils, ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ConfigurationDataType dataType, IntPtr value);
938 |
939 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
940 | internal static extern bool SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct(IntPtr utils, Configuration configuration, ConfigurationScope configurationScope, IntPtr scopeObject);
941 |
942 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
943 | internal static extern ConfigurationValueResult SteamAPI_ISteamNetworkingUtils_GetConfigValue(IntPtr utils, ConfigurationValue configurationValue, ConfigurationScope configurationScope, IntPtr scopeObject, ref ConfigurationDataType dataType, ref IntPtr result, ref IntPtr resultLength);
944 |
945 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
946 | internal static extern ConfigurationValue SteamAPI_ISteamNetworkingUtils_GetFirstConfigValue(IntPtr utils);
947 |
948 | [DllImport(nativeLibrary, CallingConvention = CallingConvention.Cdecl)]
949 | internal static extern void SteamAPI_SteamNetworkingMessage_t_Release(IntPtr nativeMessage);
950 | }
951 | }
952 |
--------------------------------------------------------------------------------