mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-01-15 22:50:56 +00:00
reformat code
This commit is contained in:
parent
e7accbdf17
commit
c9f9ba0801
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 = "";
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,41 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
public class RandomString {
|
||||
public class RandomString
|
||||
{
|
||||
// Generates a random string with a given size.
|
||||
public static string Generate(int size)
|
||||
{
|
||||
var builder = new StringBuilder(size);
|
||||
|
||||
// Generates a random string with a given size.
|
||||
public static string Generate(int size) {
|
||||
var builder = new StringBuilder(size);
|
||||
Random random = new Random();
|
||||
|
||||
Random random = new Random();
|
||||
// Unicode/ASCII Letters are divided into two blocks
|
||||
// (Letters 65–90 / 97–122):
|
||||
// The first group containing the uppercase letters and
|
||||
// the second group containing the lowercase.
|
||||
|
||||
// Unicode/ASCII Letters are divided into two blocks
|
||||
// (Letters 65–90 / 97–122):
|
||||
// The first group containing the uppercase letters and
|
||||
// the second group containing the lowercase.
|
||||
// char is a single Unicode character
|
||||
char offsetLowerCase = 'a';
|
||||
char offsetUpperCase = 'A';
|
||||
const int lettersOffset = 26; // A...Z or a..z: length=26
|
||||
|
||||
// char is a single Unicode character
|
||||
char offsetLowerCase = 'a';
|
||||
char offsetUpperCase = 'A';
|
||||
const int lettersOffset = 26; // A...Z or a..z: length=26
|
||||
|
||||
for (var i = 0; i < size; i++) {
|
||||
char offset;
|
||||
if(random.Next(0,2) == 0) {
|
||||
offset = offsetLowerCase;
|
||||
} else {
|
||||
offset = offsetUpperCase;
|
||||
}
|
||||
for (var i = 0; i < size; i++)
|
||||
{
|
||||
char offset;
|
||||
if (random.Next(0, 2) == 0)
|
||||
{
|
||||
offset = offsetLowerCase;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = offsetUpperCase;
|
||||
}
|
||||
|
||||
var @char = (char) random.Next(offset, offset + lettersOffset);
|
||||
builder.Append(@char);
|
||||
}
|
||||
var @char = (char)random.Next(offset, offset + lettersOffset);
|
||||
builder.Append(@char);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user