quantum-space-buddies/EpicOnlineTransport/Common.cs

334 lines
10 KiB
C#
Raw Normal View History

2022-02-06 04:17:08 +00:00
using Epic.OnlineServices;
2022-02-06 02:06:25 +00:00
using Epic.OnlineServices.P2P;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
2022-03-03 03:46:33 +00:00
namespace EpicTransport;
public abstract class Common
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
private PacketReliability[] channels;
private int internal_ch => channels.Length;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected enum InternalMessages : byte
{
CONNECT,
ACCEPT_CONNECT,
DISCONNECT
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected struct PacketKey
{
public ProductUserId productUserId;
public byte channel;
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
private OnIncomingConnectionRequestCallback OnIncomingConnectionRequest;
private ulong incomingNotificationId = 0;
private OnRemoteConnectionClosedCallback OnRemoteConnectionClosed;
private ulong outgoingNotificationId = 0;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected readonly EosTransport transport;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected List<string> deadSockets;
public bool ignoreAllMessages = false;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
// Mapping from PacketKey to a List of Packet Lists
protected Dictionary<PacketKey, List<List<Packet>>> incomingPackets = new();
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected Common(EosTransport transport)
{
channels = transport.Channels;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
deadSockets = new List<string>();
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
var addNotifyPeerConnectionRequestOptions = new AddNotifyPeerConnectionRequestOptions();
addNotifyPeerConnectionRequestOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
addNotifyPeerConnectionRequestOptions.SocketId = null;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
OnIncomingConnectionRequest += OnNewConnection;
OnRemoteConnectionClosed += OnConnectFail;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
incomingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionRequest(addNotifyPeerConnectionRequestOptions,
null, OnIncomingConnectionRequest);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
var addNotifyPeerConnectionClosedOptions = new AddNotifyPeerConnectionClosedOptions();
addNotifyPeerConnectionClosedOptions.LocalUserId = EOSSDKComponent.LocalUserProductId;
addNotifyPeerConnectionClosedOptions.SocketId = null;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
outgoingNotificationId = EOSSDKComponent.GetP2PInterface().AddNotifyPeerConnectionClosed(addNotifyPeerConnectionClosedOptions,
null, OnRemoteConnectionClosed);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
if (outgoingNotificationId == 0 || incomingNotificationId == 0)
{
Debug.LogError("Couldn't bind notifications with P2P interface");
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
incomingPackets = new Dictionary<PacketKey, List<List<Packet>>>();
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
this.transport = transport;
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected void Dispose()
{
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionRequest(incomingNotificationId);
EOSSDKComponent.GetP2PInterface().RemoveNotifyPeerConnectionClosed(outgoingNotificationId);
2022-03-03 03:46:33 +00:00
transport.ResetIgnoreMessagesAtStartUpTimer();
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected abstract void OnNewConnection(OnIncomingConnectionRequestInfo result);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
private void OnConnectFail(OnRemoteConnectionClosedInfo result)
{
if (ignoreAllMessages)
{
2022-03-03 03:46:33 +00:00
return;
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
OnConnectionFailed(result.RemoteUserId);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
switch (result.Reason)
{
case ConnectionClosedReason.ClosedByLocalUser:
throw new Exception("Connection cLosed: The Connection was gracecfully closed by the local user.");
case ConnectionClosedReason.ClosedByPeer:
throw new Exception("Connection closed: The connection was gracefully closed by remote user.");
case ConnectionClosedReason.ConnectionClosed:
throw new Exception("Connection closed: The connection was unexpectedly closed.");
case ConnectionClosedReason.ConnectionFailed:
throw new Exception("Connection failed: Failled to establish connection.");
case ConnectionClosedReason.InvalidData:
throw new Exception("Connection failed: The remote user sent us invalid data..");
case ConnectionClosedReason.InvalidMessage:
throw new Exception("Connection failed: The remote user sent us an invalid message.");
case ConnectionClosedReason.NegotiationFailed:
throw new Exception("Connection failed: Negotiation failed.");
case ConnectionClosedReason.TimedOut:
throw new Exception("Connection failed: Timeout.");
case ConnectionClosedReason.TooManyConnections:
throw new Exception("Connection failed: Too many connections.");
case ConnectionClosedReason.UnexpectedError:
throw new Exception("Unexpected Error, connection will be closed");
case ConnectionClosedReason.Unknown:
default:
throw new Exception("Unknown Error, connection has been closed.");
}
2022-03-03 03:46:33 +00:00
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected void SendInternal(ProductUserId target, SocketId socketId, InternalMessages type)
{
EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions()
{
2022-03-03 03:46:33 +00:00
AllowDelayedDelivery = true,
Channel = (byte)internal_ch,
Data = new byte[] { (byte)type },
LocalUserId = EOSSDKComponent.LocalUserProductId,
Reliability = PacketReliability.ReliableOrdered,
RemoteUserId = target,
SocketId = socketId
});
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
protected void Send(ProductUserId host, SocketId socketId, byte[] msgBuffer, byte channel)
{
var result = EOSSDKComponent.GetP2PInterface().SendPacket(new SendPacketOptions()
{
2022-03-03 03:46:33 +00:00
AllowDelayedDelivery = true,
Channel = channel,
Data = msgBuffer,
LocalUserId = EOSSDKComponent.LocalUserProductId,
Reliability = channels[channel],
RemoteUserId = host,
SocketId = socketId
});
if (result != Result.Success)
{
Debug.LogError("Send failed " + result);
}
2022-03-03 03:46:33 +00:00
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
private bool Receive(out ProductUserId clientProductUserId, out SocketId socketId, out byte[] receiveBuffer, byte channel)
{
var result = EOSSDKComponent.GetP2PInterface().ReceivePacket(new ReceivePacketOptions()
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
LocalUserId = EOSSDKComponent.LocalUserProductId,
MaxDataSizeBytes = P2PInterface.MaxPacketSize,
RequestedChannel = channel
}, out clientProductUserId, out socketId, out channel, out receiveBuffer);
2022-03-03 03:46:33 +00:00
if (result == Result.Success)
{
2022-03-03 03:46:33 +00:00
return true;
}
2022-03-03 03:46:33 +00:00
receiveBuffer = null;
clientProductUserId = null;
return false;
}
2022-03-03 03:46:33 +00:00
protected virtual void CloseP2PSessionWithUser(ProductUserId clientUserID, SocketId socketId)
{
if (socketId == null)
{
Debug.LogWarning("Socket ID == null | " + ignoreAllMessages);
return;
}
2022-03-03 03:46:33 +00:00
if (deadSockets == null)
{
Debug.LogWarning("DeadSockets == null");
return;
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
if (deadSockets.Contains(socketId.SocketName))
{
2022-03-03 03:46:33 +00:00
return;
}
2022-03-03 03:46:33 +00:00
else
{
deadSockets.Add(socketId.SocketName);
}
}
protected void WaitForClose(ProductUserId clientUserID, SocketId socketId) => transport.StartCoroutine(DelayedClose(clientUserID, socketId));
2022-03-03 03:46:33 +00:00
private IEnumerator DelayedClose(ProductUserId clientUserID, SocketId socketId)
{
yield return null;
CloseP2PSessionWithUser(clientUserID, socketId);
}
public void ReceiveData()
{
try
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
// Internal Channel, no fragmentation here
var socketId = new SocketId();
while (transport.enabled && Receive(out var clientUserID, out socketId, out var internalMessage, (byte)internal_ch))
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
if (internalMessage.Length == 1)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
OnReceiveInternalData((InternalMessages)internalMessage[0], clientUserID, socketId);
return; // Wait one frame
}
else
{
Debug.Log("Incorrect package length on internal channel.");
2022-02-06 04:17:08 +00:00
}
2022-03-03 03:46:33 +00:00
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
// 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))
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
var incomingPacketKey = new PacketKey();
incomingPacketKey.productUserId = clientUserID;
incomingPacketKey.channel = (byte)chNum;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
var packet = new Packet();
packet.FromBytes(receiveBuffer);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
if (!incomingPackets.ContainsKey(incomingPacketKey))
{
incomingPackets.Add(incomingPacketKey, new List<List<Packet>>());
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
var packetListIndex = incomingPackets[incomingPacketKey].Count;
for (var i = 0; i < incomingPackets[incomingPacketKey].Count; i++)
{
if (incomingPackets[incomingPacketKey][i][0].id == packet.id)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
packetListIndex = i;
break;
2022-02-06 04:17:08 +00:00
}
2022-03-03 03:46:33 +00:00
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
if (packetListIndex == incomingPackets[incomingPacketKey].Count)
{
incomingPackets[incomingPacketKey].Add(new List<Packet>());
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
var insertionIndex = -1;
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
for (var i = 0; i < incomingPackets[incomingPacketKey][packetListIndex].Count; i++)
{
if (incomingPackets[incomingPacketKey][packetListIndex][i].fragment > packet.fragment)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
insertionIndex = i;
break;
2022-02-06 04:17:08 +00:00
}
2022-03-03 03:46:33 +00:00
}
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
if (insertionIndex >= 0)
{
incomingPackets[incomingPacketKey][packetListIndex].Insert(insertionIndex, packet);
}
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)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
packetReady = false;
2022-02-06 04:17:08 +00:00
}
else
{
2022-03-03 03:46:33 +00:00
packetLength += tempPacket.data.Length;
2022-02-06 04:17:08 +00:00
}
}
2022-03-03 03:46:33 +00:00
if (packetReady)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
var data = new byte[packetLength];
var dataIndex = 0;
for (var packet = 0; packet < keyValuePair.Value[packetList].Count; packet++)
2022-02-06 04:17:08 +00:00
{
2022-03-03 03:46:33 +00:00
Array.Copy(keyValuePair.Value[packetList][packet].data, 0, data, dataIndex, keyValuePair.Value[packetList][packet].data.Length);
dataIndex += keyValuePair.Value[packetList][packet].data.Length;
2022-02-06 04:17:08 +00:00
}
2022-03-03 03:46:33 +00:00
OnReceiveData(data, keyValuePair.Key.productUserId, keyValuePair.Key.channel);
2022-02-06 04:17:08 +00:00
2022-03-03 03:46:33 +00:00
//keyValuePair.Value[packetList].Clear();
emptyPacketLists.Add(keyValuePair.Value[packetList]);
}
2022-03-03 03:46:33 +00:00
}
2022-03-03 03:46:33 +00:00
for (var i = 0; i < emptyPacketLists.Count; i++)
{
keyValuePair.Value.Remove(emptyPacketLists[i]);
}
2022-03-03 03:46:33 +00:00
emptyPacketLists.Clear();
2022-02-06 04:17:08 +00:00
}
}
2022-03-03 03:46:33 +00:00
catch (Exception e)
{
Debug.LogException(e);
}
}
2022-03-03 03:46:33 +00:00
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);
}