Revert "Revert "cleanup fizzyfacepunch""

This reverts commit c049b94527a16c3ae0f04c644362cf5b3f3f114b.
This commit is contained in:
Mister_Nebula 2022-01-31 19:33:55 +00:00
parent c049b94527
commit f7ed57a787
12 changed files with 1045 additions and 1065 deletions

View File

@ -3,79 +3,79 @@ using System.Collections.Generic;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public class BidirectionalDictionary<T1, T2> : IEnumerable public class BidirectionalDictionary<T1, T2> : IEnumerable
{ {
private Dictionary<T1, T2> t1ToT2Dict = new Dictionary<T1, T2>(); private readonly Dictionary<T1, T2> t1ToT2Dict = new Dictionary<T1, T2>();
private Dictionary<T2, T1> t2ToT1Dict = new Dictionary<T2, T1>(); private readonly Dictionary<T2, T1> t2ToT1Dict = new Dictionary<T2, T1>();
public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys; public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys;
public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys; public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys;
public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator(); public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator();
public int Count => t1ToT2Dict.Count; public int Count => t1ToT2Dict.Count;
public void Add(T1 key, T2 value) public void Add(T1 key, T2 value)
{ {
t1ToT2Dict[key] = value; t1ToT2Dict[key] = value;
t2ToT1Dict[value] = key; t2ToT1Dict[value] = key;
} }
public void Add(T2 key, T1 value) public void Add(T2 key, T1 value)
{ {
t2ToT1Dict[key] = value; t2ToT1Dict[key] = value;
t1ToT2Dict[value] = key; t1ToT2Dict[value] = key;
} }
public T2 Get(T1 key) => t1ToT2Dict[key]; public T2 Get(T1 key) => t1ToT2Dict[key];
public T1 Get(T2 key) => t2ToT1Dict[key]; public T1 Get(T2 key) => t2ToT1Dict[key];
public bool TryGetValue(T1 key, out T2 value) => t1ToT2Dict.TryGetValue(key, out value); public bool TryGetValue(T1 key, out T2 value) => t1ToT2Dict.TryGetValue(key, out value);
public bool TryGetValue(T2 key, out T1 value) => t2ToT1Dict.TryGetValue(key, out value); public bool TryGetValue(T2 key, out T1 value) => t2ToT1Dict.TryGetValue(key, out value);
public bool Contains(T1 key) => t1ToT2Dict.ContainsKey(key); public bool Contains(T1 key) => t1ToT2Dict.ContainsKey(key);
public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key); public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key);
public void Remove(T1 key) public void Remove(T1 key)
{ {
if (Contains(key)) if (Contains(key))
{ {
T2 val = t1ToT2Dict[key]; var val = t1ToT2Dict[key];
t1ToT2Dict.Remove(key); t1ToT2Dict.Remove(key);
t2ToT1Dict.Remove(val); t2ToT1Dict.Remove(val);
} }
} }
public void Remove(T2 key) public void Remove(T2 key)
{ {
if (Contains(key)) if (Contains(key))
{ {
T1 val = t2ToT1Dict[key]; var val = t2ToT1Dict[key];
t1ToT2Dict.Remove(val); t1ToT2Dict.Remove(val);
t2ToT1Dict.Remove(key); t2ToT1Dict.Remove(key);
} }
} }
public T1 this[T2 key] public T1 this[T2 key]
{ {
get => t2ToT1Dict[key]; get => t2ToT1Dict[key];
set set
{ {
t2ToT1Dict[key] = value; t2ToT1Dict[key] = value;
t1ToT2Dict[value] = key; t1ToT2Dict[value] = key;
} }
} }
public T2 this[T1 key] public T2 this[T1 key]
{ {
get => t1ToT2Dict[key]; get => t1ToT2Dict[key];
set set
{ {
t1ToT2Dict[key] = value; t1ToT2Dict[key] = value;
t2ToT1Dict[value] = key; t2ToT1Dict[value] = key;
} }
} }
} }
} }

View File

@ -3,10 +3,7 @@ using System;
public class FizzyConnectionManager : ConnectionManager public class FizzyConnectionManager : ConnectionManager
{ {
public Action<IntPtr, int> ForwardMessage; public Action<IntPtr, int> ForwardMessage;
public override void OnMessage(IntPtr data, int size, long messageNum, long recvTime, int channel) public override void OnMessage(IntPtr data, int size, long messageNum, long recvTime, int channel) => ForwardMessage(data, size);
{
ForwardMessage(data, size);
}
} }

View File

