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