mirror of
https://github.com/Steffo99/better-tee.git
synced 2024-11-29 09:54:18 +00:00
324 lines
12 KiB
C#
324 lines
12 KiB
C#
|
// Coburn: LLAPI is not available on UWP. There are a lot of compile directives here that we're checking against.
|
||
|
// Checking all of them may be overkill, but it's better to cover all the possible UWP directives. Sourced from
|
||
|
// https://docs.unity3d.com/Manual/PlatformDependentCompilation.html
|
||
|
// TODO: Check if LLAPI is supported on Xbox One?
|
||
|
|
||
|
// LLAPITransport wraps UNET's LLAPI for use as a HLAPI TransportLayer, only if you're not on a UWP platform.
|
||
|
#if !(UNITY_WSA || UNITY_WSA_10_0 || UNITY_WINRT || UNITY_WINRT_10_0 || NETFX_CORE)
|
||
|
|
||
|
using System;
|
||
|
using System.ComponentModel;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Networking;
|
||
|
using UnityEngine.Networking.Types;
|
||
|
|
||
|
namespace Mirror
|
||
|
{
|
||
|
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("LLAPI is obsolete and will be removed from future versions of Unity")]
|
||
|
public class LLAPITransport : Transport
|
||
|
{
|
||
|
public ushort port = 7777;
|
||
|
|
||
|
[Tooltip("Enable for WebGL games. Can only do either WebSockets or regular Sockets, not both (yet).")]
|
||
|
public bool useWebsockets;
|
||
|
|
||
|
// settings copied from uMMORPG configuration for best results
|
||
|
public ConnectionConfig connectionConfig = new ConnectionConfig
|
||
|
{
|
||
|
PacketSize = 1500,
|
||
|
FragmentSize = 500,
|
||
|
ResendTimeout = 1200,
|
||
|
DisconnectTimeout = 6000,
|
||
|
ConnectTimeout = 6000,
|
||
|
MinUpdateTimeout = 1,
|
||
|
PingTimeout = 2000,
|
||
|
ReducedPingTimeout = 100,
|
||
|
AllCostTimeout = 20,
|
||
|
NetworkDropThreshold = 80,
|
||
|
OverflowDropThreshold = 80,
|
||
|
MaxConnectionAttempt = 10,
|
||
|
AckDelay = 33,
|
||
|
SendDelay = 10,
|
||
|
MaxCombinedReliableMessageSize = 100,
|
||
|
MaxCombinedReliableMessageCount = 10,
|
||
|
MaxSentMessageQueueSize = 512,
|
||
|
AcksType = ConnectionAcksType.Acks128,
|
||
|
InitialBandwidth = 0,
|
||
|
BandwidthPeakFactor = 2,
|
||
|
WebSocketReceiveBufferMaxSize = 0,
|
||
|
UdpSocketReceiveBufferMaxSize = 0
|
||
|
};
|
||
|
|
||
|
// settings copied from uMMORPG configuration for best results
|
||
|
public GlobalConfig globalConfig = new GlobalConfig
|
||
|
{
|
||
|
ReactorModel = ReactorModel.SelectReactor,
|
||
|
ThreadAwakeTimeout = 1,
|
||
|
ReactorMaximumSentMessages = 4096,
|
||
|
ReactorMaximumReceivedMessages = 4096,
|
||
|
MaxPacketSize = 2000,
|
||
|
MaxHosts = 16,
|
||
|
ThreadPoolSize = 3,
|
||
|
MinTimerTimeout = 1,
|
||
|
MaxTimerTimeout = 12000
|
||
|
};
|
||
|
|
||
|
readonly int channelId; // always use first channel
|
||
|
byte error;
|
||
|
|
||
|
int clientId = -1;
|
||
|
int clientConnectionId = -1;
|
||
|
readonly byte[] clientReceiveBuffer = new byte[4096];
|
||
|
|
||
|
int serverHostId = -1;
|
||
|
readonly byte[] serverReceiveBuffer = new byte[4096];
|
||
|
|
||
|
void OnValidate()
|
||
|
{
|
||
|
// add connectionconfig channels if none
|
||
|
if (connectionConfig.Channels.Count == 0)
|
||
|
{
|
||
|
// channel 0 is reliable fragmented sequenced
|
||
|
connectionConfig.AddChannel(QosType.ReliableFragmentedSequenced);
|
||
|
// channel 1 is unreliable
|
||
|
connectionConfig.AddChannel(QosType.Unreliable);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Awake()
|
||
|
{
|
||
|
NetworkTransport.Init(globalConfig);
|
||
|
Debug.Log("LLAPITransport initialized!");
|
||
|
}
|
||
|
|
||
|
#region client
|
||
|
public override bool ClientConnected()
|
||
|
{
|
||
|
return clientConnectionId != -1;
|
||
|
}
|
||
|
|
||
|
public override void ClientConnect(string address)
|
||
|
{
|
||
|
// LLAPI can't handle 'localhost'
|
||
|
if (address.ToLower() == "localhost") address = "127.0.0.1";
|
||
|
|
||
|
HostTopology hostTopology = new HostTopology(connectionConfig, 1);
|
||
|
|
||
|
// important:
|
||
|
// AddHost(topology) doesn't work in WebGL.
|
||
|
// AddHost(topology, port) works in standalone and webgl if port=0
|
||
|
clientId = NetworkTransport.AddHost(hostTopology, 0);
|
||
|
|
||
|
clientConnectionId = NetworkTransport.Connect(clientId, address, port, 0, out error);
|
||
|
NetworkError networkError = (NetworkError)error;
|
||
|
if (networkError != NetworkError.Ok)
|
||
|
{
|
||
|
Debug.LogWarning("NetworkTransport.Connect failed: clientId=" + clientId + " address= " + address + " port=" + port + " error=" + error);
|
||
|
clientConnectionId = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool ClientSend(int channelId, byte[] data)
|
||
|
{
|
||
|
return NetworkTransport.Send(clientId, clientConnectionId, channelId, data, data.Length, out error);
|
||
|
}
|
||
|
|
||
|
public bool ProcessClientMessage()
|
||
|
{
|
||
|
if (clientId == -1) return false;
|
||
|
|
||
|
NetworkEventType networkEvent = NetworkTransport.ReceiveFromHost(clientId, out int connectionId, out int channel, clientReceiveBuffer, clientReceiveBuffer.Length, out int receivedSize, out error);
|
||
|
|
||
|
// note: 'error' is used for extra information, e.g. the reason for
|
||
|
// a disconnect. we don't necessarily have to throw an error if
|
||
|
// error != 0. but let's log it for easier debugging.
|
||
|
//
|
||
|
// DO NOT return after error != 0. otherwise Disconnect won't be
|
||
|
// registered.
|
||
|
NetworkError networkError = (NetworkError)error;
|
||
|
if (networkError != NetworkError.Ok)
|
||
|
{
|
||
|
string message = "NetworkTransport.Receive failed: hostid=" + clientId + " connId=" + connectionId + " channelId=" + channel + " error=" + networkError;
|
||
|
OnClientError.Invoke(new Exception(message));
|
||
|
}
|
||
|
|
||
|
// raise events
|
||
|
switch (networkEvent)
|
||
|
{
|
||
|
case NetworkEventType.ConnectEvent:
|
||
|
OnClientConnected.Invoke();
|
||
|
break;
|
||
|
case NetworkEventType.DataEvent:
|
||
|
ArraySegment<byte> data = new ArraySegment<byte>(clientReceiveBuffer, 0, receivedSize);
|
||
|
OnClientDataReceived.Invoke(data);
|
||
|
break;
|
||
|
case NetworkEventType.DisconnectEvent:
|
||
|
OnClientDisconnected.Invoke();
|
||
|
break;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public string ClientGetAddress()
|
||
|
{
|
||
|
NetworkTransport.GetConnectionInfo(serverHostId, clientId, out string address, out int port, out NetworkID networkId, out NodeID node, out error);
|
||
|
return address;
|
||
|
}
|
||
|
|
||
|
public override void ClientDisconnect()
|
||
|
{
|
||
|
if (clientId != -1)
|
||
|
{
|
||
|
NetworkTransport.RemoveHost(clientId);
|
||
|
clientId = -1;
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region server
|
||
|
public override bool ServerActive()
|
||
|
{
|
||
|
return serverHostId != -1;
|
||
|
}
|
||
|
|
||
|
public override void ServerStart()
|
||
|
{
|
||
|
if (useWebsockets)
|
||
|
{
|
||
|
HostTopology topology = new HostTopology(connectionConfig, ushort.MaxValue - 1);
|
||
|
serverHostId = NetworkTransport.AddWebsocketHost(topology, port);
|
||
|
//Debug.Log("LLAPITransport.ServerStartWebsockets port=" + port + " max=" + maxConnections + " hostid=" + serverHostId);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HostTopology topology = new HostTopology(connectionConfig, ushort.MaxValue - 1);
|
||
|
serverHostId = NetworkTransport.AddHost(topology, port);
|
||
|
//Debug.Log("LLAPITransport.ServerStart port=" + port + " max=" + maxConnections + " hostid=" + serverHostId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool ServerSend(int connectionId, int channelId, byte[] data)
|
||
|
{
|
||
|
return NetworkTransport.Send(serverHostId, connectionId, channelId, data, data.Length, out error);
|
||
|
}
|
||
|
|
||
|
public bool ProcessServerMessage()
|
||
|
{
|
||
|
if (serverHostId == -1) return false;
|
||
|
|
||
|
NetworkEventType networkEvent = NetworkTransport.ReceiveFromHost(serverHostId, out int connectionId, out int channel, serverReceiveBuffer, serverReceiveBuffer.Length, out int receivedSize, out error);
|
||
|
|
||
|
// note: 'error' is used for extra information, e.g. the reason for
|
||
|
// a disconnect. we don't necessarily have to throw an error if
|
||
|
// error != 0. but let's log it for easier debugging.
|
||
|
//
|
||
|
// DO NOT return after error != 0. otherwise Disconnect won't be
|
||
|
// registered.
|
||
|
NetworkError networkError = (NetworkError)error;
|
||
|
if (networkError != NetworkError.Ok)
|
||
|
{
|
||
|
string message = "NetworkTransport.Receive failed: hostid=" + serverHostId + " connId=" + connectionId + " channelId=" + channel + " error=" + networkError;
|
||
|
|
||
|
// TODO write a TransportException or better
|
||
|
OnServerError.Invoke(connectionId, new Exception(message));
|
||
|
}
|
||
|
|
||
|
// LLAPI client sends keep alive messages (75-6C-6C) on channel=110.
|
||
|
// ignore all messages that aren't for our selected channel.
|
||
|
/*if (channel != channelId)
|
||
|
{
|
||
|
return false;
|
||
|
}*/
|
||
|
|
||
|
switch (networkEvent)
|
||
|
{
|
||
|
case NetworkEventType.ConnectEvent:
|
||
|
OnServerConnected.Invoke(connectionId);
|
||
|
break;
|
||
|
case NetworkEventType.DataEvent:
|
||
|
ArraySegment<byte> data = new ArraySegment<byte>(serverReceiveBuffer, 0, receivedSize);
|
||
|
OnServerDataReceived.Invoke(connectionId, data);
|
||
|
break;
|
||
|
case NetworkEventType.DisconnectEvent:
|
||
|
OnServerDisconnected.Invoke(connectionId);
|
||
|
break;
|
||
|
default:
|
||
|
// nothing or a message we don't recognize
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override bool ServerDisconnect(int connectionId)
|
||
|
{
|
||
|
return NetworkTransport.Disconnect(serverHostId, connectionId, out error);
|
||
|
}
|
||
|
|
||
|
public override string ServerGetClientAddress(int connectionId)
|
||
|
{
|
||
|
NetworkTransport.GetConnectionInfo(serverHostId, connectionId, out string address, out int port, out NetworkID networkId, out NodeID node, out error);
|
||
|
return address;
|
||
|
}
|
||
|
|
||
|
public override void ServerStop()
|
||
|
{
|
||
|
NetworkTransport.RemoveHost(serverHostId);
|
||
|
serverHostId = -1;
|
||
|
Debug.Log("LLAPITransport.ServerStop");
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region common
|
||
|
// IMPORTANT: set script execution order to >1000 to call Transport's
|
||
|
// LateUpdate after all others. Fixes race condition where
|
||
|
// e.g. in uSurvival Transport would apply Cmds before
|
||
|
// ShoulderRotation.LateUpdate, resulting in projectile
|
||
|
// spawns at the point before shoulder rotation.
|
||
|
public void LateUpdate()
|
||
|
{
|
||
|
// process all messages
|
||
|
while (ProcessClientMessage()) {}
|
||
|
while (ProcessServerMessage()) {}
|
||
|
}
|
||
|
|
||
|
public override bool Available()
|
||
|
{
|
||
|
// websocket is available in all platforms (including webgl)
|
||
|
return useWebsockets || base.Available();
|
||
|
}
|
||
|
|
||
|
public override void Shutdown()
|
||
|
{
|
||
|
NetworkTransport.Shutdown();
|
||
|
serverHostId = -1;
|
||
|
clientConnectionId = -1;
|
||
|
Debug.Log("LLAPITransport.Shutdown");
|
||
|
}
|
||
|
|
||
|
public override int GetMaxPacketSize(int channelId)
|
||
|
{
|
||
|
return globalConfig.MaxPacketSize;
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
if (ServerActive())
|
||
|
{
|
||
|
return "LLAPI Server port: " + port;
|
||
|
}
|
||
|
else if (ClientConnected())
|
||
|
{
|
||
|
string ip = ClientGetAddress();
|
||
|
return "LLAPI Client ip: " + ip + " port: " + port;
|
||
|
}
|
||
|
return "LLAPI (inactive/disconnected)";
|
||
|
}
|
||
|
#endregion
|
||
|
}
|
||
|
}
|
||
|
#endif
|