@ -1,303 +1,301 @@
using Steamworks; using Steamworks;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using UnityEngine; using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
[HelpURL("https://github.com/Chykary/FizzyFacepunch")] [HelpURL("https://github.com/Chykary/FizzyFacepunch")]
public class FizzyFacepunch : Transport public class FizzyFacepunch : Transport
{ {
private const string STEAM_SCHEME = "steam"; private const string STEAM_SCHEME = "steam";
private static IClient client; private static IClient client;
private static IServer server; private static IServer server;
[SerializeField] [SerializeField]
public P2PSend[] Channels = new P2PSend[2] { P2PSend.Reliable, P2PSend.UnreliableNoDelay }; public P2PSend[] Channels = new P2PSend[2] { P2PSend.Reliable, P2PSend.UnreliableNoDelay };
[Tooltip("Timeout for connecting in seconds.")] [Tooltip("Timeout for connecting in seconds.")]
public int Timeout = 25; public int Timeout = 25;
[Tooltip("The Steam ID for your application.")] [Tooltip("The Steam ID for your application.")]
public string SteamAppID = "480"; public string SteamAppID = "480";
[Tooltip("Allow or disallow P2P connections to fall back to being relayed through the Steam servers if a direct connection or NAT-traversal cannot be established.")] [Tooltip("Allow or disallow P2P connections to fall back to being relayed through the Steam servers if a direct connection or NAT-traversal cannot be established.")]
public bool AllowSteamRelay = true; public bool AllowSteamRelay = true;
[Tooltip("Use SteamSockets instead of the (deprecated) SteamNetworking. This will always use Relay.")] [Tooltip("Use SteamSockets instead of the (deprecated) SteamNetworking. This will always use Relay.")]
public bool UseNextGenSteamNetworking = true; public bool UseNextGenSteamNetworking = true;
[Tooltip("Check this if you want the transport to initialise Facepunch.")] [Tooltip("Check this if you want the transport to initialise Facepunch.")]
public bool InitFacepunch = true; public bool InitFacepunch = true;
[Header("Info")] [Header("Info")]
[Tooltip("This will display your Steam User ID when you start or connect to a server.")] [Tooltip("This will display your Steam User ID when you start or connect to a server.")]
public ulong SteamUserID; public ulong SteamUserID;
public Action<string> SetTransportError; public Action<string> SetTransportError;
private void Awake() private void Awake()
{ {
const string fileName = "steam_appid.txt"; const string fileName = "steam_appid.txt";
if (File.Exists(fileName)) if (File.Exists(fileName))
{ {
string content = File.ReadAllText(fileName); var content = File.ReadAllText(fileName);
if (content != SteamAppID) if (content != SteamAppID)
{ {
File.WriteAllText(fileName, SteamAppID.ToString()); File.WriteAllText(fileName, SteamAppID.ToString());
Debug.Log($"Updating {fileName}. Previous: {content}, new SteamAppID {SteamAppID}"); Debug.Log($"Updating {fileName}. Previous: {content}, new SteamAppID {SteamAppID}");
} }
} }
else else
{ {
File.WriteAllText(fileName, SteamAppID.ToString()); File.WriteAllText(fileName, SteamAppID.ToString());
Debug.Log($"New {fileName} written with SteamAppID {SteamAppID}"); Debug.Log($"New {fileName} written with SteamAppID {SteamAppID}");
} }
Debug.Assert(Channels != null && Channels.Length > 0, "No channel configured for FizzySteamworks."); Debug.Assert(Channels != null && Channels.Length > 0, "No channel configured for FizzySteamworks.");
if (InitFacepunch) if (InitFacepunch)
{ {
SteamClient.Init(uint.Parse(SteamAppID), true); SteamClient.Init(uint.Parse(SteamAppID), true);
} }
Invoke(nameof(FetchSteamID), 1f); Invoke(nameof(FetchSteamID), 1f);
} }
public override void ClientEarlyUpdate() public override void ClientEarlyUpdate()
{ {
if (enabled && client != null && !client.Error) if (enabled && client != null && !client.Error)
{ {
client?.ReceiveData(); client?.ReceiveData();
} }
} }
public override void ServerEarlyUpdate() public override void ServerEarlyUpdate()
{ {
if (enabled) if (enabled)
{ {
server?.ReceiveData(); server?.ReceiveData();
} }
} }
public override void ClientLateUpdate() public override void ClientLateUpdate()
{ {
if (enabled && client != null && !client.Error) if (enabled && client != null && !client.Error)
{ {
client?.FlushData(); client?.FlushData();
} }
} }
public override void ServerLateUpdate() public override void ServerLateUpdate()
{ {
if (enabled) if (enabled)
{ {
server?.FlushData(); server?.FlushData();
} }
} }
public override bool ClientConnected() => ClientActive() && client.Connected; public override bool ClientConnected() => ClientActive() && client.Connected;
public override void ClientConnect(string address) public override void ClientConnect(string address)
{ {
if (!SteamClient.IsValid) if (!SteamClient.IsValid)
{ {
Debug.LogError("SteamWorks not initialized. Client could not be started."); Debug.LogError("SteamWorks not initialized. Client could not be started.");
OnClientDisconnected.Invoke(); OnClientDisconnected.Invoke();
return; return;
} }
FetchSteamID(); FetchSteamID();
if (ServerActive()) if (ServerActive())
{ {
Debug.LogError("Transport already running as server!"); Debug.LogError("Transport already running as server!");
return; return;
} }
if (!ClientActive() || client.Error) if (!ClientActive() || client.Error)
{ {
if (UseNextGenSteamNetworking) if (UseNextGenSteamNetworking)
{ {
Debug.Log($"Starting client [SteamSockets], target address {address}."); Debug.Log($"Starting client [SteamSockets], target address {address}.");
client = NextClient.CreateClient(this, address); client = NextClient.CreateClient(this, address);
} }
else else
{ {
Debug.Log($"Starting client [DEPRECATED SteamNetworking], target address {address}. Relay enabled: {AllowSteamRelay}"); Debug.Log($"Starting client [DEPRECATED SteamNetworking], target address {address}. Relay enabled: {AllowSteamRelay}");
SteamNetworking.AllowP2PPacketRelay(AllowSteamRelay); SteamNetworking.AllowP2PPacketRelay(AllowSteamRelay);
client = LegacyClient.CreateClient(this, address); client = LegacyClient.CreateClient(this, address);
} }
} }
else else
{ {
Debug.LogError("Client already running!"); Debug.LogError("Client already running!");
} }
} }
public override void ClientConnect(Uri uri) public override void ClientConnect(Uri uri)
{ {
if (uri.Scheme != STEAM_SCHEME) if (uri.Scheme != STEAM_SCHEME)
throw new ArgumentException($"Invalid url {uri}, use {STEAM_SCHEME}://SteamID instead", nameof(uri)); {
throw new ArgumentException($"Invalid url {uri}, use {STEAM_SCHEME}://SteamID instead", nameof(uri));
}
ClientConnect(uri.Host); ClientConnect(uri.Host);
} }
public override void ClientSend(ArraySegment<byte> segment, int channelId) public override void ClientSend(ArraySegment<byte> segment, int channelId)
{ {
byte[] data = new byte[segment.Count]; var data = new byte[segment.Count];
Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count); Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
client.Send(data, channelId); client.Send(data, channelId);
} }
public override void ClientDisconnect() public override void ClientDisconnect()
{ {
if (ClientActive()) if (ClientActive())
{ {
Shutdown(); Shutdown();
} }
} }
public bool ClientActive() => client != null; public bool ClientActive() => client != null;
public override bool ServerActive() => server != null; public override bool ServerActive() => server != null;
public override void ServerStart() public override void ServerStart()
{ {
if (!SteamClient.IsValid) if (!SteamClient.IsValid)
{ {
Debug.LogError("SteamWorks not initialized. Server could not be started."); Debug.LogError("SteamWorks not initialized. Server could not be started.");
return; return;
} }
FetchSteamID(); FetchSteamID();
if (ClientActive()) if (ClientActive())
{ {
Debug.LogError("Transport already running as client!"); Debug.LogError("Transport already running as client!");
return; return;
} }
if (!ServerActive()) if (!ServerActive())
{ {
if (UseNextGenSteamNetworking) if (UseNextGenSteamNetworking)
{ {
Debug.Log($"Starting server [SteamSockets]."); Debug.Log($"Starting server [SteamSockets].");
server = NextServer.CreateServer(this, NetworkManager.singleton.maxConnections); server = NextServer.CreateServer(this, NetworkManager.singleton.maxConnections);
} }
else else
{ {
Debug.Log($"Starting server [DEPRECATED SteamNetworking]. Relay enabled: {AllowSteamRelay}"); Debug.Log($"Starting server [DEPRECATED SteamNetworking]. Relay enabled: {AllowSteamRelay}");
SteamNetworking.AllowP2PPacketRelay(AllowSteamRelay); SteamNetworking.AllowP2PPacketRelay(AllowSteamRelay);
server = LegacyServer.CreateServer(this, NetworkManager.singleton.maxConnections); server = LegacyServer.CreateServer(this, NetworkManager.singleton.maxConnections);
} }
} }
else else
{ {
Debug.LogError("Server already started!"); Debug.LogError("Server already started!");
} }
} }
public override Uri ServerUri() public override Uri ServerUri()
{ {
var steamBuilder = new UriBuilder var steamBuilder = new UriBuilder
{ {
Scheme = STEAM_SCHEME, Scheme = STEAM_SCHEME,
Host = SteamClient.SteamId.Value.ToString() Host = SteamClient.SteamId.Value.ToString()
}; };
return steamBuilder.Uri; return steamBuilder.Uri;
} }
public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId) public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId)
{ {
if (ServerActive()) if (ServerActive())
{ {
byte[] data = new byte[segment.Count]; var data = new byte[segment.Count];
Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count); Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
server.Send(connectionId, data, channelId); server.Send(connectionId, data, channelId);
} }
} }
public override void ServerDisconnect(int connectionId) public override void ServerDisconnect(int connectionId)
{ {
if (ServerActive()) if (ServerActive())
{ {
server.Disconnect(connectionId); server.Disconnect(connectionId);
} }
} }
public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty; public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty;
public override void ServerStop() public override void ServerStop()
{ {
if (ServerActive()) if (ServerActive())
{ {
Shutdown(); Shutdown();
} }
} }
public override void Shutdown() public override void Shutdown()
{ {
if (server != null) if (server != null)
{ {
server.Shutdown(); server.Shutdown();
server = null; server = null;
Debug.Log("Transport shut down - was server."); Debug.Log("Transport shut down - was server.");
} }
if (client != null) if (client != null)
{ {
client.Disconnect(); client.Disconnect();
client = null; client = null;
Debug.Log("Transport shut down - was client."); Debug.Log("Transport shut down - was client.");
} }
} }
public override int GetMaxPacketSize(int channelId) public override int GetMaxPacketSize(int channelId)
{ {
if (channelId >= Channels.Length) if (channelId >= Channels.Length)
{ {
Debug.LogError("Channel Id exceeded configured channels! Please configure more channels."); Debug.LogError("Channel Id exceeded configured channels! Please configure more channels.");
return 1200; return 1200;
} }
switch (Channels[channelId]) switch (Channels[channelId])
{ {
case P2PSend.Unreliable: case P2PSend.Unreliable:
case P2PSend.UnreliableNoDelay: case P2PSend.UnreliableNoDelay:
return 1200; return 1200;
case P2PSend.Reliable: case P2PSend.Reliable:
case P2PSend.ReliableWithBuffering: case P2PSend.ReliableWithBuffering:
return 1048576; return 1048576;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
} }
public override bool Available() public override bool Available()
{ {
try try
{ {
return SteamClient.IsValid; return SteamClient.IsValid;
} }
catch catch
{ {
return false; return false;
} }
} }
private void FetchSteamID() private void FetchSteamID()
{ {
if (SteamClient.IsValid) if (SteamClient.IsValid)
{ {
if (UseNextGenSteamNetworking) if (UseNextGenSteamNetworking)
{ {
SteamNetworkingUtils.InitRelayNetworkAccess(); SteamNetworkingUtils.InitRelayNetworkAccess();
} }
SteamUserID = SteamClient.SteamId; SteamUserID = SteamClient.SteamId;
} }
} }
private void OnDestroy() private void OnDestroy() => Shutdown();
{ }
Shutdown();
}
}
} }

