monopoly/Assets/Mirror/Runtime/Transport/FallbackTransport.cs
2020-11-30 08:12:07 +00:00

190 lines
6.1 KiB
C#

// uses the first available transport for server and client.
// example: to use Apathy if on Windows/Mac/Linux and fall back to Telepathy
// otherwise.
using System;
using UnityEngine;
namespace Mirror
{
[HelpURL("https://mirror-networking.com/docs/Transports/Fallback.html")]
public class FallbackTransport : Transport
{
public Transport[] transports;
// the first transport that is available on this platform
Transport available;
public void Awake()
{
if (transports == null || transports.Length == 0)
{
throw new Exception("FallbackTransport requires at least 1 underlying transport");
}
InitClient();
InitServer();
available = GetAvailableTransport();
Debug.Log("FallbackTransport available: " + available.GetType());
}
void OnEnable()
{
available.enabled = true;
}
void OnDisable()
{
available.enabled = false;
}
// The client just uses the first transport available
Transport GetAvailableTransport()
{
foreach (Transport transport in transports)
{
if (transport.Available())
{
return transport;
}
}
throw new Exception("No transport suitable for this platform");
}
public override bool Available()
{
return available.Available();
}
// clients always pick the first transport
void InitClient()
{
// wire all the base transports to our events
foreach (Transport transport in transports)
{
transport.OnClientConnected.AddListener(OnClientConnected.Invoke);
transport.OnClientDataReceived.AddListener(OnClientDataReceived.Invoke);
transport.OnClientError.AddListener(OnClientError.Invoke);
transport.OnClientDisconnected.AddListener(OnClientDisconnected.Invoke);
}
}
public override void ClientConnect(string address)
{
available.ClientConnect(address);
}
public override void ClientConnect(Uri uri)
{
foreach (Transport transport in transports)
{
if (transport.Available())
{
try
{
transport.ClientConnect(uri);
available = transport;
}
catch (ArgumentException)
{
// transport does not support the schema, just move on to the next one
}
}
}
throw new Exception("No transport suitable for this platform");
}
public override bool ClientConnected()
{
return available.ClientConnected();
}
public override void ClientDisconnect()
{
available.ClientDisconnect();
}
public override void ClientSend(int channelId, ArraySegment<byte> segment)
{
available.ClientSend(channelId, segment);
}
void InitServer()
{
// wire all the base transports to our events
foreach (Transport transport in transports)
{
transport.OnServerConnected.AddListener(OnServerConnected.Invoke);
transport.OnServerDataReceived.AddListener(OnServerDataReceived.Invoke);
transport.OnServerError.AddListener(OnServerError.Invoke);
transport.OnServerDisconnected.AddListener(OnServerDisconnected.Invoke);
}
}
// right now this just returns the first available uri,
// should we return the list of all available uri?
public override Uri ServerUri() => available.ServerUri();
public override bool ServerActive()
{
return available.ServerActive();
}
public override string ServerGetClientAddress(int connectionId)
{
return available.ServerGetClientAddress(connectionId);
}
public override bool ServerDisconnect(int connectionId)
{
return available.ServerDisconnect(connectionId);
}
public override void ServerSend(int connectionId, int channelId, ArraySegment<byte> segment)
{
available.ServerSend(connectionId, channelId, segment);
}
public override void ServerStart()
{
available.ServerStart();
}
public override void ServerStop()
{
available.ServerStop();
}
public override void Shutdown()
{
available.Shutdown();
}
public override int GetMaxPacketSize(int channelId = 0)
{
// finding the max packet size in a fallback environment has to be
// done very carefully:
// * servers and clients might run different transports depending on
// which platform they are on.
// * there should only ever be ONE true max packet size for everyone,
// otherwise a spawn message might be sent to all tcp sockets, but
// be too big for some udp sockets. that would be a debugging
// nightmare and allow for possible exploits and players on
// different platforms seeing a different game state.
// => the safest solution is to use the smallest max size for all
// transports. that will never fail.
int mininumAllowedSize = int.MaxValue;
foreach (Transport transport in transports)
{
int size = transport.GetMaxPacketSize(channelId);
mininumAllowedSize = Mathf.Min(size, mininumAllowedSize);
}
return mininumAllowedSize;
}
public override string ToString()
{
return available.ToString();
}
}
}