Steam Networking Sockets (#179)
This commit is contained in:
Родитель
9a480a5863
Коммит
fddadc8364
|
@ -27,6 +27,7 @@ Check our [contribution guidelines](CONTRIBUTING.md) for information on how to c
|
|||
|**[Enet](/Transports/com.community.netcode.transport.enet)**| Desktop, Mobile\* | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|**[LiteNetLib](/Transports/com.community.netcode.transport.litenetlib)**| Desktop, Mobile | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|**[SteamNetworking](/Transports/com.community.netcode.transport.steamnetworking)**| Steam | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|**[SteamNetworkingSockets](/Transports/com.community.netcode.transport.steamnetworkingsockets)**| Steam | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|**[WebSocket](/Transports/com.community.netcode.transport.websocket)**| Desktop, Mobile, WebGL | :heavy_check_mark: | :heavy_check_mark:||
|
||||
|**[Photon Realtime](/Transports/com.community.netcode.transport.photon-realtime)**| Desktop, Mobile, WebGL\** | :heavy_check_mark: | :heavy_check_mark: | |
|
||||
|**[Facepunch](/Transports/com.community.netcode.transport.facepunch)**| Steam | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|
|
|
@ -16,7 +16,7 @@ The SteamNetworking Transport leverages Valve's SteamNetworking APIs enabling se
|
|||
This transport does require that you first initalize the Steam API before use. To do so you will need to either
|
||||
|
||||
- Author your own initalization logic using the documentation provided by [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET)
|
||||
- Use a 3rd party solution such as [Steamworks V2 Foundaiton (free)](https://assetstore.unity.com/packages/tools/integration/steamworks-v2-foundation-186949) or [Steamworks V2 Complete (paid)](https://assetstore.unity.com/packages/tools/integration/steamworks-v2-complete-190316) or comparable solution
|
||||
- Use a 3rd party solution such as [Steamworks Foundaiton (lite & free)](https://github.com/heathen-engineering/SteamworksFoundation) or [Steamworks Complete (full & paid)](https://www.heathen.group/steamworks) or comparable solution
|
||||
- Use the example SteamManager from [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET) **NOTE This is not recomended as the SteamManager does not support Steam Game Server and is very limited in funcitonlity, it can however be a good learning tool for creating your own logic**
|
||||
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ namespace Netcode.Transports
|
|||
|
||||
connectedUsers.Remove(clientId);
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworking.CloseP2PSessionWithUser(remoteId);
|
||||
SteamGameServerNetworking.CloseP2PSessionWithUser(remoteId);
|
||||
#else
|
||||
SteamNetworking.CloseP2PSessionWithUser(remoteId);
|
||||
#endif
|
||||
|
@ -264,7 +264,7 @@ namespace Netcode.Transports
|
|||
if (isServer)
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworking.SendP2PPacket(remoteId, new byte[] { 0 }, 1, EP2PSend.k_EP2PSendReliable, (int)InternalChannelType.Connect);
|
||||
SteamGameServerNetworking.SendP2PPacket(remoteId, new byte[] { 0 }, 1, EP2PSend.k_EP2PSendReliable, (int)InternalChannelType.Connect);
|
||||
#else
|
||||
SteamNetworking.SendP2PPacket(remoteId, new byte[] { 0 }, 1, EP2PSend.k_EP2PSendReliable, (int)InternalChannelType.Connect);
|
||||
#endif
|
||||
|
@ -290,7 +290,7 @@ namespace Netcode.Transports
|
|||
|
||||
pingPongMessageBuffer[0] = messageBuffer[0];
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworking.SendP2PPacket(remoteId, pingPongMessageBuffer, msgSize, EP2PSend.k_EP2PSendUnreliableNoDelay, (int)InternalChannelType.Pong);
|
||||
SteamGameServerNetworking.SendP2PPacket(remoteId, pingPongMessageBuffer, msgSize, EP2PSend.k_EP2PSendUnreliableNoDelay, (int)InternalChannelType.Pong);
|
||||
#else
|
||||
SteamNetworking.SendP2PPacket(remoteId, pingPongMessageBuffer, msgSize, EP2PSend.k_EP2PSendUnreliableNoDelay, (int)InternalChannelType.Pong);
|
||||
#endif
|
||||
|
@ -302,7 +302,8 @@ namespace Netcode.Transports
|
|||
uint pingValue = sentPings[messageBuffer[0]].getPingTime();
|
||||
if (isServer)
|
||||
{
|
||||
connectedUsers[remoteId.m_SteamID].Ping.SetPing(pingValue);
|
||||
if (connectedUsers.ContainsKey(remoteId.m_SteamID))
|
||||
connectedUsers[remoteId.m_SteamID].Ping.SetPing(pingValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -313,9 +314,18 @@ namespace Netcode.Transports
|
|||
break;
|
||||
|
||||
case (byte)InternalChannelType.NetcodeData:
|
||||
payload = new ArraySegment<byte>(messageBuffer, 0, (int)msgSize);
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
return NetworkEvent.Data;
|
||||
if (connectedUsers.ContainsKey(clientId))
|
||||
{
|
||||
payload = new ArraySegment<byte>(messageBuffer, 0, (int)msgSize);
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
return NetworkEvent.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
NetworkLog.LogInfoServer(nameof(SteamNetworkingTransport) + " - PollEvent - Recieved a message from an unknown user with clientId: " + clientId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
@ -573,6 +583,39 @@ namespace Netcode.Transports
|
|||
await Task.Delay(TimeSpan.FromSeconds(PingInterval));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (connectedUsers != null && connectedUsers.Count > 0)
|
||||
{
|
||||
foreach (User user in connectedUsers.Values)
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworking.CloseP2PSessionWithUser(user.SteamId);
|
||||
#else
|
||||
SteamNetworking.CloseP2PSessionWithUser(user.SteamId);
|
||||
#endif
|
||||
}
|
||||
|
||||
connectedUsers.Clear();
|
||||
}
|
||||
|
||||
if (serverUser != null)
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworking.CloseP2PSessionWithUser(serverUser.SteamId);
|
||||
#else
|
||||
SteamNetworking.CloseP2PSessionWithUser(serverUser.SteamId);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
UnityEngine.Debug.LogError("Failed to properly close network sessions: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"unity": "2020.3",
|
||||
"description": "SteamNetworking Transport for NetCode for GameObjects with support for both peer to peer and client server architectures. Derived from SteamAPI originally authored by Petter Vernersson",
|
||||
"author": {
|
||||
"name": "Heathen Engineering",
|
||||
"name": "Heathen Group",
|
||||
"url": "https://assetstore.unity.com/publishers/5836"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Changelog
|
||||
All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
|
||||
v2.0.0 submitted by [Heathen Engineering](https://assetstore.unity.com/publishers/5836). The objective of these changes is to allow this transport to
|
||||
|
||||
1. Work with any implamentation of [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET) including [Heathen's Steamworks V2](https://assetstore.unity.com/packages/tools/integration/steamworks-v2-complete-190316)
|
||||
2. To enable this transport to be used in both Peer to Peer and Client Server architectures
|
||||
|
||||
The [Heathen Assets Discord](https://discord.gg/6X3xrRc) server can be used to ask any questions regarding Heathen's modifications or to see community support with Heathen related Steam integration and Steam networking questions
|
||||
|
||||
## [2.0.1] - 2021-01-06
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug in the internal channel implementation which did not allow Netcode for GameObject to send any data over the transport.
|
||||
|
||||
## [2.0.0] - 2021-11-25
|
||||
### Add
|
||||
- Added support for Steam Game Server Networking APIs
|
||||
|
||||
### Changed
|
||||
- Transport is now named SteamNetworkingTransport as it is no longer limited to peer to peer architectures
|
||||
- Namespace simplified to Netcode.Transports
|
||||
- Updated all API calls to test for platform, in the case of UNITY_SERVER being defined the transport will use the SteamGameServerNetworking APIs otherwise it will use the client equivelent SteamNetworking APIs
|
||||
|
||||
### Removed
|
||||
- dependency on SteamManager and SteamManager code has been removed. This makes it easier for users to use whatever initalization logic the user wishes including SteamManager but also custom logic and 3rd party logic such as SteamworksBehaviour from [Heathen's Steamworks V2](https://assetstore.unity.com/packages/tools/integration/steamworks-v2-complete-190316)
|
||||
- pre-packaged Steamworks.NET; this being removed allows the user to use whatever version they please including other 3rd party extensions such as [Heathen's Steamworks V2](https://assetstore.unity.com/packages/tools/integration/steamworks-v2-complete-190316)
|
||||
- Removed unused and unessisary Client API calls such as calls to SteamUser in various debug log messages
|
||||
|
||||
## 1.0.0
|
||||
First version of the Steam transport as a Unity package.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 217833d4ffbc2834191c103e3637b0f7
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Unity Technologies
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4eb039928356500468c82ad21fb735c6
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,23 @@
|
|||
# SteamNetworkingSockets Transport for Unity NetCode for GameObjects
|
||||
The SteamNetworkingSockets Transport leverages Valve's SteamNetworkingSockets APIs enabling secure and efficent networking in both peer to peer and client server architectures. The Steam networking sockets APIs address via CSteamID, not IP/Port. These APIs handle routing via Valve's backend services and do not require NAT punch or additional routing solutions.
|
||||
|
||||
## Dependencies
|
||||
**[Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET)** This transport relies on Steamworks.NET to communicate with the **[Steamworks API](https://partner.steamgames.com/doc/sdk)**.
|
||||
**[Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET) its self requires .Net 4.x**
|
||||
|
||||
## Set Up
|
||||
|
||||
1. Install [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET) via the package manager by clicking the '+' (plus) button located in the upper left of the window and selecting `Add package from git URL...` when prompted provide the following URL:
|
||||
`https://github.com/rlabrecque/Steamworks.NET.git?path=/com.rlabrecque.steamworks.net`
|
||||
2. Install this package via the package manager by clicking the '+' (plus) button located in the upper left of the window and selecting `Add package from git URL...` when prompted provide the following URL:
|
||||
`https://github.com/Unity-Technologies/multiplayer-community-contributions.git?path=/Transports/com.community.netcode.transport.steamnetworkingsockets`
|
||||
|
||||
## Usage
|
||||
This transport does require that you first initalize the Steam API before use. To do so you will need to either
|
||||
|
||||
- Author your own initalization logic using the documentation provided by [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET)
|
||||
- Use a 3rd party solution such as [Steamworks Foundaiton (lite & free)](https://github.com/heathen-engineering/SteamworksFoundation) or [Steamworks Complete (full & paid)](https://www.heathen.group/steamworks) or comparable solution
|
||||
- Use the example SteamManager from [Steamworks.NET](https://github.com/rlabrecque/Steamworks.NET) **NOTE This is not recomended as the SteamManager does not support Steam Game Server and is very limited in funcitonlity, it can however be a good learning tool for creating your own logic**
|
||||
|
||||
|
||||
Steam Networking Sockets uses the CSteamID as the network address to connect to. For P2P games this would require you to provide the Steam ID of the peer to connect to. For Client Server games this would require you to log your server onto Steam as a Steam Game Server, this act will issue your server a Steam ID which would be used as the address in this transport.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7a09aff8ae82b434db8621094fa64645
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a8e5e412fec28534c86d8f84fe01a075
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,478 @@
|
|||
#if !DISABLESTEAMWORKS && STEAMWORKSNET && NETCODEGAMEOBJECTS
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Steamworks;
|
||||
using System;
|
||||
using Unity.Netcode;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Netcode.Transports
|
||||
{
|
||||
public class SteamNetworkingSocketsTransport : NetworkTransport
|
||||
{
|
||||
#region Internal Object Model
|
||||
private class SteamConnectionData
|
||||
{
|
||||
internal SteamConnectionData(CSteamID steamId)
|
||||
{
|
||||
id = steamId;
|
||||
}
|
||||
|
||||
internal CSteamID id;
|
||||
internal HSteamNetConnection connection;
|
||||
}
|
||||
|
||||
private Callback<SteamNetConnectionStatusChangedCallback_t> c_onConnectionChange = null;
|
||||
private HSteamListenSocket listenSocket;
|
||||
private SteamConnectionData serverUser;
|
||||
private readonly Dictionary<ulong, SteamConnectionData> connectionMapping = new Dictionary<ulong, SteamConnectionData>();
|
||||
private readonly Queue<SteamNetConnectionStatusChangedCallback_t> connectionStatusChangeQueue = new Queue<SteamNetConnectionStatusChangedCallback_t>();
|
||||
private bool isServer = false;
|
||||
#endregion
|
||||
|
||||
public ulong ConnectToSteamID;
|
||||
public SteamNetworkingConfigValue_t[] options = new SteamNetworkingConfigValue_t[0];
|
||||
|
||||
public override ulong ServerClientId => 0;
|
||||
public override bool IsSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
InteropHelp.TestIfAvailableGameServer();
|
||||
#else
|
||||
InteropHelp.TestIfAvailableClient();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisconnectLocalClient()
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer) NetworkLog.LogInfoServer(nameof(SteamNetworkingSocketsTransport) + " - DisconnectLocalClient");
|
||||
|
||||
if (connectionMapping.ContainsKey(serverUser.id.m_SteamID))
|
||||
connectionMapping.Remove(serverUser.id.m_SteamID);
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
serverUser = null;
|
||||
}
|
||||
|
||||
public override void DisconnectRemoteClient(ulong clientId)
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
NetworkLog.LogInfoServer(nameof(SteamNetworkingSocketsTransport.DisconnectRemoteClient) + " - clientId: " + clientId);
|
||||
|
||||
if (!connectionMapping.ContainsKey(clientId))
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Error)
|
||||
NetworkLog.LogErrorServer(nameof(SteamNetworkingSocketsTransport) + " - Can't disconect client, client not connected, clientId: " + clientId);
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(connectionMapping[clientId].connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(connectionMapping[clientId].connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
|
||||
connectionMapping.Remove(clientId);
|
||||
}
|
||||
|
||||
public override ulong GetCurrentRtt(ulong clientId)
|
||||
{
|
||||
if (isServer)
|
||||
{
|
||||
if (connectionMapping.ContainsKey(clientId))
|
||||
{
|
||||
//TODO: We need to figure out how Valve expects you to use ISteamNetworkingUtils ... the issue is no one thought to document WTF a SteamNetworkingPingLocation was or how to get them
|
||||
return 0ul;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Error)
|
||||
NetworkLog.LogErrorServer(nameof(SteamNetworkingSocketsTransport) + " - Can't GetCurrentRtt from client, client not connected, clientId: " + clientId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0ul;
|
||||
}
|
||||
|
||||
return 0ul;
|
||||
}
|
||||
|
||||
public override void Initialize(NetworkManager networkManager = null)
|
||||
{
|
||||
if (!IsSupported)
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Error)
|
||||
NetworkLog.LogErrorServer(nameof(SteamNetworkingSocketsTransport) + " - Initialize - Steamworks.NET not ready, " + nameof(SteamNetworkingSocketsTransport) + " can not run without it");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
|
||||
{
|
||||
//Handle any connection state changes we may have
|
||||
#region Connnection State Changes
|
||||
while (connectionStatusChangeQueue.Count > 0)
|
||||
{
|
||||
var param = connectionStatusChangeQueue.Dequeue();
|
||||
|
||||
if (param.m_info.m_eState == ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connecting)
|
||||
{
|
||||
//This happens when someone asked to connect to us, in the case of NetCode for GameObject this should only happen if we are a server/host
|
||||
//the current standard is to blindly accept ... NetCode for GO should really consider a validation model for connections
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
NetworkLog.LogInfoServer(nameof(SteamNetworkingSocketsTransport) + " - connection request from " + param.m_info.m_identityRemote.GetSteamID64());
|
||||
|
||||
if (isServer)
|
||||
{
|
||||
EResult res;
|
||||
#if UNITY_SERVER
|
||||
if ((res = SteamGameServerNetworkingSockets.AcceptConnection(param.m_hConn)) == EResult.k_EResultOK)
|
||||
#else
|
||||
if ((res = SteamNetworkingSockets.AcceptConnection(param.m_hConn)) == EResult.k_EResultOK)
|
||||
#endif
|
||||
{
|
||||
if (isServer)
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
Debug.Log($"Accepting connection {param.m_info.m_identityRemote.GetSteamID64()}");
|
||||
|
||||
|
||||
clientId = param.m_info.m_identityRemote.GetSteamID64();
|
||||
payload = new ArraySegment<byte>();
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
|
||||
//This should be a new connection, record it
|
||||
if (connectionMapping.ContainsKey(clientId) == false)
|
||||
{
|
||||
var nCon = new SteamConnectionData(param.m_info.m_identityRemote.GetSteamID());
|
||||
nCon.connection = param.m_hConn;
|
||||
connectionMapping.Add(clientId, nCon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
Debug.Log($"Connection {param.m_info.m_identityRemote.GetSteamID64()} could not be accepted: this is not a server");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
Debug.Log($"Connection {param.m_info.m_identityRemote.GetSteamID64()} could not be accepted: {res}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (param.m_info.m_eState == ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_Connected)
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
NetworkLog.LogInfoServer(nameof(SteamNetworkingSocketsTransport) + " - connection request to " + param.m_info.m_identityRemote.GetSteamID64() + " was accepted!");
|
||||
|
||||
clientId = param.m_info.m_identityRemote.GetSteamID64();
|
||||
payload = new ArraySegment<byte>();
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
|
||||
//We should already have it but if not record the server connection that was just accepted
|
||||
if (connectionMapping.ContainsKey(clientId) == false)
|
||||
{
|
||||
var nCon = new SteamConnectionData(param.m_info.m_identityRemote.GetSteamID());
|
||||
nCon.connection = param.m_hConn;
|
||||
connectionMapping.Add(clientId, nCon);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Should be redundent but update the conneciton handle anyway
|
||||
connectionMapping[clientId].connection = param.m_hConn;
|
||||
}
|
||||
|
||||
return NetworkEvent.Connect;
|
||||
}
|
||||
else if (param.m_info.m_eState == ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ClosedByPeer
|
||||
|| param.m_info.m_eState == ESteamNetworkingConnectionState.k_ESteamNetworkingConnectionState_ProblemDetectedLocally)
|
||||
{
|
||||
//The connection is no more
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
NetworkLog.LogInfoServer(nameof(SteamNetworkingSocketsTransport) + $" - connection closed for {param.m_info.m_identityRemote.GetSteamID64()} state responce: {param.m_info.m_eState}");
|
||||
|
||||
clientId = param.m_info.m_identityRemote.GetSteamID64();
|
||||
payload = new ArraySegment<byte>();
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
|
||||
//Remove the mapped connection info
|
||||
if (connectionMapping.ContainsKey(clientId) != false)
|
||||
connectionMapping.Remove(clientId);
|
||||
|
||||
return NetworkEvent.Disconnect;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
Debug.Log($"Connection {param.m_info.m_identityRemote.GetSteamID64()} state changed: {param.m_info.m_eState}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
foreach (var connectionData in connectionMapping.Values)
|
||||
{
|
||||
IntPtr[] ptrs = new IntPtr[1];
|
||||
int messageCount;
|
||||
|
||||
#if UNITY_SERVER
|
||||
if ((messageCount = SteamGameServerNetworkingSockets.ReceiveMessagesOnConnection(connectionData.connection, ptrs, 1)) > 0)
|
||||
#else
|
||||
if ((messageCount = SteamNetworkingSockets.ReceiveMessagesOnConnection(connectionData.connection, ptrs, 1)) > 0)
|
||||
#endif
|
||||
{
|
||||
if (messageCount > 0)
|
||||
{
|
||||
clientId = connectionData.id.m_SteamID;
|
||||
|
||||
SteamNetworkingMessage_t data = Marshal.PtrToStructure<SteamNetworkingMessage_t>(ptrs[0]);
|
||||
var buffer = new byte[data.m_cbSize];
|
||||
Marshal.Copy(data.m_pData, buffer, 0, data.m_cbSize);
|
||||
payload = buffer;
|
||||
SteamNetworkingMessage_t.Release(ptrs[0]);
|
||||
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
return NetworkEvent.Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
payload = new ArraySegment<byte>();
|
||||
clientId = 0;
|
||||
receiveTime = Time.realtimeSinceStartup;
|
||||
return NetworkEvent.Nothing;
|
||||
}
|
||||
|
||||
public override void Send(ulong clientId, ArraySegment<byte> segment, NetworkDelivery delivery)
|
||||
{
|
||||
if(clientId == 0)
|
||||
clientId = serverUser.id.m_SteamID;
|
||||
|
||||
//Check if we have a mapped user for this ID
|
||||
if (connectionMapping.ContainsKey(clientId))
|
||||
{
|
||||
//Grab a pointer to the user's connection
|
||||
var connection = connectionMapping[clientId].connection;
|
||||
|
||||
//Build a standard array + 1 for the channel
|
||||
byte[] data = new byte[segment.Count + 1];
|
||||
Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
|
||||
//The segment count is the last index in our (+1) array, on that last index write a byte indicating the delivery channel
|
||||
data[segment.Count] = Convert.ToByte((int)delivery);
|
||||
//Create an unmanaged array and get a pointer to it
|
||||
GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||
IntPtr pData = pinnedArray.AddrOfPinnedObject();
|
||||
//Translate the NetworkDelivery (channle) to the Steam QoS send type .. we assume unreliable if nothing matches
|
||||
int sendFlag = Constants.k_nSteamNetworkingSend_Unreliable;
|
||||
switch (delivery)
|
||||
{
|
||||
case NetworkDelivery.Reliable:
|
||||
case NetworkDelivery.ReliableFragmentedSequenced:
|
||||
sendFlag = Constants.k_nSteamNetworkingSend_Reliable;
|
||||
break;
|
||||
case NetworkDelivery.ReliableSequenced:
|
||||
sendFlag = Constants.k_nSteamNetworkingSend_ReliableNoNagle;
|
||||
break;
|
||||
case NetworkDelivery.UnreliableSequenced:
|
||||
sendFlag = Constants.k_nSteamNetworkingSend_UnreliableNoNagle;
|
||||
break;
|
||||
}
|
||||
//Send to the target
|
||||
#if UNITY_SERVER
|
||||
EResult responce = SteamGameServerNetworkingSockets.SendMessageToConnection(connection, pData, (uint)data.Length, sendFlag, out long _);
|
||||
#else
|
||||
EResult responce = SteamNetworkingSockets.SendMessageToConnection(connection, pData, (uint)data.Length, sendFlag, out long _);
|
||||
#endif
|
||||
//Free the unmanaged array
|
||||
pinnedArray.Free();
|
||||
|
||||
//If we had some error report that and move on
|
||||
if ((responce == EResult.k_EResultNoConnection || responce == EResult.k_EResultInvalidParam)
|
||||
&& NetworkManager.Singleton.LogLevel <= LogLevel.Normal)
|
||||
{
|
||||
Debug.LogWarning($"Connection to server was lost.");
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
}
|
||||
else if (responce != EResult.k_EResultOK
|
||||
&& NetworkManager.Singleton.LogLevel <= LogLevel.Error)
|
||||
{
|
||||
Debug.LogError($"Could not send: {responce}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//No client found so report that
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Error)
|
||||
{
|
||||
Debug.LogError("Trying to send on unknown connection: " + clientId);
|
||||
NetworkLog.LogErrorServer(nameof(SteamNetworkingSocketsTransport.Send) + " - Trying to send on unknown connection: " + clientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
UnityEngine.Debug.Log(nameof(SteamNetworkingSocketsTransport.Shutdown));
|
||||
|
||||
if (isServer)
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseListenSocket(listenSocket);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseListenSocket(listenSocket);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serverUser != null)
|
||||
{
|
||||
if (connectionMapping.ContainsKey(serverUser.id.m_SteamID))
|
||||
connectionMapping.Remove(serverUser.id.m_SteamID);
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
isServer = false;
|
||||
|
||||
if (NetworkManager.Singleton != null)
|
||||
{
|
||||
//Delay
|
||||
NetworkManager.Singleton.StartCoroutine(Delay(0.1f, () =>
|
||||
{
|
||||
CloseP2PSessions();
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseP2PSessions();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool StartClient()
|
||||
{
|
||||
if (c_onConnectionChange == null)
|
||||
c_onConnectionChange = Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
|
||||
|
||||
serverUser = new SteamConnectionData(new CSteamID(ConnectToSteamID));
|
||||
|
||||
try
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingUtils.InitRelayNetworkAccess();
|
||||
#else
|
||||
SteamNetworkingUtils.InitRelayNetworkAccess();
|
||||
#endif
|
||||
SteamNetworkingIdentity smi = new SteamNetworkingIdentity();
|
||||
smi.SetSteamID(serverUser.id);
|
||||
#if UNITY_SERVER
|
||||
serverUser.connection = SteamGameServerNetworkingSockets.ConnectP2P(ref smi, 0, options.Length, options);
|
||||
#else
|
||||
serverUser.connection = SteamNetworkingSockets.ConnectP2P(ref smi, 0, options.Length, options);
|
||||
#endif
|
||||
connectionMapping.Add(ConnectToSteamID, serverUser);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("Exception: " + ex.Message + ". Client could not be started.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool StartServer()
|
||||
{
|
||||
isServer = true;
|
||||
|
||||
if(c_onConnectionChange == null)
|
||||
c_onConnectionChange = Callback<SteamNetConnectionStatusChangedCallback_t>.Create(OnConnectionStatusChanged);
|
||||
|
||||
if (options == null)
|
||||
options = new SteamNetworkingConfigValue_t[0];
|
||||
|
||||
#if UNITY_SERVER
|
||||
listenSocket = SteamGameServerNetworkingSockets.CreateListenSocketP2P(0, options.Length, options);
|
||||
#else
|
||||
listenSocket = SteamNetworkingSockets.CreateListenSocketP2P(0, options.Length, options);
|
||||
#endif
|
||||
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
UnityEngine.Debug.Log(nameof(SteamNetworkingSocketsTransport.StartServer));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CloseP2PSessions()
|
||||
{
|
||||
if (serverUser != null)
|
||||
{
|
||||
if(connectionMapping.ContainsKey(serverUser.id.m_SteamID))
|
||||
connectionMapping.Remove(serverUser.id.m_SteamID);
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(serverUser.connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
}
|
||||
|
||||
foreach (SteamConnectionData user in connectionMapping.Values)
|
||||
{
|
||||
#if UNITY_SERVER
|
||||
SteamGameServerNetworkingSockets.CloseConnection(user.connection, 0, "Disconnected", false);
|
||||
#else
|
||||
SteamNetworkingSockets.CloseConnection(user.connection, 0, "Disconnected", false);
|
||||
#endif
|
||||
}
|
||||
|
||||
connectionMapping.Clear();
|
||||
serverUser = null;
|
||||
if (NetworkManager.Singleton.LogLevel <= LogLevel.Developer)
|
||||
UnityEngine.Debug.Log(nameof(SteamNetworkingSocketsTransport) + " - CloseP2PSessions - has Closed P2P Sessions With all Users");
|
||||
|
||||
if (c_onConnectionChange != null)
|
||||
{
|
||||
c_onConnectionChange.Dispose();
|
||||
c_onConnectionChange = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t param)
|
||||
{
|
||||
connectionStatusChangeQueue.Enqueue(param);
|
||||
}
|
||||
|
||||
private static IEnumerator Delay(float time, Action action)
|
||||
{
|
||||
yield return new WaitForSeconds(time);
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc4ccaff1920208429cca7c350560301
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "SteamNetworkingSockets Transport for Netcode for GameObjects",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:1491147abca9d7d4bb7105af628b223e",
|
||||
"GUID:68bd7fdb68ef2684e982e8a9825b18a5"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor",
|
||||
"LinuxStandalone64",
|
||||
"macOSStandalone",
|
||||
"WindowsStandalone32",
|
||||
"WindowsStandalone64"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.rlabrecque.steamworks.net",
|
||||
"expression": "",
|
||||
"define": "STEAMWORKSNET"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.netcode.gameobjects",
|
||||
"expression": "",
|
||||
"define": "NETCODEGAMEOBJECTS"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 98d94cfe204587a4f92ed81e64a8e624
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "com.community.netcode.transport.steamnetworkingsockets",
|
||||
"displayName": "SteamNetworkingSockets Transport for NetCode for Gameobjects",
|
||||
"version": "1.0.0",
|
||||
"unity": "2020.3",
|
||||
"description": "SteamNetworkingSockets Transport for NetCode for GameObjects with support for both peer to peer and client server architectures.",
|
||||
"author": {
|
||||
"name": "Heathen Group",
|
||||
"url": "https://assetstore.unity.com/publishers/5836"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 553e5c0d0214d5849abdd9a465394696
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Загрузка…
Ссылка в новой задаче