View File

@ -4,10 +4,7 @@ using System;
public class FizzySocketManager : SocketManager public class FizzySocketManager : SocketManager
{ {
public Action<Connection, IntPtr, int> ForwardMessage; public Action<Connection, IntPtr, int> ForwardMessage;
public override void OnMessage(Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel) public override void OnMessage(Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel) => ForwardMessage(connection, data, size);
{
ForwardMessage(connection, data, size);
}
} }

View File

@ -1,12 +1,12 @@
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public interface IClient public interface IClient
{ {
bool Connected { get; } bool Connected { get; }
bool Error { get; } bool Error { get; }
void ReceiveData(); void ReceiveData();
void Disconnect(); void Disconnect();
void FlushData(); void FlushData();
void Send(byte[] data, int channelId); void Send(byte[] data, int channelId);
} }
} }

View File

@ -1,12 +1,12 @@
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public interface IServer public interface IServer
{ {
void ReceiveData(); void ReceiveData();
void Send(int connectionId, byte[] data, int channelId); void Send(int connectionId, byte[] data, int channelId);
void Disconnect(int connectionId); void Disconnect(int connectionId);
void FlushData(); void FlushData();
string ServerGetClientAddress(int connectionId); string ServerGetClientAddress(int connectionId);
void Shutdown(); void Shutdown();
} }
} }

View File

@ -6,159 +6,156 @@ using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public class LegacyClient : LegacyCommon, IClient public class LegacyClient : LegacyCommon, IClient
{ {
public bool Error { get; private set; } public bool Error { get; private set; }
public bool Connected { get; private set; } public bool Connected { get; private set; }
private event Action<byte[], int> OnReceivedData; private event Action<byte[], int> OnReceivedData;
private event Action OnConnected; private event Action OnConnected;
private event Action OnDisconnected; private event Action OnDisconnected;
private TimeSpan ConnectionTimeout; private TimeSpan ConnectionTimeout;
private SteamId hostSteamID = 0; private SteamId hostSteamID = 0;
private TaskCompletionSource<Task> connectedComplete; private TaskCompletionSource<Task> connectedComplete;
private CancellationTokenSource cancelToken; private CancellationTokenSource cancelToken;
private LegacyClient(FizzyFacepunch transport) : base(transport) private LegacyClient(FizzyFacepunch transport) : base(transport) => ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.Timeout));
{
ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.Timeout));
}
public static LegacyClient CreateClient(FizzyFacepunch transport, string host) public static LegacyClient CreateClient(FizzyFacepunch transport, string host)
{ {
LegacyClient c = new LegacyClient(transport); var c = new LegacyClient(transport);
c.OnConnected += () => transport.OnClientConnected.Invoke(); c.OnConnected += () => transport.OnClientConnected.Invoke();
c.OnDisconnected += () => transport.OnClientDisconnected.Invoke(); c.OnDisconnected += () => transport.OnClientDisconnected.Invoke();
c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), channel); c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), channel);
if (SteamClient.IsValid) if (SteamClient.IsValid)
{ {
c.Connect(host); c.Connect(host);
} }
else else
{ {
Debug.LogError("SteamWorks not initialized."); Debug.LogError("SteamWorks not initialized.");
c.OnConnectionFailed(new SteamId()); c.OnConnectionFailed(new SteamId());
} }
return c; return c;
} }
private async void Connect(string host) private async void Connect(string host)
{ {
cancelToken = new CancellationTokenSource(); cancelToken = new CancellationTokenSource();
try try
{ {
hostSteamID = ulong.Parse(host); hostSteamID = ulong.Parse(host);
connectedComplete = new TaskCompletionSource<Task>(); connectedComplete = new TaskCompletionSource<Task>();
OnConnected += SetConnectedComplete; OnConnected += SetConnectedComplete;
SendInternal(hostSteamID, InternalMessages.CONNECT); SendInternal(hostSteamID, InternalMessages.CONNECT);
Task connectedCompleteTask = connectedComplete.Task; Task connectedCompleteTask = connectedComplete.Task;
Task timeOutTask = Task.Delay(ConnectionTimeout, cancelToken.Token); var timeOutTask = Task.Delay(ConnectionTimeout, cancelToken.Token);
if (await Task.WhenAny(connectedCompleteTask, timeOutTask) != connectedCompleteTask) if (await Task.WhenAny(connectedCompleteTask, timeOutTask) != connectedCompleteTask)
{ {
if (cancelToken.IsCancellationRequested) if (cancelToken.IsCancellationRequested)
{ {
Debug.LogError($"The connection attempt was cancelled."); Debug.LogError($"The connection attempt was cancelled.");
} }
else if (timeOutTask.IsCompleted) else if (timeOutTask.IsCompleted)
{ {
Debug.LogError($"Connection to {host} timed out."); Debug.LogError($"Connection to {host} timed out.");
} }
OnConnected -= SetConnectedComplete; OnConnected -= SetConnectedComplete;
Debug.LogError("Connection timed out."); Debug.LogError("Connection timed out.");
OnConnectionFailed(hostSteamID); OnConnectionFailed(hostSteamID);
} }
OnConnected -= SetConnectedComplete; OnConnected -= SetConnectedComplete;
} }
catch (FormatException) catch (FormatException)
{ {
Debug.LogError($"Connection string was not in the right format. Did you enter a SteamId?"); Debug.LogError($"Connection string was not in the right format. Did you enter a SteamId?");
Error = true; Error = true;
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.LogError(ex.Message); Debug.LogError(ex.Message);
Error = true; Error = true;
} }
finally finally
{ {
if (Error) if (Error)
{ {
OnConnectionFailed(new SteamId()); OnConnectionFailed(new SteamId());
} }
} }
} }
public void Disconnect() public void Disconnect()
{ {
Debug.LogError("Sending Disconnect message"); Debug.LogError("Sending Disconnect message");
SendInternal(hostSteamID, InternalMessages.DISCONNECT); SendInternal(hostSteamID, InternalMessages.DISCONNECT);
Dispose(); Dispose();
cancelToken?.Cancel(); cancelToken?.Cancel();
WaitForClose(hostSteamID); WaitForClose(hostSteamID);
} }
private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task); private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task);
protected override void OnReceiveData(byte[] data, SteamId clientSteamID, int channel) protected override void OnReceiveData(byte[] data, SteamId clientSteamID, int channel)
{ {
if (clientSteamID != hostSteamID) if (clientSteamID != hostSteamID)
{ {
Debug.LogError("Received a message from an unknown"); Debug.LogError("Received a message from an unknown");
return; return;
} }
OnReceivedData.Invoke(data, channel); OnReceivedData.Invoke(data, channel);
} }
protected override void OnNewConnection(SteamId id) protected override void OnNewConnection(SteamId id)
{ {
if (hostSteamID == id) if (hostSteamID == id)
{ {
SteamNetworking.AcceptP2PSessionWithUser(id); SteamNetworking.AcceptP2PSessionWithUser(id);
} }
else else
{ {
Debug.LogError("P2P Acceptance Request from unknown host ID."); Debug.LogError("P2P Acceptance Request from unknown host ID.");
} }
} }
protected override void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID) protected override void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID)
{ {
switch (type) switch (type)
{ {
case InternalMessages.ACCEPT_CONNECT: case InternalMessages.ACCEPT_CONNECT:
if (!Connected) if (!Connected)
{ {
Connected = true; Connected = true;
Debug.LogError("Connection established."); Debug.LogError("Connection established.");
OnConnected.Invoke(); OnConnected.Invoke();
} }
break; break;
case InternalMessages.DISCONNECT: case InternalMessages.DISCONNECT:
if (Connected) if (Connected)
{ {
Connected = false; Connected = false;
Debug.LogError("Disconnected."); Debug.LogError("Disconnected.");
OnDisconnected.Invoke(); OnDisconnected.Invoke();
} }
break; break;
default: default:
Debug.LogError("Received unknown message type"); Debug.LogError("Received unknown message type");
break; break;
} }
} }
public void Send(byte[] data, int channelId) => Send(hostSteamID, data, channelId); public void Send(byte[] data, int channelId) => Send(hostSteamID, data, channelId);
protected override void OnConnectionFailed(SteamId remoteId) => OnDisconnected.Invoke(); protected override void OnConnectionFailed(SteamId remoteId) => OnDisconnected.Invoke();
public void FlushData() { } public void FlushData() { }
} }
} }

