From c9f9ba08019ccc1c1fa094c491697865f59db9cb Mon Sep 17 00:00:00 2001 From: JohnCorby Date: Sat, 5 Feb 2022 20:17:08 -0800 Subject: [PATCH] reformat code --- .../BidirectionalDictionary.cs | 117 +-- EpicOnlineTransport/Client.cs | 279 +++---- EpicOnlineTransport/Common.cs | 511 +++++++------ EpicOnlineTransport/EOSSDKComponent.cs | 694 +++++++++-------- EpicOnlineTransport/EosApiKey.cs | 18 +- EpicOnlineTransport/EosTransport.cs | 701 ++++++++++-------- EpicOnlineTransport/Logger.cs | 51 +- EpicOnlineTransport/Packet.cs | 74 +- EpicOnlineTransport/RandomString.cs | 57 +- EpicOnlineTransport/Server.cs | 338 +++++---- 10 files changed, 1562 insertions(+), 1278 deletions(-) diff --git a/EpicOnlineTransport/BidirectionalDictionary.cs b/EpicOnlineTransport/BidirectionalDictionary.cs index cc68a019..a531e401 100644 --- a/EpicOnlineTransport/BidirectionalDictionary.cs +++ b/EpicOnlineTransport/BidirectionalDictionary.cs @@ -50,71 +50,82 @@ using System.Collections.Generic; /// MIT License /// -namespace EpicTransport { +namespace EpicTransport +{ + public class BidirectionalDictionary : IEnumerable + { + private Dictionary t1ToT2Dict = new Dictionary(); + private Dictionary t2ToT1Dict = new Dictionary(); - public class BidirectionalDictionary : IEnumerable { - private Dictionary t1ToT2Dict = new Dictionary(); - private Dictionary t2ToT1Dict = new Dictionary(); + public IEnumerable FirstTypes => t1ToT2Dict.Keys; + public IEnumerable SecondTypes => t2ToT1Dict.Keys; - public IEnumerable FirstTypes => t1ToT2Dict.Keys; - public IEnumerable 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) + { + t1ToT2Dict[key] = value; + t2ToT1Dict[value] = key; + } - public void Add(T1 key, T2 value) { - t1ToT2Dict[key] = value; - t2ToT1Dict[value] = key; - } + public void Add(T2 key, T1 value) + { + t2ToT1Dict[key] = value; + t1ToT2Dict[value] = key; + } - public void Add(T2 key, T1 value) { - t2ToT1Dict[key] = value; - 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) + { + if (Contains(key)) + { + T2 val = t1ToT2Dict[key]; + t1ToT2Dict.Remove(key); + t2ToT1Dict.Remove(val); + } + } - public void Remove(T1 key) { - if (Contains(key)) { - T2 val = t1ToT2Dict[key]; - t1ToT2Dict.Remove(key); - t2ToT1Dict.Remove(val); - } - } - public void Remove(T2 key) { - if (Contains(key)) { - T1 val = t2ToT1Dict[key]; - t1ToT2Dict.Remove(val); - t2ToT1Dict.Remove(key); - } - } + public void Remove(T2 key) + { + if (Contains(key)) + { + T1 val = t2ToT1Dict[key]; + t1ToT2Dict.Remove(val); + t2ToT1Dict.Remove(key); + } + } - public T1 this[T2 key] { - get => t2ToT1Dict[key]; - set { - t2ToT1Dict[key] = value; - t1ToT2Dict[value] = key; - } - } + public T1 this[T2 key] + { + get => t2ToT1Dict[key]; + set + { + t2ToT1Dict[key] = value; + t1ToT2Dict[value] = key; + } + } - public T2 this[T1 key] { - get => t1ToT2Dict[key]; - set { - t1ToT2Dict[key] = value; - t2ToT1Dict[value] = key; - } - } - - } -} \ No newline at end of file + public T2 this[T1 key] + { + get => t1ToT2Dict[key]; + set + { + t1ToT2Dict[key] = value; + t2ToT1Dict[value] = key; + } + } + } +} diff --git a/EpicOnlineTransport/Client.cs b/EpicOnlineTransport/Client.cs index 8d5e5dd9..968ee0ce 100644 --- a/EpicOnlineTransport/Client.cs +++ b/EpicOnlineTransport/Client.cs @@ -6,161 +6,190 @@ using System.Threading; using System.Threading.Tasks; using UnityEngine; -namespace EpicTransport { - public class Client : Common { +namespace EpicTransport +{ + public class Client : Common + { + public SocketId socketId; + public ProductUserId serverId; - public SocketId socketId; - public ProductUserId serverId; + public bool Connected { get; private set; } + public bool Error { get; private set; } - public bool Connected { get; private set; } - public bool Error { get; private set; } + private event Action OnReceivedData; + private event Action OnConnected; + public event Action OnDisconnected; - private event Action OnReceivedData; - private event Action OnConnected; - public event Action OnDisconnected; + private TimeSpan ConnectionTimeout; - private TimeSpan ConnectionTimeout; + public bool isConnecting = false; + public string hostAddress = ""; + private ProductUserId hostProductId = null; + private TaskCompletionSource connectedComplete; + private CancellationTokenSource cancelToken; - public bool isConnecting = false; - public string hostAddress = ""; - private ProductUserId hostProductId = null; - private TaskCompletionSource connectedComplete; - private CancellationTokenSource cancelToken; + private Client(EosTransport transport) : base(transport) + { + ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.timeout)); + } - private Client(EosTransport transport) : base(transport) { - ConnectionTimeout = TimeSpan.FromSeconds(Math.Max(1, transport.timeout)); - } + public static Client CreateClient(EosTransport transport, string host) + { + Client c = new Client(transport); - public static Client CreateClient(EosTransport transport, string host) { - Client c = new Client(transport); + c.hostAddress = host; + c.socketId = new SocketId() { SocketName = RandomString.Generate(20) }; - c.hostAddress = host; - c.socketId = new SocketId() { SocketName = RandomString.Generate(20) }; + c.OnConnected += () => transport.OnClientConnected.Invoke(); + c.OnDisconnected += () => transport.OnClientDisconnected.Invoke(); + c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment(data), channel); - c.OnConnected += () => transport.OnClientConnected.Invoke(); - c.OnDisconnected += () => transport.OnClientDisconnected.Invoke(); - c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment(data), channel); + return c; + } - return c; - } + public async void Connect(string host) + { + cancelToken = new CancellationTokenSource(); - public async void Connect(string host) { - cancelToken = new CancellationTokenSource(); + try + { + hostProductId = ProductUserId.FromString(host); + serverId = hostProductId; + connectedComplete = new TaskCompletionSource(); - try { - hostProductId = ProductUserId.FromString(host); - serverId = hostProductId; - connectedComplete = new TaskCompletionSource(); + OnConnected += SetConnectedComplete; - OnConnected += SetConnectedComplete; + SendInternal(hostProductId, socketId, InternalMessages.CONNECT); - SendInternal(hostProductId, socketId, InternalMessages.CONNECT); + Task connectedCompleteTask = connectedComplete.Task; - Task connectedCompleteTask = connectedComplete.Task; + if (await Task.WhenAny(connectedCompleteTask, Task.Delay(ConnectionTimeout /*, cancelToken.Token*/)) != connectedCompleteTask) + { + Debug.LogError($"Connection to {host} timed out."); + OnConnected -= SetConnectedComplete; + OnConnectionFailed(hostProductId); + } - if (await Task.WhenAny(connectedCompleteTask, Task.Delay(ConnectionTimeout/*, cancelToken.Token*/)) != connectedCompleteTask) { - Debug.LogError($"Connection to {host} timed out."); - OnConnected -= SetConnectedComplete; - OnConnectionFailed(hostProductId); - } + OnConnected -= SetConnectedComplete; + } + catch (FormatException) + { + Debug.LogError($"Connection string was not in the right format. Did you enter a ProductId?"); + Error = true; + OnConnectionFailed(hostProductId); + } + catch (Exception ex) + { + Debug.LogError(ex.Message); + Error = true; + OnConnectionFailed(hostProductId); + } + finally + { + if (Error) + { + OnConnectionFailed(null); + } + } + } - OnConnected -= SetConnectedComplete; - } catch (FormatException) { - Debug.LogError($"Connection string was not in the right format. Did you enter a ProductId?"); - Error = true; - OnConnectionFailed(hostProductId); - } catch (Exception ex) { - Debug.LogError(ex.Message); - Error = true; - OnConnectionFailed(hostProductId); - } finally { - if (Error) { - OnConnectionFailed(null); - } - } + public void Disconnect() + { + if (serverId != null) + { + CloseP2PSessionWithUser(serverId, socketId); - } + serverId = null; + } + else + { + return; + } - public void Disconnect() { - if (serverId != null) { - CloseP2PSessionWithUser(serverId, socketId); + SendInternal(hostProductId, socketId, InternalMessages.DISCONNECT); - serverId = null; - } else { - return; - } + Dispose(); + cancelToken?.Cancel(); - SendInternal(hostProductId, socketId, InternalMessages.DISCONNECT); + WaitForClose(hostProductId, socketId); + } - Dispose(); - cancelToken?.Cancel(); + private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task); - WaitForClose(hostProductId, socketId); - } + protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) + { + if (ignoreAllMessages) + { + return; + } - private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task); + if (clientUserId != hostProductId) + { + Debug.LogError("Received a message from an unknown"); + return; + } - protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) { - if (ignoreAllMessages) { - return; - } + OnReceivedData.Invoke(data, channel); + } - if (clientUserId != hostProductId) { - Debug.LogError("Received a message from an unknown"); - return; - } + protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) + { + if (ignoreAllMessages) + { + return; + } - OnReceivedData.Invoke(data, channel); - } + if (deadSockets.Contains(result.SocketId.SocketName)) + { + Debug.LogError("Received incoming connection request from dead socket"); + return; + } - protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) { - if (ignoreAllMessages) { - return; - } + if (hostProductId == result.RemoteUserId) + { + EOSSDKComponent.GetP2PInterface().AcceptConnection( + new AcceptConnectionOptions() + { + LocalUserId = EOSSDKComponent.LocalUserProductId, + RemoteUserId = result.RemoteUserId, + SocketId = result.SocketId + }); + } + else + { + Debug.LogError("P2P Acceptance Request from unknown host ID."); + } + } - if (deadSockets.Contains(result.SocketId.SocketName)) { - Debug.LogError("Received incoming connection request from dead socket"); - return; - } + protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) + { + if (ignoreAllMessages) + { + return; + } - if (hostProductId == result.RemoteUserId) { - EOSSDKComponent.GetP2PInterface().AcceptConnection( - new AcceptConnectionOptions() { - LocalUserId = EOSSDKComponent.LocalUserProductId, - RemoteUserId = result.RemoteUserId, - SocketId = result.SocketId - }); - } else { - Debug.LogError("P2P Acceptance Request from unknown host ID."); - } - } + switch (type) + { + case InternalMessages.ACCEPT_CONNECT: + Connected = true; + OnConnected.Invoke(); + Debug.Log("Connection established."); + break; + case InternalMessages.DISCONNECT: + Connected = false; + Debug.Log("Disconnected."); - protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) { - if (ignoreAllMessages) { - return; - } + OnDisconnected.Invoke(); + break; + default: + Debug.Log("Received unknown message type"); + break; + } + } - switch (type) { - case InternalMessages.ACCEPT_CONNECT: - Connected = true; - OnConnected.Invoke(); - Debug.Log("Connection established."); - break; - case InternalMessages.DISCONNECT: - Connected = false; - Debug.Log("Disconnected."); + public void Send(byte[] data, int channelId) => Send(hostProductId, socketId, data, (byte)channelId); - OnDisconnected.Invoke(); - break; - default: - Debug.Log("Received unknown message type"); - break; - } - } - - public void Send(byte[] data, int channelId) => Send(hostProductId, socketId, data, (byte) channelId); - - protected override void OnConnectionFailed(ProductUserId remoteId) => OnDisconnected.Invoke(); - public void EosNotInitialized() => OnDisconnected.Invoke(); - } -} \ No newline at end of file + protected override void OnConnectionFailed(ProductUserId remoteId) => OnDisconnected.Invoke(); + public void EosNotInitialized() => OnDisconnected.Invoke(); + } +} diff --git a/EpicOnlineTransport/Common.cs b/EpicOnlineTransport/Common.cs index a9d34aba..b219ed83 100644 --- a/EpicOnlineTransport/Common.cs +++ b/EpicOnlineTransport/Common.cs @@ -1,288 +1,335 @@ - -using Epic.OnlineServices; +using Epic.OnlineServices; using Epic.OnlineServices.P2P; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace EpicTransport { - public abstract class Common { +namespace EpicTransport +{ + public abstract class Common + { + private PacketReliability[] channels; + private int internal_ch => channels.Length; - private PacketReliability[] channels; - private int internal_ch => channels.Length; + protected enum InternalMessages : byte + { + CONNECT, + ACCEPT_CONNECT, + DISCONNECT + } - protected enum InternalMessages : byte { - CONNECT, - ACCEPT_CONNECT, - DISCONNECT - } + protected struct PacketKey + { + public ProductUserId productUserId; + public byte channel; + } - protected struct PacketKey { - public ProductUserId productUserId; - public byte channel; - } + private OnIncomingConnectionRequestCallback OnIncomingConnectionRequest; + ulong incomingNotificationId = 0; + private OnRemoteConnectionClosedCallback OnRemoteConnectionClosed; + ulong outgoingNotificationId = 0; - private OnIncomingConnectionRequestCallback OnIncomingConnectionRequest; - ulong incomingNotificationId = 0; - private OnRemoteConnectionClosedCallback OnRemoteConnectionClosed; - ulong outgoingNotificationId = 0; + protected readonly EosTransport transport; - protected readonly EosTransport transport; + protected List deadSockets; + public bool ignoreAllMessages = false; - protected List deadSockets; - public bool ignoreAllMessages = false; + // Mapping from PacketKey to a List of Packet Lists + protected Dictionary>> incomingPackets = new Dictionary>>(); - // Mapping from PacketKey to a List of Packet Lists - protected Dictionary>> incomingPackets = new Dictionary>>(); + protected Common(EosTransport transport) + { + channels = transport.Channels; - protected Common(EosTransport transport) { - channels = transport.Channels; + deadSockets = new List(); - deadSockets = new List(); + AddNotifyPeerConnectionRequestOptions addNotifyPeerConnectionRequestOptions = new AddNotifyPeerConnectionRequestOptions(); + addNotifyPeerConnectionRequestOptions.LocalUserId = EOSSDKComponent.LocalUserProductId; + addNotifyPeerConnectionRequestOptions.SocketId = null; - AddNotifyPeerConnectionRequestOptions addNotifyPeerConnectionRequestOptions = new AddNotifyPeerConnectionRequestOptions(); - addNotifyPeerConnectionRequestOptions.LocalUserId = EOSSDKComponent.LocalUserProductId; - addNotifyPeerConnectionRequestOptions.SocketId = null; + OnIncomingConnectionRequest += OnNewConnection; + OnRemoteConnectionClosed += OnConnectFail; - OnIncomingConnectionRequest += OnNewConnection; - OnRemoteConnectionClosed += OnConnectFail; + incomingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionRequest(addNotifyPeerConnectionRequestOptions, + null, OnIncomingConnectionRequest); - incomingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionRequest(addNotifyPeerConnectionRequestOptions, - null, OnIncomingConnectionRequest); + AddNotifyPeerConnectionClosedOptions addNotifyPeerConnectionClosedOptions = new AddNotifyPeerConnectionClosedOptions(); + addNotifyPeerConnectionClosedOptions.LocalUserId = EOSSDKComponent.LocalUserProductId; + addNotifyPeerConnectionClosedOptions.SocketId = null; - AddNotifyPeerConnectionClosedOptions addNotifyPeerConnectionClosedOptions = new AddNotifyPeerConnectionClosedOptions(); - addNotifyPeerConnectionClosedOptions.LocalUserId = EOSSDKComponent.LocalUserProductId; - addNotifyPeerConnectionClosedOptions.SocketId = null; + outgoingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionClosed(addNotifyPeerConnectionClosedOptions, + null, OnRemoteConnectionClosed); - outgoingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionClosed(addNotifyPeerConnectionClosedOptions, - null, OnRemoteConnectionClosed); + if (outgoingNotificationId == 0 || incomingNotificationId == 0) + { + Debug.LogError("Couldn't bind notifications with P2P interface"); + } - if (outgoingNotificationId == 0 || incomingNotificationId == 0) { - Debug.LogError("Couldn't bind notifications with P2P interface"); - } + incomingPackets = new Dictionary>>(); - incomingPackets = new Dictionary>>(); + this.transport = transport; + } - this.transport = transport; + protected void Dispose() + { + EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionRequest(incomingNotificationId); + EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionClosed(outgoingNotificationId); - } + transport.ResetIgnoreMessagesAtStartUpTimer(); + } - protected void Dispose() { - EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionRequest(incomingNotificationId); - EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionClosed(outgoingNotificationId); + protected abstract void OnNewConnection(OnIncomingConnectionRequestInfo result); - transport.ResetIgnoreMessagesAtStartUpTimer(); - } + private void OnConnectFail(OnRemoteConnectionClosedInfo result) + { + if (ignoreAllMessages) + { + return; + } - protected abstract void OnNewConnection(OnIncomingConnectionRequestInfo result); + OnConnectionFailed(result.RemoteUserId); - private void OnConnectFail(OnRemoteConnectionClosedInfo result) { - if (ignoreAllMessages) { - return; - } + switch (result.Reason) + { + case ConnectionClosedReason.ClosedByLocalUser: + throw new Exception("Connection cLosed: The Connection was gracecfully closed by the local user."); + case ConnectionClosedReason.ClosedByPeer: + throw new Exception("Connection closed: The connection was gracefully closed by remote user."); + case ConnectionClosedReason.ConnectionClosed: + throw new Exception("Connection closed: The connection was unexpectedly closed."); + case ConnectionClosedReason.ConnectionFailed: + throw new Exception("Connection failed: Failled to establish connection."); + case ConnectionClosedReason.InvalidData: + throw new Exception("Connection failed: The remote user sent us invalid data.."); + case ConnectionClosedReason.InvalidMessage: + throw new Exception("Connection failed: The remote user sent us an invalid message."); + case ConnectionClosedReason.NegotiationFailed: + throw new Exception("Connection failed: Negotiation failed."); + case ConnectionClosedReason.TimedOut: + throw new Exception("Connection failed: Timeout."); + case ConnectionClosedReason.TooManyConnections: + throw new Exception("Connection failed: Too many connections."); + case ConnectionClosedReason.UnexpectedError: + throw new Exception("Unexpected Error, connection will be closed"); + case ConnectionClosedReason.Unknown: + default: + throw new Exception("Unknown Error, connection has been closed."); + } + } - OnConnectionFailed(result.RemoteUserId); + protected void SendInternal(ProductUserId target, SocketId socketId, InternalMessages type) + { + EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() + { + AllowDelayedDelivery = true, + Channel = (byte)internal_ch, + Data = new byte[] { (byte)type }, + LocalUserId = EOSSDKComponent.LocalUserProductId, + Reliability = PacketReliability.ReliableOrdered, + RemoteUserId = target, + SocketId = socketId + }); + } - switch (result.Reason) { - case ConnectionClosedReason.ClosedByLocalUser: - throw new Exception("Connection cLosed: The Connection was gracecfully closed by the local user."); - case ConnectionClosedReason.ClosedByPeer: - throw new Exception("Connection closed: The connection was gracefully closed by remote user."); - case ConnectionClosedReason.ConnectionClosed: - throw new Exception("Connection closed: The connection was unexpectedly closed."); - case ConnectionClosedReason.ConnectionFailed: - throw new Exception("Connection failed: Failled to establish connection."); - case ConnectionClosedReason.InvalidData: - throw new Exception("Connection failed: The remote user sent us invalid data.."); - case ConnectionClosedReason.InvalidMessage: - throw new Exception("Connection failed: The remote user sent us an invalid message."); - case ConnectionClosedReason.NegotiationFailed: - throw new Exception("Connection failed: Negotiation failed."); - case ConnectionClosedReason.TimedOut: - throw new Exception("Connection failed: Timeout."); - case ConnectionClosedReason.TooManyConnections: - throw new Exception("Connection failed: Too many connections."); - case ConnectionClosedReason.UnexpectedError: - throw new Exception("Unexpected Error, connection will be closed"); - case ConnectionClosedReason.Unknown: - default: - throw new Exception("Unknown Error, connection has been closed."); - } - } + protected void Send(ProductUserId host, SocketId socketId, byte[] msgBuffer, byte channel) + { + Result result = EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() + { + AllowDelayedDelivery = true, + Channel = channel, + Data = msgBuffer, + LocalUserId = EOSSDKComponent.LocalUserProductId, + Reliability = channels[channel], + RemoteUserId = host, + SocketId = socketId + }); - protected void SendInternal(ProductUserId target, SocketId socketId, InternalMessages type) { - EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() { - AllowDelayedDelivery = true, - Channel = (byte) internal_ch, - Data = new byte[] { (byte) type }, - LocalUserId = EOSSDKComponent.LocalUserProductId, - Reliability = PacketReliability.ReliableOrdered, - RemoteUserId = target, - SocketId = socketId - }); - } + if (result != Result.Success) + { + Debug.LogError("Send failed " + result); + } + } + private bool Receive(out ProductUserId clientProductUserId, out SocketId socketId, out byte[] receiveBuffer, byte channel) + { + Result result = EOSSDKComponent.GetP2PInterface().ReceivePacket(new ReceivePacketOptions() + { + LocalUserId = EOSSDKComponent.LocalUserProductId, + MaxDataSizeBytes = P2PInterface.MaxPacketSize, + RequestedChannel = channel + }, out clientProductUserId, out socketId, out channel, out receiveBuffer); - protected void Send(ProductUserId host, SocketId socketId, byte[] msgBuffer, byte channel) { - Result result = EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() { - AllowDelayedDelivery = true, - Channel = channel, - Data = msgBuffer, - LocalUserId = EOSSDKComponent.LocalUserProductId, - Reliability = channels[channel], - RemoteUserId = host, - SocketId = socketId - }); + if (result == Result.Success) + { + return true; + } - if(result != Result.Success) { - Debug.LogError("Send failed " + result); - } - } + receiveBuffer = null; + clientProductUserId = null; + return false; + } - private bool Receive(out ProductUserId clientProductUserId, out SocketId socketId, out byte[] receiveBuffer, byte channel) { - Result result = EOSSDKComponent.GetP2PInterface().ReceivePacket(new ReceivePacketOptions() { - LocalUserId = EOSSDKComponent.LocalUserProductId, - MaxDataSizeBytes = P2PInterface.MaxPacketSize, - RequestedChannel = channel - }, out clientProductUserId, out socketId, out channel, out receiveBuffer); + protected virtual void CloseP2PSessionWithUser(ProductUserId clientUserID, SocketId socketId) + { + if (socketId == null) + { + Debug.LogWarning("Socket ID == null | " + ignoreAllMessages); + return; + } - if (result == Result.Success) { - return true; - } + if (deadSockets == null) + { + Debug.LogWarning("DeadSockets == null"); + return; + } - receiveBuffer = null; - clientProductUserId = null; - return false; - } + if (deadSockets.Contains(socketId.SocketName)) + { + return; + } + else + { + deadSockets.Add(socketId.SocketName); + } + } - protected virtual void CloseP2PSessionWithUser(ProductUserId clientUserID, SocketId socketId) { - if (socketId == null) { - Debug.LogWarning("Socket ID == null | " + ignoreAllMessages); - return; - } + protected void WaitForClose(ProductUserId clientUserID, SocketId socketId) => transport.StartCoroutine(DelayedClose(clientUserID, socketId)); - if (deadSockets == null) { - Debug.LogWarning("DeadSockets == null"); - return; - } + private IEnumerator DelayedClose(ProductUserId clientUserID, SocketId socketId) + { + yield return null; + CloseP2PSessionWithUser(clientUserID, socketId); + } - if (deadSockets.Contains(socketId.SocketName)) { - return; - } else { - deadSockets.Add(socketId.SocketName); - } - } + public void ReceiveData() + { + try + { + // Internal Channel, no fragmentation here + SocketId socketId = new SocketId(); + while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] internalMessage, (byte)internal_ch)) + { + if (internalMessage.Length == 1) + { + OnReceiveInternalData((InternalMessages)internalMessage[0], clientUserID, socketId); + return; // Wait one frame + } + else + { + Debug.Log("Incorrect package length on internal channel."); + } + } + // Insert new packet at the correct location in the incoming queue + for (int chNum = 0; chNum < channels.Length; chNum++) + { + while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] receiveBuffer, (byte)chNum)) + { + PacketKey incomingPacketKey = new PacketKey(); + incomingPacketKey.productUserId = clientUserID; + incomingPacketKey.channel = (byte)chNum; - protected void WaitForClose(ProductUserId clientUserID, SocketId socketId) => transport.StartCoroutine(DelayedClose(clientUserID, socketId)); - private IEnumerator DelayedClose(ProductUserId clientUserID, SocketId socketId) { - yield return null; - CloseP2PSessionWithUser(clientUserID, socketId); - } + Packet packet = new Packet(); + packet.FromBytes(receiveBuffer); - public void ReceiveData() { - try { - // Internal Channel, no fragmentation here - SocketId socketId = new SocketId(); - while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] internalMessage, (byte) internal_ch)) { - if (internalMessage.Length == 1) { - OnReceiveInternalData((InternalMessages) internalMessage[0], clientUserID, socketId); - return; // Wait one frame - } else { - Debug.Log("Incorrect package length on internal channel."); - } - } + if (!incomingPackets.ContainsKey(incomingPacketKey)) + { + incomingPackets.Add(incomingPacketKey, new List>()); + } - // Insert new packet at the correct location in the incoming queue - for (int chNum = 0; chNum < channels.Length; chNum++) { - while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] receiveBuffer, (byte) chNum)) { - PacketKey incomingPacketKey = new PacketKey(); - incomingPacketKey.productUserId = clientUserID; - incomingPacketKey.channel = (byte)chNum; + int packetListIndex = incomingPackets[incomingPacketKey].Count; + for (int i = 0; i < incomingPackets[incomingPacketKey].Count; i++) + { + if (incomingPackets[incomingPacketKey][i][0].id == packet.id) + { + packetListIndex = i; + break; + } + } - Packet packet = new Packet(); - packet.FromBytes(receiveBuffer); + if (packetListIndex == incomingPackets[incomingPacketKey].Count) + { + incomingPackets[incomingPacketKey].Add(new List()); + } - if (!incomingPackets.ContainsKey(incomingPacketKey)) { - incomingPackets.Add(incomingPacketKey, new List>()); - } + int insertionIndex = -1; - int packetListIndex = incomingPackets[incomingPacketKey].Count; - for(int i = 0; i < incomingPackets[incomingPacketKey].Count; i++) { - if(incomingPackets[incomingPacketKey][i][0].id == packet.id) { - packetListIndex = i; - break; - } - } - - if (packetListIndex == incomingPackets[incomingPacketKey].Count) { - incomingPackets[incomingPacketKey].Add(new List()); - } + for (int i = 0; i < incomingPackets[incomingPacketKey][packetListIndex].Count; i++) + { + if (incomingPackets[incomingPacketKey][packetListIndex][i].fragment > packet.fragment) + { + insertionIndex = i; + break; + } + } - int insertionIndex = -1; + if (insertionIndex >= 0) + { + incomingPackets[incomingPacketKey][packetListIndex].Insert(insertionIndex, packet); + } + else + { + incomingPackets[incomingPacketKey][packetListIndex].Add(packet); + } + } + } - for (int i = 0; i < incomingPackets[incomingPacketKey][packetListIndex].Count; i++) { - if (incomingPackets[incomingPacketKey][packetListIndex][i].fragment > packet.fragment) { - insertionIndex = i; - break; - } - } + // Find fully received packets + List> emptyPacketLists = new List>(); + foreach (KeyValuePair>> keyValuePair in incomingPackets) + { + for (int packetList = 0; packetList < keyValuePair.Value.Count; packetList++) + { + bool packetReady = true; + int packetLength = 0; + for (int packet = 0; packet < keyValuePair.Value[packetList].Count; packet++) + { + Packet tempPacket = keyValuePair.Value[packetList][packet]; + if (tempPacket.fragment != packet || (packet == keyValuePair.Value[packetList].Count - 1 && tempPacket.moreFragments)) + { + packetReady = false; + } + else + { + packetLength += tempPacket.data.Length; + } + } - if (insertionIndex >= 0) { - incomingPackets[incomingPacketKey][packetListIndex].Insert(insertionIndex, packet); - } else { - incomingPackets[incomingPacketKey][packetListIndex].Add(packet); - } - } - } + if (packetReady) + { + byte[] data = new byte[packetLength]; + int dataIndex = 0; - // Find fully received packets - List> emptyPacketLists = new List>(); - foreach(KeyValuePair>> keyValuePair in incomingPackets) { - for(int packetList = 0; packetList < keyValuePair.Value.Count; packetList++) { - bool packetReady = true; - int packetLength = 0; - for (int packet = 0; packet < keyValuePair.Value[packetList].Count; packet++) { - Packet tempPacket = keyValuePair.Value[packetList][packet]; - if (tempPacket.fragment != packet || (packet == keyValuePair.Value[packetList].Count - 1 && tempPacket.moreFragments)) { - packetReady = false; - } else { - packetLength += tempPacket.data.Length; - } - } + for (int packet = 0; packet < keyValuePair.Value[packetList].Count; packet++) + { + Array.Copy(keyValuePair.Value[packetList][packet].data, 0, data, dataIndex, keyValuePair.Value[packetList][packet].data.Length); + dataIndex += keyValuePair.Value[packetList][packet].data.Length; + } - if (packetReady) { - byte[] data = new byte[packetLength]; - int dataIndex = 0; + OnReceiveData(data, keyValuePair.Key.productUserId, keyValuePair.Key.channel); - for (int packet = 0; packet < keyValuePair.Value[packetList].Count; packet++) { - Array.Copy(keyValuePair.Value[packetList][packet].data, 0, data, dataIndex, keyValuePair.Value[packetList][packet].data.Length); - dataIndex += keyValuePair.Value[packetList][packet].data.Length; - } + //keyValuePair.Value[packetList].Clear(); + emptyPacketLists.Add(keyValuePair.Value[packetList]); + } + } - OnReceiveData(data, keyValuePair.Key.productUserId, keyValuePair.Key.channel); + for (int i = 0; i < emptyPacketLists.Count; i++) + { + keyValuePair.Value.Remove(emptyPacketLists[i]); + } - //keyValuePair.Value[packetList].Clear(); - emptyPacketLists.Add(keyValuePair.Value[packetList]); - } - } + emptyPacketLists.Clear(); + } + } + catch (Exception e) + { + Debug.LogException(e); + } + } - for (int i = 0; i < emptyPacketLists.Count; i++) { - keyValuePair.Value.Remove(emptyPacketLists[i]); - } - emptyPacketLists.Clear(); - } - - - - } catch (Exception e) { - Debug.LogException(e); - } - } - - protected abstract void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserID, SocketId socketId); - protected abstract void OnReceiveData(byte[] data, ProductUserId clientUserID, int channel); - protected abstract void OnConnectionFailed(ProductUserId remoteId); - } -} \ No newline at end of file + protected abstract void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserID, SocketId socketId); + protected abstract void OnReceiveData(byte[] data, ProductUserId clientUserID, int channel); + protected abstract void OnConnectionFailed(ProductUserId remoteId); + } +} diff --git a/EpicOnlineTransport/EOSSDKComponent.cs b/EpicOnlineTransport/EOSSDKComponent.cs index d96b5901..9a7904c7 100644 --- a/EpicOnlineTransport/EOSSDKComponent.cs +++ b/EpicOnlineTransport/EOSSDKComponent.cs @@ -1,10 +1,8 @@ using Epic.OnlineServices; using Epic.OnlineServices.Logging; using Epic.OnlineServices.Platform; - using System; using System.Runtime.InteropServices; - using UnityEngine; /// @@ -14,142 +12,164 @@ using UnityEngine; /// after releasing the SDK the game has to be restarted in order to initialize the SDK again. /// In the unity editor the OnDestroy function will not run so that we dont have to restart the editor after play. /// -namespace EpicTransport { - [DefaultExecutionOrder(-32000)] - public class EOSSDKComponent : MonoBehaviour { +namespace EpicTransport +{ + [DefaultExecutionOrder(-32000)] + public class EOSSDKComponent : MonoBehaviour + { + // Unity Inspector shown variables - // Unity Inspector shown variables - - [SerializeField] - public EosApiKey apiKeys; + [SerializeField] + public EosApiKey apiKeys; - [Header("User Login")] - public bool authInterfaceLogin = false; - public Epic.OnlineServices.Auth.LoginCredentialType authInterfaceCredentialType = Epic.OnlineServices.Auth.LoginCredentialType.AccountPortal; - public uint devAuthToolPort = 7878; - public string devAuthToolCredentialName = ""; - public Epic.OnlineServices.ExternalCredentialType connectInterfaceCredentialType = Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken; - public string deviceModel = "PC Windows 64bit"; - [SerializeField] private string displayName = "User"; - public static string DisplayName { - get { - return Instance.displayName; - } - set { - Instance.displayName = value; - } - } + [Header("User Login")] + public bool authInterfaceLogin = false; + public Epic.OnlineServices.Auth.LoginCredentialType authInterfaceCredentialType = Epic.OnlineServices.Auth.LoginCredentialType.AccountPortal; + public uint devAuthToolPort = 7878; + public string devAuthToolCredentialName = ""; + public Epic.OnlineServices.ExternalCredentialType connectInterfaceCredentialType = Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken; + public string deviceModel = "PC Windows 64bit"; + [SerializeField] private string displayName = "User"; + public static string DisplayName + { + get + { + return Instance.displayName; + } + set + { + Instance.displayName = value; + } + } - [Header("Misc")] - public LogLevel epicLoggerLevel = LogLevel.Error; + [Header("Misc")] + public LogLevel epicLoggerLevel = LogLevel.Error; - [SerializeField] - public bool collectPlayerMetrics = true; - public static bool CollectPlayerMetrics { - get { - return Instance.collectPlayerMetrics; - } - } + [SerializeField] + public bool collectPlayerMetrics = true; + public static bool CollectPlayerMetrics + { + get + { + return Instance.collectPlayerMetrics; + } + } - public bool checkForEpicLauncherAndRestart = false; - public bool delayedInitialization = false; - public float platformTickIntervalInSeconds = 0.0f; - private float platformTickTimer = 0f; - public uint tickBudgetInMilliseconds = 0; + public bool checkForEpicLauncherAndRestart = false; + public bool delayedInitialization = false; + public float platformTickIntervalInSeconds = 0.0f; + private float platformTickTimer = 0f; + public uint tickBudgetInMilliseconds = 0; - // End Unity Inspector shown variables + // End Unity Inspector shown variables - private ulong authExpirationHandle; + private ulong authExpirationHandle; + private string authInterfaceLoginCredentialId = null; + public static void SetAuthInterfaceLoginCredentialId(string credentialId) => Instance.authInterfaceLoginCredentialId = credentialId; + private string authInterfaceCredentialToken = null; + public static void SetAuthInterfaceCredentialToken(string credentialToken) => Instance.authInterfaceCredentialToken = credentialToken; + private string connectInterfaceCredentialToken = null; + public static void SetConnectInterfaceCredentialToken(string credentialToken) => Instance.connectInterfaceCredentialToken = credentialToken; - private string authInterfaceLoginCredentialId = null; - public static void SetAuthInterfaceLoginCredentialId(string credentialId) => Instance.authInterfaceLoginCredentialId = credentialId; - private string authInterfaceCredentialToken = null; - public static void SetAuthInterfaceCredentialToken(string credentialToken) => Instance.authInterfaceCredentialToken = credentialToken; - private string connectInterfaceCredentialToken = null; - public static void SetConnectInterfaceCredentialToken(string credentialToken) => Instance.connectInterfaceCredentialToken = credentialToken; + private PlatformInterface EOS; - private PlatformInterface EOS; + // Interfaces + public static Epic.OnlineServices.Achievements.AchievementsInterface GetAchievementsInterface() => Instance.EOS.GetAchievementsInterface(); + public static Epic.OnlineServices.Auth.AuthInterface GetAuthInterface() => Instance.EOS.GetAuthInterface(); + public static Epic.OnlineServices.Connect.ConnectInterface GetConnectInterface() => Instance.EOS.GetConnectInterface(); + public static Epic.OnlineServices.Ecom.EcomInterface GetEcomInterface() => Instance.EOS.GetEcomInterface(); + public static Epic.OnlineServices.Friends.FriendsInterface GetFriendsInterface() => Instance.EOS.GetFriendsInterface(); + public static Epic.OnlineServices.Leaderboards.LeaderboardsInterface GetLeaderboardsInterface() => Instance.EOS.GetLeaderboardsInterface(); + public static Epic.OnlineServices.Lobby.LobbyInterface GetLobbyInterface() => Instance.EOS.GetLobbyInterface(); + public static Epic.OnlineServices.Metrics.MetricsInterface GetMetricsInterface() => Instance.EOS.GetMetricsInterface(); // Handled by the transport automatically, only use this interface if Mirror is not used for singleplayer + public static Epic.OnlineServices.Mods.ModsInterface GetModsInterface() => Instance.EOS.GetModsInterface(); + public static Epic.OnlineServices.P2P.P2PInterface GetP2PInterface() => Instance.EOS.GetP2PInterface(); + public static Epic.OnlineServices.PlayerDataStorage.PlayerDataStorageInterface GetPlayerDataStorageInterface() => Instance.EOS.GetPlayerDataStorageInterface(); + public static Epic.OnlineServices.Presence.PresenceInterface GetPresenceInterface() => Instance.EOS.GetPresenceInterface(); + public static Epic.OnlineServices.Sessions.SessionsInterface GetSessionsInterface() => Instance.EOS.GetSessionsInterface(); + public static Epic.OnlineServices.TitleStorage.TitleStorageInterface GetTitleStorageInterface() => Instance.EOS.GetTitleStorageInterface(); + public static Epic.OnlineServices.UI.UIInterface GetUIInterface() => Instance.EOS.GetUIInterface(); + public static Epic.OnlineServices.UserInfo.UserInfoInterface GetUserInfoInterface() => Instance.EOS.GetUserInfoInterface(); - // Interfaces - public static Epic.OnlineServices.Achievements.AchievementsInterface GetAchievementsInterface() => Instance.EOS.GetAchievementsInterface(); - public static Epic.OnlineServices.Auth.AuthInterface GetAuthInterface() => Instance.EOS.GetAuthInterface(); - public static Epic.OnlineServices.Connect.ConnectInterface GetConnectInterface() => Instance.EOS.GetConnectInterface(); - public static Epic.OnlineServices.Ecom.EcomInterface GetEcomInterface() => Instance.EOS.GetEcomInterface(); - public static Epic.OnlineServices.Friends.FriendsInterface GetFriendsInterface() => Instance.EOS.GetFriendsInterface(); - public static Epic.OnlineServices.Leaderboards.LeaderboardsInterface GetLeaderboardsInterface() => Instance.EOS.GetLeaderboardsInterface(); - public static Epic.OnlineServices.Lobby.LobbyInterface GetLobbyInterface() => Instance.EOS.GetLobbyInterface(); - public static Epic.OnlineServices.Metrics.MetricsInterface GetMetricsInterface() => Instance.EOS.GetMetricsInterface(); // Handled by the transport automatically, only use this interface if Mirror is not used for singleplayer - public static Epic.OnlineServices.Mods.ModsInterface GetModsInterface() => Instance.EOS.GetModsInterface(); - public static Epic.OnlineServices.P2P.P2PInterface GetP2PInterface() => Instance.EOS.GetP2PInterface(); - public static Epic.OnlineServices.PlayerDataStorage.PlayerDataStorageInterface GetPlayerDataStorageInterface() => Instance.EOS.GetPlayerDataStorageInterface(); - public static Epic.OnlineServices.Presence.PresenceInterface GetPresenceInterface() => Instance.EOS.GetPresenceInterface(); - public static Epic.OnlineServices.Sessions.SessionsInterface GetSessionsInterface() => Instance.EOS.GetSessionsInterface(); - public static Epic.OnlineServices.TitleStorage.TitleStorageInterface GetTitleStorageInterface() => Instance.EOS.GetTitleStorageInterface(); - public static Epic.OnlineServices.UI.UIInterface GetUIInterface() => Instance.EOS.GetUIInterface(); - public static Epic.OnlineServices.UserInfo.UserInfoInterface GetUserInfoInterface() => Instance.EOS.GetUserInfoInterface(); + protected EpicAccountId localUserAccountId; + public static EpicAccountId LocalUserAccountId + { + get + { + return Instance.localUserAccountId; + } + } + protected string localUserAccountIdString; + public static string LocalUserAccountIdString + { + get + { + return Instance.localUserAccountIdString; + } + } - protected EpicAccountId localUserAccountId; - public static EpicAccountId LocalUserAccountId { - get { - return Instance.localUserAccountId; - } - } + protected ProductUserId localUserProductId; + public static ProductUserId LocalUserProductId + { + get + { + return Instance.localUserProductId; + } + } - protected string localUserAccountIdString; - public static string LocalUserAccountIdString { - get { - return Instance.localUserAccountIdString; - } - } + protected string localUserProductIdString; + public static string LocalUserProductIdString + { + get + { + return Instance.localUserProductIdString; + } + } - protected ProductUserId localUserProductId; - public static ProductUserId LocalUserProductId { - get { - return Instance.localUserProductId; - } - } + protected bool initialized; + public static bool Initialized + { + get + { + return Instance.initialized; + } + } - protected string localUserProductIdString; - public static string LocalUserProductIdString { - get { - return Instance.localUserProductIdString; - } - } + protected bool isConnecting; + public static bool IsConnecting + { + get + { + return Instance.isConnecting; + } + } - protected bool initialized; - public static bool Initialized { - get { - return Instance.initialized; - } - } + protected static EOSSDKComponent instance; + protected static EOSSDKComponent Instance + { + get + { + if (instance == null) + { + return new GameObject("EOSSDKComponent").AddComponent(); + } + else + { + return instance; + } + } + } - protected bool isConnecting; - public static bool IsConnecting { - get { - return Instance.isConnecting; - } - } + public static void Tick() + { + instance.platformTickTimer -= Time.deltaTime; + instance.EOS.Tick(); + } - protected static EOSSDKComponent instance; - protected static EOSSDKComponent Instance { - get { - if (instance == null) { - return new GameObject("EOSSDKComponent").AddComponent(); - } else { - return instance; - } - } - } - - public static void Tick() { - instance.platformTickTimer -= Time.deltaTime; - instance.EOS.Tick(); - } - - // If we're in editor, we should dynamically load and unload the SDK between play sessions. - // This allows us to initialize the SDK each time the game is run in editor. + // If we're in editor, we should dynamically load and unload the SDK between play sessions. + // This allows us to initialize the SDK each time the game is run in editor. #if UNITY_EDITOR_WIN [DllImport("Kernel32.dll")] private static extern IntPtr LoadLibrary(string lpLibFileName); @@ -162,7 +182,7 @@ namespace EpicTransport { private IntPtr libraryPointer; #endif - + #if UNITY_EDITOR_LINUX [DllImport("libdl.so", EntryPoint = "dlopen")] private static extern IntPtr LoadLibrary(String lpFileName, int flags = 2); @@ -189,24 +209,27 @@ namespace EpicTransport { private IntPtr libraryPointer; #endif - private void Awake() { - // Initialize Java version of the SDK with a reference to the VM with JNI - // See https://eoshelp.epicgames.com/s/question/0D54z00006ufJBNCA2/cant-get-createdeviceid-to-work-in-unity-android-c-sdk?language=en_US - if (Application.platform == RuntimePlatform.Android) - { - AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); - AndroidJavaObject activity = unityPlayer.GetStatic("currentActivity"); - AndroidJavaObject context = activity.Call("getApplicationContext"); - AndroidJavaClass EOS_SDK_JAVA = new AndroidJavaClass("com.epicgames.mobile.eossdk.EOSSDK"); - EOS_SDK_JAVA.CallStatic("init", context); - } - - // Prevent multiple instances - if (instance != null) { - Destroy(gameObject); - return; - } - instance = this; + private void Awake() + { + // Initialize Java version of the SDK with a reference to the VM with JNI + // See https://eoshelp.epicgames.com/s/question/0D54z00006ufJBNCA2/cant-get-createdeviceid-to-work-in-unity-android-c-sdk?language=en_US + if (Application.platform == RuntimePlatform.Android) + { + AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + AndroidJavaObject activity = unityPlayer.GetStatic("currentActivity"); + AndroidJavaObject context = activity.Call("getApplicationContext"); + AndroidJavaClass EOS_SDK_JAVA = new AndroidJavaClass("com.epicgames.mobile.eossdk.EOSSDK"); + EOS_SDK_JAVA.CallStatic("init", context); + } + + // Prevent multiple instances + if (instance != null) + { + Destroy(gameObject); + return; + } + + instance = this; #if UNITY_EDITOR var libraryPath = "Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/" + Config.LibraryName; @@ -219,207 +242,260 @@ namespace EpicTransport { Bindings.Hook(libraryPointer, GetProcAddress); #endif - if (!delayedInitialization) { - Initialize(); - } - } + if (!delayedInitialization) + { + Initialize(); + } + } - protected void InitializeImplementation() { - isConnecting = true; + protected void InitializeImplementation() + { + isConnecting = true; - var initializeOptions = new InitializeOptions() { - ProductName = apiKeys.epicProductName, - ProductVersion = apiKeys.epicProductVersion - }; + var initializeOptions = new InitializeOptions() + { + ProductName = apiKeys.epicProductName, + ProductVersion = apiKeys.epicProductVersion + }; - var initializeResult = PlatformInterface.Initialize(initializeOptions); + var initializeResult = PlatformInterface.Initialize(initializeOptions); - // This code is called each time the game is run in the editor, so we catch the case where the SDK has already been initialized in the editor. - var isAlreadyConfiguredInEditor = Application.isEditor && initializeResult == Result.AlreadyConfigured; - if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor) { - throw new System.Exception("Failed to initialize platform: " + initializeResult); - } + // This code is called each time the game is run in the editor, so we catch the case where the SDK has already been initialized in the editor. + var isAlreadyConfiguredInEditor = Application.isEditor && initializeResult == Result.AlreadyConfigured; + if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor) + { + throw new System.Exception("Failed to initialize platform: " + initializeResult); + } - // The SDK outputs lots of information that is useful for debugging. - // Make sure to set up the logging interface as early as possible: after initializing. - LoggingInterface.SetLogLevel(LogCategory.AllCategories, epicLoggerLevel); - LoggingInterface.SetCallback(message => Logger.EpicDebugLog(message)); + // The SDK outputs lots of information that is useful for debugging. + // Make sure to set up the logging interface as early as possible: after initializing. + LoggingInterface.SetLogLevel(LogCategory.AllCategories, epicLoggerLevel); + LoggingInterface.SetCallback(message => Logger.EpicDebugLog(message)); - var options = new Options() { - ProductId = apiKeys.epicProductId, - SandboxId = apiKeys.epicSandboxId, - DeploymentId = apiKeys.epicDeploymentId, - ClientCredentials = new ClientCredentials() { - ClientId = apiKeys.epicClientId, - ClientSecret = apiKeys.epicClientSecret - }, - TickBudgetInMilliseconds = tickBudgetInMilliseconds - }; + var options = new Options() + { + ProductId = apiKeys.epicProductId, + SandboxId = apiKeys.epicSandboxId, + DeploymentId = apiKeys.epicDeploymentId, + ClientCredentials = new ClientCredentials() + { + ClientId = apiKeys.epicClientId, + ClientSecret = apiKeys.epicClientSecret + }, + TickBudgetInMilliseconds = tickBudgetInMilliseconds + }; - EOS = PlatformInterface.Create(options); - if (EOS == null) { - throw new System.Exception("Failed to create platform"); - } + EOS = PlatformInterface.Create(options); + if (EOS == null) + { + throw new System.Exception("Failed to create platform"); + } - if (checkForEpicLauncherAndRestart) { - Result result = EOS.CheckForLauncherAndRestart(); + if (checkForEpicLauncherAndRestart) + { + Result result = EOS.CheckForLauncherAndRestart(); - // If not started through epic launcher the app will be restarted and we can quit - if (result != Result.NoChange) { + // If not started through epic launcher the app will be restarted and we can quit + if (result != Result.NoChange) + { + // Log error if launcher check failed, but still quit to prevent hacking + if (result == Result.UnexpectedError) + { + Debug.LogError("Unexpected Error while checking if app was started through epic launcher"); + } - // Log error if launcher check failed, but still quit to prevent hacking - if (result == Result.UnexpectedError) { - Debug.LogError("Unexpected Error while checking if app was started through epic launcher"); - } + Application.Quit(); + } + } - Application.Quit(); - } - } + // If we use the Auth interface then only login into the Connect interface after finishing the auth interface login + // If we don't use the Auth interface we can directly login to the Connect interface + if (authInterfaceLogin) + { + if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer) + { + authInterfaceLoginCredentialId = "localhost:" + devAuthToolPort; + authInterfaceCredentialToken = devAuthToolCredentialName; + } - // If we use the Auth interface then only login into the Connect interface after finishing the auth interface login - // If we don't use the Auth interface we can directly login to the Connect interface - if (authInterfaceLogin) { - if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer) { - authInterfaceLoginCredentialId = "localhost:" + devAuthToolPort; - authInterfaceCredentialToken = devAuthToolCredentialName; - } + // Login to Auth Interface + Epic.OnlineServices.Auth.LoginOptions loginOptions = new Epic.OnlineServices.Auth.LoginOptions() + { + Credentials = new Epic.OnlineServices.Auth.Credentials() + { + Type = authInterfaceCredentialType, + Id = authInterfaceLoginCredentialId, + Token = authInterfaceCredentialToken + }, + ScopeFlags = Epic.OnlineServices.Auth.AuthScopeFlags.BasicProfile | Epic.OnlineServices.Auth.AuthScopeFlags.FriendsList | Epic.OnlineServices.Auth.AuthScopeFlags.Presence + }; - // Login to Auth Interface - Epic.OnlineServices.Auth.LoginOptions loginOptions = new Epic.OnlineServices.Auth.LoginOptions() { - Credentials = new Epic.OnlineServices.Auth.Credentials() { - Type = authInterfaceCredentialType, - Id = authInterfaceLoginCredentialId, - Token = authInterfaceCredentialToken - }, - ScopeFlags = Epic.OnlineServices.Auth.AuthScopeFlags.BasicProfile | Epic.OnlineServices.Auth.AuthScopeFlags.FriendsList | Epic.OnlineServices.Auth.AuthScopeFlags.Presence - }; + EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin); + } + else + { + // Login to Connect Interface + if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) + { + Epic.OnlineServices.Connect.CreateDeviceIdOptions createDeviceIdOptions = new Epic.OnlineServices.Connect.CreateDeviceIdOptions(); + createDeviceIdOptions.DeviceModel = deviceModel; + EOS.GetConnectInterface().CreateDeviceId(createDeviceIdOptions, null, OnCreateDeviceId); + } + else + { + ConnectInterfaceLogin(); + } + } + } - EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin); - } else { - // Login to Connect Interface - if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) { - Epic.OnlineServices.Connect.CreateDeviceIdOptions createDeviceIdOptions = new Epic.OnlineServices.Connect.CreateDeviceIdOptions(); - createDeviceIdOptions.DeviceModel = deviceModel; - EOS.GetConnectInterface().CreateDeviceId(createDeviceIdOptions, null, OnCreateDeviceId); - } else { - ConnectInterfaceLogin(); - } - } + public static void Initialize() + { + if (Instance.initialized || Instance.isConnecting) + { + return; + } - } - public static void Initialize() { - if (Instance.initialized || Instance.isConnecting) { - return; - } + Instance.InitializeImplementation(); + } - Instance.InitializeImplementation(); - } + private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) + { + if (loginCallbackInfo.ResultCode == Result.Success) + { + Debug.Log("Auth Interface Login succeeded"); - private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) { - if (loginCallbackInfo.ResultCode == Result.Success) { - Debug.Log("Auth Interface Login succeeded"); + string accountIdString; + Result result = loginCallbackInfo.LocalUserId.ToString(out accountIdString); + if (Result.Success == result) + { + Debug.Log("EOS User ID:" + accountIdString); - string accountIdString; - Result result = loginCallbackInfo.LocalUserId.ToString(out accountIdString); - if (Result.Success == result) { - Debug.Log("EOS User ID:" + accountIdString); + localUserAccountIdString = accountIdString; + localUserAccountId = loginCallbackInfo.LocalUserId; + } - localUserAccountIdString = accountIdString; - localUserAccountId = loginCallbackInfo.LocalUserId; - } - - ConnectInterfaceLogin(); - } else if(Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)){ - Debug.Log("Login returned " + loginCallbackInfo.ResultCode); - } - } + ConnectInterfaceLogin(); + } + else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) + { + Debug.Log("Login returned " + loginCallbackInfo.ResultCode); + } + } - private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo) { - if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed) { - ConnectInterfaceLogin(); - } else if(Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode)) { - Debug.Log("Device ID creation returned " + createDeviceIdCallbackInfo.ResultCode); - } - } + private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo) + { + if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed) + { + ConnectInterfaceLogin(); + } + else if (Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode)) + { + Debug.Log("Device ID creation returned " + createDeviceIdCallbackInfo.ResultCode); + } + } - private void ConnectInterfaceLogin() { - var loginOptions = new Epic.OnlineServices.Connect.LoginOptions(); + private void ConnectInterfaceLogin() + { + var loginOptions = new Epic.OnlineServices.Connect.LoginOptions(); - if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.Epic) { - Epic.OnlineServices.Auth.Token token; - Result result = EOS.GetAuthInterface().CopyUserAuthToken(new Epic.OnlineServices.Auth.CopyUserAuthTokenOptions(), localUserAccountId, out token); + if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.Epic) + { + Epic.OnlineServices.Auth.Token token; + Result result = EOS.GetAuthInterface().CopyUserAuthToken(new Epic.OnlineServices.Auth.CopyUserAuthTokenOptions(), localUserAccountId, out token); - if (result == Result.Success) { - connectInterfaceCredentialToken = token.AccessToken; - } else { - Debug.LogError("Failed to retrieve User Auth Token"); - } - } else if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) { - loginOptions.UserLoginInfo = new Epic.OnlineServices.Connect.UserLoginInfo(); - loginOptions.UserLoginInfo.DisplayName = displayName; - } + if (result == Result.Success) + { + connectInterfaceCredentialToken = token.AccessToken; + } + else + { + Debug.LogError("Failed to retrieve User Auth Token"); + } + } + else if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) + { + loginOptions.UserLoginInfo = new Epic.OnlineServices.Connect.UserLoginInfo(); + loginOptions.UserLoginInfo.DisplayName = displayName; + } - loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials(); - loginOptions.Credentials.Type = connectInterfaceCredentialType; - loginOptions.Credentials.Token = connectInterfaceCredentialToken; + loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials(); + loginOptions.Credentials.Type = connectInterfaceCredentialType; + loginOptions.Credentials.Token = connectInterfaceCredentialToken; - EOS.GetConnectInterface().Login(loginOptions, null, OnConnectInterfaceLogin); - } + EOS.GetConnectInterface().Login(loginOptions, null, OnConnectInterfaceLogin); + } - private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) { - if (loginCallbackInfo.ResultCode == Result.Success) { - Debug.Log("Connect Interface Login succeeded"); + private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) + { + if (loginCallbackInfo.ResultCode == Result.Success) + { + Debug.Log("Connect Interface Login succeeded"); - string productIdString; - Result result = loginCallbackInfo.LocalUserId.ToString(out productIdString); - if (Result.Success == result) { - Debug.Log("EOS User Product ID:" + productIdString); + string productIdString; + Result result = loginCallbackInfo.LocalUserId.ToString(out productIdString); + if (Result.Success == result) + { + Debug.Log("EOS User Product ID:" + productIdString); - localUserProductIdString = productIdString; - localUserProductId = loginCallbackInfo.LocalUserId; - } - - initialized = true; - isConnecting = false; + localUserProductIdString = productIdString; + localUserProductId = loginCallbackInfo.LocalUserId; + } - var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions(); - authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration); - } else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) { - Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying..."); - EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) => { - if (cb.ResultCode != Result.Success) { Debug.Log(cb.ResultCode); return; } - localUserProductId = cb.LocalUserId; - ConnectInterfaceLogin(); - }); - } - } - - private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo) { - Debug.Log("AuthExpiration callback"); - EOS.GetConnectInterface().RemoveNotifyAuthExpiration(authExpirationHandle); - ConnectInterfaceLogin(); - } + initialized = true; + isConnecting = false; - // Calling tick on a regular interval is required for callbacks to work. - private void LateUpdate() { - if (EOS != null) { - platformTickTimer += Time.deltaTime; + var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions(); + authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration); + } + else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) + { + Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying..."); + EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) => + { + if (cb.ResultCode != Result.Success) + { + Debug.Log(cb.ResultCode); + return; + } - if (platformTickTimer >= platformTickIntervalInSeconds) { - platformTickTimer = 0; - EOS.Tick(); - } - } - } + localUserProductId = cb.LocalUserId; + ConnectInterfaceLogin(); + }); + } + } - private void OnApplicationQuit() { - if (EOS != null) { - EOS.Release(); - EOS = null; - PlatformInterface.Shutdown(); - } + private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo) + { + Debug.Log("AuthExpiration callback"); + EOS.GetConnectInterface().RemoveNotifyAuthExpiration(authExpirationHandle); + ConnectInterfaceLogin(); + } - // Unhook the library in the editor, this makes it possible to load the library again after stopping to play + // Calling tick on a regular interval is required for callbacks to work. + private void LateUpdate() + { + if (EOS != null) + { + platformTickTimer += Time.deltaTime; + + if (platformTickTimer >= platformTickIntervalInSeconds) + { + platformTickTimer = 0; + EOS.Tick(); + } + } + } + + private void OnApplicationQuit() + { + if (EOS != null) + { + EOS.Release(); + EOS = null; + PlatformInterface.Shutdown(); + } + + // Unhook the library in the editor, this makes it possible to load the library again after stopping to play #if UNITY_EDITOR if (libraryPointer != IntPtr.Zero) { Bindings.Unhook(); @@ -430,6 +506,6 @@ namespace EpicTransport { libraryPointer = IntPtr.Zero; } #endif - } - } -} \ No newline at end of file + } + } +} diff --git a/EpicOnlineTransport/EosApiKey.cs b/EpicOnlineTransport/EosApiKey.cs index ddc037d1..0ba68a08 100644 --- a/EpicOnlineTransport/EosApiKey.cs +++ b/EpicOnlineTransport/EosApiKey.cs @@ -10,14 +10,14 @@ using UnityEngine; /// Create -> EOS -> API Key /// in order to create an instance of this scriptable object /// - [CreateAssetMenu(fileName = "EosApiKey", menuName = "EOS/API Key", order = 1)] -public class EosApiKey : ScriptableObject { - public string epicProductName = "MyApplication"; - public string epicProductVersion = "1.0"; - public string epicProductId = ""; - public string epicSandboxId = ""; - public string epicDeploymentId = ""; - public string epicClientId = ""; - public string epicClientSecret = ""; +public class EosApiKey : ScriptableObject +{ + public string epicProductName = "MyApplication"; + public string epicProductVersion = "1.0"; + public string epicProductId = ""; + public string epicSandboxId = ""; + public string epicDeploymentId = ""; + public string epicClientId = ""; + public string epicClientSecret = ""; } diff --git a/EpicOnlineTransport/EosTransport.cs b/EpicOnlineTransport/EosTransport.cs index 1b373f34..47aea920 100644 --- a/EpicOnlineTransport/EosTransport.cs +++ b/EpicOnlineTransport/EosTransport.cs @@ -8,318 +8,391 @@ using Mirror; using Epic.OnlineServices.Metrics; using System.Collections; -namespace EpicTransport { - - /// - /// EOS Transport following the Mirror transport standard - /// - public class EosTransport : Transport { - private const string EPIC_SCHEME = "epic"; - - private Client client; - private Server server; - - private Common activeNode; - - [SerializeField] - public PacketReliability[] Channels = new PacketReliability[2] { PacketReliability.ReliableOrdered, PacketReliability.UnreliableUnordered }; - - [Tooltip("Timeout for connecting in seconds.")] - public int timeout = 25; - - [Tooltip("The max fragments used in fragmentation before throwing an error.")] - public int maxFragments = 55; - - public float ignoreCachedMessagesAtStartUpInSeconds = 2.0f; - private float ignoreCachedMessagesTimer = 0.0f; - - public RelayControl relayControl = RelayControl.AllowRelays; - - [Header("Info")] - [Tooltip("This will display your Epic Account ID when you start or connect to a server.")] - public ProductUserId productUserId; - - private int packetId = 0; - - private void Awake() { - Debug.Assert(Channels != null && Channels.Length > 0, "No channel configured for EOS Transport."); - Debug.Assert(Channels.Length < byte.MaxValue, "Too many channels configured for EOS Transport"); - - if(Channels[0] != PacketReliability.ReliableOrdered) { - Debug.LogWarning("EOS Transport Channel[0] is not ReliableOrdered, Mirror expects Channel 0 to be ReliableOrdered, only change this if you know what you are doing."); - } - if (Channels[1] != PacketReliability.UnreliableUnordered) { - Debug.LogWarning("EOS Transport Channel[1] is not UnreliableUnordered, Mirror expects Channel 1 to be UnreliableUnordered, only change this if you know what you are doing."); - } - - StartCoroutine("FetchEpicAccountId"); - StartCoroutine("ChangeRelayStatus"); - } - - public override void ClientEarlyUpdate() { - EOSSDKComponent.Tick(); - - if (activeNode != null) { - ignoreCachedMessagesTimer += Time.deltaTime; - - if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) { - activeNode.ignoreAllMessages = true; - } else { - activeNode.ignoreAllMessages = false; - - if (client != null && !client.isConnecting) { - if (EOSSDKComponent.Initialized) { - client.Connect(client.hostAddress); - } else { - Debug.LogError("EOS not initialized"); - client.EosNotInitialized(); - } - client.isConnecting = true; - } - } - } - - if (enabled) { - activeNode?.ReceiveData(); - } - } - - public override void ClientLateUpdate() {} - - public override void ServerEarlyUpdate() { - EOSSDKComponent.Tick(); - - if (activeNode != null) { - ignoreCachedMessagesTimer += Time.deltaTime; - - if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) { - activeNode.ignoreAllMessages = true; - } else { - activeNode.ignoreAllMessages = false; - } - } - - if (enabled) { - activeNode?.ReceiveData(); - } - } - - public override void ServerLateUpdate() {} - - public override bool ClientConnected() => ClientActive() && client.Connected; - public override void ClientConnect(string address) { - if (!EOSSDKComponent.Initialized) { - Debug.LogError("EOS not initialized. Client could not be started."); - OnClientDisconnected.Invoke(); - return; - } - - StartCoroutine("FetchEpicAccountId"); - - if (ServerActive()) { - Debug.LogError("Transport already running as server!"); - return; - } - - if (!ClientActive() || client.Error) { - Debug.Log($"Starting client, target address {address}."); - - client = Client.CreateClient(this, address); - activeNode = client; - - if (EOSSDKComponent.CollectPlayerMetrics) { - // Start Metrics colletion session - BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions(); - sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; - sessionOptions.ControllerType = UserControllerType.Unknown; - sessionOptions.DisplayName = EOSSDKComponent.DisplayName; - sessionOptions.GameSessionId = null; - sessionOptions.ServerIp = null; - Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions); - - if(result == Result.Success) { - Debug.Log("Started Metric Session"); - } - } - } else { - Debug.LogError("Client already running!"); - } - } - - public override void ClientConnect(Uri uri) { - if (uri.Scheme != EPIC_SCHEME) - throw new ArgumentException($"Invalid url {uri}, use {EPIC_SCHEME}://EpicAccountId instead", nameof(uri)); - - ClientConnect(uri.Host); - } - - public override void ClientSend(ArraySegment segment, int channelId) { - Send(channelId, segment); - } - - public override void ClientDisconnect() { - if (ClientActive()) { - Shutdown(); - } - } - public bool ClientActive() => client != null; - - - public override bool ServerActive() => server != null; - public override void ServerStart() { - if (!EOSSDKComponent.Initialized) { - Debug.LogError("EOS not initialized. Server could not be started."); - return; - } - - StartCoroutine("FetchEpicAccountId"); - - if (ClientActive()) { - Debug.LogError("Transport already running as client!"); - return; - } - - if (!ServerActive()) { - Debug.Log("Starting server."); - - server = Server.CreateServer(this, NetworkManager.singleton.maxConnections); - activeNode = server; - - if (EOSSDKComponent.CollectPlayerMetrics) { - // Start Metrics colletion session - BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions(); - sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; - sessionOptions.ControllerType = UserControllerType.Unknown; - sessionOptions.DisplayName = EOSSDKComponent.DisplayName; - sessionOptions.GameSessionId = null; - sessionOptions.ServerIp = null; - Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions); - - if (result == Result.Success) { - Debug.Log("Started Metric Session"); - } - } - } else { - Debug.LogError("Server already started!"); - } - } - - public override Uri ServerUri() { - UriBuilder epicBuilder = new UriBuilder { - Scheme = EPIC_SCHEME, - Host = EOSSDKComponent.LocalUserProductIdString - }; - - return epicBuilder.Uri; - } - - public override void ServerSend(int connectionId, ArraySegment segment, int channelId) { - if (ServerActive()) { - Send( channelId, segment, connectionId); - } - } - public override void ServerDisconnect(int connectionId) => server.Disconnect(connectionId); - public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty; - public override void ServerStop() { - if (ServerActive()) { - Shutdown(); - } - } - - private void Send(int channelId, ArraySegment segment, int connectionId = int.MinValue) { - Packet[] packets = GetPacketArray(channelId, segment); - - for(int i = 0; i < packets.Length; i++) { - if (connectionId == int.MinValue) { - client.Send(packets[i].ToBytes(), channelId); - } else { - server.SendAll(connectionId, packets[i].ToBytes(), channelId); - } - } - - packetId++; - } - - private Packet[] GetPacketArray(int channelId, ArraySegment segment) { - int packetCount = Mathf.CeilToInt((float) segment.Count / (float)GetMaxSinglePacketSize(channelId)); - Packet[] packets = new Packet[packetCount]; - - for (int i = 0; i < segment.Count; i += GetMaxSinglePacketSize(channelId)) { - int fragment = i / GetMaxSinglePacketSize(channelId); - - packets[fragment] = new Packet(); - packets[fragment].id = packetId; - packets[fragment].fragment = fragment; - packets[fragment].moreFragments = (segment.Count - i) > GetMaxSinglePacketSize(channelId); - packets[fragment].data = new byte[segment.Count - i > GetMaxSinglePacketSize(channelId) ? GetMaxSinglePacketSize(channelId) : segment.Count - i]; - Array.Copy(segment.Array, i, packets[fragment].data, 0, packets[fragment].data.Length); - } - - return packets; - } - - public override void Shutdown() { - if (EOSSDKComponent.CollectPlayerMetrics) { - // Stop Metrics collection session - EndPlayerSessionOptions endSessionOptions = new EndPlayerSessionOptions(); - endSessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; - Result result = EOSSDKComponent.GetMetricsInterface().EndPlayerSession(endSessionOptions); - - if (result == Result.Success) { - Debug.LogError("Stopped Metric Session"); - } - } - - server?.Shutdown(); - client?.Disconnect(); - - server = null; - client = null; - activeNode = null; - Debug.Log("Transport shut down."); - } - - public int GetMaxSinglePacketSize(int channelId) => P2PInterface.MaxPacketSize - 10; // 1159 bytes, we need to remove 10 bytes for the packet header (id (4 bytes) + fragment (4 bytes) + more fragments (1 byte)) - - public override int GetMaxPacketSize(int channelId) => P2PInterface.MaxPacketSize * maxFragments; - - public override int GetBatchThreshold(int channelId) => P2PInterface.MaxPacketSize; // Use P2PInterface.MaxPacketSize as everything above will get fragmentated and will be counter effective to batching - - public override bool Available() { - try { - return EOSSDKComponent.Initialized; - } catch { - return false; - } - } - - private IEnumerator FetchEpicAccountId() { - while (!EOSSDKComponent.Initialized) { - yield return null; - } - - productUserId = EOSSDKComponent.LocalUserProductId; - } - - private IEnumerator ChangeRelayStatus() { - while (!EOSSDKComponent.Initialized) { - yield return null; - } - - SetRelayControlOptions setRelayControlOptions = new SetRelayControlOptions(); - setRelayControlOptions.RelayControl = relayControl; - - EOSSDKComponent.GetP2PInterface().SetRelayControl(setRelayControlOptions); - } - - public void ResetIgnoreMessagesAtStartUpTimer() { - ignoreCachedMessagesTimer = 0; - } - - private void OnDestroy() { - if (activeNode != null) { - Shutdown(); - } - } - } +namespace EpicTransport +{ + /// + /// EOS Transport following the Mirror transport standard + /// + public class EosTransport : Transport + { + private const string EPIC_SCHEME = "epic"; + + private Client client; + private Server server; + + private Common activeNode; + + [SerializeField] + public PacketReliability[] Channels = new PacketReliability[2] { PacketReliability.ReliableOrdered, PacketReliability.UnreliableUnordered }; + + [Tooltip("Timeout for connecting in seconds.")] + public int timeout = 25; + + [Tooltip("The max fragments used in fragmentation before throwing an error.")] + public int maxFragments = 55; + + public float ignoreCachedMessagesAtStartUpInSeconds = 2.0f; + private float ignoreCachedMessagesTimer = 0.0f; + + public RelayControl relayControl = RelayControl.AllowRelays; + + [Header("Info")] + [Tooltip("This will display your Epic Account ID when you start or connect to a server.")] + public ProductUserId productUserId; + + private int packetId = 0; + + private void Awake() + { + Debug.Assert(Channels != null && Channels.Length > 0, "No channel configured for EOS Transport."); + Debug.Assert(Channels.Length < byte.MaxValue, "Too many channels configured for EOS Transport"); + + if (Channels[0] != PacketReliability.ReliableOrdered) + { + Debug.LogWarning("EOS Transport Channel[0] is not ReliableOrdered, Mirror expects Channel 0 to be ReliableOrdered, only change this if you know what you are doing."); + } + + if (Channels[1] != PacketReliability.UnreliableUnordered) + { + Debug.LogWarning("EOS Transport Channel[1] is not UnreliableUnordered, Mirror expects Channel 1 to be UnreliableUnordered, only change this if you know what you are doing."); + } + + StartCoroutine("FetchEpicAccountId"); + StartCoroutine("ChangeRelayStatus"); + } + + public override void ClientEarlyUpdate() + { + EOSSDKComponent.Tick(); + + if (activeNode != null) + { + ignoreCachedMessagesTimer += Time.deltaTime; + + if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) + { + activeNode.ignoreAllMessages = true; + } + else + { + activeNode.ignoreAllMessages = false; + + if (client != null && !client.isConnecting) + { + if (EOSSDKComponent.Initialized) + { + client.Connect(client.hostAddress); + } + else + { + Debug.LogError("EOS not initialized"); + client.EosNotInitialized(); + } + + client.isConnecting = true; + } + } + } + + if (enabled) + { + activeNode?.ReceiveData(); + } + } + + public override void ClientLateUpdate() { } + + public override void ServerEarlyUpdate() + { + EOSSDKComponent.Tick(); + + if (activeNode != null) + { + ignoreCachedMessagesTimer += Time.deltaTime; + + if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) + { + activeNode.ignoreAllMessages = true; + } + else + { + activeNode.ignoreAllMessages = false; + } + } + + if (enabled) + { + activeNode?.ReceiveData(); + } + } + + public override void ServerLateUpdate() { } + + public override bool ClientConnected() => ClientActive() && client.Connected; + + public override void ClientConnect(string address) + { + if (!EOSSDKComponent.Initialized) + { + Debug.LogError("EOS not initialized. Client could not be started."); + OnClientDisconnected.Invoke(); + return; + } + + StartCoroutine("FetchEpicAccountId"); + + if (ServerActive()) + { + Debug.LogError("Transport already running as server!"); + return; + } + + if (!ClientActive() || client.Error) + { + Debug.Log($"Starting client, target address {address}."); + + client = Client.CreateClient(this, address); + activeNode = client; + + if (EOSSDKComponent.CollectPlayerMetrics) + { + // Start Metrics colletion session + BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions(); + sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; + sessionOptions.ControllerType = UserControllerType.Unknown; + sessionOptions.DisplayName = EOSSDKComponent.DisplayName; + sessionOptions.GameSessionId = null; + sessionOptions.ServerIp = null; + Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions); + + if (result == Result.Success) + { + Debug.Log("Started Metric Session"); + } + } + } + else + { + Debug.LogError("Client already running!"); + } + } + + public override void ClientConnect(Uri uri) + { + if (uri.Scheme != EPIC_SCHEME) + throw new ArgumentException($"Invalid url {uri}, use {EPIC_SCHEME}://EpicAccountId instead", nameof(uri)); + + ClientConnect(uri.Host); + } + + public override void ClientSend(ArraySegment segment, int channelId) + { + Send(channelId, segment); + } + + public override void ClientDisconnect() + { + if (ClientActive()) + { + Shutdown(); + } + } + + public bool ClientActive() => client != null; + + public override bool ServerActive() => server != null; + + public override void ServerStart() + { + if (!EOSSDKComponent.Initialized) + { + Debug.LogError("EOS not initialized. Server could not be started."); + return; + } + + StartCoroutine("FetchEpicAccountId"); + + if (ClientActive()) + { + Debug.LogError("Transport already running as client!"); + return; + } + + if (!ServerActive()) + { + Debug.Log("Starting server."); + + server = Server.CreateServer(this, NetworkManager.singleton.maxConnections); + activeNode = server; + + if (EOSSDKComponent.CollectPlayerMetrics) + { + // Start Metrics colletion session + BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions(); + sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; + sessionOptions.ControllerType = UserControllerType.Unknown; + sessionOptions.DisplayName = EOSSDKComponent.DisplayName; + sessionOptions.GameSessionId = null; + sessionOptions.ServerIp = null; + Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions); + + if (result == Result.Success) + { + Debug.Log("Started Metric Session"); + } + } + } + else + { + Debug.LogError("Server already started!"); + } + } + + public override Uri ServerUri() + { + UriBuilder epicBuilder = new UriBuilder + { + Scheme = EPIC_SCHEME, + Host = EOSSDKComponent.LocalUserProductIdString + }; + + return epicBuilder.Uri; + } + + public override void ServerSend(int connectionId, ArraySegment segment, int channelId) + { + if (ServerActive()) + { + Send(channelId, segment, connectionId); + } + } + + public override void ServerDisconnect(int connectionId) => server.Disconnect(connectionId); + public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty; + + public override void ServerStop() + { + if (ServerActive()) + { + Shutdown(); + } + } + + private void Send(int channelId, ArraySegment segment, int connectionId = int.MinValue) + { + Packet[] packets = GetPacketArray(channelId, segment); + + for (int i = 0; i < packets.Length; i++) + { + if (connectionId == int.MinValue) + { + client.Send(packets[i].ToBytes(), channelId); + } + else + { + server.SendAll(connectionId, packets[i].ToBytes(), channelId); + } + } + + packetId++; + } + + private Packet[] GetPacketArray(int channelId, ArraySegment segment) + { + int packetCount = Mathf.CeilToInt((float)segment.Count / (float)GetMaxSinglePacketSize(channelId)); + Packet[] packets = new Packet[packetCount]; + + for (int i = 0; i < segment.Count; i += GetMaxSinglePacketSize(channelId)) + { + int fragment = i / GetMaxSinglePacketSize(channelId); + + packets[fragment] = new Packet(); + packets[fragment].id = packetId; + packets[fragment].fragment = fragment; + packets[fragment].moreFragments = (segment.Count - i) > GetMaxSinglePacketSize(channelId); + packets[fragment].data = new byte[segment.Count - i > GetMaxSinglePacketSize(channelId) ? GetMaxSinglePacketSize(channelId) : segment.Count - i]; + Array.Copy(segment.Array, i, packets[fragment].data, 0, packets[fragment].data.Length); + } + + return packets; + } + + public override void Shutdown() + { + if (EOSSDKComponent.CollectPlayerMetrics) + { + // Stop Metrics collection session + EndPlayerSessionOptions endSessionOptions = new EndPlayerSessionOptions(); + endSessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId; + Result result = EOSSDKComponent.GetMetricsInterface().EndPlayerSession(endSessionOptions); + + if (result == Result.Success) + { + Debug.LogError("Stopped Metric Session"); + } + } + + server?.Shutdown(); + client?.Disconnect(); + + server = null; + client = null; + activeNode = null; + Debug.Log("Transport shut down."); + } + + public int GetMaxSinglePacketSize(int channelId) => P2PInterface.MaxPacketSize - 10; // 1159 bytes, we need to remove 10 bytes for the packet header (id (4 bytes) + fragment (4 bytes) + more fragments (1 byte)) + + public override int GetMaxPacketSize(int channelId) => P2PInterface.MaxPacketSize * maxFragments; + + public override int GetBatchThreshold(int channelId) => P2PInterface.MaxPacketSize; // Use P2PInterface.MaxPacketSize as everything above will get fragmentated and will be counter effective to batching + + public override bool Available() + { + try + { + return EOSSDKComponent.Initialized; + } + catch + { + return false; + } + } + + private IEnumerator FetchEpicAccountId() + { + while (!EOSSDKComponent.Initialized) + { + yield return null; + } + + productUserId = EOSSDKComponent.LocalUserProductId; + } + + private IEnumerator ChangeRelayStatus() + { + while (!EOSSDKComponent.Initialized) + { + yield return null; + } + + SetRelayControlOptions setRelayControlOptions = new SetRelayControlOptions(); + setRelayControlOptions.RelayControl = relayControl; + + EOSSDKComponent.GetP2PInterface().SetRelayControl(setRelayControlOptions); + } + + public void ResetIgnoreMessagesAtStartUpTimer() + { + ignoreCachedMessagesTimer = 0; + } + + private void OnDestroy() + { + if (activeNode != null) + { + Shutdown(); + } + } + } } diff --git a/EpicOnlineTransport/Logger.cs b/EpicOnlineTransport/Logger.cs index 197c6e0c..fe928db4 100644 --- a/EpicOnlineTransport/Logger.cs +++ b/EpicOnlineTransport/Logger.cs @@ -4,27 +4,30 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace EpicTransport { - public static class Logger { - - public static void EpicDebugLog(LogMessage message) { - switch (message.Level) { - case LogLevel.Info: - Debug.Log($"Epic Manager: Category - {message.Category} Message - {message.Message}"); - break; - case LogLevel.Error: - Debug.LogError($"Epic Manager: Category - {message.Category} Message - {message.Message}"); - break; - case LogLevel.Warning: - Debug.LogWarning($"Epic Manager: Category - {message.Category} Message - {message.Message}"); - break; - case LogLevel.Fatal: - Debug.LogException(new Exception($"Epic Manager: Category - {message.Category} Message - {message.Message}")); - break; - default: - Debug.Log($"Epic Manager: Unknown log processing. Category - {message.Category} Message - {message.Message}"); - break; - } - } - } -} \ No newline at end of file +namespace EpicTransport +{ + public static class Logger + { + public static void EpicDebugLog(LogMessage message) + { + switch (message.Level) + { + case LogLevel.Info: + Debug.Log($"Epic Manager: Category - {message.Category} Message - {message.Message}"); + break; + case LogLevel.Error: + Debug.LogError($"Epic Manager: Category - {message.Category} Message - {message.Message}"); + break; + case LogLevel.Warning: + Debug.LogWarning($"Epic Manager: Category - {message.Category} Message - {message.Message}"); + break; + case LogLevel.Fatal: + Debug.LogException(new Exception($"Epic Manager: Category - {message.Category} Message - {message.Message}")); + break; + default: + Debug.Log($"Epic Manager: Unknown log processing. Category - {message.Category} Message - {message.Message}"); + break; + } + } + } +} diff --git a/EpicOnlineTransport/Packet.cs b/EpicOnlineTransport/Packet.cs index cb43d755..20275016 100644 --- a/EpicOnlineTransport/Packet.cs +++ b/EpicOnlineTransport/Packet.cs @@ -1,47 +1,51 @@ using System; -namespace EpicTransport { - public struct Packet { - public const int headerSize = sizeof(uint) + sizeof(uint) + 1; - public int size => headerSize + data.Length; +namespace EpicTransport +{ + public struct Packet + { + public const int headerSize = sizeof(uint) + sizeof(uint) + 1; + public int size => headerSize + data.Length; - // header - public int id; - public int fragment; - public bool moreFragments; + // header + public int id; + public int fragment; + public bool moreFragments; - // body - public byte[] data; + // body + public byte[] data; - public byte[] ToBytes() { - byte[] array = new byte[size]; + public byte[] ToBytes() + { + byte[] array = new byte[size]; - // Copy id - array[0] = (byte) id; - array[1] = (byte) (id >> 8); - array[2] = (byte) (id >> 0x10); - array[3] = (byte) (id >> 0x18); + // Copy id + array[0] = (byte)id; + array[1] = (byte)(id >> 8); + array[2] = (byte)(id >> 0x10); + array[3] = (byte)(id >> 0x18); - // Copy fragment - array[4] = (byte) fragment; - array[5] = (byte) (fragment >> 8); - array[6] = (byte) (fragment >> 0x10); - array[7] = (byte) (fragment >> 0x18); + // Copy fragment + array[4] = (byte)fragment; + array[5] = (byte)(fragment >> 8); + array[6] = (byte)(fragment >> 0x10); + array[7] = (byte)(fragment >> 0x18); - array[8] = moreFragments ? (byte)1 : (byte)0; + array[8] = moreFragments ? (byte)1 : (byte)0; - Array.Copy(data, 0, array, 9, data.Length); + Array.Copy(data, 0, array, 9, data.Length); - return array; - } + return array; + } - public void FromBytes(byte[] array) { - id = BitConverter.ToInt32(array, 0); - fragment = BitConverter.ToInt32(array, 4); - moreFragments = array[8] == 1; + public void FromBytes(byte[] array) + { + id = BitConverter.ToInt32(array, 0); + fragment = BitConverter.ToInt32(array, 4); + moreFragments = array[8] == 1; - data = new byte[array.Length - 9]; - Array.Copy(array, 9, data, 0, data.Length); - } - } -} \ No newline at end of file + data = new byte[array.Length - 9]; + Array.Copy(array, 9, data, 0, data.Length); + } + } +} diff --git a/EpicOnlineTransport/RandomString.cs b/EpicOnlineTransport/RandomString.cs index 46b7dc1d..dfc97d4f 100644 --- a/EpicOnlineTransport/RandomString.cs +++ b/EpicOnlineTransport/RandomString.cs @@ -1,36 +1,41 @@ using System; using System.Text; -public class RandomString { +public class RandomString +{ + // Generates a random string with a given size. + public static string Generate(int size) + { + var builder = new StringBuilder(size); - // Generates a random string with a given size. - public static string Generate(int size) { - var builder = new StringBuilder(size); + Random random = new Random(); - Random random = new Random(); + // Unicode/ASCII Letters are divided into two blocks + // (Letters 65–90 / 97–122): + // The first group containing the uppercase letters and + // the second group containing the lowercase. - // Unicode/ASCII Letters are divided into two blocks - // (Letters 65–90 / 97–122): - // The first group containing the uppercase letters and - // the second group containing the lowercase. + // char is a single Unicode character + char offsetLowerCase = 'a'; + char offsetUpperCase = 'A'; + const int lettersOffset = 26; // A...Z or a..z: length=26 - // char is a single Unicode character - char offsetLowerCase = 'a'; - char offsetUpperCase = 'A'; - const int lettersOffset = 26; // A...Z or a..z: length=26 - - for (var i = 0; i < size; i++) { - char offset; - if(random.Next(0,2) == 0) { - offset = offsetLowerCase; - } else { - offset = offsetUpperCase; - } + for (var i = 0; i < size; i++) + { + char offset; + if (random.Next(0, 2) == 0) + { + offset = offsetLowerCase; + } + else + { + offset = offsetUpperCase; + } - var @char = (char) random.Next(offset, offset + lettersOffset); - builder.Append(@char); - } + var @char = (char)random.Next(offset, offset + lettersOffset); + builder.Append(@char); + } - return builder.ToString(); - } + return builder.ToString(); + } } diff --git a/EpicOnlineTransport/Server.cs b/EpicOnlineTransport/Server.cs index 6959f0e3..d950897c 100644 --- a/EpicOnlineTransport/Server.cs +++ b/EpicOnlineTransport/Server.cs @@ -4,182 +4,218 @@ using System; using System.Collections.Generic; using UnityEngine; -namespace EpicTransport { - public class Server : Common { - private event Action OnConnected; - private event Action OnReceivedData; - private event Action OnDisconnected; - private event Action OnReceivedError; +namespace EpicTransport +{ + public class Server : Common + { + private event Action OnConnected; + private event Action OnReceivedData; + private event Action OnDisconnected; + private event Action OnReceivedError; - private BidirectionalDictionary epicToMirrorIds; - private Dictionary epicToSocketIds; - private int maxConnections; - private int nextConnectionID; + private BidirectionalDictionary epicToMirrorIds; + private Dictionary epicToSocketIds; + private int maxConnections; + private int nextConnectionID; - public static Server CreateServer(EosTransport transport, int maxConnections) { - Server s = new Server(transport, maxConnections); + public static Server CreateServer(EosTransport transport, int maxConnections) + { + Server s = new Server(transport, maxConnections); - s.OnConnected += (id) => transport.OnServerConnected.Invoke(id); - s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id); - s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment(data), channel); - s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception); + s.OnConnected += (id) => transport.OnServerConnected.Invoke(id); + s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id); + s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment(data), channel); + s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception); - if (!EOSSDKComponent.Initialized) { - Debug.LogError("EOS not initialized."); - } + if (!EOSSDKComponent.Initialized) + { + Debug.LogError("EOS not initialized."); + } - return s; - } + return s; + } - private Server(EosTransport transport, int maxConnections) : base(transport) { - this.maxConnections = maxConnections; - epicToMirrorIds = new BidirectionalDictionary(); - epicToSocketIds = new Dictionary(); - nextConnectionID = 1; - } + private Server(EosTransport transport, int maxConnections) : base(transport) + { + this.maxConnections = maxConnections; + epicToMirrorIds = new BidirectionalDictionary(); + epicToSocketIds = new Dictionary(); + nextConnectionID = 1; + } - protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) { - if (ignoreAllMessages) { - return; - } + protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) + { + if (ignoreAllMessages) + { + return; + } - if (deadSockets.Contains(result.SocketId.SocketName)) { - Debug.LogError("Received incoming connection request from dead socket"); - return; - } + if (deadSockets.Contains(result.SocketId.SocketName)) + { + Debug.LogError("Received incoming connection request from dead socket"); + return; + } - EOSSDKComponent.GetP2PInterface().AcceptConnection( - new AcceptConnectionOptions() { - LocalUserId = EOSSDKComponent.LocalUserProductId, - RemoteUserId = result.RemoteUserId, - SocketId = result.SocketId - }); - } + EOSSDKComponent.GetP2PInterface().AcceptConnection( + new AcceptConnectionOptions() + { + LocalUserId = EOSSDKComponent.LocalUserProductId, + RemoteUserId = result.RemoteUserId, + SocketId = result.SocketId + }); + } - protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) { - if (ignoreAllMessages) { - return; - } + protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) + { + if (ignoreAllMessages) + { + return; + } - switch (type) { - case InternalMessages.CONNECT: - if (epicToMirrorIds.Count >= maxConnections) { - Debug.LogError("Reached max connections"); - //CloseP2PSessionWithUser(clientUserId, socketId); - SendInternal(clientUserId, socketId, InternalMessages.DISCONNECT); - return; - } + switch (type) + { + case InternalMessages.CONNECT: + if (epicToMirrorIds.Count >= maxConnections) + { + Debug.LogError("Reached max connections"); + //CloseP2PSessionWithUser(clientUserId, socketId); + SendInternal(clientUserId, socketId, InternalMessages.DISCONNECT); + return; + } - SendInternal(clientUserId, socketId, InternalMessages.ACCEPT_CONNECT); + SendInternal(clientUserId, socketId, InternalMessages.ACCEPT_CONNECT); - int connectionId = nextConnectionID++; - epicToMirrorIds.Add(clientUserId, connectionId); - epicToSocketIds.Add(clientUserId, socketId); - OnConnected.Invoke(connectionId); + int connectionId = nextConnectionID++; + epicToMirrorIds.Add(clientUserId, connectionId); + epicToSocketIds.Add(clientUserId, socketId); + OnConnected.Invoke(connectionId); - string clientUserIdString; - clientUserId.ToString(out clientUserIdString); - Debug.Log($"Client with Product User ID {clientUserIdString} connected. Assigning connection id {connectionId}"); - break; - case InternalMessages.DISCONNECT: - if (epicToMirrorIds.TryGetValue(clientUserId, out int connId)) { - OnDisconnected.Invoke(connId); - //CloseP2PSessionWithUser(clientUserId, socketId); - epicToMirrorIds.Remove(clientUserId); - epicToSocketIds.Remove(clientUserId); - Debug.Log($"Client with Product User ID {clientUserId} disconnected."); - } else { - OnReceivedError.Invoke(-1, new Exception("ERROR Unknown Product User ID")); - } + string clientUserIdString; + clientUserId.ToString(out clientUserIdString); + Debug.Log($"Client with Product User ID {clientUserIdString} connected. Assigning connection id {connectionId}"); + break; + case InternalMessages.DISCONNECT: + if (epicToMirrorIds.TryGetValue(clientUserId, out int connId)) + { + OnDisconnected.Invoke(connId); + //CloseP2PSessionWithUser(clientUserId, socketId); + epicToMirrorIds.Remove(clientUserId); + epicToSocketIds.Remove(clientUserId); + Debug.Log($"Client with Product User ID {clientUserId} disconnected."); + } + else + { + OnReceivedError.Invoke(-1, new Exception("ERROR Unknown Product User ID")); + } - break; - default: - Debug.Log("Received unknown message type"); - break; - } - } + break; + default: + Debug.Log("Received unknown message type"); + break; + } + } - protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) { - if (ignoreAllMessages) { - return; - } + protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) + { + if (ignoreAllMessages) + { + return; + } - if (epicToMirrorIds.TryGetValue(clientUserId, out int connectionId)) { - OnReceivedData.Invoke(connectionId, data, channel); - } else { - SocketId socketId; - epicToSocketIds.TryGetValue(clientUserId, out socketId); - CloseP2PSessionWithUser(clientUserId, socketId); + if (epicToMirrorIds.TryGetValue(clientUserId, out int connectionId)) + { + OnReceivedData.Invoke(connectionId, data, channel); + } + else + { + SocketId socketId; + epicToSocketIds.TryGetValue(clientUserId, out socketId); + CloseP2PSessionWithUser(clientUserId, socketId); - string productId; - clientUserId.ToString(out productId); + string productId; + clientUserId.ToString(out productId); - Debug.LogError("Data received from epic client thats not known " + productId); - OnReceivedError.Invoke(-1, new Exception("ERROR Unknown product ID")); - } - } + Debug.LogError("Data received from epic client thats not known " + productId); + OnReceivedError.Invoke(-1, new Exception("ERROR Unknown product ID")); + } + } - public void Disconnect(int connectionId) { - if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) { - SocketId socketId; - epicToSocketIds.TryGetValue(userId, out socketId); - SendInternal(userId, socketId, InternalMessages.DISCONNECT); - epicToMirrorIds.Remove(userId); - epicToSocketIds.Remove(userId); - } else { - Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId); - } - } + public void Disconnect(int connectionId) + { + if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) + { + SocketId socketId; + epicToSocketIds.TryGetValue(userId, out socketId); + SendInternal(userId, socketId, InternalMessages.DISCONNECT); + epicToMirrorIds.Remove(userId); + epicToSocketIds.Remove(userId); + } + else + { + Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId); + } + } - public void Shutdown() { - foreach (KeyValuePair client in epicToMirrorIds) { - Disconnect(client.Value); - SocketId socketId; - epicToSocketIds.TryGetValue(client.Key, out socketId); - WaitForClose(client.Key, socketId); - } + public void Shutdown() + { + foreach (KeyValuePair client in epicToMirrorIds) + { + Disconnect(client.Value); + SocketId socketId; + epicToSocketIds.TryGetValue(client.Key, out socketId); + WaitForClose(client.Key, socketId); + } - ignoreAllMessages = true; - ReceiveData(); + ignoreAllMessages = true; + ReceiveData(); - Dispose(); - } + Dispose(); + } - public void SendAll(int connectionId, byte[] data, int channelId) { - if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) { - SocketId socketId; - epicToSocketIds.TryGetValue(userId, out socketId); - Send(userId, socketId, data, (byte)channelId); - } else { - Debug.LogError("Trying to send on unknown connection: " + connectionId); - OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); - } + public void SendAll(int connectionId, byte[] data, int channelId) + { + if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) + { + SocketId socketId; + epicToSocketIds.TryGetValue(userId, out socketId); + Send(userId, socketId, data, (byte)channelId); + } + else + { + Debug.LogError("Trying to send on unknown connection: " + connectionId); + OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); + } + } - } + public string ServerGetClientAddress(int connectionId) + { + if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) + { + string userIdString; + userId.ToString(out userIdString); + return userIdString; + } + else + { + Debug.LogError("Trying to get info on unknown connection: " + connectionId); + OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); + return string.Empty; + } + } - public string ServerGetClientAddress(int connectionId) { - if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) { - string userIdString; - userId.ToString(out userIdString); - return userIdString; - } else { - Debug.LogError("Trying to get info on unknown connection: " + connectionId); - OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection")); - return string.Empty; - } - } + protected override void OnConnectionFailed(ProductUserId remoteId) + { + if (ignoreAllMessages) + { + return; + } - protected override void OnConnectionFailed(ProductUserId remoteId) { - if (ignoreAllMessages) { - return; - } + int connectionId = epicToMirrorIds.TryGetValue(remoteId, out int connId) ? connId : nextConnectionID++; + OnDisconnected.Invoke(connectionId); - int connectionId = epicToMirrorIds.TryGetValue(remoteId, out int connId) ? connId : nextConnectionID++; - OnDisconnected.Invoke(connectionId); - - Debug.LogError("Connection Failed, removing user"); - epicToMirrorIds.Remove(remoteId); - epicToSocketIds.Remove(remoteId); - } - } -} \ No newline at end of file + Debug.LogError("Connection Failed, removing user"); + epicToMirrorIds.Remove(remoteId); + epicToSocketIds.Remove(remoteId); + } + } +}