reformat code

This commit is contained in:
JohnCorby 2022-02-05 20:17:08 -08:00
parent e7accbdf17
commit c9f9ba0801
10 changed files with 1562 additions and 1278 deletions

View File

@ -50,71 +50,82 @@ using System.Collections.Generic;
/// MIT License
/// </summary>
namespace EpicTransport {
namespace EpicTransport
{
public class BidirectionalDictionary<T1, T2> : IEnumerable
{
private Dictionary<T1, T2> t1ToT2Dict = new Dictionary<T1, T2>();
private Dictionary<T2, T1> t2ToT1Dict = new Dictionary<T2, T1>();
public class BidirectionalDictionary<T1, T2> : IEnumerable {
private Dictionary<T1, T2> t1ToT2Dict = new Dictionary<T1, T2>();
private Dictionary<T2, T1> t2ToT1Dict = new Dictionary<T2, T1>();
public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys;
public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys;
public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys;
public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys;
public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator();
public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator();
public int Count => t1ToT2Dict.Count;
public int Count => t1ToT2Dict.Count;
public void Add(T1 key, T2 value)
{
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;
}
}
}
}
public T2 this[T1 key]
{
get => t1ToT2Dict[key];
set
{
t1ToT2Dict[key] = value;
t2ToT1Dict[value] = key;
}
}
}
}

View File

@ -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<byte[], int> OnReceivedData;
private event Action OnConnected;
public event Action OnDisconnected;
private event Action<byte[], int> 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<Task> connectedComplete;
private CancellationTokenSource cancelToken;
public bool isConnecting = false;
public string hostAddress = "";
private ProductUserId hostProductId = null;
private TaskCompletionSource<Task> 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<byte>(data), channel);
c.OnConnected += () => transport.OnClientConnected.Invoke();
c.OnDisconnected += () => transport.OnClientDisconnected.Invoke();
c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(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<Task>();
try {
hostProductId = ProductUserId.FromString(host);
serverId = hostProductId;
connectedComplete = new TaskCompletionSource<Task>();
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();
}
}
protected override void OnConnectionFailed(ProductUserId remoteId) => OnDisconnected.Invoke();
public void EosNotInitialized() => OnDisconnected.Invoke();
}
}

View File

@ -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<string> deadSockets;
public bool ignoreAllMessages = false;
protected List<string> deadSockets;
public bool ignoreAllMessages = false;
// Mapping from PacketKey to a List of Packet Lists
protected Dictionary<PacketKey, List<List<Packet>>> incomingPackets = new Dictionary<PacketKey, List<List<Packet>>>();
// Mapping from PacketKey to a List of Packet Lists
protected Dictionary<PacketKey, List<List<Packet>>> incomingPackets = new Dictionary<PacketKey, List<List<Packet>>>();
protected Common(EosTransport transport)
{
channels = transport.Channels;
protected Common(EosTransport transport) {
channels = transport.Channels;
deadSockets = new List<string>();
deadSockets = new List<string>();
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<PacketKey, List<List<Packet>>>();
incomingPackets = new Dictionary<PacketKey, List<List<Packet>>>();
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<List<Packet>>());
}
// 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<Packet>());
}
if (!incomingPackets.ContainsKey(incomingPacketKey)) {
incomingPackets.Add(incomingPacketKey, new List<List<Packet>>());
}
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<Packet>());
}
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<List<Packet>> emptyPacketLists = new List<List<Packet>>();
foreach (KeyValuePair<PacketKey, List<List<Packet>>> 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<List<Packet>> emptyPacketLists = new List<List<Packet>>();
foreach(KeyValuePair<PacketKey, List<List<Packet>>> 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);
}
}
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);
}
}

View File

@ -1,10 +1,8 @@
using Epic.OnlineServices;
using Epic.OnlineServices.Logging;
using Epic.OnlineServices.Platform;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
/// <summary>
@ -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.
/// </summary>
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<EOSSDKComponent>();
}
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<EOSSDKComponent>();
} 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<AndroidJavaObject>("currentActivity");
AndroidJavaObject context = activity.Call<AndroidJavaObject>("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<AndroidJavaObject>("currentActivity");
AndroidJavaObject context = activity.Call<AndroidJavaObject>("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
}
}
}
}
}
}

View File

@ -10,14 +10,14 @@ using UnityEngine;
/// Create -> EOS -> API Key
/// in order to create an instance of this scriptable object
/// </summary>
[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 = "";
}

View File

@ -8,318 +8,391 @@ using Mirror;
using Epic.OnlineServices.Metrics;
using System.Collections;
namespace EpicTransport {
/// <summary>
/// EOS Transport following the Mirror transport standard
/// </summary>
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<byte> 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<byte> 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<byte> 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<byte> 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
{
/// <summary>
/// EOS Transport following the Mirror transport standard
/// </summary>
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<byte> 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<byte> 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<byte> 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<byte> 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();
}
}
}
}

View File

@ -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;
}
}
}
}
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;
}
}
}
}

View File

@ -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);
}
}
}
data = new byte[array.Length - 9];
Array.Copy(array, 9, data, 0, data.Length);
}
}
}

View File

@ -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 6590 / 97122):
// The first group containing the uppercase letters and
// the second group containing the lowercase.
// Unicode/ASCII Letters are divided into two blocks
// (Letters 6590 / 97122):
// 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();
}
}

View File

@ -4,182 +4,218 @@ using System;
using System.Collections.Generic;
using UnityEngine;
namespace EpicTransport {
public class Server : Common {
private event Action<int> OnConnected;
private event Action<int, byte[], int> OnReceivedData;
private event Action<int> OnDisconnected;
private event Action<int, Exception> OnReceivedError;
namespace EpicTransport
{
public class Server : Common
{
private event Action<int> OnConnected;
private event Action<int, byte[], int> OnReceivedData;
private event Action<int> OnDisconnected;
private event Action<int, Exception> OnReceivedError;
private BidirectionalDictionary<ProductUserId, int> epicToMirrorIds;
private Dictionary<ProductUserId, SocketId> epicToSocketIds;
private int maxConnections;
private int nextConnectionID;
private BidirectionalDictionary<ProductUserId, int> epicToMirrorIds;
private Dictionary<ProductUserId, SocketId> 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<byte>(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<byte>(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<ProductUserId, int>();
epicToSocketIds = new Dictionary<ProductUserId, SocketId>();
nextConnectionID = 1;
}
private Server(EosTransport transport, int maxConnections) : base(transport)
{
this.maxConnections = maxConnections;
epicToMirrorIds = new BidirectionalDictionary<ProductUserId, int>();
epicToSocketIds = new Dictionary<ProductUserId, SocketId>();
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<ProductUserId, int> client in epicToMirrorIds) {
Disconnect(client.Value);
SocketId socketId;
epicToSocketIds.TryGetValue(client.Key, out socketId);
WaitForClose(client.Key, socketId);
}
public void Shutdown()
{
foreach (KeyValuePair<ProductUserId, int> 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);
}
}
}
Debug.LogError("Connection Failed, removing user");
epicToMirrorIds.Remove(remoteId);
epicToSocketIds.Remove(remoteId);
}
}
}