View File

@ -5,121 +5,121 @@ using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public abstract class LegacyCommon public abstract class LegacyCommon
{ {
private P2PSend[] channels; private readonly P2PSend[] channels;
private int internal_ch => channels.Length; private int internal_ch => channels.Length;
protected enum InternalMessages : byte protected enum InternalMessages : byte
{ {
CONNECT, CONNECT,
ACCEPT_CONNECT, ACCEPT_CONNECT,
DISCONNECT DISCONNECT
} }
protected readonly FizzyFacepunch transport; protected readonly FizzyFacepunch transport;
protected LegacyCommon(FizzyFacepunch transport) protected LegacyCommon(FizzyFacepunch transport)
{ {
channels = transport.Channels; channels = transport.Channels;
SteamNetworking.OnP2PSessionRequest += OnNewConnection; SteamNetworking.OnP2PSessionRequest += OnNewConnection;
SteamNetworking.OnP2PConnectionFailed += OnConnectFail; SteamNetworking.OnP2PConnectionFailed += OnConnectFail;
this.transport = transport; this.transport = transport;
} }
protected void WaitForClose(SteamId cSteamID) => transport.StartCoroutine(DelayedClose(cSteamID)); protected void WaitForClose(SteamId cSteamID) => transport.StartCoroutine(DelayedClose(cSteamID));
private IEnumerator DelayedClose(SteamId cSteamID) private IEnumerator DelayedClose(SteamId cSteamID)
{ {
yield return null; yield return null;
CloseP2PSessionWithUser(cSteamID); CloseP2PSessionWithUser(cSteamID);
} }
protected void Dispose() protected void Dispose()
{ {
SteamNetworking.OnP2PSessionRequest -= OnNewConnection; SteamNetworking.OnP2PSessionRequest -= OnNewConnection;
SteamNetworking.OnP2PConnectionFailed -= OnConnectFail; SteamNetworking.OnP2PConnectionFailed -= OnConnectFail;
} }
protected abstract void OnNewConnection(SteamId steamID); protected abstract void OnNewConnection(SteamId steamID);
private void OnConnectFail(SteamId id, P2PSessionError err) private void OnConnectFail(SteamId id, P2PSessionError err)
{ {
OnConnectionFailed(id); OnConnectionFailed(id);
CloseP2PSessionWithUser(id); CloseP2PSessionWithUser(id);
switch (err) switch (err)
{ {
case P2PSessionError.NotRunningApp: case P2PSessionError.NotRunningApp:
throw new Exception("Connection failed: The target user is not running the same game."); throw new Exception("Connection failed: The target user is not running the same game.");
case P2PSessionError.NoRightsToApp: case P2PSessionError.NoRightsToApp:
throw new Exception("Connection failed: The local user doesn't own the app that is running."); throw new Exception("Connection failed: The local user doesn't own the app that is running.");
case P2PSessionError.DestinationNotLoggedIn: case P2PSessionError.DestinationNotLoggedIn:
throw new Exception("Connection failed: Target user isn't connected to Steam."); throw new Exception("Connection failed: Target user isn't connected to Steam.");
case P2PSessionError.Timeout: case P2PSessionError.Timeout:
throw new Exception("Connection failed: The connection timed out because the target user didn't respond."); throw new Exception("Connection failed: The connection timed out because the target user didn't respond.");
default: default:
throw new Exception("Connection failed: Unknown error."); throw new Exception("Connection failed: Unknown error.");
} }
} }
protected bool SendInternal(SteamId target, InternalMessages type) => SteamNetworking.SendP2PPacket(target, new byte[] { (byte)type }, 1, internal_ch); protected bool SendInternal(SteamId target, InternalMessages type) => SteamNetworking.SendP2PPacket(target, new byte[] { (byte)type }, 1, internal_ch);
protected void Send(SteamId host, byte[] msgBuffer, int channel) => SteamNetworking.SendP2PPacket(host, msgBuffer, msgBuffer.Length, channel, channels[Mathf.Min(channel, channels.Length - 1)]); protected void Send(SteamId host, byte[] msgBuffer, int channel) => SteamNetworking.SendP2PPacket(host, msgBuffer, msgBuffer.Length, channel, channels[Mathf.Min(channel, channels.Length - 1)]);
private bool Receive(out SteamId clientSteamID, out byte[] receiveBuffer, int channel) private bool Receive(out SteamId clientSteamID, out byte[] receiveBuffer, int channel)
{ {
if (SteamNetworking.IsP2PPacketAvailable(channel)) if (SteamNetworking.IsP2PPacketAvailable(channel))
{ {
var data = SteamNetworking.ReadP2PPacket(channel); var data = SteamNetworking.ReadP2PPacket(channel);
if (data != null) if (data != null)
{ {
receiveBuffer = data.Value.Data; receiveBuffer = data.Value.Data;
clientSteamID = data.Value.SteamId; clientSteamID = data.Value.SteamId;
return true; return true;
} }
} }
receiveBuffer = null; receiveBuffer = null;
clientSteamID = 0; clientSteamID = 0;
return false; return false;
} }
protected void CloseP2PSessionWithUser(SteamId clientSteamID) => SteamNetworking.CloseP2PSessionWithUser(clientSteamID); protected void CloseP2PSessionWithUser(SteamId clientSteamID) => SteamNetworking.CloseP2PSessionWithUser(clientSteamID);
public void ReceiveData() public void ReceiveData()
{ {
try try
{ {
while (transport.enabled && Receive(out SteamId clientSteamID, out byte[] internalMessage, internal_ch)) while (transport.enabled && Receive(out var clientSteamID, out var internalMessage, internal_ch))
{ {
if (internalMessage.Length == 1) if (internalMessage.Length == 1)
{ {
OnReceiveInternalData((InternalMessages)internalMessage[0], clientSteamID); OnReceiveInternalData((InternalMessages)internalMessage[0], clientSteamID);
return; return;
} }
else else
{ {
Debug.LogError("Incorrect package length on internal channel."); Debug.LogError("Incorrect package length on internal channel.");
} }
} }
for (int chNum = 0; chNum < channels.Length; chNum++) for (var chNum = 0; chNum < channels.Length; chNum++)
{ {
while (transport.enabled && Receive(out SteamId clientSteamID, out byte[] receiveBuffer, chNum)) while (transport.enabled && Receive(out var clientSteamID, out var receiveBuffer, chNum))
{ {
OnReceiveData(receiveBuffer, clientSteamID, chNum); OnReceiveData(receiveBuffer, clientSteamID, chNum);
} }
} }
} }
catch (Exception e) catch (Exception e)
{ {
Debug.LogException(e); Debug.LogException(e);
} }
} }
protected abstract void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID); protected abstract void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID);
protected abstract void OnReceiveData(byte[] data, SteamId clientSteamID, int channel); protected abstract void OnReceiveData(byte[] data, SteamId clientSteamID, int channel);
protected abstract void OnConnectionFailed(SteamId remoteId); protected abstract void OnConnectionFailed(SteamId remoteId);
} }
} }

