Custom Inspector

This commit is contained in:
Derek S 2021-04-05 20:03:42 -05:00
parent c9ea1a03cc
commit 69682453be
5 changed files with 296 additions and 10 deletions

View file

@ -110,6 +110,7 @@ namespace LightReflectiveMirror
_NATRequestPosition = 0; _NATRequestPosition = 0;
_NATRequest.WriteByte(ref _NATRequestPosition, (byte)OpCodes.RequestNATConnection); _NATRequest.WriteByte(ref _NATRequestPosition, (byte)OpCodes.RequestNATConnection);
_NATRequest.WriteString(ref _NATRequestPosition, natID); _NATRequest.WriteString(ref _NATRequestPosition, natID);
_NATRequest.WriteInt(ref _NATRequestPosition, conf.NATPunchtroughPort);
transport.ServerSend(clientID, 0, new ArraySegment<byte>(_NATRequest, 0, _NATRequestPosition)); transport.ServerSend(clientID, 0, new ArraySegment<byte>(_NATRequest, 0, _NATRequestPosition));
} }
}; };

View file

@ -0,0 +1,245 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Net;
using System.Reflection;
using System.Linq;
using Mirror;
using Mirror.SimpleWeb;
using System;
using kcp2k;
namespace LightReflectiveMirror
{
[CustomEditor(typeof(LightReflectiveMirrorTransport))]
public class LRMInspector : Editor
{
int serverPort = 7070;
string serverIP;
float invalidServerIP = 0;
bool usingLLB = false;
LRMDirectConnectModule directModule;
string[] tabs = new string[] { "LRM Settings", "NAT Punch", "Load Balancer", "Other" };
int currentTab = 0;
Type[] supportedTransports = new Type[3] { typeof(KcpTransport), typeof(SimpleWebTransport), typeof(TelepathyTransport) };
public override void OnInspectorGUI()
{
var lrm = (LightReflectiveMirrorTransport)target;
directModule = lrm.GetComponent<LRMDirectConnectModule>();
if (string.IsNullOrEmpty(lrm.loadBalancerAddress))
{
// First setup screen, ask if they are using LLB or just a single LRM node.
EditorGUILayout.HelpBox("Thank you for using LRM!\nTo get started, please select which setup you are using.", MessageType.None);
if (GUILayout.Button("Load Balancer Setup"))
{
usingLLB = true;
lrm.loadBalancerAddress = "127.0.0.1";
}
if (GUILayout.Button("Single LRM Node Setup"))
{
lrm.loadBalancerAddress = "127.0.0.1";
lrm.useLoadBalancer = false;
usingLLB = false;
}
}
else if (usingLLB)
{
// They said they are using LLB, configure it!
EditorGUILayout.HelpBox("The Load Balancer is another server that is different than the LRM node. Please enter the IP address or domain name of your Load Balancer server, along with the port.", MessageType.None);
EditorGUILayout.HelpBox("Acceptable Examples: 127.0.0.1, mydomain.com", MessageType.Info);
if (Time.realtimeSinceStartup - invalidServerIP < 5)
EditorGUILayout.HelpBox("Invalid Server Address!", MessageType.Error);
serverIP = EditorGUILayout.TextField("Server Address", serverIP);
serverPort = Mathf.Clamp(EditorGUILayout.IntField("Server Port", serverPort), ushort.MinValue, ushort.MaxValue);
if (GUILayout.Button("Continue"))
{
if (IPAddress.TryParse(serverIP, out IPAddress serverAddr))
{
lrm.loadBalancerAddress = serverAddr.ToString();
lrm.loadBalancerPort = (ushort)serverPort;
lrm.serverIP = "127.0.0.1";
usingLLB = false;
serverIP = "";
}
else
{
try
{
if (Dns.GetHostEntry(serverIP).AddressList.Length > 0)
{
lrm.loadBalancerAddress = serverIP;
lrm.loadBalancerPort = (ushort)serverPort;
lrm.serverIP = "127.0.0.1";
usingLLB = false;
serverIP = "";
}
else
invalidServerIP = Time.realtimeSinceStartup;
}
catch
{
invalidServerIP = Time.realtimeSinceStartup;
}
}
}
}
else if (lrm.clientToServerTransport == null)
{
// next up, the actual transport. We are going to loop over all the transport types here and let them select one.
EditorGUILayout.HelpBox("We need to use the same transport used on the server. Please select the same transport used on your LRM Node(s)", MessageType.None);
foreach (var transport in supportedTransports)
{
if (GUILayout.Button(transport.Name))
{
var newTransportGO = new GameObject("LRM - Connector");
newTransportGO.transform.SetParent(lrm.transform);
var newTransport = newTransportGO.AddComponent(transport);
lrm.clientToServerTransport = (Transport)newTransport;
}
}
}
else if (string.IsNullOrEmpty(lrm.serverIP))
{
// Empty server IP, this is pretty important! Lets show the UI to require it.
EditorGUILayout.HelpBox("For a single LRM node setup, we need the IP address or domain name of your LRM server.", MessageType.None);
EditorGUILayout.HelpBox("Acceptable Examples: 127.0.0.1, mydomain.com", MessageType.Info);
if (Time.realtimeSinceStartup - invalidServerIP < 5)
EditorGUILayout.HelpBox("Invalid Server Address!", MessageType.Error);
serverIP = EditorGUILayout.TextField("Server Address", serverIP);
serverPort = Mathf.Clamp(EditorGUILayout.IntField("Server Port", serverPort), ushort.MinValue, ushort.MaxValue);
if (GUILayout.Button("Continue"))
{
if (IPAddress.TryParse(serverIP, out IPAddress serverAddr))
{
lrm.serverIP = serverAddr.ToString();
lrm.SetTransportPort((ushort)serverPort);
}
else
{
try
{
if (Dns.GetHostEntry(serverIP).AddressList.Length > 0)
{
lrm.serverIP = serverIP;
lrm.SetTransportPort((ushort)serverPort);
}
else
invalidServerIP = Time.realtimeSinceStartup;
}
catch
{
invalidServerIP = Time.realtimeSinceStartup;
}
}
}
}
else if(lrm.NATPunchtroughPort < 0)
{
// NAT Punchthrough configuration.
EditorGUILayout.HelpBox("Do you wish to use NAT Punchthrough? This can reduce load by up to 80% on your LRM nodes, but exposes players IP's to other players.", MessageType.None);
if(GUILayout.Button("Use NAT Punchthrough"))
{
lrm.NATPunchtroughPort = 1;
lrm.useNATPunch = true;
lrm.gameObject.AddComponent<LRMDirectConnectModule>();
}
if(GUILayout.Button("Do NOT use NAT Punchthrough"))
lrm.NATPunchtroughPort = 1;
}else if(directModule != null && directModule.directConnectTransport == null)
{
// NAT Punchthrough setup.
EditorGUILayout.HelpBox("To use direct connecting, we need a transport to communicate with the other clients. Please select a transport to use.", MessageType.None);
foreach (var transport in supportedTransports)
{
if (lrm.useNATPunch && transport != typeof(KcpTransport))
continue;
if (GUILayout.Button(transport.Name))
{
var newTransportGO = new GameObject("LRM - Direct Connect");
newTransportGO.transform.SetParent(lrm.transform);
var newTransport = newTransportGO.AddComponent(transport);
directModule.directConnectTransport = (Transport)newTransport;
}
}
}
else
{
// They have completed the "setup guide" Show them the main UI
currentTab = GUILayout.Toolbar(currentTab, tabs);
EditorGUILayout.Space();
switch (currentTab)
{
case 0:
// They are in the LRM Settings tab.
if (lrm.useLoadBalancer)
{
EditorGUILayout.HelpBox("While using a Load Balancer, you don't set the LRM node IP or port.", MessageType.Info);
GUI.enabled = false;
}
lrm.serverIP = EditorGUILayout.TextField("LRM Node IP", lrm.serverIP);
lrm.endpointServerPort = (ushort)Mathf.Clamp(EditorGUILayout.IntField("Endpoint Port", lrm.endpointServerPort), ushort.MinValue, ushort.MaxValue);
if (lrm.useLoadBalancer)
{
GUI.enabled = true;
}
lrm.authenticationKey = EditorGUILayout.TextField("LRM Auth Key", lrm.authenticationKey);
lrm.heartBeatInterval = EditorGUILayout.Slider("Heartbeat Time", lrm.heartBeatInterval, 0.1f, 5f);
lrm.connectOnAwake = EditorGUILayout.Toggle("Connect on Awake", lrm.connectOnAwake);
lrm.clientToServerTransport = (Transport)EditorGUILayout.ObjectField("LRM Transport", lrm.clientToServerTransport, typeof(Transport), true);
break;
case 1:
// NAT punch tab.
if(directModule == null)
{
EditorGUILayout.HelpBox("If you wish to use NAT punch, you will need to add a \"Direct Connect Module\" to this gameobject.", MessageType.Info);
}
else
{
lrm.useNATPunch = EditorGUILayout.Toggle("Use NAT Punch", lrm.useNATPunch);
directModule.directConnectTransport = (Transport)EditorGUILayout.ObjectField("Direct Transport", directModule.directConnectTransport, typeof(Transport), true);
}
break;
case 2:
// Load balancer tab
lrm.useLoadBalancer = EditorGUILayout.Toggle("Use Load Balancer", lrm.useLoadBalancer);
lrm.loadBalancerAddress = EditorGUILayout.TextField("Load Balancer Address", lrm.loadBalancerAddress);
lrm.loadBalancerPort = (ushort)Mathf.Clamp(EditorGUILayout.IntField("Load Balancer Port", lrm.endpointServerPort), ushort.MinValue, ushort.MaxValue);
break;
case 3:
// Other tab...
//EditorGUIUtility.LookLikeControls();
lrm.serverName = EditorGUILayout.TextField("Server Name", lrm.serverName);
lrm.extraServerData = EditorGUILayout.TextField("Extra Server Data", lrm.extraServerData);
lrm.maxServerPlayers = EditorGUILayout.IntField("Max Server Players", lrm.maxServerPlayers);
lrm.isPublicServer = EditorGUILayout.Toggle("Is Public Server", lrm.isPublicServer);
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(serializedObject.FindProperty("diconnectedFromRelay"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("serverListUpdated"));
break;
}
}
}
}
}

18
UnityTransport/LRM.asmdef Normal file
View file

@ -0,0 +1,18 @@
{
"name": "LRM",
"references": [
"GUID:30817c1a0e6d646d99c048fc403f5979",
"GUID:3b5390adca4e2bb4791cb930316d6f3e",
"GUID:725ee7191c021de4dbf9269590ded755",
"GUID:6806a62c384838046a3c66c44f06d75f"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View file

@ -9,6 +9,7 @@ using LightReflectiveMirror;
[RequireComponent(typeof(LightReflectiveMirrorTransport))] [RequireComponent(typeof(LightReflectiveMirrorTransport))]
public class LRMDirectConnectModule : MonoBehaviour public class LRMDirectConnectModule : MonoBehaviour
{ {
[HideInInspector]
public Transport directConnectTransport; public Transport directConnectTransport;
public bool showDebugLogs; public bool showDebugLogs;
private LightReflectiveMirrorTransport lightMirrorTransport; private LightReflectiveMirrorTransport lightMirrorTransport;

View file

@ -1,4 +1,6 @@
using kcp2k;
using Mirror; using Mirror;
using Mirror.SimpleWeb;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections; using System.Collections;
@ -17,7 +19,7 @@ namespace LightReflectiveMirror
{ {
[Header("Connection Variables")] [Header("Connection Variables")]
public Transport clientToServerTransport; public Transport clientToServerTransport;
public string serverIP = "34.67.125.123"; public string serverIP = null;
public ushort endpointServerPort = 8080; public ushort endpointServerPort = 8080;
public float heartBeatInterval = 3; public float heartBeatInterval = 3;
public bool connectOnAwake = true; public bool connectOnAwake = true;
@ -26,13 +28,13 @@ namespace LightReflectiveMirror
[Header("NAT Punchthrough")] [Header("NAT Punchthrough")]
[Help("NAT Punchthrough will require the Direct Connect module attached.")] [Help("NAT Punchthrough will require the Direct Connect module attached.")]
public bool useNATPunch = true; public bool useNATPunch = false;
public ushort NATPunchtroughPort = 7776; public int NATPunchtroughPort = -1;
[Header("Load Balancer")] [Header("Load Balancer")]
public bool useLoadBalancer = false; public bool useLoadBalancer = false;
public ushort loadBalancerPort = 7070; public ushort loadBalancerPort = 7070;
public string loadBalancerAddress = "127.0.0.1"; public string loadBalancerAddress = null;
[Header("Server Hosting Data")] [Header("Server Hosting Data")]
public string serverName = "My awesome server!"; public string serverName = "My awesome server!";
@ -425,17 +427,24 @@ namespace LightReflectiveMirror
case OpCodes.RequestNATConnection: case OpCodes.RequestNATConnection:
if (GetLocalIp() != null && _directConnectModule != null) if (GetLocalIp() != null && _directConnectModule != null)
{ {
_NATPuncher = new UdpClient { ExclusiveAddressUse = false };
_NATIP = new IPEndPoint(IPAddress.Parse(GetLocalIp()), UnityEngine.Random.Range(16000, 17000));
_NATPuncher.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_NATPuncher.Client.Bind(_NATIP);
_relayPuncherIP = new IPEndPoint(IPAddress.Parse(serverIP), NATPunchtroughPort);
byte[] initalData = new byte[150]; byte[] initalData = new byte[150];
int sendPos = 0; int sendPos = 0;
initalData.WriteBool(ref sendPos, true); initalData.WriteBool(ref sendPos, true);
initalData.WriteString(ref sendPos, data.ReadString(ref pos)); initalData.WriteString(ref sendPos, data.ReadString(ref pos));
NATPunchtroughPort = data.ReadInt(ref pos);
_NATPuncher = new UdpClient { ExclusiveAddressUse = false };
_NATIP = new IPEndPoint(IPAddress.Parse(GetLocalIp()), UnityEngine.Random.Range(16000, 17000));
_NATPuncher.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_NATPuncher.Client.Bind(_NATIP);
IPAddress serverAddr;
if (!IPAddress.TryParse(serverIP, out serverAddr))
serverAddr = Dns.GetHostEntry(serverIP).AddressList[0];
_relayPuncherIP = new IPEndPoint(IPAddress.Parse(serverIP), NATPunchtroughPort);
// Send 3 to lower chance of it being dropped or corrupted when received on server. // Send 3 to lower chance of it being dropped or corrupted when received on server.
_NATPuncher.Send(initalData, sendPos, _relayPuncherIP); _NATPuncher.Send(initalData, sendPos, _relayPuncherIP);
@ -449,6 +458,18 @@ namespace LightReflectiveMirror
catch (Exception e) { print(e); } catch (Exception e) { print(e); }
} }
public void SetTransportPort(ushort port)
{
if (clientToServerTransport is KcpTransport kcp)
kcp.Port = port;
if (clientToServerTransport is TelepathyTransport telepathy)
telepathy.port = port;
if (clientToServerTransport is SimpleWebTransport swt)
swt.port = port;
}
IEnumerator GetServerList() IEnumerator GetServerList()
{ {
string uri = $"http://{serverIP}:{endpointServerPort}/api/compressed/servers"; string uri = $"http://{serverIP}:{endpointServerPort}/api/compressed/servers";