mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-02-22 03:40:54 +00:00
commit
9ab9158a50
@ -50,12 +50,11 @@ using System.Collections.Generic;
|
|||||||
/// MIT License
|
/// MIT License
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
|
||||||
public class BidirectionalDictionary<T1, T2> : IEnumerable
|
public class BidirectionalDictionary<T1, T2> : IEnumerable {
|
||||||
{
|
private Dictionary<T1, T2> t1ToT2Dict = new Dictionary<T1, T2>();
|
||||||
private Dictionary<T1, T2> t1ToT2Dict = new();
|
private Dictionary<T2, T1> t2ToT1Dict = new Dictionary<T2, T1>();
|
||||||
private Dictionary<T2, T1> t2ToT1Dict = new();
|
|
||||||
|
|
||||||
public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys;
|
public IEnumerable<T1> FirstTypes => t1ToT2Dict.Keys;
|
||||||
public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys;
|
public IEnumerable<T2> SecondTypes => t2ToT1Dict.Keys;
|
||||||
@ -64,14 +63,12 @@ public class BidirectionalDictionary<T1, T2> : IEnumerable
|
|||||||
|
|
||||||
public int Count => t1ToT2Dict.Count;
|
public int Count => t1ToT2Dict.Count;
|
||||||
|
|
||||||
public void Add(T1 key, T2 value)
|
public void Add(T1 key, T2 value) {
|
||||||
{
|
|
||||||
t1ToT2Dict[key] = value;
|
t1ToT2Dict[key] = value;
|
||||||
t2ToT1Dict[value] = key;
|
t2ToT1Dict[value] = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(T2 key, T1 value)
|
public void Add(T2 key, T1 value) {
|
||||||
{
|
|
||||||
t2ToT1Dict[key] = value;
|
t2ToT1Dict[key] = value;
|
||||||
t1ToT2Dict[value] = key;
|
t1ToT2Dict[value] = key;
|
||||||
}
|
}
|
||||||
@ -88,43 +85,36 @@ public class BidirectionalDictionary<T1, T2> : IEnumerable
|
|||||||
|
|
||||||
public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key);
|
public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key);
|
||||||
|
|
||||||
public void Remove(T1 key)
|
public void Remove(T1 key) {
|
||||||
{
|
if (Contains(key)) {
|
||||||
if (Contains(key))
|
T2 val = t1ToT2Dict[key];
|
||||||
{
|
|
||||||
var val = t1ToT2Dict[key];
|
|
||||||
t1ToT2Dict.Remove(key);
|
t1ToT2Dict.Remove(key);
|
||||||
t2ToT1Dict.Remove(val);
|
t2ToT1Dict.Remove(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Remove(T2 key) {
|
||||||
public void Remove(T2 key)
|
if (Contains(key)) {
|
||||||
{
|
T1 val = t2ToT1Dict[key];
|
||||||
if (Contains(key))
|
|
||||||
{
|
|
||||||
var val = t2ToT1Dict[key];
|
|
||||||
t1ToT2Dict.Remove(val);
|
t1ToT2Dict.Remove(val);
|
||||||
t2ToT1Dict.Remove(key);
|
t2ToT1Dict.Remove(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T1 this[T2 key]
|
public T1 this[T2 key] {
|
||||||
{
|
|
||||||
get => t2ToT1Dict[key];
|
get => t2ToT1Dict[key];
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
t2ToT1Dict[key] = value;
|
t2ToT1Dict[key] = value;
|
||||||
t1ToT2Dict[value] = key;
|
t1ToT2Dict[value] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T2 this[T1 key]
|
public T2 this[T1 key] {
|
||||||
{
|
|
||||||
get => t1ToT2Dict[key];
|
get => t1ToT2Dict[key];
|
||||||
set
|
set {
|
||||||
{
|
|
||||||
t1ToT2Dict[key] = value;
|
t1ToT2Dict[key] = value;
|
||||||
t2ToT1Dict[value] = key;
|
t2ToT1Dict[value] = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
using Epic.OnlineServices;
|
using Epic.OnlineServices;
|
||||||
using Epic.OnlineServices.P2P;
|
using Epic.OnlineServices.P2P;
|
||||||
|
using Mirror;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
public class Client : Common {
|
||||||
|
|
||||||
public class Client : Common
|
|
||||||
{
|
|
||||||
public SocketId socketId;
|
public SocketId socketId;
|
||||||
public ProductUserId serverId;
|
public ProductUserId serverId;
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ public class Client : Common
|
|||||||
private event Action<byte[], int> OnReceivedData;
|
private event Action<byte[], int> OnReceivedData;
|
||||||
private event Action OnConnected;
|
private event Action OnConnected;
|
||||||
public event Action OnDisconnected;
|
public event Action OnDisconnected;
|
||||||
|
// CHANGED
|
||||||
private Action<string> SetTransportError;
|
private Action<string> SetTransportError;
|
||||||
|
|
||||||
private TimeSpan ConnectionTimeout;
|
private TimeSpan ConnectionTimeout;
|
||||||
@ -28,11 +29,12 @@ public class Client : Common
|
|||||||
private TaskCompletionSource<Task> connectedComplete;
|
private TaskCompletionSource<Task> connectedComplete;
|
||||||
private CancellationTokenSource cancelToken;
|
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)
|
public static Client CreateClient(EosTransport transport, string host) {
|
||||||
{
|
Client c = new Client(transport);
|
||||||
var c = new Client(transport);
|
|
||||||
|
|
||||||
c.hostAddress = host;
|
c.hostAddress = host;
|
||||||
c.socketId = new SocketId() { SocketName = RandomString.Generate(20) };
|
c.socketId = new SocketId() { SocketName = RandomString.Generate(20) };
|
||||||
@ -40,17 +42,16 @@ public class Client : Common
|
|||||||
c.OnConnected += () => transport.OnClientConnected.Invoke();
|
c.OnConnected += () => transport.OnClientConnected.Invoke();
|
||||||
c.OnDisconnected += () => transport.OnClientDisconnected.Invoke();
|
c.OnDisconnected += () => transport.OnClientDisconnected.Invoke();
|
||||||
c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), channel);
|
c.OnReceivedData += (data, channel) => transport.OnClientDataReceived.Invoke(new ArraySegment<byte>(data), channel);
|
||||||
|
// CHANGED
|
||||||
c.SetTransportError = transport.SetTransportError;
|
c.SetTransportError = transport.SetTransportError;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void Connect(string host)
|
public async void Connect(string host) {
|
||||||
{
|
|
||||||
cancelToken = new CancellationTokenSource();
|
cancelToken = new CancellationTokenSource();
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
hostProductId = ProductUserId.FromString(host);
|
hostProductId = ProductUserId.FromString(host);
|
||||||
serverId = hostProductId;
|
serverId = hostProductId;
|
||||||
connectedComplete = new TaskCompletionSource<Task>();
|
connectedComplete = new TaskCompletionSource<Task>();
|
||||||
@ -61,8 +62,8 @@ public class Client : Common
|
|||||||
|
|
||||||
Task connectedCompleteTask = connectedComplete.Task;
|
Task connectedCompleteTask = connectedComplete.Task;
|
||||||
|
|
||||||
if (await Task.WhenAny(connectedCompleteTask, Task.Delay(ConnectionTimeout /*, cancelToken.Token*/)) != connectedCompleteTask)
|
if (await Task.WhenAny(connectedCompleteTask, Task.Delay(ConnectionTimeout/*, cancelToken.Token*/)) != connectedCompleteTask) {
|
||||||
{
|
// CHANGED
|
||||||
SetTransportError($"Connection to {host} timed out.");
|
SetTransportError($"Connection to {host} timed out.");
|
||||||
Debug.LogError($"Connection to {host} timed out.");
|
Debug.LogError($"Connection to {host} timed out.");
|
||||||
OnConnected -= SetConnectedComplete;
|
OnConnected -= SetConnectedComplete;
|
||||||
@ -70,40 +71,32 @@ public class Client : Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnConnected -= SetConnectedComplete;
|
OnConnected -= SetConnectedComplete;
|
||||||
}
|
} catch (FormatException) {
|
||||||
catch (FormatException)
|
// CHANGED
|
||||||
{
|
|
||||||
SetTransportError("Connection string was not in the right format. Did you enter a ProductId?");
|
SetTransportError("Connection string was not in the right format. Did you enter a ProductId?");
|
||||||
Debug.LogError($"Connection string was not in the right format. Did you enter a ProductId?");
|
Debug.LogError($"Connection string was not in the right format. Did you enter a ProductId?");
|
||||||
Error = true;
|
Error = true;
|
||||||
OnConnectionFailed(hostProductId);
|
OnConnectionFailed(hostProductId);
|
||||||
}
|
} catch (Exception ex) {
|
||||||
catch (Exception ex)
|
// CHANGED
|
||||||
{
|
|
||||||
SetTransportError(ex.Message);
|
SetTransportError(ex.Message);
|
||||||
Debug.LogError(ex.Message);
|
Debug.LogError(ex.Message);
|
||||||
Error = true;
|
Error = true;
|
||||||
OnConnectionFailed(hostProductId);
|
OnConnectionFailed(hostProductId);
|
||||||
}
|
} finally {
|
||||||
finally
|
if (Error) {
|
||||||
{
|
|
||||||
if (Error)
|
|
||||||
{
|
|
||||||
OnConnectionFailed(null);
|
OnConnectionFailed(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect()
|
public void Disconnect() {
|
||||||
{
|
if (serverId != null) {
|
||||||
if (serverId != null)
|
|
||||||
{
|
|
||||||
CloseP2PSessionWithUser(serverId, socketId);
|
CloseP2PSessionWithUser(serverId, socketId);
|
||||||
|
|
||||||
serverId = null;
|
serverId = null;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,15 +110,12 @@ public class Client : Common
|
|||||||
|
|
||||||
private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task);
|
private void SetConnectedComplete() => connectedComplete.SetResult(connectedComplete.Task);
|
||||||
|
|
||||||
protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel)
|
protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientUserId != hostProductId)
|
if (clientUserId != hostProductId) {
|
||||||
{
|
|
||||||
Debug.LogError("Received a message from an unknown");
|
Debug.LogError("Received a message from an unknown");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -133,50 +123,41 @@ public class Client : Common
|
|||||||
OnReceivedData.Invoke(data, channel);
|
OnReceivedData.Invoke(data, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewConnection(OnIncomingConnectionRequestInfo result)
|
protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deadSockets.Contains(result.SocketId.SocketName))
|
if (deadSockets.Contains(result.SocketId.SocketName)) {
|
||||||
{
|
|
||||||
Debug.LogError("Received incoming connection request from dead socket");
|
Debug.LogError("Received incoming connection request from dead socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hostProductId == result.RemoteUserId)
|
if (hostProductId == result.RemoteUserId) {
|
||||||
{
|
|
||||||
EOSSDKComponent.GetP2PInterface().AcceptConnection(
|
EOSSDKComponent.GetP2PInterface().AcceptConnection(
|
||||||
new AcceptConnectionOptions()
|
new AcceptConnectionOptions() {
|
||||||
{
|
|
||||||
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
||||||
RemoteUserId = result.RemoteUserId,
|
RemoteUserId = result.RemoteUserId,
|
||||||
SocketId = result.SocketId
|
SocketId = result.SocketId
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("P2P Acceptance Request from unknown host ID.");
|
Debug.LogError("P2P Acceptance Request from unknown host ID.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId)
|
protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type) {
|
||||||
{
|
|
||||||
case InternalMessages.ACCEPT_CONNECT:
|
case InternalMessages.ACCEPT_CONNECT:
|
||||||
Connected = true;
|
Connected = true;
|
||||||
OnConnected.Invoke();
|
OnConnected.Invoke();
|
||||||
Debug.Log("Connection established.");
|
Debug.Log("Connection established.");
|
||||||
break;
|
break;
|
||||||
case InternalMessages.DISCONNECT:
|
case InternalMessages.DISCONNECT:
|
||||||
|
// CHANGED
|
||||||
SetTransportError("host disconnected");
|
SetTransportError("host disconnected");
|
||||||
Connected = false;
|
Connected = false;
|
||||||
Debug.Log("Disconnected.");
|
Debug.Log("Disconnected.");
|
||||||
@ -189,8 +170,9 @@ public class Client : Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(byte[] data, int channelId) => Send(hostProductId, socketId, data, (byte)channelId);
|
public void Send(byte[] data, int channelId) => Send(hostProductId, socketId, data, (byte) channelId);
|
||||||
|
|
||||||
protected override void OnConnectionFailed(ProductUserId remoteId) => OnDisconnected.Invoke();
|
protected override void OnConnectionFailed(ProductUserId remoteId) => OnDisconnected.Invoke();
|
||||||
public void EosNotInitialized() => OnDisconnected.Invoke();
|
public void EosNotInitialized() => OnDisconnected.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,34 +1,32 @@
|
|||||||
using Epic.OnlineServices;
|
|
||||||
|
using Epic.OnlineServices;
|
||||||
using Epic.OnlineServices.P2P;
|
using Epic.OnlineServices.P2P;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
public abstract class Common {
|
||||||
|
|
||||||
public abstract class Common
|
|
||||||
{
|
|
||||||
private PacketReliability[] channels;
|
private PacketReliability[] channels;
|
||||||
private int internal_ch => channels.Length;
|
private int internal_ch => channels.Length;
|
||||||
|
|
||||||
protected enum InternalMessages : byte
|
protected enum InternalMessages : byte {
|
||||||
{
|
|
||||||
CONNECT,
|
CONNECT,
|
||||||
ACCEPT_CONNECT,
|
ACCEPT_CONNECT,
|
||||||
DISCONNECT
|
DISCONNECT
|
||||||
}
|
}
|
||||||
|
|
||||||
protected struct PacketKey
|
protected struct PacketKey {
|
||||||
{
|
|
||||||
public ProductUserId productUserId;
|
public ProductUserId productUserId;
|
||||||
public byte channel;
|
public byte channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnIncomingConnectionRequestCallback OnIncomingConnectionRequest;
|
private OnIncomingConnectionRequestCallback OnIncomingConnectionRequest;
|
||||||
private ulong incomingNotificationId = 0;
|
ulong incomingNotificationId = 0;
|
||||||
private OnRemoteConnectionClosedCallback OnRemoteConnectionClosed;
|
private OnRemoteConnectionClosedCallback OnRemoteConnectionClosed;
|
||||||
private ulong outgoingNotificationId = 0;
|
ulong outgoingNotificationId = 0;
|
||||||
|
|
||||||
protected readonly EosTransport transport;
|
protected readonly EosTransport transport;
|
||||||
|
|
||||||
@ -36,15 +34,14 @@ public abstract class Common
|
|||||||
public bool ignoreAllMessages = false;
|
public bool ignoreAllMessages = false;
|
||||||
|
|
||||||
// Mapping from PacketKey to a List of Packet Lists
|
// Mapping from PacketKey to a List of Packet Lists
|
||||||
protected Dictionary<PacketKey, List<List<Packet>>> incomingPackets = new();
|
protected Dictionary<PacketKey, List<List<Packet>>> incomingPackets = new Dictionary<PacketKey, List<List<Packet>>>();
|
||||||
|
|
||||||
protected Common(EosTransport transport)
|
protected Common(EosTransport transport) {
|
||||||
{
|
|
||||||
channels = transport.Channels;
|
channels = transport.Channels;
|
||||||
|
|
||||||
deadSockets = new List<string>();
|
deadSockets = new List<string>();
|
||||||
|
|
||||||
var addNotifyPeerConnectionRequestOptions = new AddNotifyPeerConnectionRequestOptions();
|
AddNotifyPeerConnectionRequestOptions addNotifyPeerConnectionRequestOptions = new AddNotifyPeerConnectionRequestOptions();
|
||||||
addNotifyPeerConnectionRequestOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
|
addNotifyPeerConnectionRequestOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
|
||||||
addNotifyPeerConnectionRequestOptions.SocketId = null;
|
addNotifyPeerConnectionRequestOptions.SocketId = null;
|
||||||
|
|
||||||
@ -54,25 +51,24 @@ public abstract class Common
|
|||||||
incomingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionRequest(addNotifyPeerConnectionRequestOptions,
|
incomingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionRequest(addNotifyPeerConnectionRequestOptions,
|
||||||
null, OnIncomingConnectionRequest);
|
null, OnIncomingConnectionRequest);
|
||||||
|
|
||||||
var addNotifyPeerConnectionClosedOptions = new AddNotifyPeerConnectionClosedOptions();
|
AddNotifyPeerConnectionClosedOptions addNotifyPeerConnectionClosedOptions = new AddNotifyPeerConnectionClosedOptions();
|
||||||
addNotifyPeerConnectionClosedOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
|
addNotifyPeerConnectionClosedOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
|
||||||
addNotifyPeerConnectionClosedOptions.SocketId = null;
|
addNotifyPeerConnectionClosedOptions.SocketId = null;
|
||||||
|
|
||||||
outgoingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionClosed(addNotifyPeerConnectionClosedOptions,
|
outgoingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionClosed(addNotifyPeerConnectionClosedOptions,
|
||||||
null, OnRemoteConnectionClosed);
|
null, OnRemoteConnectionClosed);
|
||||||
|
|
||||||
if (outgoingNotificationId == 0 || incomingNotificationId == 0)
|
if (outgoingNotificationId == 0 || incomingNotificationId == 0) {
|
||||||
{
|
|
||||||
Debug.LogError("Couldn't bind notifications with P2P interface");
|
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()
|
protected void Dispose() {
|
||||||
{
|
|
||||||
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionRequest(incomingNotificationId);
|
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionRequest(incomingNotificationId);
|
||||||
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionClosed(outgoingNotificationId);
|
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionClosed(outgoingNotificationId);
|
||||||
|
|
||||||
@ -81,17 +77,14 @@ public abstract class Common
|
|||||||
|
|
||||||
protected abstract void OnNewConnection(OnIncomingConnectionRequestInfo result);
|
protected abstract void OnNewConnection(OnIncomingConnectionRequestInfo result);
|
||||||
|
|
||||||
private void OnConnectFail(OnRemoteConnectionClosedInfo result)
|
private void OnConnectFail(OnRemoteConnectionClosedInfo result) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnConnectionFailed(result.RemoteUserId);
|
OnConnectionFailed(result.RemoteUserId);
|
||||||
|
|
||||||
switch (result.Reason)
|
switch (result.Reason) {
|
||||||
{
|
|
||||||
case ConnectionClosedReason.ClosedByLocalUser:
|
case ConnectionClosedReason.ClosedByLocalUser:
|
||||||
throw new Exception("Connection cLosed: The Connection was gracecfully closed by the local user.");
|
throw new Exception("Connection cLosed: The Connection was gracecfully closed by the local user.");
|
||||||
case ConnectionClosedReason.ClosedByPeer:
|
case ConnectionClosedReason.ClosedByPeer:
|
||||||
@ -118,13 +111,11 @@ public abstract class Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SendInternal(ProductUserId target, SocketId socketId, InternalMessages type)
|
protected void SendInternal(ProductUserId target, SocketId socketId, InternalMessages type) {
|
||||||
{
|
EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() {
|
||||||
EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions()
|
|
||||||
{
|
|
||||||
AllowDelayedDelivery = true,
|
AllowDelayedDelivery = true,
|
||||||
Channel = (byte)internal_ch,
|
Channel = (byte) internal_ch,
|
||||||
Data = new byte[] { (byte)type },
|
Data = new byte[] { (byte) type },
|
||||||
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
||||||
Reliability = PacketReliability.ReliableOrdered,
|
Reliability = PacketReliability.ReliableOrdered,
|
||||||
RemoteUserId = target,
|
RemoteUserId = target,
|
||||||
@ -132,10 +123,9 @@ public abstract class Common
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Send(ProductUserId host, SocketId socketId, byte[] msgBuffer, byte channel)
|
|
||||||
{
|
protected void Send(ProductUserId host, SocketId socketId, byte[] msgBuffer, byte channel) {
|
||||||
var result = EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions()
|
Result result = EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions() {
|
||||||
{
|
|
||||||
AllowDelayedDelivery = true,
|
AllowDelayedDelivery = true,
|
||||||
Channel = channel,
|
Channel = channel,
|
||||||
Data = msgBuffer,
|
Data = msgBuffer,
|
||||||
@ -145,23 +135,19 @@ public abstract class Common
|
|||||||
SocketId = socketId
|
SocketId = socketId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result != Result.Success)
|
if(result != Result.Success) {
|
||||||
{
|
|
||||||
Debug.LogError("Send failed " + result);
|
Debug.LogError("Send failed " + result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Receive(out ProductUserId clientProductUserId, out SocketId socketId, out byte[] receiveBuffer, byte channel)
|
private bool Receive(out ProductUserId clientProductUserId, out SocketId socketId, out byte[] receiveBuffer, byte channel) {
|
||||||
{
|
Result result = EOSSDKComponent.GetP2PInterface().ReceivePacket(new ReceivePacketOptions() {
|
||||||
var result = EOSSDKComponent.GetP2PInterface().ReceivePacket(new ReceivePacketOptions()
|
|
||||||
{
|
|
||||||
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
||||||
MaxDataSizeBytes = P2PInterface.MaxPacketSize,
|
MaxDataSizeBytes = P2PInterface.MaxPacketSize,
|
||||||
RequestedChannel = channel
|
RequestedChannel = channel
|
||||||
}, out clientProductUserId, out socketId, out channel, out receiveBuffer);
|
}, out clientProductUserId, out socketId, out channel, out receiveBuffer);
|
||||||
|
|
||||||
if (result == Result.Success)
|
if (result == Result.Success) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,160 +156,127 @@ public abstract class Common
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CloseP2PSessionWithUser(ProductUserId clientUserID, SocketId socketId)
|
protected virtual void CloseP2PSessionWithUser(ProductUserId clientUserID, SocketId socketId) {
|
||||||
{
|
if (socketId == null) {
|
||||||
if (socketId == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("Socket ID == null | " + ignoreAllMessages);
|
Debug.LogWarning("Socket ID == null | " + ignoreAllMessages);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deadSockets == null)
|
if (deadSockets == null) {
|
||||||
{
|
|
||||||
Debug.LogWarning("DeadSockets == null");
|
Debug.LogWarning("DeadSockets == null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deadSockets.Contains(socketId.SocketName))
|
if (deadSockets.Contains(socketId.SocketName)) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
deadSockets.Add(socketId.SocketName);
|
deadSockets.Add(socketId.SocketName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void WaitForClose(ProductUserId clientUserID, SocketId socketId) => transport.StartCoroutine(DelayedClose(clientUserID, socketId));
|
|
||||||
|
|
||||||
private IEnumerator DelayedClose(ProductUserId clientUserID, SocketId socketId)
|
protected void WaitForClose(ProductUserId clientUserID, SocketId socketId) => transport.StartCoroutine(DelayedClose(clientUserID, socketId));
|
||||||
{
|
private IEnumerator DelayedClose(ProductUserId clientUserID, SocketId socketId) {
|
||||||
yield return null;
|
yield return null;
|
||||||
CloseP2PSessionWithUser(clientUserID, socketId);
|
CloseP2PSessionWithUser(clientUserID, socketId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReceiveData()
|
public void ReceiveData() {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
// Internal Channel, no fragmentation here
|
// Internal Channel, no fragmentation here
|
||||||
var socketId = new SocketId();
|
SocketId socketId = new SocketId();
|
||||||
while (transport.enabled && Receive(out var clientUserID, out socketId, out var internalMessage, (byte)internal_ch))
|
while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] internalMessage, (byte) internal_ch)) {
|
||||||
{
|
if (internalMessage.Length == 1) {
|
||||||
if (internalMessage.Length == 1)
|
OnReceiveInternalData((InternalMessages) internalMessage[0], clientUserID, socketId);
|
||||||
{
|
|
||||||
OnReceiveInternalData((InternalMessages)internalMessage[0], clientUserID, socketId);
|
|
||||||
return; // Wait one frame
|
return; // Wait one frame
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Log("Incorrect package length on internal channel.");
|
Debug.Log("Incorrect package length on internal channel.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert new packet at the correct location in the incoming queue
|
// Insert new packet at the correct location in the incoming queue
|
||||||
for (var chNum = 0; chNum < channels.Length; chNum++)
|
for (int chNum = 0; chNum < channels.Length; chNum++) {
|
||||||
{
|
while (transport.enabled && Receive(out ProductUserId clientUserID, out socketId, out byte[] receiveBuffer, (byte) chNum)) {
|
||||||
while (transport.enabled && Receive(out var clientUserID, out socketId, out var receiveBuffer, (byte)chNum))
|
PacketKey incomingPacketKey = new PacketKey();
|
||||||
{
|
|
||||||
var incomingPacketKey = new PacketKey();
|
|
||||||
incomingPacketKey.productUserId = clientUserID;
|
incomingPacketKey.productUserId = clientUserID;
|
||||||
incomingPacketKey.channel = (byte)chNum;
|
incomingPacketKey.channel = (byte)chNum;
|
||||||
|
|
||||||
var packet = new Packet();
|
Packet packet = new Packet();
|
||||||
packet.FromBytes(receiveBuffer);
|
packet.FromBytes(receiveBuffer);
|
||||||
|
|
||||||
if (!incomingPackets.ContainsKey(incomingPacketKey))
|
if (!incomingPackets.ContainsKey(incomingPacketKey)) {
|
||||||
{
|
|
||||||
incomingPackets.Add(incomingPacketKey, new List<List<Packet>>());
|
incomingPackets.Add(incomingPacketKey, new List<List<Packet>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
var packetListIndex = incomingPackets[incomingPacketKey].Count;
|
int packetListIndex = incomingPackets[incomingPacketKey].Count;
|
||||||
for (var i = 0; i < incomingPackets[incomingPacketKey].Count; i++)
|
for(int i = 0; i < incomingPackets[incomingPacketKey].Count; i++) {
|
||||||
{
|
if(incomingPackets[incomingPacketKey][i][0].id == packet.id) {
|
||||||
if (incomingPackets[incomingPacketKey][i][0].id == packet.id)
|
|
||||||
{
|
|
||||||
packetListIndex = i;
|
packetListIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packetListIndex == incomingPackets[incomingPacketKey].Count)
|
if (packetListIndex == incomingPackets[incomingPacketKey].Count) {
|
||||||
{
|
|
||||||
incomingPackets[incomingPacketKey].Add(new List<Packet>());
|
incomingPackets[incomingPacketKey].Add(new List<Packet>());
|
||||||
}
|
}
|
||||||
|
|
||||||
var insertionIndex = -1;
|
int insertionIndex = -1;
|
||||||
|
|
||||||
for (var i = 0; i < incomingPackets[incomingPacketKey][packetListIndex].Count; i++)
|
for (int i = 0; i < incomingPackets[incomingPacketKey][packetListIndex].Count; i++) {
|
||||||
{
|
if (incomingPackets[incomingPacketKey][packetListIndex][i].fragment > packet.fragment) {
|
||||||
if (incomingPackets[incomingPacketKey][packetListIndex][i].fragment > packet.fragment)
|
|
||||||
{
|
|
||||||
insertionIndex = i;
|
insertionIndex = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (insertionIndex >= 0)
|
if (insertionIndex >= 0) {
|
||||||
{
|
|
||||||
incomingPackets[incomingPacketKey][packetListIndex].Insert(insertionIndex, packet);
|
incomingPackets[incomingPacketKey][packetListIndex].Insert(insertionIndex, packet);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
incomingPackets[incomingPacketKey][packetListIndex].Add(packet);
|
incomingPackets[incomingPacketKey][packetListIndex].Add(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find fully received packets
|
// Find fully received packets
|
||||||
var emptyPacketLists = new List<List<Packet>>();
|
List<List<Packet>> emptyPacketLists = new List<List<Packet>>();
|
||||||
foreach (var keyValuePair in incomingPackets)
|
foreach(KeyValuePair<PacketKey, List<List<Packet>>> keyValuePair in incomingPackets) {
|
||||||
{
|
for(int packetList = 0; packetList < keyValuePair.Value.Count; packetList++) {
|
||||||
for (var packetList = 0; packetList < keyValuePair.Value.Count; packetList++)
|
bool packetReady = true;
|
||||||
{
|
int packetLength = 0;
|
||||||
var packetReady = true;
|
for (int packet = 0; packet < keyValuePair.Value[packetList].Count; packet++) {
|
||||||
var packetLength = 0;
|
Packet tempPacket = keyValuePair.Value[packetList][packet];
|
||||||
for (var packet = 0; packet < keyValuePair.Value[packetList].Count; packet++)
|
if (tempPacket.fragment != packet || (packet == keyValuePair.Value[packetList].Count - 1 && tempPacket.moreFragments)) {
|
||||||
{
|
|
||||||
var tempPacket = keyValuePair.Value[packetList][packet];
|
|
||||||
if (tempPacket.fragment != packet || packet == keyValuePair.Value[packetList].Count - 1 && tempPacket.moreFragments)
|
|
||||||
{
|
|
||||||
packetReady = false;
|
packetReady = false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
packetLength += tempPacket.data.Length;
|
packetLength += tempPacket.data.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packetReady)
|
if (packetReady) {
|
||||||
{
|
byte[] data = new byte[packetLength];
|
||||||
var data = new byte[packetLength];
|
int dataIndex = 0;
|
||||||
var dataIndex = 0;
|
|
||||||
|
|
||||||
for (var packet = 0; packet < keyValuePair.Value[packetList].Count; packet++)
|
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);
|
Array.Copy(keyValuePair.Value[packetList][packet].data, 0, data, dataIndex, keyValuePair.Value[packetList][packet].data.Length);
|
||||||
dataIndex += keyValuePair.Value[packetList][packet].data.Length;
|
dataIndex += keyValuePair.Value[packetList][packet].data.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnReceiveData(data, keyValuePair.Key.productUserId, keyValuePair.Key.channel);
|
OnReceiveData(data, keyValuePair.Key.productUserId, keyValuePair.Key.channel);
|
||||||
|
|
||||||
//keyValuePair.Value[packetList].Clear();
|
if(transport.ServerActive() || transport.ClientActive())
|
||||||
emptyPacketLists.Add(keyValuePair.Value[packetList]);
|
emptyPacketLists.Add(keyValuePair.Value[packetList]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < emptyPacketLists.Count; i++)
|
for (int i = 0; i < emptyPacketLists.Count; i++) {
|
||||||
{
|
|
||||||
keyValuePair.Value.Remove(emptyPacketLists[i]);
|
keyValuePair.Value.Remove(emptyPacketLists[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyPacketLists.Clear();
|
emptyPacketLists.Clear();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
|
} catch (Exception e) {
|
||||||
Debug.LogException(e);
|
Debug.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,4 +284,5 @@ public abstract class Common
|
|||||||
protected abstract void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserID, SocketId socketId);
|
protected abstract void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserID, SocketId socketId);
|
||||||
protected abstract void OnReceiveData(byte[] data, ProductUserId clientUserID, int channel);
|
protected abstract void OnReceiveData(byte[] data, ProductUserId clientUserID, int channel);
|
||||||
protected abstract void OnConnectionFailed(ProductUserId remoteId);
|
protected abstract void OnConnectionFailed(ProductUserId remoteId);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,10 @@
|
|||||||
using Epic.OnlineServices;
|
using Epic.OnlineServices;
|
||||||
using Epic.OnlineServices.Logging;
|
using Epic.OnlineServices.Logging;
|
||||||
using Epic.OnlineServices.Platform;
|
using Epic.OnlineServices.Platform;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -10,39 +14,42 @@ using UnityEngine;
|
|||||||
/// after releasing the SDK the game has to be restarted in order to initialize the SDK again.
|
/// 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.
|
/// In the unity editor the OnDestroy function will not run so that we dont have to restart the editor after play.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
[DefaultExecutionOrder(-32000)]
|
||||||
|
public class EOSSDKComponent : MonoBehaviour {
|
||||||
|
|
||||||
[DefaultExecutionOrder(-32000)]
|
|
||||||
public class EOSSDKComponent : MonoBehaviour
|
|
||||||
{
|
|
||||||
// Unity Inspector shown variables
|
// Unity Inspector shown variables
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
|
// CHANGED
|
||||||
public EosApiKey apiKeys;
|
public EosApiKey apiKeys;
|
||||||
|
|
||||||
[Header("User Login")]
|
[Header("User Login")]
|
||||||
public bool authInterfaceLogin = false;
|
public bool authInterfaceLogin = false;
|
||||||
|
|
||||||
public Epic.OnlineServices.Auth.LoginCredentialType authInterfaceCredentialType = Epic.OnlineServices.Auth.LoginCredentialType.AccountPortal;
|
public Epic.OnlineServices.Auth.LoginCredentialType authInterfaceCredentialType = Epic.OnlineServices.Auth.LoginCredentialType.AccountPortal;
|
||||||
public uint devAuthToolPort = 7878;
|
public uint devAuthToolPort = 7878;
|
||||||
public string devAuthToolCredentialName = "";
|
public string devAuthToolCredentialName = "";
|
||||||
public ExternalCredentialType connectInterfaceCredentialType = ExternalCredentialType.DeviceidAccessToken;
|
public Epic.OnlineServices.ExternalCredentialType connectInterfaceCredentialType = Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken;
|
||||||
public string deviceModel = "PC Windows 64bit";
|
public string deviceModel = "PC Windows 64bit";
|
||||||
[SerializeField] private string displayName = "User";
|
[SerializeField] private string displayName = "User";
|
||||||
|
public static string DisplayName {
|
||||||
public static string DisplayName
|
get {
|
||||||
{
|
return Instance.displayName;
|
||||||
get => Instance.displayName;
|
}
|
||||||
set => Instance.displayName = value;
|
set {
|
||||||
|
Instance.displayName = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Header("Misc")]
|
[Header("Misc")]
|
||||||
public LogLevel epicLoggerLevel = LogLevel.Error;
|
public LogLevel epicLoggerLevel = LogLevel.Error;
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField] private bool collectPlayerMetrics = true;
|
||||||
private bool collectPlayerMetrics = true;
|
public static bool CollectPlayerMetrics {
|
||||||
|
get {
|
||||||
public static bool CollectPlayerMetrics => Instance.collectPlayerMetrics;
|
return Instance.collectPlayerMetrics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool checkForEpicLauncherAndRestart = false;
|
public bool checkForEpicLauncherAndRestart = false;
|
||||||
public bool delayedInitialization = false;
|
public bool delayedInitialization = false;
|
||||||
@ -54,6 +61,7 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
|
|
||||||
private ulong authExpirationHandle;
|
private ulong authExpirationHandle;
|
||||||
|
|
||||||
|
|
||||||
private string authInterfaceLoginCredentialId = null;
|
private string authInterfaceLoginCredentialId = null;
|
||||||
public static void SetAuthInterfaceLoginCredentialId(string credentialId) => Instance.authInterfaceLoginCredentialId = credentialId;
|
public static void SetAuthInterfaceLoginCredentialId(string credentialId) => Instance.authInterfaceLoginCredentialId = credentialId;
|
||||||
private string authInterfaceCredentialToken = null;
|
private string authInterfaceCredentialToken = null;
|
||||||
@ -81,43 +89,61 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
public static Epic.OnlineServices.UI.UIInterface GetUIInterface() => Instance.EOS.GetUIInterface();
|
public static Epic.OnlineServices.UI.UIInterface GetUIInterface() => Instance.EOS.GetUIInterface();
|
||||||
public static Epic.OnlineServices.UserInfo.UserInfoInterface GetUserInfoInterface() => Instance.EOS.GetUserInfoInterface();
|
public static Epic.OnlineServices.UserInfo.UserInfoInterface GetUserInfoInterface() => Instance.EOS.GetUserInfoInterface();
|
||||||
|
|
||||||
|
|
||||||
protected EpicAccountId localUserAccountId;
|
protected EpicAccountId localUserAccountId;
|
||||||
public static EpicAccountId LocalUserAccountId => Instance.localUserAccountId;
|
public static EpicAccountId LocalUserAccountId {
|
||||||
|
get {
|
||||||
|
return Instance.localUserAccountId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected string localUserAccountIdString;
|
protected string localUserAccountIdString;
|
||||||
public static string LocalUserAccountIdString => Instance.localUserAccountIdString;
|
public static string LocalUserAccountIdString {
|
||||||
|
get {
|
||||||
|
return Instance.localUserAccountIdString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected ProductUserId localUserProductId;
|
protected ProductUserId localUserProductId;
|
||||||
public static ProductUserId LocalUserProductId => Instance.localUserProductId;
|
public static ProductUserId LocalUserProductId {
|
||||||
|
get {
|
||||||
|
return Instance.localUserProductId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected string localUserProductIdString;
|
protected string localUserProductIdString;
|
||||||
public static string LocalUserProductIdString => Instance.localUserProductIdString;
|
public static string LocalUserProductIdString {
|
||||||
|
get {
|
||||||
|
return Instance.localUserProductIdString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected bool initialized;
|
protected bool initialized;
|
||||||
public static bool Initialized => Instance.initialized;
|
public static bool Initialized {
|
||||||
|
get {
|
||||||
|
return Instance.initialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected bool isConnecting;
|
protected bool isConnecting;
|
||||||
public static bool IsConnecting => Instance.isConnecting;
|
public static bool IsConnecting {
|
||||||
|
get {
|
||||||
|
return Instance.isConnecting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static EOSSDKComponent instance;
|
protected static EOSSDKComponent instance;
|
||||||
|
protected static EOSSDKComponent Instance {
|
||||||
protected static EOSSDKComponent Instance
|
get {
|
||||||
{
|
if (instance == null) {
|
||||||
get
|
|
||||||
{
|
|
||||||
if (instance == null)
|
|
||||||
{
|
|
||||||
return new GameObject("EOSSDKComponent").AddComponent<EOSSDKComponent>();
|
return new GameObject("EOSSDKComponent").AddComponent<EOSSDKComponent>();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tick()
|
public static void Tick() {
|
||||||
{
|
|
||||||
instance.platformTickTimer -= Time.deltaTime;
|
instance.platformTickTimer -= Time.deltaTime;
|
||||||
instance.EOS.Tick();
|
instance.EOS.Tick();
|
||||||
}
|
}
|
||||||
@ -163,26 +189,23 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
private IntPtr libraryPointer;
|
private IntPtr libraryPointer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private void Awake()
|
private void Awake() {
|
||||||
{
|
|
||||||
// Initialize Java version of the SDK with a reference to the VM with JNI
|
// 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
|
// 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)
|
if (Application.platform == RuntimePlatform.Android)
|
||||||
{
|
{
|
||||||
var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
||||||
var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
|
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
|
||||||
var context = activity.Call<AndroidJavaObject>("getApplicationContext");
|
AndroidJavaObject context = activity.Call<AndroidJavaObject>("getApplicationContext");
|
||||||
var EOS_SDK_JAVA = new AndroidJavaClass("com.epicgames.mobile.eossdk.EOSSDK");
|
AndroidJavaClass EOS_SDK_JAVA = new AndroidJavaClass("com.epicgames.mobile.eossdk.EOSSDK");
|
||||||
EOS_SDK_JAVA.CallStatic("init", context);
|
EOS_SDK_JAVA.CallStatic("init", context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent multiple instances
|
// Prevent multiple instances
|
||||||
if (instance != null)
|
if (instance != null) {
|
||||||
{
|
|
||||||
Destroy(gameObject);
|
Destroy(gameObject);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
@ -196,18 +219,15 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
Bindings.Hook(libraryPointer, GetProcAddress);
|
Bindings.Hook(libraryPointer, GetProcAddress);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!delayedInitialization)
|
if (!delayedInitialization) {
|
||||||
{
|
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void InitializeImplementation()
|
protected void InitializeImplementation() {
|
||||||
{
|
|
||||||
isConnecting = true;
|
isConnecting = true;
|
||||||
|
|
||||||
var initializeOptions = new InitializeOptions()
|
var initializeOptions = new InitializeOptions() {
|
||||||
{
|
|
||||||
ProductName = apiKeys.epicProductName,
|
ProductName = apiKeys.epicProductName,
|
||||||
ProductVersion = apiKeys.epicProductVersion
|
ProductVersion = apiKeys.epicProductVersion
|
||||||
};
|
};
|
||||||
@ -216,8 +236,7 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
|
|
||||||
// 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.
|
// 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;
|
var isAlreadyConfiguredInEditor = Application.isEditor && initializeResult == Result.AlreadyConfigured;
|
||||||
if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor)
|
if (initializeResult != Result.Success && !isAlreadyConfiguredInEditor) {
|
||||||
{
|
|
||||||
throw new System.Exception("Failed to initialize platform: " + initializeResult);
|
throw new System.Exception("Failed to initialize platform: " + initializeResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,13 +245,11 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
LoggingInterface.SetLogLevel(LogCategory.AllCategories, epicLoggerLevel);
|
LoggingInterface.SetLogLevel(LogCategory.AllCategories, epicLoggerLevel);
|
||||||
LoggingInterface.SetCallback(message => Logger.EpicDebugLog(message));
|
LoggingInterface.SetCallback(message => Logger.EpicDebugLog(message));
|
||||||
|
|
||||||
var options = new Options()
|
var options = new Options() {
|
||||||
{
|
|
||||||
ProductId = apiKeys.epicProductId,
|
ProductId = apiKeys.epicProductId,
|
||||||
SandboxId = apiKeys.epicSandboxId,
|
SandboxId = apiKeys.epicSandboxId,
|
||||||
DeploymentId = apiKeys.epicDeploymentId,
|
DeploymentId = apiKeys.epicDeploymentId,
|
||||||
ClientCredentials = new ClientCredentials()
|
ClientCredentials = new ClientCredentials() {
|
||||||
{
|
|
||||||
ClientId = apiKeys.epicClientId,
|
ClientId = apiKeys.epicClientId,
|
||||||
ClientSecret = apiKeys.epicClientSecret
|
ClientSecret = apiKeys.epicClientSecret
|
||||||
},
|
},
|
||||||
@ -240,21 +257,18 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
};
|
};
|
||||||
|
|
||||||
EOS = PlatformInterface.Create(options);
|
EOS = PlatformInterface.Create(options);
|
||||||
if (EOS == null)
|
if (EOS == null) {
|
||||||
{
|
|
||||||
throw new System.Exception("Failed to create platform");
|
throw new System.Exception("Failed to create platform");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkForEpicLauncherAndRestart)
|
if (checkForEpicLauncherAndRestart) {
|
||||||
{
|
Result result = EOS.CheckForLauncherAndRestart();
|
||||||
var result = EOS.CheckForLauncherAndRestart();
|
|
||||||
|
|
||||||
// If not started through epic launcher the app will be restarted and we can quit
|
// If not started through epic launcher the app will be restarted and we can quit
|
||||||
if (result != Result.NoChange)
|
if (result != Result.NoChange) {
|
||||||
{
|
|
||||||
// Log error if launcher check failed, but still quit to prevent hacking
|
// Log error if launcher check failed, but still quit to prevent hacking
|
||||||
if (result == Result.UnexpectedError)
|
if (result == Result.UnexpectedError) {
|
||||||
{
|
|
||||||
Debug.LogError("Unexpected Error while checking if app was started through epic launcher");
|
Debug.LogError("Unexpected Error while checking if app was started through epic launcher");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,19 +278,15 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
|
|
||||||
// If we use the Auth interface then only login into the Connect interface after finishing the auth interface login
|
// 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 we don't use the Auth interface we can directly login to the Connect interface
|
||||||
if (authInterfaceLogin)
|
if (authInterfaceLogin) {
|
||||||
{
|
if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer) {
|
||||||
if (authInterfaceCredentialType == Epic.OnlineServices.Auth.LoginCredentialType.Developer)
|
|
||||||
{
|
|
||||||
authInterfaceLoginCredentialId = "localhost:" + devAuthToolPort;
|
authInterfaceLoginCredentialId = "localhost:" + devAuthToolPort;
|
||||||
authInterfaceCredentialToken = devAuthToolCredentialName;
|
authInterfaceCredentialToken = devAuthToolCredentialName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login to Auth Interface
|
// Login to Auth Interface
|
||||||
var loginOptions = new Epic.OnlineServices.Auth.LoginOptions()
|
Epic.OnlineServices.Auth.LoginOptions loginOptions = new Epic.OnlineServices.Auth.LoginOptions() {
|
||||||
{
|
Credentials = new Epic.OnlineServices.Auth.Credentials() {
|
||||||
Credentials = new Epic.OnlineServices.Auth.Credentials()
|
|
||||||
{
|
|
||||||
Type = authInterfaceCredentialType,
|
Type = authInterfaceCredentialType,
|
||||||
Id = authInterfaceLoginCredentialId,
|
Id = authInterfaceLoginCredentialId,
|
||||||
Token = authInterfaceCredentialToken
|
Token = authInterfaceCredentialToken
|
||||||
@ -285,43 +295,33 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
};
|
};
|
||||||
|
|
||||||
EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin);
|
EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// Login to Connect Interface
|
// Login to Connect Interface
|
||||||
if (connectInterfaceCredentialType == ExternalCredentialType.DeviceidAccessToken)
|
if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) {
|
||||||
{
|
Epic.OnlineServices.Connect.CreateDeviceIdOptions createDeviceIdOptions = new Epic.OnlineServices.Connect.CreateDeviceIdOptions();
|
||||||
var createDeviceIdOptions = new Epic.OnlineServices.Connect.CreateDeviceIdOptions();
|
|
||||||
createDeviceIdOptions.DeviceModel = deviceModel;
|
createDeviceIdOptions.DeviceModel = deviceModel;
|
||||||
EOS.GetConnectInterface().CreateDeviceId(createDeviceIdOptions, null, OnCreateDeviceId);
|
EOS.GetConnectInterface().CreateDeviceId(createDeviceIdOptions, null, OnCreateDeviceId);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ConnectInterfaceLogin();
|
ConnectInterfaceLogin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static void Initialize()
|
}
|
||||||
{
|
public static void Initialize() {
|
||||||
if (Instance.initialized || Instance.isConnecting)
|
if (Instance.initialized || Instance.isConnecting) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance.InitializeImplementation();
|
Instance.InitializeImplementation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo)
|
private void OnAuthInterfaceLogin(Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo) {
|
||||||
{
|
if (loginCallbackInfo.ResultCode == Result.Success) {
|
||||||
if (loginCallbackInfo.ResultCode == Result.Success)
|
|
||||||
{
|
|
||||||
Debug.Log("Auth Interface Login succeeded");
|
Debug.Log("Auth Interface Login succeeded");
|
||||||
|
|
||||||
string accountIdString;
|
string accountIdString;
|
||||||
var result = loginCallbackInfo.LocalUserId.ToString(out accountIdString);
|
Result result = loginCallbackInfo.LocalUserId.ToString(out accountIdString);
|
||||||
if (Result.Success == result)
|
if (Result.Success == result) {
|
||||||
{
|
|
||||||
Debug.Log("EOS User ID:" + accountIdString);
|
Debug.Log("EOS User ID:" + accountIdString);
|
||||||
|
|
||||||
localUserAccountIdString = accountIdString;
|
localUserAccountIdString = accountIdString;
|
||||||
@ -329,45 +329,32 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConnectInterfaceLogin();
|
ConnectInterfaceLogin();
|
||||||
}
|
} else if(Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)){
|
||||||
else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode))
|
|
||||||
{
|
|
||||||
Debug.Log("Login returned " + loginCallbackInfo.ResultCode);
|
Debug.Log("Login returned " + loginCallbackInfo.ResultCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo)
|
private void OnCreateDeviceId(Epic.OnlineServices.Connect.CreateDeviceIdCallbackInfo createDeviceIdCallbackInfo) {
|
||||||
{
|
if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed) {
|
||||||
if (createDeviceIdCallbackInfo.ResultCode == Result.Success || createDeviceIdCallbackInfo.ResultCode == Result.DuplicateNotAllowed)
|
|
||||||
{
|
|
||||||
ConnectInterfaceLogin();
|
ConnectInterfaceLogin();
|
||||||
}
|
} else if(Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode)) {
|
||||||
else if (Epic.OnlineServices.Common.IsOperationComplete(createDeviceIdCallbackInfo.ResultCode))
|
|
||||||
{
|
|
||||||
Debug.Log("Device ID creation returned " + createDeviceIdCallbackInfo.ResultCode);
|
Debug.Log("Device ID creation returned " + createDeviceIdCallbackInfo.ResultCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConnectInterfaceLogin()
|
private void ConnectInterfaceLogin() {
|
||||||
{
|
|
||||||
var loginOptions = new Epic.OnlineServices.Connect.LoginOptions();
|
var loginOptions = new Epic.OnlineServices.Connect.LoginOptions();
|
||||||
|
|
||||||
if (connectInterfaceCredentialType == ExternalCredentialType.Epic)
|
if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.Epic) {
|
||||||
{
|
|
||||||
Epic.OnlineServices.Auth.Token token;
|
Epic.OnlineServices.Auth.Token token;
|
||||||
var result = EOS.GetAuthInterface().CopyUserAuthToken(new Epic.OnlineServices.Auth.CopyUserAuthTokenOptions(), localUserAccountId, out token);
|
Result result = EOS.GetAuthInterface().CopyUserAuthToken(new Epic.OnlineServices.Auth.CopyUserAuthTokenOptions(), localUserAccountId, out token);
|
||||||
|
|
||||||
if (result == Result.Success)
|
if (result == Result.Success) {
|
||||||
{
|
|
||||||
connectInterfaceCredentialToken = token.AccessToken;
|
connectInterfaceCredentialToken = token.AccessToken;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Failed to retrieve User Auth Token");
|
Debug.LogError("Failed to retrieve User Auth Token");
|
||||||
}
|
}
|
||||||
}
|
} else if (connectInterfaceCredentialType == Epic.OnlineServices.ExternalCredentialType.DeviceidAccessToken) {
|
||||||
else if (connectInterfaceCredentialType == ExternalCredentialType.DeviceidAccessToken)
|
|
||||||
{
|
|
||||||
loginOptions.UserLoginInfo = new Epic.OnlineServices.Connect.UserLoginInfo();
|
loginOptions.UserLoginInfo = new Epic.OnlineServices.Connect.UserLoginInfo();
|
||||||
loginOptions.UserLoginInfo.DisplayName = displayName;
|
loginOptions.UserLoginInfo.DisplayName = displayName;
|
||||||
}
|
}
|
||||||
@ -379,16 +366,13 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
EOS.GetConnectInterface().Login(loginOptions, null, OnConnectInterfaceLogin);
|
EOS.GetConnectInterface().Login(loginOptions, null, OnConnectInterfaceLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo)
|
private void OnConnectInterfaceLogin(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo) {
|
||||||
{
|
if (loginCallbackInfo.ResultCode == Result.Success) {
|
||||||
if (loginCallbackInfo.ResultCode == Result.Success)
|
|
||||||
{
|
|
||||||
Debug.Log("Connect Interface Login succeeded");
|
Debug.Log("Connect Interface Login succeeded");
|
||||||
|
|
||||||
string productIdString;
|
string productIdString;
|
||||||
var result = loginCallbackInfo.LocalUserId.ToString(out productIdString);
|
Result result = loginCallbackInfo.LocalUserId.ToString(out productIdString);
|
||||||
if (Result.Success == result)
|
if (Result.Success == result) {
|
||||||
{
|
|
||||||
Debug.Log("EOS User Product ID:" + productIdString);
|
Debug.Log("EOS User Product ID:" + productIdString);
|
||||||
|
|
||||||
localUserProductIdString = productIdString;
|
localUserProductIdString = productIdString;
|
||||||
@ -400,50 +384,36 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
|
|
||||||
var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions();
|
var authExpirationOptions = new Epic.OnlineServices.Connect.AddNotifyAuthExpirationOptions();
|
||||||
authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration);
|
authExpirationHandle = EOS.GetConnectInterface().AddNotifyAuthExpiration(authExpirationOptions, null, OnAuthExpiration);
|
||||||
}
|
} else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode)) {
|
||||||
else if (Epic.OnlineServices.Common.IsOperationComplete(loginCallbackInfo.ResultCode))
|
|
||||||
{
|
|
||||||
Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying...");
|
Debug.Log("Login returned " + loginCallbackInfo.ResultCode + "\nRetrying...");
|
||||||
EOS.GetConnectInterface().CreateUser(new Epic.OnlineServices.Connect.CreateUserOptions() { ContinuanceToken = loginCallbackInfo.ContinuanceToken }, null, (Epic.OnlineServices.Connect.CreateUserCallbackInfo cb) =>
|
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 (cb.ResultCode != Result.Success)
|
|
||||||
{
|
|
||||||
Debug.Log(cb.ResultCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
localUserProductId = cb.LocalUserId;
|
localUserProductId = cb.LocalUserId;
|
||||||
ConnectInterfaceLogin();
|
ConnectInterfaceLogin();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo)
|
private void OnAuthExpiration(Epic.OnlineServices.Connect.AuthExpirationCallbackInfo authExpirationCallbackInfo) {
|
||||||
{
|
|
||||||
Debug.Log("AuthExpiration callback");
|
Debug.Log("AuthExpiration callback");
|
||||||
EOS.GetConnectInterface().RemoveNotifyAuthExpiration(authExpirationHandle);
|
EOS.GetConnectInterface().RemoveNotifyAuthExpiration(authExpirationHandle);
|
||||||
ConnectInterfaceLogin();
|
ConnectInterfaceLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling tick on a regular interval is required for callbacks to work.
|
// Calling tick on a regular interval is required for callbacks to work.
|
||||||
private void LateUpdate()
|
private void LateUpdate() {
|
||||||
{
|
if (EOS != null) {
|
||||||
if (EOS != null)
|
|
||||||
{
|
|
||||||
platformTickTimer += Time.deltaTime;
|
platformTickTimer += Time.deltaTime;
|
||||||
|
|
||||||
if (platformTickTimer >= platformTickIntervalInSeconds)
|
if (platformTickTimer >= platformTickIntervalInSeconds) {
|
||||||
{
|
|
||||||
platformTickTimer = 0;
|
platformTickTimer = 0;
|
||||||
EOS.Tick();
|
EOS.Tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnApplicationQuit()
|
private void OnApplicationQuit() {
|
||||||
{
|
if (EOS != null) {
|
||||||
if (EOS != null)
|
|
||||||
{
|
|
||||||
EOS.Release();
|
EOS.Release();
|
||||||
EOS = null;
|
EOS = null;
|
||||||
PlatformInterface.Shutdown();
|
PlatformInterface.Shutdown();
|
||||||
@ -461,4 +431,5 @@ public class EOSSDKComponent : MonoBehaviour
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -8,9 +10,9 @@ using UnityEngine;
|
|||||||
/// Create -> EOS -> API Key
|
/// Create -> EOS -> API Key
|
||||||
/// in order to create an instance of this scriptable object
|
/// in order to create an instance of this scriptable object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
[CreateAssetMenu(fileName = "EosApiKey", menuName = "EOS/API Key", order = 1)]
|
[CreateAssetMenu(fileName = "EosApiKey", menuName = "EOS/API Key", order = 1)]
|
||||||
public class EosApiKey : ScriptableObject
|
public class EosApiKey : ScriptableObject {
|
||||||
{
|
|
||||||
public string epicProductName = "MyApplication";
|
public string epicProductName = "MyApplication";
|
||||||
public string epicProductVersion = "1.0";
|
public string epicProductVersion = "1.0";
|
||||||
public string epicProductId = "";
|
public string epicProductId = "";
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
using Epic.OnlineServices;
|
|
||||||
using Epic.OnlineServices.Metrics;
|
|
||||||
using Epic.OnlineServices.P2P;
|
|
||||||
using Mirror;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Epic.OnlineServices.P2P;
|
||||||
|
using Epic.OnlineServices;
|
||||||
|
using Mirror;
|
||||||
|
using Epic.OnlineServices.Metrics;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// EOS Transport following the Mirror transport standard
|
/// EOS Transport following the Mirror transport standard
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EosTransport : Transport
|
public class EosTransport : Transport {
|
||||||
{
|
|
||||||
private const string EPIC_SCHEME = "epic";
|
private const string EPIC_SCHEME = "epic";
|
||||||
|
|
||||||
private Client client;
|
private Client client;
|
||||||
@ -40,20 +41,17 @@ public class EosTransport : Transport
|
|||||||
|
|
||||||
private int packetId = 0;
|
private int packetId = 0;
|
||||||
|
|
||||||
|
// CHANGED
|
||||||
public Action<string> SetTransportError;
|
public Action<string> SetTransportError;
|
||||||
|
|
||||||
private void Awake()
|
private void Awake() {
|
||||||
{
|
|
||||||
Debug.Assert(Channels != null && Channels.Length > 0, "No channel configured for EOS Transport.");
|
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");
|
Debug.Assert(Channels.Length < byte.MaxValue, "Too many channels configured for EOS Transport");
|
||||||
|
|
||||||
if (Channels[0] != PacketReliability.ReliableOrdered)
|
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.");
|
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) {
|
||||||
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.");
|
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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,79 +59,59 @@ public class EosTransport : Transport
|
|||||||
StartCoroutine("ChangeRelayStatus");
|
StartCoroutine("ChangeRelayStatus");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientEarlyUpdate()
|
public override void ClientEarlyUpdate() {
|
||||||
{
|
|
||||||
EOSSDKComponent.Tick();
|
EOSSDKComponent.Tick();
|
||||||
|
|
||||||
if (activeNode != null)
|
if (activeNode != null) {
|
||||||
{
|
|
||||||
ignoreCachedMessagesTimer += Time.deltaTime;
|
ignoreCachedMessagesTimer += Time.deltaTime;
|
||||||
|
|
||||||
if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds)
|
if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) {
|
||||||
{
|
|
||||||
activeNode.ignoreAllMessages = true;
|
activeNode.ignoreAllMessages = true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
activeNode.ignoreAllMessages = false;
|
activeNode.ignoreAllMessages = false;
|
||||||
|
|
||||||
if (client != null && !client.isConnecting)
|
if (client != null && !client.isConnecting) {
|
||||||
{
|
if (EOSSDKComponent.Initialized) {
|
||||||
if (EOSSDKComponent.Initialized)
|
|
||||||
{
|
|
||||||
client.Connect(client.hostAddress);
|
client.Connect(client.hostAddress);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("EOS not initialized");
|
Debug.LogError("EOS not initialized");
|
||||||
client.EosNotInitialized();
|
client.EosNotInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
client.isConnecting = true;
|
client.isConnecting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled)
|
if (enabled) {
|
||||||
{
|
|
||||||
activeNode?.ReceiveData();
|
activeNode?.ReceiveData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientLateUpdate() { }
|
public override void ClientLateUpdate() {}
|
||||||
|
|
||||||
public override void ServerEarlyUpdate()
|
public override void ServerEarlyUpdate() {
|
||||||
{
|
|
||||||
EOSSDKComponent.Tick();
|
EOSSDKComponent.Tick();
|
||||||
|
|
||||||
if (activeNode != null)
|
if (activeNode != null) {
|
||||||
{
|
|
||||||
ignoreCachedMessagesTimer += Time.deltaTime;
|
ignoreCachedMessagesTimer += Time.deltaTime;
|
||||||
|
|
||||||
if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds)
|
if (ignoreCachedMessagesTimer <= ignoreCachedMessagesAtStartUpInSeconds) {
|
||||||
{
|
|
||||||
activeNode.ignoreAllMessages = true;
|
activeNode.ignoreAllMessages = true;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
activeNode.ignoreAllMessages = false;
|
activeNode.ignoreAllMessages = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled)
|
if (enabled) {
|
||||||
{
|
|
||||||
activeNode?.ReceiveData();
|
activeNode?.ReceiveData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ServerLateUpdate() { }
|
public override void ServerLateUpdate() {}
|
||||||
|
|
||||||
public override bool ClientConnected() => ClientActive() && client.Connected;
|
public override bool ClientConnected() => ClientActive() && client.Connected;
|
||||||
|
public override void ClientConnect(string address) {
|
||||||
public override void ClientConnect(string address)
|
if (!EOSSDKComponent.Initialized) {
|
||||||
{
|
|
||||||
if (!EOSSDKComponent.Initialized)
|
|
||||||
{
|
|
||||||
Debug.LogError("EOS not initialized. Client could not be started.");
|
Debug.LogError("EOS not initialized. Client could not be started.");
|
||||||
OnClientDisconnected.Invoke();
|
OnClientDisconnected.Invoke();
|
||||||
return;
|
return;
|
||||||
@ -141,119 +119,96 @@ public class EosTransport : Transport
|
|||||||
|
|
||||||
StartCoroutine("FetchEpicAccountId");
|
StartCoroutine("FetchEpicAccountId");
|
||||||
|
|
||||||
if (ServerActive())
|
if (ServerActive()) {
|
||||||
{
|
|
||||||
Debug.LogError("Transport already running as server!");
|
Debug.LogError("Transport already running as server!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ClientActive() || client.Error)
|
if (!ClientActive() || client.Error) {
|
||||||
{
|
|
||||||
Debug.Log($"Starting client, target address {address}.");
|
Debug.Log($"Starting client, target address {address}.");
|
||||||
|
|
||||||
client = Client.CreateClient(this, address);
|
client = Client.CreateClient(this, address);
|
||||||
activeNode = client;
|
activeNode = client;
|
||||||
|
|
||||||
if (EOSSDKComponent.CollectPlayerMetrics)
|
if (EOSSDKComponent.CollectPlayerMetrics) {
|
||||||
{
|
|
||||||
// Start Metrics colletion session
|
// Start Metrics colletion session
|
||||||
var sessionOptions = new BeginPlayerSessionOptions();
|
BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions();
|
||||||
sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
||||||
sessionOptions.ControllerType = UserControllerType.Unknown;
|
sessionOptions.ControllerType = UserControllerType.Unknown;
|
||||||
sessionOptions.DisplayName = EOSSDKComponent.DisplayName;
|
sessionOptions.DisplayName = EOSSDKComponent.DisplayName;
|
||||||
sessionOptions.GameSessionId = null;
|
sessionOptions.GameSessionId = null;
|
||||||
sessionOptions.ServerIp = null;
|
sessionOptions.ServerIp = null;
|
||||||
var result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions);
|
Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions);
|
||||||
|
|
||||||
if (result == Result.Success)
|
if(result == Result.Success) {
|
||||||
{
|
|
||||||
Debug.Log("Started Metric Session");
|
Debug.Log("Started Metric Session");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Client already running!");
|
Debug.LogError("Client already running!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientConnect(Uri uri)
|
public override void ClientConnect(Uri uri) {
|
||||||
{
|
|
||||||
if (uri.Scheme != EPIC_SCHEME)
|
if (uri.Scheme != EPIC_SCHEME)
|
||||||
{
|
|
||||||
throw new ArgumentException($"Invalid url {uri}, use {EPIC_SCHEME}://EpicAccountId instead", nameof(uri));
|
throw new ArgumentException($"Invalid url {uri}, use {EPIC_SCHEME}://EpicAccountId instead", nameof(uri));
|
||||||
}
|
|
||||||
|
|
||||||
ClientConnect(uri.Host);
|
ClientConnect(uri.Host);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientSend(ArraySegment<byte> segment, int channelId)
|
public override void ClientSend(ArraySegment<byte> segment, int channelId) {
|
||||||
{
|
|
||||||
Send(channelId, segment);
|
Send(channelId, segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientDisconnect()
|
public override void ClientDisconnect() {
|
||||||
{
|
if (ClientActive()) {
|
||||||
if (ClientActive())
|
|
||||||
{
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ClientActive() => client != null;
|
public bool ClientActive() => client != null;
|
||||||
|
|
||||||
public override bool ServerActive() => server != null;
|
|
||||||
|
|
||||||
public override void ServerStart()
|
public override bool ServerActive() => server != null;
|
||||||
{
|
public override void ServerStart() {
|
||||||
if (!EOSSDKComponent.Initialized)
|
if (!EOSSDKComponent.Initialized) {
|
||||||
{
|
|
||||||
Debug.LogError("EOS not initialized. Server could not be started.");
|
Debug.LogError("EOS not initialized. Server could not be started.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartCoroutine("FetchEpicAccountId");
|
StartCoroutine("FetchEpicAccountId");
|
||||||
|
|
||||||
if (ClientActive())
|
if (ClientActive()) {
|
||||||
{
|
|
||||||
Debug.LogError("Transport already running as client!");
|
Debug.LogError("Transport already running as client!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ServerActive())
|
if (!ServerActive()) {
|
||||||
{
|
|
||||||
Debug.Log("Starting server.");
|
Debug.Log("Starting server.");
|
||||||
|
|
||||||
server = Server.CreateServer(this, NetworkManager.singleton.maxConnections);
|
server = Server.CreateServer(this, NetworkManager.singleton.maxConnections);
|
||||||
activeNode = server;
|
activeNode = server;
|
||||||
|
|
||||||
if (EOSSDKComponent.CollectPlayerMetrics)
|
if (EOSSDKComponent.CollectPlayerMetrics) {
|
||||||
{
|
|
||||||
// Start Metrics colletion session
|
// Start Metrics colletion session
|
||||||
var sessionOptions = new BeginPlayerSessionOptions();
|
BeginPlayerSessionOptions sessionOptions = new BeginPlayerSessionOptions();
|
||||||
sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
sessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
||||||
sessionOptions.ControllerType = UserControllerType.Unknown;
|
sessionOptions.ControllerType = UserControllerType.Unknown;
|
||||||
sessionOptions.DisplayName = EOSSDKComponent.DisplayName;
|
sessionOptions.DisplayName = EOSSDKComponent.DisplayName;
|
||||||
sessionOptions.GameSessionId = null;
|
sessionOptions.GameSessionId = null;
|
||||||
sessionOptions.ServerIp = null;
|
sessionOptions.ServerIp = null;
|
||||||
var result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions);
|
Result result = EOSSDKComponent.GetMetricsInterface().BeginPlayerSession(sessionOptions);
|
||||||
|
|
||||||
if (result == Result.Success)
|
if (result == Result.Success) {
|
||||||
{
|
|
||||||
Debug.Log("Started Metric Session");
|
Debug.Log("Started Metric Session");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Server already started!");
|
Debug.LogError("Server already started!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Uri ServerUri()
|
public override Uri ServerUri() {
|
||||||
{
|
UriBuilder epicBuilder = new UriBuilder {
|
||||||
var epicBuilder = new UriBuilder
|
|
||||||
{
|
|
||||||
Scheme = EPIC_SCHEME,
|
Scheme = EPIC_SCHEME,
|
||||||
Host = EOSSDKComponent.LocalUserProductIdString
|
Host = EOSSDKComponent.LocalUserProductIdString
|
||||||
};
|
};
|
||||||
@ -261,37 +216,32 @@ public class EosTransport : Transport
|
|||||||
return epicBuilder.Uri;
|
return epicBuilder.Uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId)
|
public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId) {
|
||||||
{
|
if (ServerActive()) {
|
||||||
if (ServerActive())
|
Send( channelId, segment, connectionId);
|
||||||
{
|
|
||||||
Send(channelId, segment, connectionId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ServerDisconnect(int connectionId) => server.Disconnect(connectionId);
|
public override void ServerDisconnect(int connectionId) => server.Disconnect(connectionId);
|
||||||
public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty;
|
public override string ServerGetClientAddress(int connectionId) => ServerActive() ? server.ServerGetClientAddress(connectionId) : string.Empty;
|
||||||
|
public override void ServerStop() {
|
||||||
public override void ServerStop()
|
if (ServerActive()) {
|
||||||
{
|
|
||||||
if (ServerActive())
|
|
||||||
{
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Send(int channelId, ArraySegment<byte> segment, int connectionId = int.MinValue)
|
private void Send(int channelId, ArraySegment<byte> segment, int connectionId = int.MinValue) {
|
||||||
{
|
Packet[] packets = GetPacketArray(channelId, segment);
|
||||||
var packets = GetPacketArray(channelId, segment);
|
|
||||||
|
|
||||||
for (var i = 0; i < packets.Length; i++)
|
for(int i = 0; i < packets.Length; i++) {
|
||||||
|
if (connectionId == int.MinValue) {
|
||||||
|
if (client == null)
|
||||||
{
|
{
|
||||||
if (connectionId == int.MinValue)
|
OnClientDisconnected.Invoke();
|
||||||
{
|
return;
|
||||||
client.Send(packets[i].ToBytes(), channelId);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
client.Send(packets[i].ToBytes(), channelId);
|
||||||
|
} else {
|
||||||
server.SendAll(connectionId, packets[i].ToBytes(), channelId);
|
server.SendAll(connectionId, packets[i].ToBytes(), channelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,19 +249,17 @@ public class EosTransport : Transport
|
|||||||
packetId++;
|
packetId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Packet[] GetPacketArray(int channelId, ArraySegment<byte> segment)
|
private Packet[] GetPacketArray(int channelId, ArraySegment<byte> segment) {
|
||||||
{
|
int packetCount = Mathf.CeilToInt((float) segment.Count / (float)GetMaxSinglePacketSize(channelId));
|
||||||
var packetCount = Mathf.CeilToInt((float)segment.Count / (float)GetMaxSinglePacketSize(channelId));
|
Packet[] packets = new Packet[packetCount];
|
||||||
var packets = new Packet[packetCount];
|
|
||||||
|
|
||||||
for (var i = 0; i < segment.Count; i += GetMaxSinglePacketSize(channelId))
|
for (int i = 0; i < segment.Count; i += GetMaxSinglePacketSize(channelId)) {
|
||||||
{
|
int fragment = i / GetMaxSinglePacketSize(channelId);
|
||||||
var fragment = i / GetMaxSinglePacketSize(channelId);
|
|
||||||
|
|
||||||
packets[fragment] = new Packet();
|
packets[fragment] = new Packet();
|
||||||
packets[fragment].id = packetId;
|
packets[fragment].id = packetId;
|
||||||
packets[fragment].fragment = fragment;
|
packets[fragment].fragment = fragment;
|
||||||
packets[fragment].moreFragments = segment.Count - i > GetMaxSinglePacketSize(channelId);
|
packets[fragment].moreFragments = (segment.Count - i) > GetMaxSinglePacketSize(channelId);
|
||||||
packets[fragment].data = new byte[segment.Count - i > GetMaxSinglePacketSize(channelId) ? GetMaxSinglePacketSize(channelId) : segment.Count - i];
|
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);
|
Array.Copy(segment.Array, i, packets[fragment].data, 0, packets[fragment].data.Length);
|
||||||
}
|
}
|
||||||
@ -319,17 +267,14 @@ public class EosTransport : Transport
|
|||||||
return packets;
|
return packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown() {
|
||||||
{
|
if (EOSSDKComponent.CollectPlayerMetrics) {
|
||||||
if (EOSSDKComponent.CollectPlayerMetrics)
|
|
||||||
{
|
|
||||||
// Stop Metrics collection session
|
// Stop Metrics collection session
|
||||||
var endSessionOptions = new EndPlayerSessionOptions();
|
EndPlayerSessionOptions endSessionOptions = new EndPlayerSessionOptions();
|
||||||
endSessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
endSessionOptions.AccountId = EOSSDKComponent.LocalUserAccountId;
|
||||||
var result = EOSSDKComponent.GetMetricsInterface().EndPlayerSession(endSessionOptions);
|
Result result = EOSSDKComponent.GetMetricsInterface().EndPlayerSession(endSessionOptions);
|
||||||
|
|
||||||
if (result == Result.Success)
|
if (result == Result.Success) {
|
||||||
{
|
|
||||||
Debug.LogError("Stopped Metric Session");
|
Debug.LogError("Stopped Metric Session");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -349,51 +294,41 @@ public class EosTransport : Transport
|
|||||||
|
|
||||||
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 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()
|
public override bool Available() {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
return EOSSDKComponent.Initialized;
|
return EOSSDKComponent.Initialized;
|
||||||
}
|
} catch {
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator FetchEpicAccountId()
|
private IEnumerator FetchEpicAccountId() {
|
||||||
{
|
while (!EOSSDKComponent.Initialized) {
|
||||||
while (!EOSSDKComponent.Initialized)
|
|
||||||
{
|
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
productUserId = EOSSDKComponent.LocalUserProductId;
|
productUserId = EOSSDKComponent.LocalUserProductId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator ChangeRelayStatus()
|
private IEnumerator ChangeRelayStatus() {
|
||||||
{
|
while (!EOSSDKComponent.Initialized) {
|
||||||
while (!EOSSDKComponent.Initialized)
|
|
||||||
{
|
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var setRelayControlOptions = new SetRelayControlOptions();
|
SetRelayControlOptions setRelayControlOptions = new SetRelayControlOptions();
|
||||||
setRelayControlOptions.RelayControl = relayControl;
|
setRelayControlOptions.RelayControl = relayControl;
|
||||||
|
|
||||||
EOSSDKComponent.GetP2PInterface().SetRelayControl(setRelayControlOptions);
|
EOSSDKComponent.GetP2PInterface().SetRelayControl(setRelayControlOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetIgnoreMessagesAtStartUpTimer()
|
public void ResetIgnoreMessagesAtStartUpTimer() {
|
||||||
{
|
|
||||||
ignoreCachedMessagesTimer = 0;
|
ignoreCachedMessagesTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDestroy()
|
private void OnDestroy() {
|
||||||
{
|
if (activeNode != null) {
|
||||||
if (activeNode != null)
|
|
||||||
{
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,15 +1,14 @@
|
|||||||
using Epic.OnlineServices.Logging;
|
using Epic.OnlineServices.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
public static class Logger {
|
||||||
|
|
||||||
public static class Logger
|
public static void EpicDebugLog(LogMessage message) {
|
||||||
{
|
switch (message.Level) {
|
||||||
public static void EpicDebugLog(LogMessage message)
|
|
||||||
{
|
|
||||||
switch (message.Level)
|
|
||||||
{
|
|
||||||
case LogLevel.Info:
|
case LogLevel.Info:
|
||||||
Debug.Log($"Epic Manager: Category - {message.Category} Message - {message.Message}");
|
Debug.Log($"Epic Manager: Category - {message.Category} Message - {message.Message}");
|
||||||
break;
|
break;
|
||||||
@ -27,4 +26,5 @@ public static class Logger
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
public struct Packet {
|
||||||
public struct Packet
|
|
||||||
{
|
|
||||||
public const int headerSize = sizeof(uint) + sizeof(uint) + 1;
|
public const int headerSize = sizeof(uint) + sizeof(uint) + 1;
|
||||||
public int size => headerSize + data.Length;
|
public int size => headerSize + data.Length;
|
||||||
|
|
||||||
@ -15,21 +13,20 @@ public struct Packet
|
|||||||
// body
|
// body
|
||||||
public byte[] data;
|
public byte[] data;
|
||||||
|
|
||||||
public byte[] ToBytes()
|
public byte[] ToBytes() {
|
||||||
{
|
byte[] array = new byte[size];
|
||||||
var array = new byte[size];
|
|
||||||
|
|
||||||
// Copy id
|
// Copy id
|
||||||
array[0] = (byte)id;
|
array[0] = (byte) id;
|
||||||
array[1] = (byte)(id >> 8);
|
array[1] = (byte) (id >> 8);
|
||||||
array[2] = (byte)(id >> 0x10);
|
array[2] = (byte) (id >> 0x10);
|
||||||
array[3] = (byte)(id >> 0x18);
|
array[3] = (byte) (id >> 0x18);
|
||||||
|
|
||||||
// Copy fragment
|
// Copy fragment
|
||||||
array[4] = (byte)fragment;
|
array[4] = (byte) fragment;
|
||||||
array[5] = (byte)(fragment >> 8);
|
array[5] = (byte) (fragment >> 8);
|
||||||
array[6] = (byte)(fragment >> 0x10);
|
array[6] = (byte) (fragment >> 0x10);
|
||||||
array[7] = (byte)(fragment >> 0x18);
|
array[7] = (byte) (fragment >> 0x18);
|
||||||
|
|
||||||
array[8] = moreFragments ? (byte)1 : (byte)0;
|
array[8] = moreFragments ? (byte)1 : (byte)0;
|
||||||
|
|
||||||
@ -38,8 +35,7 @@ public struct Packet
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FromBytes(byte[] array)
|
public void FromBytes(byte[] array) {
|
||||||
{
|
|
||||||
id = BitConverter.ToInt32(array, 0);
|
id = BitConverter.ToInt32(array, 0);
|
||||||
fragment = BitConverter.ToInt32(array, 4);
|
fragment = BitConverter.ToInt32(array, 4);
|
||||||
moreFragments = array[8] == 1;
|
moreFragments = array[8] == 1;
|
||||||
@ -47,4 +43,5 @@ public struct Packet
|
|||||||
data = new byte[array.Length - 9];
|
data = new byte[array.Length - 9];
|
||||||
Array.Copy(array, 9, data, 0, data.Length);
|
Array.Copy(array, 9, data, 0, data.Length);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,14 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
public class RandomString
|
public class RandomString {
|
||||||
{
|
|
||||||
// Generates a random string with a given size.
|
// Generates a random string with a given size.
|
||||||
public static string Generate(int size)
|
public static string Generate(int size) {
|
||||||
{
|
|
||||||
var builder = new StringBuilder(size);
|
var builder = new StringBuilder(size);
|
||||||
|
|
||||||
var random = new Random();
|
Random random = new Random();
|
||||||
|
|
||||||
// Unicode/ASCII Letters are divided into two blocks
|
// Unicode/ASCII Letters are divided into two blocks
|
||||||
// (Letters 65–90 / 97–122):
|
// (Letters 65–90 / 97–122):
|
||||||
@ -16,23 +15,19 @@ public class RandomString
|
|||||||
// the second group containing the lowercase.
|
// the second group containing the lowercase.
|
||||||
|
|
||||||
// char is a single Unicode character
|
// char is a single Unicode character
|
||||||
var offsetLowerCase = 'a';
|
char offsetLowerCase = 'a';
|
||||||
var offsetUpperCase = 'A';
|
char offsetUpperCase = 'A';
|
||||||
const int lettersOffset = 26; // A...Z or a..z: length=26
|
const int lettersOffset = 26; // A...Z or a..z: length=26
|
||||||
|
|
||||||
for (var i = 0; i < size; i++)
|
for (var i = 0; i < size; i++) {
|
||||||
{
|
|
||||||
char offset;
|
char offset;
|
||||||
if (random.Next(0, 2) == 0)
|
if(random.Next(0,2) == 0) {
|
||||||
{
|
|
||||||
offset = offsetLowerCase;
|
offset = offsetLowerCase;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = offsetUpperCase;
|
offset = offsetUpperCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
var @char = (char)random.Next(offset, offset + lettersOffset);
|
var @char = (char) random.Next(offset, offset + lettersOffset);
|
||||||
builder.Append(@char);
|
builder.Append(@char);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,8 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace EpicTransport;
|
namespace EpicTransport {
|
||||||
|
public class Server : Common {
|
||||||
public class Server : Common
|
|
||||||
{
|
|
||||||
private event Action<int> OnConnected;
|
private event Action<int> OnConnected;
|
||||||
private event Action<int, byte[], int> OnReceivedData;
|
private event Action<int, byte[], int> OnReceivedData;
|
||||||
private event Action<int> OnDisconnected;
|
private event Action<int> OnDisconnected;
|
||||||
@ -18,65 +16,55 @@ public class Server : Common
|
|||||||
private int maxConnections;
|
private int maxConnections;
|
||||||
private int nextConnectionID;
|
private int nextConnectionID;
|
||||||
|
|
||||||
public static Server CreateServer(EosTransport transport, int maxConnections)
|
public static Server CreateServer(EosTransport transport, int maxConnections) {
|
||||||
{
|
Server s = new Server(transport, maxConnections);
|
||||||
var s = new Server(transport, maxConnections);
|
|
||||||
|
|
||||||
s.OnConnected += (id) => transport.OnServerConnected.Invoke(id);
|
s.OnConnected += (id) => transport.OnServerConnected.Invoke(id);
|
||||||
s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id);
|
s.OnDisconnected += (id) => transport.OnServerDisconnected.Invoke(id);
|
||||||
s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), channel);
|
s.OnReceivedData += (id, data, channel) => transport.OnServerDataReceived.Invoke(id, new ArraySegment<byte>(data), channel);
|
||||||
s.OnReceivedError += (id, exception) => transport.OnServerError.Invoke(id, exception);
|
// CHANGED
|
||||||
|
s.OnReceivedError += (id, exception) => transport.OnServerError?.Invoke(id, Mirror.TransportError.Unexpected, exception.ToString());
|
||||||
|
|
||||||
if (!EOSSDKComponent.Initialized)
|
if (!EOSSDKComponent.Initialized) {
|
||||||
{
|
|
||||||
Debug.LogError("EOS not initialized.");
|
Debug.LogError("EOS not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Server(EosTransport transport, int maxConnections) : base(transport)
|
private Server(EosTransport transport, int maxConnections) : base(transport) {
|
||||||
{
|
|
||||||
this.maxConnections = maxConnections;
|
this.maxConnections = maxConnections;
|
||||||
epicToMirrorIds = new BidirectionalDictionary<ProductUserId, int>();
|
epicToMirrorIds = new BidirectionalDictionary<ProductUserId, int>();
|
||||||
epicToSocketIds = new Dictionary<ProductUserId, SocketId>();
|
epicToSocketIds = new Dictionary<ProductUserId, SocketId>();
|
||||||
nextConnectionID = 1;
|
nextConnectionID = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNewConnection(OnIncomingConnectionRequestInfo result)
|
protected override void OnNewConnection(OnIncomingConnectionRequestInfo result) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deadSockets.Contains(result.SocketId.SocketName))
|
if (deadSockets.Contains(result.SocketId.SocketName)) {
|
||||||
{
|
|
||||||
Debug.LogError("Received incoming connection request from dead socket");
|
Debug.LogError("Received incoming connection request from dead socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EOSSDKComponent.GetP2PInterface().AcceptConnection(
|
EOSSDKComponent.GetP2PInterface().AcceptConnection(
|
||||||
new AcceptConnectionOptions()
|
new AcceptConnectionOptions() {
|
||||||
{
|
|
||||||
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
LocalUserId = EOSSDKComponent.LocalUserProductId,
|
||||||
RemoteUserId = result.RemoteUserId,
|
RemoteUserId = result.RemoteUserId,
|
||||||
SocketId = result.SocketId
|
SocketId = result.SocketId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId)
|
protected override void OnReceiveInternalData(InternalMessages type, ProductUserId clientUserId, SocketId socketId) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type) {
|
||||||
{
|
|
||||||
case InternalMessages.CONNECT:
|
case InternalMessages.CONNECT:
|
||||||
if (epicToMirrorIds.Count >= maxConnections)
|
if (epicToMirrorIds.Count >= maxConnections) {
|
||||||
{
|
|
||||||
Debug.LogError("Reached max connections");
|
Debug.LogError("Reached max connections");
|
||||||
//CloseP2PSessionWithUser(clientUserId, socketId);
|
//CloseP2PSessionWithUser(clientUserId, socketId);
|
||||||
SendInternal(clientUserId, socketId, InternalMessages.DISCONNECT);
|
SendInternal(clientUserId, socketId, InternalMessages.DISCONNECT);
|
||||||
@ -85,7 +73,7 @@ public class Server : Common
|
|||||||
|
|
||||||
SendInternal(clientUserId, socketId, InternalMessages.ACCEPT_CONNECT);
|
SendInternal(clientUserId, socketId, InternalMessages.ACCEPT_CONNECT);
|
||||||
|
|
||||||
var connectionId = nextConnectionID++;
|
int connectionId = nextConnectionID++;
|
||||||
epicToMirrorIds.Add(clientUserId, connectionId);
|
epicToMirrorIds.Add(clientUserId, connectionId);
|
||||||
epicToSocketIds.Add(clientUserId, socketId);
|
epicToSocketIds.Add(clientUserId, socketId);
|
||||||
OnConnected.Invoke(connectionId);
|
OnConnected.Invoke(connectionId);
|
||||||
@ -95,16 +83,13 @@ public class Server : Common
|
|||||||
Debug.Log($"Client with Product User ID {clientUserIdString} connected. Assigning connection id {connectionId}");
|
Debug.Log($"Client with Product User ID {clientUserIdString} connected. Assigning connection id {connectionId}");
|
||||||
break;
|
break;
|
||||||
case InternalMessages.DISCONNECT:
|
case InternalMessages.DISCONNECT:
|
||||||
if (epicToMirrorIds.TryGetValue(clientUserId, out var connId))
|
if (epicToMirrorIds.TryGetValue(clientUserId, out int connId)) {
|
||||||
{
|
|
||||||
OnDisconnected.Invoke(connId);
|
OnDisconnected.Invoke(connId);
|
||||||
//CloseP2PSessionWithUser(clientUserId, socketId);
|
//CloseP2PSessionWithUser(clientUserId, socketId);
|
||||||
epicToMirrorIds.Remove(clientUserId);
|
epicToMirrorIds.Remove(clientUserId);
|
||||||
epicToSocketIds.Remove(clientUserId);
|
epicToSocketIds.Remove(clientUserId);
|
||||||
Debug.Log($"Client with Product User ID {clientUserId} disconnected.");
|
Debug.Log($"Client with Product User ID {clientUserId} disconnected.");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
OnReceivedError.Invoke(-1, new Exception("ERROR Unknown Product User ID"));
|
OnReceivedError.Invoke(-1, new Exception("ERROR Unknown Product User ID"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,19 +100,14 @@ public class Server : Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel)
|
protected override void OnReceiveData(byte[] data, ProductUserId clientUserId, int channel) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (epicToMirrorIds.TryGetValue(clientUserId, out var connectionId))
|
if (epicToMirrorIds.TryGetValue(clientUserId, out int connectionId)) {
|
||||||
{
|
|
||||||
OnReceivedData.Invoke(connectionId, data, channel);
|
OnReceivedData.Invoke(connectionId, data, channel);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
SocketId socketId;
|
SocketId socketId;
|
||||||
epicToSocketIds.TryGetValue(clientUserId, out socketId);
|
epicToSocketIds.TryGetValue(clientUserId, out socketId);
|
||||||
CloseP2PSessionWithUser(clientUserId, socketId);
|
CloseP2PSessionWithUser(clientUserId, socketId);
|
||||||
@ -140,26 +120,20 @@ public class Server : Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(int connectionId)
|
public void Disconnect(int connectionId) {
|
||||||
{
|
if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) {
|
||||||
if (epicToMirrorIds.TryGetValue(connectionId, out var userId))
|
|
||||||
{
|
|
||||||
SocketId socketId;
|
SocketId socketId;
|
||||||
epicToSocketIds.TryGetValue(userId, out socketId);
|
epicToSocketIds.TryGetValue(userId, out socketId);
|
||||||
SendInternal(userId, socketId, InternalMessages.DISCONNECT);
|
SendInternal(userId, socketId, InternalMessages.DISCONNECT);
|
||||||
epicToMirrorIds.Remove(userId);
|
epicToMirrorIds.Remove(userId);
|
||||||
epicToSocketIds.Remove(userId);
|
epicToSocketIds.Remove(userId);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId);
|
Debug.LogWarning("Trying to disconnect unknown connection id: " + connectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shutdown()
|
public void Shutdown() {
|
||||||
{
|
foreach (KeyValuePair<ProductUserId, int> client in epicToMirrorIds) {
|
||||||
foreach (KeyValuePair<ProductUserId, int> client in epicToMirrorIds)
|
|
||||||
{
|
|
||||||
Disconnect(client.Value);
|
Disconnect(client.Value);
|
||||||
SocketId socketId;
|
SocketId socketId;
|
||||||
epicToSocketIds.TryGetValue(client.Key, out socketId);
|
epicToSocketIds.TryGetValue(client.Key, out socketId);
|
||||||
@ -172,49 +146,41 @@ public class Server : Common
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAll(int connectionId, byte[] data, int channelId)
|
public void SendAll(int connectionId, byte[] data, int channelId) {
|
||||||
{
|
if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) {
|
||||||
if (epicToMirrorIds.TryGetValue(connectionId, out var userId))
|
|
||||||
{
|
|
||||||
SocketId socketId;
|
SocketId socketId;
|
||||||
epicToSocketIds.TryGetValue(userId, out socketId);
|
epicToSocketIds.TryGetValue(userId, out socketId);
|
||||||
Send(userId, socketId, data, (byte)channelId);
|
Send(userId, socketId, data, (byte)channelId);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Trying to send on unknown connection: " + connectionId);
|
Debug.LogError("Trying to send on unknown connection: " + connectionId);
|
||||||
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
|
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ServerGetClientAddress(int connectionId)
|
public string ServerGetClientAddress(int connectionId) {
|
||||||
{
|
if (epicToMirrorIds.TryGetValue(connectionId, out ProductUserId userId)) {
|
||||||
if (epicToMirrorIds.TryGetValue(connectionId, out var userId))
|
|
||||||
{
|
|
||||||
string userIdString;
|
string userIdString;
|
||||||
userId.ToString(out userIdString);
|
userId.ToString(out userIdString);
|
||||||
return userIdString;
|
return userIdString;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Trying to get info on unknown connection: " + connectionId);
|
Debug.LogError("Trying to get info on unknown connection: " + connectionId);
|
||||||
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
|
OnReceivedError.Invoke(connectionId, new Exception("ERROR Unknown Connection"));
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConnectionFailed(ProductUserId remoteId)
|
protected override void OnConnectionFailed(ProductUserId remoteId) {
|
||||||
{
|
if (ignoreAllMessages) {
|
||||||
if (ignoreAllMessages)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var connectionId = epicToMirrorIds.TryGetValue(remoteId, out var connId) ? connId : nextConnectionID++;
|
int connectionId = epicToMirrorIds.TryGetValue(remoteId, out int connId) ? connId : nextConnectionID++;
|
||||||
OnDisconnected.Invoke(connectionId);
|
OnDisconnected.Invoke(connectionId);
|
||||||
|
|
||||||
Debug.LogError("Connection Failed, removing user");
|
Debug.LogError("Connection Failed, removing user");
|
||||||
epicToMirrorIds.Remove(remoteId);
|
epicToMirrorIds.Remove(remoteId);
|
||||||
epicToSocketIds.Remove(remoteId);
|
epicToSocketIds.Remove(remoteId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Binary file not shown.
BIN
Mirror/Mirror.Transports.dll
Normal file
BIN
Mirror/Mirror.Transports.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Mirror/kcp2k.dll
BIN
Mirror/kcp2k.dll
Binary file not shown.
Binary file not shown.
@ -12,8 +12,18 @@ namespace Mirror.Weaver
|
|||||||
? td.GetElementType().FullName == type.FullName
|
? td.GetElementType().FullName == type.FullName
|
||||||
: td.FullName == type.FullName;
|
: td.FullName == type.FullName;
|
||||||
|
|
||||||
|
// check if 'td' is exactly of type T.
|
||||||
|
// it does not check if any base type is of <T>, only the specific type.
|
||||||
|
// for example:
|
||||||
|
// NetworkConnection Is NetworkConnection: true
|
||||||
|
// NetworkConnectionToClient Is NetworkConnection: false
|
||||||
public static bool Is<T>(this TypeReference td) => Is(td, typeof(T));
|
public static bool Is<T>(this TypeReference td) => Is(td, typeof(T));
|
||||||
|
|
||||||
|
// check if 'tr' is derived from T.
|
||||||
|
// it does not check if 'tr' is exactly T.
|
||||||
|
// for example:
|
||||||
|
// NetworkConnection IsDerivedFrom<NetworkConnection>: false
|
||||||
|
// NetworkConnectionToClient IsDerivedFrom<NetworkConnection>: true
|
||||||
public static bool IsDerivedFrom<T>(this TypeReference tr) => IsDerivedFrom(tr, typeof(T));
|
public static bool IsDerivedFrom<T>(this TypeReference tr) => IsDerivedFrom(tr, typeof(T));
|
||||||
|
|
||||||
public static bool IsDerivedFrom(this TypeReference tr, Type baseClass)
|
public static bool IsDerivedFrom(this TypeReference tr, Type baseClass)
|
||||||
@ -79,7 +89,10 @@ namespace Mirror.Weaver
|
|||||||
public static bool IsNetworkIdentityField(this TypeReference tr) =>
|
public static bool IsNetworkIdentityField(this TypeReference tr) =>
|
||||||
tr.Is<UnityEngine.GameObject>() ||
|
tr.Is<UnityEngine.GameObject>() ||
|
||||||
tr.Is<NetworkIdentity>() ||
|
tr.Is<NetworkIdentity>() ||
|
||||||
tr.IsDerivedFrom<NetworkBehaviour>();
|
// handle both NetworkBehaviour and inheritors.
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
|
tr.IsDerivedFrom<NetworkBehaviour>() ||
|
||||||
|
tr.Is<NetworkBehaviour>();
|
||||||
|
|
||||||
public static bool CanBeResolved(this TypeReference parent)
|
public static bool CanBeResolved(this TypeReference parent)
|
||||||
{
|
{
|
||||||
|
@ -10,10 +10,11 @@ namespace Mirror.Weaver
|
|||||||
// generates code like:
|
// generates code like:
|
||||||
public void CmdThrust(float thrusting, int spin)
|
public void CmdThrust(float thrusting, int spin)
|
||||||
{
|
{
|
||||||
NetworkWriter networkWriter = new NetworkWriter();
|
NetworkWriterPooled writer = NetworkWriterPool.Get();
|
||||||
networkWriter.Write(thrusting);
|
writer.Write(thrusting);
|
||||||
networkWriter.WritePackedUInt32((uint)spin);
|
writer.WritePackedUInt32((uint)spin);
|
||||||
base.SendCommandInternal(cmdName, networkWriter, channel);
|
base.SendCommandInternal(cmdName, cmdHash, writer, channel);
|
||||||
|
NetworkWriterPool.Return(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CallCmdThrust(float thrusting, int spin)
|
public void CallCmdThrust(float thrusting, int spin)
|
||||||
@ -38,7 +39,7 @@ namespace Mirror.Weaver
|
|||||||
NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);
|
||||||
|
|
||||||
// NetworkWriter writer = new NetworkWriter();
|
// NetworkWriter writer = new NetworkWriter();
|
||||||
NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes);
|
||||||
|
|
||||||
// write all the arguments that the user passed to the Cmd call
|
// write all the arguments that the user passed to the Cmd call
|
||||||
if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.Command, ref WeavingFailed))
|
if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.Command, ref WeavingFailed))
|
||||||
@ -52,6 +53,11 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Ldarg_0);
|
worker.Emit(OpCodes.Ldarg_0);
|
||||||
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
||||||
worker.Emit(OpCodes.Ldstr, md.FullName);
|
worker.Emit(OpCodes.Ldstr, md.FullName);
|
||||||
|
// pass the function hash so we don't have to compute it at runtime
|
||||||
|
// otherwise each GetStableHash call requires O(N) complexity.
|
||||||
|
// noticeable for long function names:
|
||||||
|
// https://github.com/MirrorNetworking/Mirror/issues/3375
|
||||||
|
worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode());
|
||||||
// writer
|
// writer
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
worker.Emit(OpCodes.Ldloc_0);
|
||||||
worker.Emit(OpCodes.Ldc_I4, channel);
|
worker.Emit(OpCodes.Ldc_I4, channel);
|
||||||
@ -59,7 +65,7 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
worker.Emit(requiresAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.sendCommandInternal);
|
worker.Emit(OpCodes.Call, weaverTypes.sendCommandInternal);
|
||||||
|
|
||||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes);
|
||||||
|
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
return cmd;
|
return cmd;
|
||||||
|
@ -137,21 +137,21 @@ namespace Mirror.Weaver
|
|||||||
public static void WriteSetupLocals(ILProcessor worker, WeaverTypes weaverTypes)
|
public static void WriteSetupLocals(ILProcessor worker, WeaverTypes weaverTypes)
|
||||||
{
|
{
|
||||||
worker.Body.InitLocals = true;
|
worker.Body.InitLocals = true;
|
||||||
worker.Body.Variables.Add(new VariableDefinition(weaverTypes.Import<PooledNetworkWriter>()));
|
worker.Body.Variables.Add(new VariableDefinition(weaverTypes.Import<NetworkWriterPooled>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteCreateWriter(ILProcessor worker, WeaverTypes weaverTypes)
|
public static void WriteGetWriter(ILProcessor worker, WeaverTypes weaverTypes)
|
||||||
{
|
{
|
||||||
// create writer
|
// create writer
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.GetPooledWriterReference);
|
worker.Emit(OpCodes.Call, weaverTypes.GetWriterReference);
|
||||||
worker.Emit(OpCodes.Stloc_0);
|
worker.Emit(OpCodes.Stloc_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteRecycleWriter(ILProcessor worker, WeaverTypes weaverTypes)
|
public static void WriteReturnWriter(ILProcessor worker, WeaverTypes weaverTypes)
|
||||||
{
|
{
|
||||||
// NetworkWriterPool.Recycle(writer);
|
// NetworkWriterPool.Recycle(writer);
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
worker.Emit(OpCodes.Ldloc_0);
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.RecycleWriterReference);
|
worker.Emit(OpCodes.Call, weaverTypes.ReturnWriterReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Log, MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed)
|
public static bool WriteArguments(ILProcessor worker, Writers writers, Logger Log, MethodDefinition method, RemoteCallType callType, ref bool WeavingFailed)
|
||||||
@ -397,7 +397,7 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
MethodDefinition serialize = new MethodDefinition(SerializeMethodName,
|
MethodDefinition serialize = new MethodDefinition(SerializeMethodName,
|
||||||
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
|
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig,
|
||||||
weaverTypes.Import<bool>());
|
weaverTypes.Import(typeof(void)));
|
||||||
|
|
||||||
serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import<NetworkWriter>()));
|
serialize.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, weaverTypes.Import<NetworkWriter>()));
|
||||||
serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, weaverTypes.Import<bool>()));
|
serialize.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, weaverTypes.Import<bool>()));
|
||||||
@ -405,10 +405,7 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
serialize.Body.InitLocals = true;
|
serialize.Body.InitLocals = true;
|
||||||
|
|
||||||
// loc_0, this local variable is to determine if any variable was dirty
|
// base.SerializeSyncVars(writer, forceAll);
|
||||||
VariableDefinition dirtyLocal = new VariableDefinition(weaverTypes.Import<bool>());
|
|
||||||
serialize.Body.Variables.Add(dirtyLocal);
|
|
||||||
|
|
||||||
MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, SerializeMethodName);
|
MethodReference baseSerialize = Resolvers.TryResolveMethodInParents(netBehaviourSubclass.BaseType, assembly, SerializeMethodName);
|
||||||
if (baseSerialize != null)
|
if (baseSerialize != null)
|
||||||
{
|
{
|
||||||
@ -419,16 +416,20 @@ namespace Mirror.Weaver
|
|||||||
// forceAll
|
// forceAll
|
||||||
worker.Emit(OpCodes.Ldarg_2);
|
worker.Emit(OpCodes.Ldarg_2);
|
||||||
worker.Emit(OpCodes.Call, baseSerialize);
|
worker.Emit(OpCodes.Call, baseSerialize);
|
||||||
// set dirtyLocal to result of base.OnSerialize()
|
|
||||||
worker.Emit(OpCodes.Stloc_0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates: if (forceAll);
|
// Generates:
|
||||||
|
// if (forceAll)
|
||||||
|
// {
|
||||||
|
// writer.WriteInt(health);
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
Instruction initialStateLabel = worker.Create(OpCodes.Nop);
|
Instruction initialStateLabel = worker.Create(OpCodes.Nop);
|
||||||
// forceAll
|
// forceAll
|
||||||
worker.Emit(OpCodes.Ldarg_2);
|
worker.Emit(OpCodes.Ldarg_2); // load 'forceAll' flag
|
||||||
worker.Emit(OpCodes.Brfalse, initialStateLabel);
|
worker.Emit(OpCodes.Brfalse, initialStateLabel); // start the 'if forceAll' branch
|
||||||
|
|
||||||
|
// generates write.Write(syncVar) for each SyncVar in forceAll case
|
||||||
foreach (FieldDefinition syncVarDef in syncVars)
|
foreach (FieldDefinition syncVarDef in syncVars)
|
||||||
{
|
{
|
||||||
FieldReference syncVar = syncVarDef;
|
FieldReference syncVar = syncVarDef;
|
||||||
@ -442,7 +443,21 @@ namespace Mirror.Weaver
|
|||||||
// this
|
// this
|
||||||
worker.Emit(OpCodes.Ldarg_0);
|
worker.Emit(OpCodes.Ldarg_0);
|
||||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||||
MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
|
MethodReference writeFunc;
|
||||||
|
// For NBs we always need to use the default NetworkBehaviour write func
|
||||||
|
// since the reader counter part uses that exact layout which is not easy to change
|
||||||
|
// without introducing more edge cases
|
||||||
|
// effectively this disallows custom NB-type writers/readers on SyncVars
|
||||||
|
// see: https://github.com/MirrorNetworking/Mirror/issues/2680
|
||||||
|
if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||||
|
{
|
||||||
|
writeFunc = writers.GetWriteFunc(weaverTypes.Import<NetworkBehaviour>(), ref WeavingFailed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
|
||||||
|
}
|
||||||
|
|
||||||
if (writeFunc != null)
|
if (writeFunc != null)
|
||||||
{
|
{
|
||||||
worker.Emit(OpCodes.Call, writeFunc);
|
worker.Emit(OpCodes.Call, writeFunc);
|
||||||
@ -455,15 +470,14 @@ namespace Mirror.Weaver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always return true if forceAll
|
// if (forceAll) then always return at the end of the 'if' case
|
||||||
|
|
||||||
// Generates: return true
|
|
||||||
worker.Emit(OpCodes.Ldc_I4_1);
|
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
// Generates: end if (forceAll);
|
// end the 'if' case for "if (forceAll)"
|
||||||
worker.Append(initialStateLabel);
|
worker.Append(initialStateLabel);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// write dirty bits before the data fields
|
// write dirty bits before the data fields
|
||||||
// Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ());
|
// Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ());
|
||||||
// writer
|
// writer
|
||||||
@ -480,7 +494,6 @@ namespace Mirror.Weaver
|
|||||||
int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);
|
int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);
|
||||||
foreach (FieldDefinition syncVarDef in syncVars)
|
foreach (FieldDefinition syncVarDef in syncVars)
|
||||||
{
|
{
|
||||||
|
|
||||||
FieldReference syncVar = syncVarDef;
|
FieldReference syncVar = syncVarDef;
|
||||||
if (netBehaviourSubclass.HasGenericParameters)
|
if (netBehaviourSubclass.HasGenericParameters)
|
||||||
{
|
{
|
||||||
@ -504,7 +517,21 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Ldarg_0);
|
worker.Emit(OpCodes.Ldarg_0);
|
||||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||||
|
|
||||||
MethodReference writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
|
MethodReference writeFunc;
|
||||||
|
// For NBs we always need to use the default NetworkBehaviour write func
|
||||||
|
// since the reader counter part uses that exact layout which is not easy to change
|
||||||
|
// without introducing more edge cases
|
||||||
|
// effectively this disallows custom NB-type writers/readers on SyncVars
|
||||||
|
// see: https://github.com/MirrorNetworking/Mirror/issues/2680
|
||||||
|
if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||||
|
{
|
||||||
|
writeFunc = writers.GetWriteFunc(weaverTypes.Import<NetworkBehaviour>(), ref WeavingFailed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeFunc = writers.GetWriteFunc(syncVar.FieldType, ref WeavingFailed);
|
||||||
|
}
|
||||||
|
|
||||||
if (writeFunc != null)
|
if (writeFunc != null)
|
||||||
{
|
{
|
||||||
worker.Emit(OpCodes.Call, writeFunc);
|
worker.Emit(OpCodes.Call, writeFunc);
|
||||||
@ -516,11 +543,6 @@ namespace Mirror.Weaver
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// something was dirty
|
|
||||||
worker.Emit(OpCodes.Ldc_I4_1);
|
|
||||||
// set dirtyLocal to true
|
|
||||||
worker.Emit(OpCodes.Stloc_0);
|
|
||||||
|
|
||||||
worker.Append(varLabel);
|
worker.Append(varLabel);
|
||||||
dirtyBit += 1;
|
dirtyBit += 1;
|
||||||
}
|
}
|
||||||
@ -529,8 +551,7 @@ namespace Mirror.Weaver
|
|||||||
//worker.Emit(OpCodes.Ldstr, $"Injected Serialize {netBehaviourSubclass.Name}");
|
//worker.Emit(OpCodes.Ldstr, $"Injected Serialize {netBehaviourSubclass.Name}");
|
||||||
//worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
//worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||||
|
|
||||||
// generate: return dirtyLocal
|
// generate: return
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
netBehaviourSubclass.Methods.Add(serialize);
|
netBehaviourSubclass.Methods.Add(serialize);
|
||||||
}
|
}
|
||||||
@ -589,10 +610,9 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Ldflda, netIdField);
|
worker.Emit(OpCodes.Ldflda, netIdField);
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity);
|
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity);
|
||||||
}
|
}
|
||||||
// TODO this only uses the persistent netId for types DERIVED FROM NB.
|
// handle both NetworkBehaviour and inheritors.
|
||||||
// not if the type is just 'NetworkBehaviour'.
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
// this is what original implementation did too. fix it after.
|
else if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>() || syncVar.FieldType.Is<NetworkBehaviour>())
|
||||||
else if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
|
||||||
{
|
{
|
||||||
// reader
|
// reader
|
||||||
worker.Emit(OpCodes.Ldarg_1);
|
worker.Emit(OpCodes.Ldarg_1);
|
||||||
|
@ -68,7 +68,7 @@ namespace Mirror.Weaver
|
|||||||
//worker.Emit(OpCodes.Ldstr, $"Call ClientRpc function {md.Name}");
|
//worker.Emit(OpCodes.Ldstr, $"Call ClientRpc function {md.Name}");
|
||||||
//worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
//worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||||
|
|
||||||
NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes);
|
||||||
|
|
||||||
// write all the arguments that the user passed to the Rpc call
|
// write all the arguments that the user passed to the Rpc call
|
||||||
if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed))
|
if (!NetworkBehaviourProcessor.WriteArguments(worker, writers, Log, md, RemoteCallType.ClientRpc, ref WeavingFailed))
|
||||||
@ -82,6 +82,11 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Ldarg_0);
|
worker.Emit(OpCodes.Ldarg_0);
|
||||||
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
||||||
worker.Emit(OpCodes.Ldstr, md.FullName);
|
worker.Emit(OpCodes.Ldstr, md.FullName);
|
||||||
|
// pass the function hash so we don't have to compute it at runtime
|
||||||
|
// otherwise each GetStableHash call requires O(N) complexity.
|
||||||
|
// noticeable for long function names:
|
||||||
|
// https://github.com/MirrorNetworking/Mirror/issues/3375
|
||||||
|
worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode());
|
||||||
// writer
|
// writer
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
worker.Emit(OpCodes.Ldloc_0);
|
||||||
worker.Emit(OpCodes.Ldc_I4, channel);
|
worker.Emit(OpCodes.Ldc_I4, channel);
|
||||||
@ -89,7 +94,7 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
worker.Emit(includeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
||||||
worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal);
|
worker.Emit(OpCodes.Callvirt, weaverTypes.sendRpcInternal);
|
||||||
|
|
||||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes);
|
||||||
|
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
foreach (FieldDefinition fd in td.Fields)
|
foreach (FieldDefinition fd in td.Fields)
|
||||||
{
|
{
|
||||||
if (fd.FieldType.IsGenericParameter)
|
if (fd.FieldType.IsGenericParameter || fd.ContainsGenericParameter)
|
||||||
{
|
{
|
||||||
// can't call .Resolve on generic ones
|
// can't call .Resolve on generic ones
|
||||||
continue;
|
continue;
|
||||||
|
@ -203,7 +203,9 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference);
|
worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference);
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
// handle both NetworkBehaviour and inheritors.
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
|
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>() || fd.FieldType.Is<NetworkBehaviour>())
|
||||||
{
|
{
|
||||||
// return this.GetSyncVarNetworkBehaviour<T>(ref field, uint netId);
|
// return this.GetSyncVarNetworkBehaviour<T>(ref field, uint netId);
|
||||||
// this.
|
// this.
|
||||||
@ -331,10 +333,9 @@ namespace Mirror.Weaver
|
|||||||
worker.Emit(OpCodes.Ldflda, netIdFieldReference);
|
worker.Emit(OpCodes.Ldflda, netIdFieldReference);
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity);
|
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity);
|
||||||
}
|
}
|
||||||
// TODO this only uses the persistent netId for types DERIVED FROM NB.
|
// handle both NetworkBehaviour and inheritors.
|
||||||
// not if the type is just 'NetworkBehaviour'.
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
// this is what original implementation did too. fix it after.
|
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>() || fd.FieldType.Is<NetworkBehaviour>())
|
||||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
|
||||||
{
|
{
|
||||||
// NetworkIdentity setter needs one more parameter: netId field ref
|
// NetworkIdentity setter needs one more parameter: netId field ref
|
||||||
// (actually its a NetworkBehaviourSyncVar type)
|
// (actually its a NetworkBehaviourSyncVar type)
|
||||||
@ -368,11 +369,13 @@ namespace Mirror.Weaver
|
|||||||
// GameObject/NetworkIdentity SyncVars have a new field for netId
|
// GameObject/NetworkIdentity SyncVars have a new field for netId
|
||||||
FieldDefinition netIdField = null;
|
FieldDefinition netIdField = null;
|
||||||
// NetworkBehaviour has different field type than other NetworkIdentityFields
|
// NetworkBehaviour has different field type than other NetworkIdentityFields
|
||||||
if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
// handle both NetworkBehaviour and inheritors.
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
|
if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>() || fd.FieldType.Is<NetworkBehaviour>())
|
||||||
{
|
{
|
||||||
netIdField = new FieldDefinition($"___{fd.Name}NetId",
|
netIdField = new FieldDefinition($"___{fd.Name}NetId",
|
||||||
FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed
|
FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed
|
||||||
weaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>());
|
weaverTypes.Import<NetworkBehaviourSyncVar>());
|
||||||
netIdField.DeclaringType = td;
|
netIdField.DeclaringType = td;
|
||||||
|
|
||||||
syncVarNetIds[fd] = netIdField;
|
syncVarNetIds[fd] = netIdField;
|
||||||
@ -475,7 +478,11 @@ namespace Mirror.Weaver
|
|||||||
{
|
{
|
||||||
td.Fields.Add(fd);
|
td.Fields.Add(fd);
|
||||||
}
|
}
|
||||||
syncVarAccessLists.SetNumSyncVars(td.FullName, syncVars.Count);
|
|
||||||
|
// include parent class syncvars
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/3457
|
||||||
|
int parentSyncVarCount = syncVarAccessLists.GetSyncVarStart(td.BaseType.FullName);
|
||||||
|
syncVarAccessLists.SetNumSyncVars(td.FullName, parentSyncVarCount + syncVars.Count);
|
||||||
|
|
||||||
return (syncVars, syncVarNetIds);
|
return (syncVars, syncVarNetIds);
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,16 @@ namespace Mirror.Weaver
|
|||||||
// helper functions to check if the method has a NetworkConnection parameter
|
// helper functions to check if the method has a NetworkConnection parameter
|
||||||
public static bool HasNetworkConnectionParameter(MethodDefinition md)
|
public static bool HasNetworkConnectionParameter(MethodDefinition md)
|
||||||
{
|
{
|
||||||
return md.Parameters.Count > 0 &&
|
if (md.Parameters.Count > 0)
|
||||||
md.Parameters[0].ParameterType.Is<NetworkConnection>();
|
{
|
||||||
|
// we need to allow both NetworkConnection, and inheriting types.
|
||||||
|
// NetworkBehaviour.SendTargetRpc takes a NetworkConnection parameter.
|
||||||
|
// fixes https://github.com/vis2k/Mirror/issues/3290
|
||||||
|
TypeReference type = md.Parameters[0].ParameterType;
|
||||||
|
return type.Is<NetworkConnection>() ||
|
||||||
|
type.IsDerivedFrom<NetworkConnection>();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
|
public static MethodDefinition ProcessTargetRpcInvoke(WeaverTypes weaverTypes, Readers readers, Logger Log, TypeDefinition td, MethodDefinition md, MethodDefinition rpcCallFunc, ref bool WeavingFailed)
|
||||||
@ -34,16 +42,25 @@ namespace Mirror.Weaver
|
|||||||
// NetworkConnection parameter is optional
|
// NetworkConnection parameter is optional
|
||||||
if (HasNetworkConnectionParameter(md))
|
if (HasNetworkConnectionParameter(md))
|
||||||
{
|
{
|
||||||
// on server, the NetworkConnection parameter is a connection to client.
|
// TargetRpcs are sent from server to client.
|
||||||
// when the rpc is invoked on the client, it still has the same
|
// on server, we currently support two types:
|
||||||
// function signature. we pass in the connection to server,
|
// TargetRpc(NetworkConnection)
|
||||||
// which is cleaner than just passing null)
|
// TargetRpc(NetworkConnectionToClient)
|
||||||
//NetworkClient.readyconnection
|
// however, it's always a connection to client.
|
||||||
|
// in the future, only NetworkConnectionToClient will be supported.
|
||||||
|
// explicit typing helps catch issues at compile time.
|
||||||
//
|
//
|
||||||
// TODO
|
// on client, InvokeTargetRpc calls the original code.
|
||||||
// a) .connectionToServer = best solution. no doubt.
|
// we need to fill in the NetworkConnection parameter.
|
||||||
// b) NetworkClient.connection for now. add TODO to not use static later.
|
// NetworkClient.connection is always a connection to server.
|
||||||
worker.Emit(OpCodes.Call, weaverTypes.NetworkClientConnectionReference);
|
//
|
||||||
|
// we used to pass NetworkClient.connection as the TargetRpc parameter.
|
||||||
|
// which caused: https://github.com/MirrorNetworking/Mirror/issues/3455
|
||||||
|
// when the parameter is defined as a NetworkConnectionToClient.
|
||||||
|
//
|
||||||
|
// a client's connection never fits into a NetworkConnectionToClient.
|
||||||
|
// we need to always pass null here.
|
||||||
|
worker.Emit(OpCodes.Ldnull);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process reader parameters and skip first one if first one is NetworkConnection
|
// process reader parameters and skip first one if first one is NetworkConnection
|
||||||
@ -100,7 +117,7 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteSetupLocals(worker, weaverTypes);
|
||||||
|
|
||||||
NetworkBehaviourProcessor.WriteCreateWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteGetWriter(worker, weaverTypes);
|
||||||
|
|
||||||
// write all the arguments that the user passed to the TargetRpc call
|
// write all the arguments that the user passed to the TargetRpc call
|
||||||
// (skip first one if first one is NetworkConnection)
|
// (skip first one if first one is NetworkConnection)
|
||||||
@ -122,12 +139,17 @@ namespace Mirror.Weaver
|
|||||||
}
|
}
|
||||||
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
// pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
|
||||||
worker.Emit(OpCodes.Ldstr, md.FullName);
|
worker.Emit(OpCodes.Ldstr, md.FullName);
|
||||||
|
// pass the function hash so we don't have to compute it at runtime
|
||||||
|
// otherwise each GetStableHash call requires O(N) complexity.
|
||||||
|
// noticeable for long function names:
|
||||||
|
// https://github.com/MirrorNetworking/Mirror/issues/3375
|
||||||
|
worker.Emit(OpCodes.Ldc_I4, md.FullName.GetStableHashCode());
|
||||||
// writer
|
// writer
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
worker.Emit(OpCodes.Ldloc_0);
|
||||||
worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0));
|
worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0));
|
||||||
worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal);
|
worker.Emit(OpCodes.Callvirt, weaverTypes.sendTargetRpcInternal);
|
||||||
|
|
||||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker, weaverTypes);
|
NetworkBehaviourProcessor.WriteReturnWriter(worker, weaverTypes);
|
||||||
|
|
||||||
worker.Emit(OpCodes.Ret);
|
worker.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ namespace Mirror.Weaver
|
|||||||
AssemblyDefinition assembly;
|
AssemblyDefinition assembly;
|
||||||
WeaverTypes weaverTypes;
|
WeaverTypes weaverTypes;
|
||||||
TypeDefinition GeneratedCodeClass;
|
TypeDefinition GeneratedCodeClass;
|
||||||
|
// CHANGED
|
||||||
internal Logger Log;
|
internal Logger Log;
|
||||||
|
|
||||||
Dictionary<TypeReference, MethodReference> readFuncs =
|
Dictionary<TypeReference, MethodReference> readFuncs =
|
||||||
@ -114,7 +115,9 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList), ref WeavingFailed);
|
return GenerateReadCollection(variableReference, elementType, nameof(NetworkReaderExtensions.ReadList), ref WeavingFailed);
|
||||||
}
|
}
|
||||||
else if (variableReference.IsDerivedFrom<NetworkBehaviour>())
|
// handle both NetworkBehaviour and inheritors.
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
|
else if (variableReference.IsDerivedFrom<NetworkBehaviour>() || variableReference.Is<NetworkBehaviour>())
|
||||||
{
|
{
|
||||||
return GetNetworkBehaviourReader(variableReference);
|
return GetNetworkBehaviourReader(variableReference);
|
||||||
}
|
}
|
||||||
@ -138,6 +141,7 @@ namespace Mirror.Weaver
|
|||||||
WeavingFailed = true;
|
WeavingFailed = true;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// CHANGED
|
||||||
/*
|
/*
|
||||||
if (variableDefinition.HasGenericParameters)
|
if (variableDefinition.HasGenericParameters)
|
||||||
{
|
{
|
||||||
@ -270,6 +274,7 @@ namespace Mirror.Weaver
|
|||||||
GenerateNullCheck(worker, ref WeavingFailed);
|
GenerateNullCheck(worker, ref WeavingFailed);
|
||||||
|
|
||||||
CreateNew(variable, worker, td, ref WeavingFailed);
|
CreateNew(variable, worker, td, ref WeavingFailed);
|
||||||
|
// CHANGED
|
||||||
this.ReadAllFieldsGeneric(variable, worker, ref WeavingFailed);
|
this.ReadAllFieldsGeneric(variable, worker, ref WeavingFailed);
|
||||||
|
|
||||||
worker.Emit(OpCodes.Ldloc_0);
|
worker.Emit(OpCodes.Ldloc_0);
|
||||||
|
@ -25,6 +25,12 @@ namespace Mirror.Weaver
|
|||||||
AssemblyDefinition CurrentAssembly;
|
AssemblyDefinition CurrentAssembly;
|
||||||
Writers writers;
|
Writers writers;
|
||||||
Readers readers;
|
Readers readers;
|
||||||
|
|
||||||
|
// in case of weaver errors, we don't stop immediately.
|
||||||
|
// we log all errors and then eventually return false if
|
||||||
|
// weaving has failed.
|
||||||
|
// this way the user can fix multiple errors at once, instead of having
|
||||||
|
// to fix -> recompile -> fix -> recompile for one error at a time.
|
||||||
bool WeavingFailed;
|
bool WeavingFailed;
|
||||||
|
|
||||||
// logger functions can be set from the outside.
|
// logger functions can be set from the outside.
|
||||||
@ -200,6 +206,7 @@ namespace Mirror.Weaver
|
|||||||
ModuleDefinition moduleDefinition = CurrentAssembly.MainModule;
|
ModuleDefinition moduleDefinition = CurrentAssembly.MainModule;
|
||||||
Console.WriteLine($"Script Module: {moduleDefinition.Name}");
|
Console.WriteLine($"Script Module: {moduleDefinition.Name}");
|
||||||
|
|
||||||
|
// CHANGED
|
||||||
QSBReaderWriterProcessor.Process(moduleDefinition, writers, readers, ref WeavingFailed);
|
QSBReaderWriterProcessor.Process(moduleDefinition, writers, readers, ref WeavingFailed);
|
||||||
|
|
||||||
modified |= WeaveModule(moduleDefinition);
|
modified |= WeaveModule(moduleDefinition);
|
||||||
|
@ -11,8 +11,8 @@ namespace Mirror.Weaver
|
|||||||
public MethodReference ScriptableObjectCreateInstanceMethod;
|
public MethodReference ScriptableObjectCreateInstanceMethod;
|
||||||
|
|
||||||
public MethodReference NetworkBehaviourDirtyBitsReference;
|
public MethodReference NetworkBehaviourDirtyBitsReference;
|
||||||
public MethodReference GetPooledWriterReference;
|
public MethodReference GetWriterReference;
|
||||||
public MethodReference RecycleWriterReference;
|
public MethodReference ReturnWriterReference;
|
||||||
|
|
||||||
public MethodReference NetworkClientConnectionReference;
|
public MethodReference NetworkClientConnectionReference;
|
||||||
|
|
||||||
@ -77,28 +77,14 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
TypeReference NetworkServerType = Import(typeof(NetworkServer));
|
TypeReference NetworkServerType = Import(typeof(NetworkServer));
|
||||||
NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed);
|
NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed);
|
||||||
|
|
||||||
TypeReference NetworkClientType = Import(typeof(NetworkClient));
|
TypeReference NetworkClientType = Import(typeof(NetworkClient));
|
||||||
NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed);
|
NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed);
|
||||||
|
NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed);
|
||||||
TypeReference RemoteCallDelegateType = Import<RemoteCalls.RemoteCallDelegate>();
|
|
||||||
RemoteCallDelegateConstructor = Resolvers.ResolveMethod(RemoteCallDelegateType, assembly, Log, ".ctor", ref WeavingFailed);
|
|
||||||
|
|
||||||
TypeReference NetworkBehaviourType = Import<NetworkBehaviour>();
|
TypeReference NetworkBehaviourType = Import<NetworkBehaviour>();
|
||||||
TypeReference RemoteProcedureCallsType = Import(typeof(RemoteCalls.RemoteProcedureCalls));
|
|
||||||
|
|
||||||
TypeReference ScriptableObjectType = Import<ScriptableObject>();
|
|
||||||
|
|
||||||
ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod(
|
|
||||||
ScriptableObjectType, assembly, Log,
|
|
||||||
md => md.Name == "CreateInstance" && md.HasGenericParameters,
|
|
||||||
ref WeavingFailed);
|
|
||||||
|
|
||||||
NetworkBehaviourDirtyBitsReference = Resolvers.ResolveProperty(NetworkBehaviourType, assembly, "syncVarDirtyBits");
|
NetworkBehaviourDirtyBitsReference = Resolvers.ResolveProperty(NetworkBehaviourType, assembly, "syncVarDirtyBits");
|
||||||
TypeReference NetworkWriterPoolType = Import(typeof(NetworkWriterPool));
|
|
||||||
GetPooledWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "GetWriter", ref WeavingFailed);
|
|
||||||
RecycleWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Recycle", ref WeavingFailed);
|
|
||||||
|
|
||||||
NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed);
|
|
||||||
|
|
||||||
generatedSyncVarSetter = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter", ref WeavingFailed);
|
generatedSyncVarSetter = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter", ref WeavingFailed);
|
||||||
generatedSyncVarSetter_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_GameObject", ref WeavingFailed);
|
generatedSyncVarSetter_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_GameObject", ref WeavingFailed);
|
||||||
@ -114,9 +100,25 @@ namespace Mirror.Weaver
|
|||||||
getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed);
|
getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed);
|
||||||
getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", ref WeavingFailed);
|
getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", ref WeavingFailed);
|
||||||
|
|
||||||
|
sendCommandInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendCommandInternal", ref WeavingFailed);
|
||||||
|
sendRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendRPCInternal", ref WeavingFailed);
|
||||||
|
sendTargetRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendTargetRPCInternal", ref WeavingFailed);
|
||||||
|
|
||||||
|
InitSyncObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "InitSyncObject", ref WeavingFailed);
|
||||||
|
|
||||||
|
TypeReference RemoteProcedureCallsType = Import(typeof(RemoteCalls.RemoteProcedureCalls));
|
||||||
registerCommandReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterCommand", ref WeavingFailed);
|
registerCommandReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterCommand", ref WeavingFailed);
|
||||||
registerRpcReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterRpc", ref WeavingFailed);
|
registerRpcReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterRpc", ref WeavingFailed);
|
||||||
|
|
||||||
|
TypeReference RemoteCallDelegateType = Import<RemoteCalls.RemoteCallDelegate>();
|
||||||
|
RemoteCallDelegateConstructor = Resolvers.ResolveMethod(RemoteCallDelegateType, assembly, Log, ".ctor", ref WeavingFailed);
|
||||||
|
|
||||||
|
TypeReference ScriptableObjectType = Import<ScriptableObject>();
|
||||||
|
ScriptableObjectCreateInstanceMethod = Resolvers.ResolveMethod(
|
||||||
|
ScriptableObjectType, assembly, Log,
|
||||||
|
md => md.Name == "CreateInstance" && md.HasGenericParameters,
|
||||||
|
ref WeavingFailed);
|
||||||
|
|
||||||
TypeReference unityDebug = Import(typeof(UnityEngine.Debug));
|
TypeReference unityDebug = Import(typeof(UnityEngine.Debug));
|
||||||
// these have multiple methods with same name, so need to check parameters too
|
// these have multiple methods with same name, so need to check parameters too
|
||||||
logErrorReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md =>
|
logErrorReference = Resolvers.ResolveMethod(unityDebug, assembly, Log, md =>
|
||||||
@ -133,11 +135,10 @@ namespace Mirror.Weaver
|
|||||||
|
|
||||||
TypeReference typeType = Import(typeof(Type));
|
TypeReference typeType = Import(typeof(Type));
|
||||||
getTypeFromHandleReference = Resolvers.ResolveMethod(typeType, assembly, Log, "GetTypeFromHandle", ref WeavingFailed);
|
getTypeFromHandleReference = Resolvers.ResolveMethod(typeType, assembly, Log, "GetTypeFromHandle", ref WeavingFailed);
|
||||||
sendCommandInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendCommandInternal", ref WeavingFailed);
|
|
||||||
sendRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendRPCInternal", ref WeavingFailed);
|
|
||||||
sendTargetRpcInternal = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SendTargetRPCInternal", ref WeavingFailed);
|
|
||||||
|
|
||||||
InitSyncObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "InitSyncObject", ref WeavingFailed);
|
TypeReference NetworkWriterPoolType = Import(typeof(NetworkWriterPool));
|
||||||
|
GetWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Get", ref WeavingFailed);
|
||||||
|
ReturnWriterReference = Resolvers.ResolveMethod(NetworkWriterPoolType, assembly, Log, "Return", ref WeavingFailed);
|
||||||
|
|
||||||
TypeReference readerExtensions = Import(typeof(NetworkReaderExtensions));
|
TypeReference readerExtensions = Import(typeof(NetworkReaderExtensions));
|
||||||
readNetworkBehaviourGeneric = Resolvers.ResolveMethod(readerExtensions, assembly, Log, (md =>
|
readNetworkBehaviourGeneric = Resolvers.ResolveMethod(readerExtensions, assembly, Log, (md =>
|
||||||
@ -147,6 +148,7 @@ namespace Mirror.Weaver
|
|||||||
}),
|
}),
|
||||||
ref WeavingFailed);
|
ref WeavingFailed);
|
||||||
|
|
||||||
|
// CHANGED
|
||||||
/*
|
/*
|
||||||
// [InitializeOnLoadMethod]
|
// [InitializeOnLoadMethod]
|
||||||
// 'UnityEditor' is not available in builds.
|
// 'UnityEditor' is not available in builds.
|
||||||
|
@ -116,7 +116,9 @@ namespace Mirror.Weaver
|
|||||||
return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList), ref WeavingFailed);
|
return GenerateCollectionWriter(variableReference, elementType, nameof(NetworkWriterExtensions.WriteList), ref WeavingFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableReference.IsDerivedFrom<NetworkBehaviour>())
|
// handle both NetworkBehaviour and inheritors.
|
||||||
|
// fixes: https://github.com/MirrorNetworking/Mirror/issues/2939
|
||||||
|
if (variableReference.IsDerivedFrom<NetworkBehaviour>() || variableReference.Is<NetworkBehaviour>())
|
||||||
{
|
{
|
||||||
return GetNetworkBehaviourWriter(variableReference);
|
return GetNetworkBehaviourWriter(variableReference);
|
||||||
}
|
}
|
||||||
@ -139,6 +141,7 @@ namespace Mirror.Weaver
|
|||||||
{
|
{
|
||||||
throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference);
|
throw new GenerateWriterException($"Cannot generate writer for {variableReference.Name}. Use a supported type or provide a custom writer", variableReference);
|
||||||
}
|
}
|
||||||
|
// CHANGED
|
||||||
/*
|
/*
|
||||||
if (variableDefinition.HasGenericParameters)
|
if (variableDefinition.HasGenericParameters)
|
||||||
{
|
{
|
||||||
@ -219,6 +222,7 @@ namespace Mirror.Weaver
|
|||||||
if (!variable.Resolve().IsValueType)
|
if (!variable.Resolve().IsValueType)
|
||||||
WriteNullCheck(worker, ref WeavingFailed);
|
WriteNullCheck(worker, ref WeavingFailed);
|
||||||
|
|
||||||
|
// CHANGED
|
||||||
if (!this.WriteAllFieldsGeneric(variable, worker, ref WeavingFailed))
|
if (!this.WriteAllFieldsGeneric(variable, worker, ref WeavingFailed))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
private string _lastTransportError;
|
private string _lastTransportError;
|
||||||
private static readonly string[] _kcpErrorLogs =
|
private static readonly string[] _kcpErrorLogs =
|
||||||
{
|
{
|
||||||
"KCP: received disconnect message",
|
"KcpPeer: received disconnect message",
|
||||||
"Failed to resolve host: .*"
|
"Failed to resolve host: .*"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
QSBCore.ProfileManager.OnProfileSignInComplete += _ => InitPlayerName();
|
QSBCore.ProfileManager.OnProfileSignInComplete += _ => InitPlayerName();
|
||||||
|
|
||||||
playerPrefab = QSBCore.NetworkAssetBundle.LoadAsset<GameObject>("Assets/Prefabs/NETWORK_Player_Body.prefab");
|
playerPrefab = QSBCore.NetworkAssetBundle.LoadAsset<GameObject>("Assets/Prefabs/NETWORK_Player_Body.prefab");
|
||||||
playerPrefab.GetRequiredComponent<NetworkIdentity>().SetValue("m_AssetId", 1.ToGuid().ToString("N"));
|
playerPrefab.GetRequiredComponent<NetworkIdentity>().SetValue("_assetId", (uint)1);
|
||||||
|
|
||||||
ShipPrefab = MakeNewNetworkObject(2, "NetworkShip", typeof(ShipTransformSync));
|
ShipPrefab = MakeNewNetworkObject(2, "NetworkShip", typeof(ShipTransformSync));
|
||||||
var shipVector3Sync = ShipPrefab.AddComponent<Vector3VariableSyncer>();
|
var shipVector3Sync = ShipPrefab.AddComponent<Vector3VariableSyncer>();
|
||||||
@ -202,7 +202,7 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
/// this works by calling Unload(false) and then reloading the AssetBundle,
|
/// this works by calling Unload(false) and then reloading the AssetBundle,
|
||||||
/// which makes LoadAsset give you a new resource.
|
/// which makes LoadAsset give you a new resource.
|
||||||
/// see https://docs.unity3d.com/Manual/AssetBundles-Native.html.
|
/// see https://docs.unity3d.com/Manual/AssetBundles-Native.html.
|
||||||
private static GameObject MakeNewNetworkObject(int assetId, string name, Type networkBehaviourType)
|
private static GameObject MakeNewNetworkObject(uint assetId, string name, Type networkBehaviourType)
|
||||||
{
|
{
|
||||||
var bundle = QSBCore.Helper.Assets.LoadBundle("AssetBundles/qsb_empty");
|
var bundle = QSBCore.Helper.Assets.LoadBundle("AssetBundles/qsb_empty");
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
bundle.Unload(false);
|
bundle.Unload(false);
|
||||||
|
|
||||||
template.name = name;
|
template.name = name;
|
||||||
template.AddComponent<NetworkIdentity>().SetValue("m_AssetId", assetId.ToGuid().ToString("N"));
|
template.AddComponent<NetworkIdentity>().SetValue("_assetId", assetId);
|
||||||
template.AddComponent(networkBehaviourType);
|
template.AddComponent(networkBehaviourType);
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ public abstract class QSBNetworkBehaviour : NetworkBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var writer = NetworkWriterPool.GetWriter();
|
using var writer = NetworkWriterPool.Get();
|
||||||
Serialize(writer);
|
Serialize(writer);
|
||||||
UpdatePrevData();
|
UpdatePrevData();
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ public abstract class QSBNetworkBehaviour : NetworkBehaviour
|
|||||||
Array.Copy(data.Array!, data.Offset, _lastKnownData, 0, data.Count);
|
Array.Copy(data.Array!, data.Offset, _lastKnownData, 0, data.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
using var reader = NetworkReaderPool.GetReader(data);
|
using var reader = NetworkReaderPool.Get(data);
|
||||||
Deserialize(reader);
|
Deserialize(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user