View File

@ -5,160 +5,160 @@ using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public class LegacyServer : LegacyCommon, IServer public class LegacyServer : LegacyCommon, IServer
{ {
private event Action<int> OnConnected; private event Action<int> OnConnected;
private event Action<int, byte[], int> OnReceivedData; private event Action<int, byte[], int> OnReceivedData;
private event Action<int> OnDisconnected; private event Action<int> OnDisconnected;
private event Action<int, Exception> OnReceivedError; private event Action<int, Exception> OnReceivedError;
private BidirectionalDictionary<SteamId, int> steamToMirrorIds; private readonly BidirectionalDictionary<SteamId, int> steamToMirrorIds;
private int maxConnections; private readonly int maxConnections;
private int nextConnectionID; private int nextConnectionID;
public static LegacyServer CreateServer(FizzyFacepunch transport, int maxConnections) public static LegacyServer CreateServer(FizzyFacepunch transport, int maxConnections)
{ {
LegacyServer s = new LegacyServer(transport, maxConnections); var s = new LegacyServer(transport, maxConnections);
s.OnConnected += (id) => transport.OnServerConnected.Invoke(id); s.OnConnected += (id) => transport.OnServerConnected.Invoke(id);
s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id); s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id);
s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), channel); s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), channel);
s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception); s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception);
SteamNetworking.OnP2PSessionRequest = (steamid) => SteamNetworking.OnP2PSessionRequest = (steamid) =>
{ {
Debug.LogError($"Incoming request from SteamId {steamid}."); Debug.LogError($"Incoming request from SteamId {steamid}.");
SteamNetworking.AcceptP2PSessionWithUser(steamid); SteamNetworking.AcceptP2PSessionWithUser(steamid);
}; };
if (!SteamClient.IsValid) if (!SteamClient.IsValid)
{ {
Debug.LogError("SteamWorks not initialized."); Debug.LogError("SteamWorks not initialized.");
} }
return s; return s;
} }
private LegacyServer(FizzyFacepunch transport, int maxConnections) : base(transport) private LegacyServer(FizzyFacepunch transport, int maxConnections) : base(transport)
{ {
this.maxConnections = maxConnections; this.maxConnections = maxConnections;
steamToMirrorIds = new BidirectionalDictionary<SteamId, int>(); steamToMirrorIds = new BidirectionalDictionary<SteamId, int>();
nextConnectionID = 1; nextConnectionID = 1;
} }
protected override void OnNewConnection(SteamId id) => SteamNetworking.AcceptP2PSessionWithUser(id); protected override void OnNewConnection(SteamId id) => SteamNetworking.AcceptP2PSessionWithUser(id);
protected override void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID) protected override void OnReceiveInternalData(InternalMessages type, SteamId clientSteamID)
{ {
switch (type) switch (type)
{ {
case InternalMessages.CONNECT: case InternalMessages.CONNECT:
if (steamToMirrorIds.Count >= maxConnections) if (steamToMirrorIds.Count >= maxConnections)
{ {
SendInternal(clientSteamID, InternalMessages.DISCONNECT); SendInternal(clientSteamID, InternalMessages.DISCONNECT);
return; return;
} }
SendInternal(clientSteamID, InternalMessages.ACCEPT_CONNECT); SendInternal(clientSteamID, InternalMessages.ACCEPT_CONNECT);
int connectionId = nextConnectionID++; var connectionId = nextConnectionID++;
steamToMirrorIds.Add(clientSteamID, connectionId); steamToMirrorIds.Add(clientSteamID, connectionId);
OnConnected.Invoke(connectionId); OnConnected.Invoke(connectionId);
Debug.LogError($"Client with SteamID {clientSteamID} connected. Assigning connection id {connectionId}"); Debug.LogError($"Client with SteamID {clientSteamID} connected. Assigning connection id {connectionId}");
break; break;
case InternalMessages.DISCONNECT: case InternalMessages.DISCONNECT:
if (steamToMirrorIds.TryGetValue(clientSteamID, out int connId)) if (steamToMirrorIds.TryGetValue(clientSteamID, out var connId))
{ {
OnDisconnected.Invoke(connId); OnDisconnected.Invoke(connId);
CloseP2PSessionWithUser(clientSteamID); CloseP2PSessionWithUser(clientSteamID);
steamToMirrorIds.Remove(clientSteamID); steamToMirrorIds.Remove(clientSteamID);
Debug.LogError($"Client with SteamID {clientSteamID} disconnected."); Debug.LogError($"Client with SteamID {clientSteamID} disconnected.");
} }
else else
{ {
OnReceivedError.Invoke(-1, new Exception("ERROR Unknown SteamID while receiving disconnect message.")); OnReceivedError.Invoke(-1, new Exception("ERROR Unknown SteamID while receiving disconnect message."));
} }
break; break;
default: default:
Debug.LogError("Received unknown message type"); Debug.LogError("Received unknown message type");
break; break;
} }
} }
protected override void OnReceiveData(byte[] data, SteamId clientSteamID, int channel) protected override void OnReceiveData(byte[] data, SteamId clientSteamID, int channel)
{ {
if (steamToMirrorIds.TryGetValue(clientSteamID, out int connectionId)) if (steamToMirrorIds.TryGetValue(clientSteamID, out var connectionId))
{ {
OnReceivedData.Invoke(connectionId, data, channel); OnReceivedData.Invoke(connectionId, data, channel);
} }
else else
{ {
CloseP2PSessionWithUser(clientSteamID); CloseP2PSessionWithUser(clientSteamID);
Debug.LogError("Data received from steam client thats not known " + clientSteamID); Debug.LogError("Data received from steam client thats not known " + clientSteamID);
OnReceivedError.Invoke(-1, new Exception("ERROR Unknown SteamID")); OnReceivedError.Invoke(-1, new Exception("ERROR Unknown SteamID"));
} }
} }
public void Disconnect(int connectionId) public void Disconnect(int connectionId)
{ {
if (steamToMirrorIds.TryGetValue(connectionId, out SteamId steamID)) if (steamToMirrorIds.TryGetValue(connectionId, out var steamID))
{ {
SendInternal(steamID, InternalMessages.DISCONNECT); SendInternal(steamID, InternalMessages.DISCONNECT);
steamToMirrorIds.Remove(connectionId); steamToMirrorIds.Remove(connectionId);
} }
else else
{ {
Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId); Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId);
} }
} }
public void Shutdown() public void Shutdown()
{ {
foreach (KeyValuePair<SteamId, int> client in steamToMirrorIds) foreach (KeyValuePair<SteamId, int> client in steamToMirrorIds)
{ {
Disconnect(client.Value); Disconnect(client.Value);
WaitForClose(client.Key); WaitForClose(client.Key);
} }
SteamNetworking.OnP2PSessionRequest = null; SteamNetworking.OnP2PSessionRequest = null;
Dispose(); Dispose();
} }
public void Send(int connectionId, byte[] data, int channelId) public void Send(int connectionId, byte[] data, int channelId)
{ {
if (steamToMirrorIds.TryGetValue(connectionId, out SteamId steamId)) if (steamToMirrorIds.TryGetValue(connectionId, out var steamId))
{ {
Send(steamId, data, channelId); Send(steamId, data, channelId);
} }
else else
{ {
Debug.LogError("Trying to send on unknown connection: " + connectionId); Debug.LogError("Trying to send on unknown connection: " + connectionId);
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
} }
} }
public string ServerGetClientAddress(int connectionId) public string ServerGetClientAddress(int connectionId)
{ {
if (steamToMirrorIds.TryGetValue(connectionId, out SteamId steamId)) if (steamToMirrorIds.TryGetValue(connectionId, out var steamId))
{ {
return steamId.ToString(); return steamId.ToString();
} }
else else
{ {
Debug.LogError("Trying to get info on unknown connection: " + connectionId); Debug.LogError("Trying to get info on unknown connection: " + connectionId);
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
return string.Empty; return string.Empty;
} }
} }
protected override void OnConnectionFailed(SteamId remoteId) protected override void OnConnectionFailed(SteamId remoteId)
{ {
int connectionId = steamToMirrorIds.TryGetValue(remoteId, out int connId) ? connId : nextConnectionID++; var connectionId = steamToMirrorIds.TryGetValue(remoteId, out var connId) ? connId : nextConnectionID++;
OnDisconnected.Invoke(connectionId); OnDisconnected.Invoke(connectionId);
} }
public void FlushData() { } public void FlushData() { }
} }
} }

View File

@ -8,192 +8,186 @@ using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public class NextClient : NextCommon, IClient public class NextClient : NextCommon, IClient
{ {
public bool Connected { get; private set; } public bool Connected { get; private set; }
public bool Error { get; private set; } public bool Error { get; private set; }
private TimeSpan ConnectionTimeout; private TimeSpan ConnectionTimeout;
private event Action<byte[], int> OnReceivedData; private event Action<byte[], int> OnReceivedData;
private event Action OnConnected; private event Action OnConnected;
private event Action OnDisconnected; private event Action OnDisconnected;
private Action<string> SetTransportError; private Action<string> SetTransportError;
private CancellationTokenSource cancelToken; private CancellationTokenSource cancelToken;
private TaskCompletionSource<Task> connectedComplete; private TaskCompletionSource<Task> connectedComplete;
private SteamId hostSteamID = 0; private SteamId hostSteamID = 0;
private FizzyConnectionManager HostConnectionManager; private FizzyConnectionManager HostConnectionManager;
private Connection HostConnection => HostConnectionManager.Connection; private Connection HostConnection => HostConnectionManager.Connection;
private List<Action> BufferedData; private readonly List<Action> BufferedData;
private NextClient(FizzyFacepunch transport) private NextClient(FizzyFacepunch transport)
{ {
ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.Timeout)); ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.Timeout));
BufferedData = new List<Action>(); BufferedData = new List<Action>();
} }
public static NextClient CreateClient(FizzyFacepunch transport, string host) public static NextClient CreateClient(FizzyFacepunch transport, string host)
{ {
NextClient c = new NextClient(transport); var c = new NextClient(transport);
c.OnConnected += () => transport.OnClientConnected.Invoke(); c.OnConnected += () => transport.OnClientConnected.Invoke();
c.OnDisconnected += () => transport.OnClientDisconnected.Invoke(); c.OnDisconnected += () => transport.OnClientDisconnected.Invoke();
c.OnReceivedData += (data, ch) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), ch); c.OnReceivedData += (data, ch) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), ch);
c.SetTransportError = transport.SetTransportError; c.SetTransportError = transport.SetTransportError;
if (SteamClient.IsValid) if (SteamClient.IsValid)
{ {
c.Connect(host); c.Connect(host);
} }
else else
{ {
c.SetTransportError("SteamWorks not initialized"); c.SetTransportError("SteamWorks not initialized");
Debug.LogError("SteamWorks not initialized"); Debug.LogError("SteamWorks not initialized");
c.OnConnectionFailed(); c.OnConnectionFailed();
} }
return c; return c;
} }
private async void Connect(string host) private async void Connect(string host)
{ {
cancelToken = new CancellationTokenSource(); cancelToken = new CancellationTokenSource();
SteamNetworkingSockets.OnConnectionStatusChanged += OnConnectionStatusChanged; SteamNetworkingSockets.OnConnectionStatusChanged += OnConnectionStatusChanged;
try try
{ {
hostSteamID = UInt64.Parse(host); hostSteamID = ulong.Parse(host);
connectedComplete = new TaskCompletionSource<Task>(); connectedComplete = new TaskCompletionSource<Task>();
OnConnected += SetConnectedComplete; OnConnected += SetConnectedComplete;
HostConnectionManager = SteamNetworkingSockets.ConnectRelay<FizzyConnectionManager>(hostSteamID); HostConnectionManager = SteamNetworkingSockets.ConnectRelay<FizzyConnectionManager>(hostSteamID);
HostConnectionManager.ForwardMessage = OnMessageReceived; HostConnectionManager.ForwardMessage = OnMessageReceived;
Task connectedCompleteTask = connectedComplete.Task; Task connectedCompleteTask = connectedComplete.Task;
Task timeOutTask = Task.Delay(ConnectionTimeout, cancelToken.Token); var timeOutTask = Task.Delay(ConnectionTimeout, cancelToken.Token);
if (await Task.WhenAny(connectedCompleteTask, timeOutTask) != connectedCompleteTask) if (await Task.WhenAny(connectedCompleteTask, timeOutTask) != connectedCompleteTask)
{ {
if (cancelToken.IsCancellationRequested) if (cancelToken.IsCancellationRequested)
{ {
SetTransportError("The connection attempt was cancelled."); SetTransportError("The connection attempt was cancelled.");
Debug.LogError($"The connection attempt was cancelled."); Debug.LogError($"The connection attempt was cancelled.");
} }
else if (timeOutTask.IsCompleted) else if (timeOutTask.IsCompleted)
{ {
SetTransportError($"Connection to {host} timed out."); SetTransportError($"Connection to {host} timed out.");
Debug.LogError($"Connection to {host} timed out."); Debug.LogError($"Connection to {host} timed out.");
} }
OnConnected -= SetConnectedComplete; OnConnected -= SetConnectedComplete;
OnConnectionFailed(); OnConnectionFailed();
} }
OnConnected -= SetConnectedComplete; OnConnected -= SetConnectedComplete;
} }
catch (FormatException) catch (FormatException)
{ {
SetTransportError("Connection string was not in the right format. Did you enter a SteamId?"); SetTransportError("Connection string was not in the right format. Did you enter a SteamId?");
Debug.LogError($"Connection string was not in the right format. Did you enter a SteamId?"); Debug.LogError($"Connection string was not in the right format. Did you enter a SteamId?");
Error = true; Error = true;
OnConnectionFailed(); OnConnectionFailed();
} }
catch (Exception ex) catch (Exception ex)
{ {
SetTransportError(ex.Message); SetTransportError(ex.Message);
Debug.LogError(ex.Message); Debug.LogError(ex.Message);
Error = true; Error = true;
OnConnectionFailed(); OnConnectionFailed();
} }
finally finally
{ {
if (Error) if (Error)
{ {
Debug.LogError("Connection failed."); Debug.LogError("Connection failed.");
OnConnectionFailed(); OnConnectionFailed();
} }
} }
} }
private void OnMessageReceived(IntPtr dataPtr, int size) private void OnMessageReceived(IntPtr dataPtr, int size)
{ {
(byte[] data, int ch) = ProcessMessage(dataPtr, size); (var data, var ch) = ProcessMessage(dataPtr, size);
if (Connected) if (Connected)
{ {
OnReceivedData(data, ch); OnReceivedData(data, ch);
} }
else else
{ {
BufferedData.Add(() => OnReceivedData(data, ch)); BufferedData.Add(() => OnReceivedData(data, ch));
} }
} }
private void OnConnectionStatusChanged(Connection conn, ConnectionInfo info) private void OnConnectionStatusChanged(Connection conn, ConnectionInfo info)
{ {
ulong clientSteamID = info.Identity.SteamId; ulong clientSteamID = info.Identity.SteamId;
if (info.State == ConnectionState.Connected) if (info.State == ConnectionState.Connected)
{ {
Connected = true; Connected = true;
OnConnected.Invoke(); OnConnected.Invoke();
Debug.LogError("Connection established."); Debug.LogError("Connection established.");
if (BufferedData.Count > 0) if (BufferedData.Count > 0)
{ {
Debug.LogError($"{BufferedData.Count} received before connection was established. Processing now."); Debug.LogError($"{BufferedData.Count} received before connection was established. Processing now.");
{ {
foreach (Action a in BufferedData) foreach (var a in BufferedData)
{ {
a(); a();
} }
} }
} }
} }
else if (info.State == ConnectionState.ClosedByPeer) else if (info.State == ConnectionState.ClosedByPeer)
{ {
SetTransportError("connection closed by peer"); SetTransportError("connection closed by peer");
Connected = false; Connected = false;
OnDisconnected.Invoke(); OnDisconnected.Invoke();
Debug.LogError("Disconnected."); Debug.LogError("Disconnected.");
conn.Close(false, 0, "Disconnected"); conn.Close(false, 0, "Disconnected");
} }
else else
{ {
Debug.LogError($"Connection state changed: {info.State.ToString()}"); Debug.LogError($"Connection state changed: {info.State.ToString()}");
} }
} }
public void Disconnect() public void Disconnect()
{ {
cancelToken?.Cancel(); cancelToken?.Cancel();
SteamNetworkingSockets.OnConnectionStatusChanged -= OnConnectionStatusChanged; SteamNetworkingSockets.OnConnectionStatusChanged -= OnConnectionStatusChanged;
if (HostConnectionManager != null) if (HostConnectionManager != null)
{ {
Debug.LogError("Sending Disconnect message"); Debug.LogError("Sending Disconnect message");
HostConnection.Close(false, 0, "Graceful disconnect"); HostConnection.Close(false, 0, "Graceful disconnect");
HostConnectionManager = null; HostConnectionManager = null;
} }
} }
public void ReceiveData() public void ReceiveData() => HostConnectionManager.Receive(MAX_MESSAGES);
{
HostConnectionManager.Receive(MAX_MESSAGES);
}
public void Send(byte[] data, int channelId) public void Send(byte[] data, int channelId)
{ {
Result res = SendSocket(HostConnection, data, channelId); var res = SendSocket(HostConnection, data, channelId);
if (res != Result.OK) if (res != Result.OK)
{ {
Debug.LogError($"Could not send: {res.ToString()}"); Debug.LogError($"Could not send: {res.ToString()}");
} }
} }
private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task); private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task);
private void OnConnectionFailed() => OnDisconnected.Invoke(); private void OnConnectionFailed() => OnDisconnected.Invoke();
public void FlushData() public void FlushData() => HostConnection.Flush();
{ }
HostConnection.Flush();
}
}
} }

View File

@ -7,32 +7,32 @@ using UnityEngine;
public abstract class NextCommon public abstract class NextCommon
{ {
protected const int MAX_MESSAGES = 256; protected const int MAX_MESSAGES = 256;
protected Result SendSocket(Connection conn, byte[] data, int channelId) protected Result SendSocket(Connection conn, byte[] data, int channelId)
{ {
Array.Resize(ref data, data.Length + 1); Array.Resize(ref data, data.Length + 1);
data[data.Length - 1] = (byte)channelId; data[data.Length - 1] = (byte)channelId;
GCHandle pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned); var pinnedArray = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr pData = pinnedArray.AddrOfPinnedObject(); var pData = pinnedArray.AddrOfPinnedObject();
SendType sendFlag = channelId == Channels.Unreliable ? SendType.Unreliable : SendType.Reliable; var sendFlag = channelId == Channels.Unreliable ? SendType.Unreliable : SendType.Reliable;
Result res = conn.SendMessage(pData, data.Length, sendFlag); var res = conn.SendMessage(pData, data.Length, sendFlag);
if (res != Result.OK) if (res != Result.OK)
{ {
Debug.LogWarning($"Send issue: {res}"); Debug.LogWarning($"Send issue: {res}");
} }
pinnedArray.Free(); pinnedArray.Free();
return res; return res;
} }
protected (byte[], int) ProcessMessage(IntPtr ptrs, int size) protected (byte[], int) ProcessMessage(IntPtr ptrs, int size)
{ {
byte[] managedArray = new byte[size]; var managedArray = new byte[size];
Marshal.Copy(ptrs, managedArray, 0, size); Marshal.Copy(ptrs, managedArray, 0, size);
int channel = managedArray[managedArray.Length - 1]; int channel = managedArray[managedArray.Length - 1];
Array.Resize(ref managedArray, managedArray.Length - 1); Array.Resize(ref managedArray, managedArray.Length - 1);
return (managedArray, channel); return (managedArray, channel);
} }
} }

View File

@ -5,186 +5,183 @@ using UnityEngine;
namespace Mirror.FizzySteam namespace Mirror.FizzySteam
{ {
public class NextServer : NextCommon, IServer public class NextServer : NextCommon, IServer
{ {
private event Action<int> OnConnected; private event Action<int> OnConnected;
private event Action<int, byte[], int> OnReceivedData; private event Action<int, byte[], int> OnReceivedData;
private event Action<int> OnDisconnected; private event Action<int> OnDisconnected;
private event Action<int, Exception> OnReceivedError; private event Action<int, Exception> OnReceivedError;
private BidirectionalDictionary<Connection, int> connToMirrorID; private readonly BidirectionalDictionary<Connection, int> connToMirrorID;
private BidirectionalDictionary<SteamId, int> steamIDToMirrorID; private readonly BidirectionalDictionary<SteamId, int> steamIDToMirrorID;
private int maxConnections; private readonly int maxConnections;
private int nextConnectionID; private int nextConnectionID;
private FizzySocketManager listenSocket; private FizzySocketManager listenSocket;
private NextServer(int maxConnections) private NextServer(int maxConnections)
{ {
this.maxConnections = maxConnections; this.maxConnections = maxConnections;
connToMirrorID = new BidirectionalDictionary<Connection, int>(); connToMirrorID = new BidirectionalDictionary<Connection, int>();
steamIDToMirrorID = new BidirectionalDictionary<SteamId, int>(); steamIDToMirrorID = new BidirectionalDictionary<SteamId, int>();
nextConnectionID = 1; nextConnectionID = 1;
SteamNetworkingSockets.OnConnectionStatusChanged += OnConnectionStatusChanged; SteamNetworkingSockets.OnConnectionStatusChanged += OnConnectionStatusChanged;
} }
public static NextServer CreateServer(FizzyFacepunch transport, int maxConnections) public static NextServer CreateServer(FizzyFacepunch transport, int maxConnections)
{ {
NextServer s = new NextServer(maxConnections); var s = new NextServer(maxConnections);
s.OnConnected += (id) => transport.OnServerConnected.Invoke(id); s.OnConnected += (id) => transport.OnServerConnected.Invoke(id);
s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id); s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id);
s.OnReceivedData += (id, data, ch) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), ch); s.OnReceivedData += (id, data, ch) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), ch);
s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception); s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception);
if (!SteamClient.IsValid) if (!SteamClient.IsValid)
{ {
Debug.LogError("SteamWorks not initialized."); Debug.LogError("SteamWorks not initialized.");
} }
s.Host(); s.Host();
return s; return s;
} }
private void Host() private void Host()
{ {
listenSocket = SteamNetworkingSockets.CreateRelaySocket<FizzySocketManager>(); listenSocket = SteamNetworkingSockets.CreateRelaySocket<FizzySocketManager>();
listenSocket.ForwardMessage = OnMessageReceived; listenSocket.ForwardMessage = OnMessageReceived;
} }
private void OnConnectionStatusChanged(Connection conn, ConnectionInfo info) private void OnConnectionStatusChanged(Connection conn, ConnectionInfo info)
{ {
ulong clientSteamID = info.Identity.SteamId; ulong clientSteamID = info.Identity.SteamId;
if (info.State == ConnectionState.Connecting) if (info.State == ConnectionState.Connecting)
{ {
if (connToMirrorID.Count >= maxConnections) if (connToMirrorID.Count >= maxConnections)
{ {
Debug.LogError($"Incoming connection {clientSteamID} would exceed max connection count. Rejecting."); Debug.LogError($"Incoming connection {clientSteamID} would exceed max connection count. Rejecting.");
conn.Close(false, 0, "Max Connection Count"); conn.Close(false, 0, "Max Connection Count");
return; return;
} }
Result res; Result res;
if ((res = conn.Accept()) == Result.OK) if ((res = conn.Accept()) == Result.OK)
{ {
Debug.LogError($"Accepting connection {clientSteamID}"); Debug.LogError($"Accepting connection {clientSteamID}");
} }
else else
{ {
Debug.LogError($"Connection {clientSteamID} could not be accepted: {res.ToString()}"); Debug.LogError($"Connection {clientSteamID} could not be accepted: {res.ToString()}");
} }
} }
else if (info.State == ConnectionState.Connected) else if (info.State == ConnectionState.Connected)
{ {
int connectionId = nextConnectionID++; var connectionId = nextConnectionID++;
connToMirrorID.Add(conn, connectionId); connToMirrorID.Add(conn, connectionId);
steamIDToMirrorID.Add(clientSteamID, connectionId); steamIDToMirrorID.Add(clientSteamID, connectionId);
OnConnected.Invoke(connectionId); OnConnected.Invoke(connectionId);
Debug.LogError($"Client with SteamID {clientSteamID} connected. Assigning connection id {connectionId}"); Debug.LogError($"Client with SteamID {clientSteamID} connected. Assigning connection id {connectionId}");
} }
else if (info.State == ConnectionState.ClosedByPeer) else if (info.State == ConnectionState.ClosedByPeer)
{ {
if (connToMirrorID.TryGetValue(conn, out int connId)) if (connToMirrorID.TryGetValue(conn, out var connId))
{ {
InternalDisconnect(connId, conn); InternalDisconnect(connId, conn);
} }
} }
else else
{ {
Debug.LogError($"Connection {clientSteamID} state changed: {info.State.ToString()}"); Debug.LogError($"Connection {clientSteamID} state changed: {info.State.ToString()}");
} }
} }
private void InternalDisconnect(int connId, Connection socket) private void InternalDisconnect(int connId, Connection socket)
{ {
OnDisconnected.Invoke(connId); OnDisconnected.Invoke(connId);
socket.Close(false, 0, "Graceful disconnect"); socket.Close(false, 0, "Graceful disconnect");
connToMirrorID.Remove(connId); connToMirrorID.Remove(connId);
steamIDToMirrorID.Remove(connId); steamIDToMirrorID.Remove(connId);
Debug.LogError($"Client with SteamID {connId} disconnected."); Debug.LogError($"Client with SteamID {connId} disconnected.");
} }
public void Disconnect(int connectionId) public void Disconnect(int connectionId)
{ {
if (connToMirrorID.TryGetValue(connectionId, out Connection conn)) if (connToMirrorID.TryGetValue(connectionId, out var conn))
{ {
Debug.LogError($"Connection id {connectionId} disconnected."); Debug.LogError($"Connection id {connectionId} disconnected.");
conn.Close(false, 0, "Disconnected by server"); conn.Close(false, 0, "Disconnected by server");
steamIDToMirrorID.Remove(connectionId); steamIDToMirrorID.Remove(connectionId);
connToMirrorID.Remove(connectionId); connToMirrorID.Remove(connectionId);
OnDisconnected(connectionId); OnDisconnected(connectionId);
} }
else else
{ {
Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId); Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId);
} }
} }
public void FlushData() public void FlushData()
{ {
foreach (Connection conn in connToMirrorID.FirstTypes) foreach (var conn in connToMirrorID.FirstTypes)
{ {
conn.Flush(); conn.Flush();
} }
} }
public void ReceiveData() public void ReceiveData() => listenSocket.Receive(MAX_MESSAGES);
{
listenSocket.Receive(MAX_MESSAGES);
}
private void OnMessageReceived(Connection conn, IntPtr dataPtr, int size) private void OnMessageReceived(Connection conn, IntPtr dataPtr, int size)
{ {
(byte[] data, int ch) = ProcessMessage(dataPtr, size); (var data, var ch) = ProcessMessage(dataPtr, size);
OnReceivedData(connToMirrorID[conn], data, ch); OnReceivedData(connToMirrorID[conn], data, ch);
} }
public void Send(int connectionId, byte[] data, int channelId) public void Send(int connectionId, byte[] data, int channelId)
{ {
if (connToMirrorID.TryGetValue(connectionId, out Connection conn)) if (connToMirrorID.TryGetValue(connectionId, out var conn))
{ {
Result res = SendSocket(conn, data, channelId); var res = SendSocket(conn, data, channelId);
if (res == Result.NoConnection || res == Result.InvalidParam) if (res == Result.NoConnection || res == Result.InvalidParam)
{ {
Debug.LogError($"Connection to {connectionId} was lost."); Debug.LogError($"Connection to {connectionId} was lost.");
InternalDisconnect(connectionId, conn); InternalDisconnect(connectionId, conn);
} }
else if (res != Result.OK) else if (res != Result.OK)
{ {
Debug.LogError($"Could not send: {res.ToString()}"); Debug.LogError($"Could not send: {res.ToString()}");
} }
} }
else else
{ {
Debug.LogError("Trying to send on unknown connection: " + connectionId); Debug.LogError("Trying to send on unknown connection: " + connectionId);
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
} }
} }
public string ServerGetClientAddress(int connectionId) public string ServerGetClientAddress(int connectionId)
{ {
if (steamIDToMirrorID.TryGetValue(connectionId, out SteamId steamId)) if (steamIDToMirrorID.TryGetValue(connectionId, out var steamId))
{ {
return steamId.ToString(); return steamId.ToString();
} }
else else
{ {
Debug.LogError("Trying to get info on unknown connection: " + connectionId); Debug.LogError("Trying to get info on unknown connection: " + connectionId);
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
return string.Empty; return string.Empty;
} }
} }
public void Shutdown() public void Shutdown()
{ {
if (listenSocket != null) if (listenSocket != null)
{ {
SteamNetworkingSockets.OnConnectionStatusChanged -= OnConnectionStatusChanged; SteamNetworkingSockets.OnConnectionStatusChanged -= OnConnectionStatusChanged;
listenSocket.Close(); listenSocket.Close();
} }
} }
} }
} }