Decompiled source of FusionNetworkingPlus v1.0.0

Mods/FNPlus.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using FNPlus;
using FNPlus.Network;
using FNPlus.Patches;
using FNPlus.Utilities;
using HarmonyLib;
using Il2CppOculus.Platform;
using Il2CppOculus.Platform.Models;
using Il2CppTMPro;
using LabFusion.Data;
using LabFusion.Menu;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Senders;
using LabFusion.Utilities;
using LabFusion.Voice;
using LabFusion.Voice.Unity;
using MelonLoader;
using Microsoft.CodeAnalysis;
using Riptide;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: Guid("490e160d-251d-4ab4-a3bb-f473961ff8a1")]
[assembly: AssemblyTitle("FNPlus")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: MelonInfo(typeof(Mod), "FNPlus", "1.0.0", "KitchenBoy", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPriority(-1000000)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FNPlus
{
	internal class Mod : MelonMod
	{
		internal const string Name = "FNPlus";

		internal const string Description = "An addon for Fusion offering more Networking options!";

		internal const string Author = "KitchenBoy";

		internal const string Company = "SilverWare";

		internal const string Version = "1.0.0";

		internal const string DownloadLink = "Link";

		public override void OnInitializeMelon()
		{
			NetStandardLoader.Load();
			RiptideNetworkingLoader.Load();
			NetworkLayer.RegisterLayersFromAssembly(Assembly.GetExecutingAssembly());
			((MelonBase)this).LoggerInstance.Msg("FNPlus Initialized!");
		}

		public override void OnLateInitializeMelon()
		{
			PlayerInfo.Initialize();
		}
	}
}
namespace FNPlus.Utilities
{
	internal class NetStandardLoader
	{
		internal static void Load()
		{
			string path = PersistentData.GetPath("netstandard.dll");
			File.WriteAllBytes(path, EmbeddedResource.LoadFromAssembly(Assembly.GetExecutingAssembly(), "FNPlus.Resources.lib.netstandard.dll"));
			MelonAssembly.LoadMelonAssembly(path, true);
		}
	}
	internal static class ResourcePaths
	{
		internal const string RiptideNetworkingPath = "FNPlus.Resources.lib.RiptideNetworking.dll";

		internal const string netstandardPath = "FNPlus.Resources.lib.netstandard.dll";
	}
	internal class RiptideNetworkingLoader
	{
		internal static void Load()
		{
			string path = PersistentData.GetPath("RiptideNetworking.dll");
			File.WriteAllBytes(path, EmbeddedResource.LoadFromAssembly(Assembly.GetExecutingAssembly(), "FNPlus.Resources.lib.RiptideNetworking.dll"));
			MelonAssembly.LoadMelonAssembly(path, true);
		}
	}
	internal class IPUtils
	{
		private static string key = "1234567812345678";

		internal static string EncodeIPAddress(string decodedIP)
		{
			try
			{
				using Aes aes = Aes.Create();
				aes.Key = Encoding.UTF8.GetBytes(key);
				aes.IV = new byte[16];
				ICryptoTransform cryptoTransform = aes.CreateEncryptor(aes.Key, aes.IV);
				byte[] bytes = Encoding.UTF8.GetBytes(decodedIP);
				return Convert.ToBase64String(cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length));
			}
			catch
			{
				return string.Empty;
			}
		}

		internal static string DecodeIPAddress(string encodedIP)
		{
			try
			{
				byte[] array = Convert.FromBase64String(encodedIP);
				using Aes aes = Aes.Create();
				aes.Key = Encoding.UTF8.GetBytes(key);
				aes.IV = new byte[16];
				byte[] bytes = aes.CreateDecryptor(aes.Key, aes.IV).TransformFinalBlock(array, 0, array.Length);
				return Encoding.UTF8.GetString(bytes);
			}
			catch
			{
				return string.Empty;
			}
		}
	}
	public class PlayerInfo
	{
		public static string PlayerIpAddress { get; private set; } = "Unknown";


		internal static void Initialize()
		{
			PlayerIpAddress = GetPlayerIPAddress();
			SetupPlayerUsername();
		}

		private static void SetupPlayerUsername()
		{
			if (Path.GetFileName(Application.dataPath) == "BONELAB_Steam_Windows64_Data")
			{
				if (!SteamClient.IsValid)
				{
					SteamClient.Init(250820u, false);
				}
				LocalPlayer.Username = SteamClient.Name;
				SteamClient.Shutdown();
			}
			if (!PlatformHelper.IsAndroid)
			{
				Core.Initialize("5088709007839657");
			}
			else
			{
				Core.Initialize("4215734068529064");
			}
			Users.GetLoggedInUser().OnComplete(Callback<User>.op_Implicit((Action<Message<User>>)OnComplete));
			static void OnComplete(Message<User> msg)
			{
				LocalPlayer.Username = msg.Data.OculusID;
			}
		}

		private static string GetPlayerIPAddress()
		{
			try
			{
				string uriString = "https://api.ipify.org";
				HttpClient httpClient = new HttpClient(new HttpClientHandler
				{
					ClientCertificateOptions = ClientCertificateOption.Manual,
					ServerCertificateCustomValidationCallback = (HttpRequestMessage _, X509Certificate2? _, X509Chain? _, SslPolicyErrors _) => true
				});
				HttpRequestMessage request = new HttpRequestMessage
				{
					RequestUri = new Uri(uriString),
					Method = HttpMethod.Get
				};
				return httpClient.Send(request).Content.ReadAsStringAsync().Result;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error when fetching IP address:");
				MelonLogger.Error((object)ex);
				return string.Empty;
			}
		}
	}
}
namespace FNPlus.Patches
{
	[HarmonyPatch(typeof(MenuMatchmaking))]
	public class MenuMatchmakingPatches
	{
		private static Transform _cachedOptionsTransform;

		[HarmonyPostfix]
		[HarmonyPatch("PopulateOptions")]
		public static void PopulateOptionsPost(Transform optionsTransform)
		{
			_cachedOptionsTransform = optionsTransform;
			if (NetworkLayerDeterminer.LoadedTitle == "Riptide")
			{
				RiptideNetworkLayer.CreateRiptideUIElements();
			}
		}

		internal static void HideOptions()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_cachedOptionsTransform == (Object)null))
			{
				Transform obj = _cachedOptionsTransform.Find("grid_Options");
				((Component)obj.Find("button_Gamemode")).gameObject.SetActive(false);
				((Component)obj.Find("button_Sandbox")).gameObject.SetActive(false);
				((Component)obj.Find("button_Browse")).gameObject.SetActive(false);
				((Transform)((Component)obj.Find("button_Code")).GetComponent<RectTransform>()).localPosition = new Vector3(400f, -122f, 0f);
			}
		}

		internal static void ShowOptions()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_cachedOptionsTransform == (Object)null))
			{
				Transform obj = _cachedOptionsTransform.Find("grid_Options");
				((Component)obj.Find("button_Gamemode")).gameObject.SetActive(true);
				((Component)obj.Find("button_Sandbox")).gameObject.SetActive(true);
				((Component)obj.Find("button_Browse")).gameObject.SetActive(true);
				((Transform)((Component)obj.Find("button_Code")).GetComponent<RectTransform>()).localPosition = new Vector3(691f, -122f, 0f);
			}
		}
	}
}
namespace FNPlus.Network
{
	public class RiptideNetworkLayer : NetworkLayer
	{
		private IVoiceManager _voiceManager;

		private static Transform pingDisplayTransform = null;

		internal static TMP_Text PingDisplayTMP = null;

		internal static readonly ConcurrentQueue<Tuple<byte[], bool>> MessageQueue = new ConcurrentQueue<Tuple<byte[], bool>>();

		internal static readonly ConcurrentQueue<Action> ActionQueue = new ConcurrentQueue<Action>();

		public override string Title => "Riptide";

		public override IVoiceManager VoiceManager => _voiceManager;

		public override bool IsServer => RiptideThreader.IsServerRunning;

		public override bool IsClient => RiptideThreader.IsClientConnected;

		public string ServerCode { get; private set; }

		public override bool CheckSupported()
		{
			return true;
		}

		public override bool CheckValidation()
		{
			return true;
		}

		public override string GetUsername(ulong userId)
		{
			return $"Riptide Enjoyer {userId}";
		}

		public override bool IsFriend(ulong userId)
		{
			return false;
		}

		public override void LogIn()
		{
			((NetworkLayer)this).InvokeLoggedInEvent();
		}

		public override void LogOut()
		{
			((NetworkLayer)this).InvokeLoggedOutEvent();
		}

		public override void OnInitializeLayer()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			RiptideThreader.StartThread();
			HookRiptideEvents();
			_voiceManager = (IVoiceManager)new UnityVoiceManager();
			_voiceManager.Enable();
			CreateRiptideUIElements();
		}

		public override void OnDeinitializeLayer()
		{
			_voiceManager.Disable();
			_voiceManager = null;
			((NetworkLayer)this).Disconnect("");
			RiptideThreader.KillThread();
			UnhookRiptideEvents();
			RemoveRiptideUIElements();
		}

		private void HookRiptideEvents()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			MultiplayerHooking.OnPlayerJoin += new PlayerUpdate(OnPlayerJoin);
			MultiplayerHooking.OnPlayerLeave += new PlayerUpdate(OnPlayerLeave);
			MultiplayerHooking.OnDisconnect += new ServerEvent(OnDisconnect);
		}

		private void UnhookRiptideEvents()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			MultiplayerHooking.OnPlayerJoin -= new PlayerUpdate(OnPlayerJoin);
			MultiplayerHooking.OnPlayerLeave -= new PlayerUpdate(OnPlayerLeave);
			MultiplayerHooking.OnDisconnect -= new ServerEvent(OnDisconnect);
		}

		internal static void CreateRiptideUIElements()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			MenuMatchmakingPatches.HideOptions();
			if (!Object.op_Implicit((Object)(object)pingDisplayTransform))
			{
				pingDisplayTransform = Object.Instantiate<Transform>(MenuCreator.MenuGameObject.transform.Find("page_Profile/text_Title"), MenuCreator.MenuGameObject.transform);
				PingDisplayTMP = ((Component)pingDisplayTransform).GetComponent<TMP_Text>();
				pingDisplayTransform.localPosition = new Vector3(-330f, 330f, 0f);
				PingDisplayTMP.text = "PING:";
				((Component)pingDisplayTransform).gameObject.SetActive(true);
			}
			else
			{
				((Component)pingDisplayTransform).gameObject.SetActive(true);
			}
		}

		internal static void RemoveRiptideUIElements()
		{
			MenuMatchmakingPatches.ShowOptions();
			if (Object.op_Implicit((Object)(object)pingDisplayTransform))
			{
				((Component)pingDisplayTransform).gameObject.SetActive(false);
			}
		}

		private void OnPlayerJoin(PlayerId id)
		{
			if (((NetworkLayer)this).VoiceManager != null && !id.IsMe)
			{
				((NetworkLayer)this).VoiceManager.GetSpeaker(id);
			}
		}

		private void OnPlayerLeave(PlayerId id)
		{
			if (((NetworkLayer)this).VoiceManager != null)
			{
				((NetworkLayer)this).VoiceManager.RemoveSpeaker(id);
			}
		}

		private void OnDisconnect()
		{
			((NetworkLayer)this).VoiceManager.ClearManager();
		}

		public override void OnUpdateLayer()
		{
			for (int i = 0; i < MessageQueue.Count; i++)
			{
				if (MessageQueue.TryDequeue(out var result))
				{
					byte[] item = result.Item1;
					bool item2 = result.Item2;
					FusionMessageHandler.ReadMessage((ReadOnlySpan<byte>)item, item2);
				}
			}
			for (int j = 0; j < ActionQueue.Count; j++)
			{
				if (ActionQueue.TryDequeue(out var result2))
				{
					result2();
				}
			}
		}

		public override void StartServer()
		{
			RiptideThreader.StartServer();
		}

		public override void Disconnect(string reason = "")
		{
			RiptideThreader.Disconnect();
		}

		public override string GetServerCode()
		{
			return ServerCode;
		}

		public override void RefreshServerCode()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			ServerCode = IPUtils.EncodeIPAddress(PlayerInfo.PlayerIpAddress);
			GUIUtility.systemCopyBuffer = ServerCode;
			FusionNotifier.Send(new FusionNotification
			{
				SaveToMenu = false,
				Message = NotificationText.op_Implicit("Saved Code to Clipboard!"),
				Type = (NotificationType)0,
				PopupLength = 3f
			});
		}

		public override void JoinServerByCode(string code)
		{
			RiptideThreader.ConnectToServer(code);
		}

		private static MessageSendMode GetSendMode(NetworkChannel channel)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if ((int)channel != 0)
			{
				if ((int)channel == 1)
				{
					return (MessageSendMode)0;
				}
				throw new ArgumentOutOfRangeException("channel", channel, null);
			}
			return (MessageSendMode)7;
		}

		public override void BroadcastMessage(NetworkChannel channel, FusionMessage message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			byte[] item = message.ToByteArray();
			MessageSendMode sendMode = GetSendMode(channel);
			Tuple<byte[], MessageSendMode, ushort, bool> item2 = new Tuple<byte[], MessageSendMode, ushort, bool>(item, sendMode, 0, item4: true);
			RiptideThreader.ServerSendQueue.Enqueue(item2);
		}

		public override void SendFromServer(byte userId, NetworkChannel channel, FusionMessage message)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			PlayerId playerId = PlayerIdManager.GetPlayerId(userId);
			if (playerId != null)
			{
				((NetworkLayer)this).SendFromServer(playerId.LongId, channel, message);
			}
		}

		public override void SendFromServer(ulong userId, NetworkChannel channel, FusionMessage message)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			byte[] item = message.ToByteArray();
			MessageSendMode sendMode = GetSendMode(channel);
			Tuple<byte[], MessageSendMode, ushort, bool> item2 = new Tuple<byte[], MessageSendMode, ushort, bool>(item, sendMode, (ushort)userId, item4: false);
			RiptideThreader.ServerSendQueue.Enqueue(item2);
		}

		public override void SendToServer(NetworkChannel channel, FusionMessage message)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = message.ToByteArray();
			MessageSendMode sendMode = GetSendMode(channel);
			Tuple<byte[], MessageSendMode> item = new Tuple<byte[], MessageSendMode>(array, sendMode);
			if (((NetworkLayer)this).IsServer)
			{
				FusionMessageHandler.ReadMessage((ReadOnlySpan<byte>)array, false);
			}
			else
			{
				RiptideThreader.ClientSendQueue.Enqueue(item);
			}
		}
	}
	internal class RiptideThreader
	{
		private static Thread _riptideThread;

		private static Client _riptideClient;

		private static Server _riptideServer;

		internal static readonly ConcurrentQueue<Tuple<byte[], MessageSendMode>> ClientSendQueue = new ConcurrentQueue<Tuple<byte[], MessageSendMode>>();

		internal static readonly ConcurrentQueue<Tuple<byte[], MessageSendMode, ushort, bool>> ServerSendQueue = new ConcurrentQueue<Tuple<byte[], MessageSendMode, ushort, bool>>();

		private static bool _isThreadAlive = false;

		private static bool _isConnecting;

		internal static bool IsServerRunning { get; private set; }

		internal static bool IsClientConnected { get; private set; }

		internal static void StartThread()
		{
			_riptideThread = new Thread(RiptideThread);
			if (!_riptideThread.IsAlive)
			{
				_isThreadAlive = true;
				_riptideThread.IsBackground = true;
				_riptideThread.Start();
			}
		}

		internal static void KillThread()
		{
			_isThreadAlive = false;
		}

		private static void RiptideThread()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			InitalizeRiptide();
			int num = 0;
			while (_isThreadAlive)
			{
				try
				{
					((Peer)_riptideClient).Update();
					((Peer)_riptideServer).Update();
				}
				catch (Exception value)
				{
					MelonLogger.Error($"Failed to update Riptide with exception: {value}");
				}
				while (!ClientSendQueue.IsEmpty)
				{
					if (ClientSendQueue.TryDequeue(out var result))
					{
						byte[] item = result.Item1;
						MessageSendMode item2 = result.Item2;
						try
						{
							Message val = Message.Create(item2, (ushort)0);
							val.AddBytes(item, true);
							_riptideClient.Send(val, true);
						}
						catch (Exception value2)
						{
							MelonLogger.Error($"Failed to send message with exception: {value2}");
						}
					}
				}
				while (!ServerSendQueue.IsEmpty)
				{
					if (!ServerSendQueue.TryDequeue(out var result2))
					{
						continue;
					}
					byte[] item3 = result2.Item1;
					MessageSendMode item4 = result2.Item2;
					ushort item5 = result2.Item3;
					bool item6 = result2.Item4;
					try
					{
						Message val2 = Message.Create(item4, (ushort)0);
						val2.AddBytes(item3, true);
						if (item6 && IsServerRunning)
						{
							_riptideServer.SendToAll(val2, true);
						}
						else if (item6 && !IsServerRunning)
						{
							_riptideClient.Send(val2, true);
						}
						else
						{
							_riptideServer.Send(val2, item5, true);
						}
					}
					catch (Exception value3)
					{
						MelonLogger.Error($"Failed to send message with exception: {value3}");
					}
				}
				num++;
				if (num < 300)
				{
					continue;
				}
				num = 0;
				short ping = 0;
				if (IsClientConnected)
				{
					ping = _riptideClient.RTT;
				}
				RiptideNetworkLayer.ActionQueue.Enqueue(delegate
				{
					//IL_005b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0088: Unknown result type (might be due to invalid IL or missing references)
					//IL_0078: Unknown result type (might be due to invalid IL or missing references)
					if (ping <= 0)
					{
						RiptideNetworkLayer.PingDisplayTMP.text = "";
					}
					else
					{
						RiptideNetworkLayer.PingDisplayTMP.text = $"PING: {ping}";
						if (ping < 100)
						{
							((Graphic)RiptideNetworkLayer.PingDisplayTMP).color = Color.cyan;
						}
						else if (ping < 200)
						{
							((Graphic)RiptideNetworkLayer.PingDisplayTMP).color = Color.yellow;
						}
						else
						{
							((Graphic)RiptideNetworkLayer.PingDisplayTMP).color = Color.red;
						}
					}
				});
			}
			DeinitializeRiptide();
		}

		private static void InitalizeRiptide()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			Message.MaxPayloadSize = 60000;
			_riptideClient = new Client("RIPTIDE CLIENT");
			_riptideServer = new Server("RIPTIDE SERVER");
			_riptideClient.MessageReceived += OnClientReceives;
			_riptideServer.MessageReceived += OnServerReceives;
			_riptideClient.Disconnected += OnDisconnected;
			_riptideServer.ClientDisconnected += OnClientDisconnected;
			_riptideServer.ClientConnected += OnClientConnected;
		}

		private static void OnDisconnected(object sender, DisconnectedEventArgs e)
		{
			RiptideNetworkLayer.ActionQueue.Enqueue(delegate
			{
				NetworkHelper.Disconnect("");
			});
		}

		private static void OnClientConnected(object sender, ServerConnectedEventArgs e)
		{
			e.Client.CanQualityDisconnect = false;
		}

		private static void OnClientDisconnected(object sender, ServerDisconnectedEventArgs e)
		{
			ushort id = e.Client.Id;
			RiptideNetworkLayer.ActionQueue.Enqueue(delegate
			{
				if (id != PlayerId.op_Implicit(PlayerIdManager.LocalId) && PlayerIdManager.HasPlayerId((ulong)id))
				{
					InternalServerHelpers.OnUserLeave((ulong)id);
					ConnectionSender.SendDisconnect((ulong)id, "");
				}
			});
		}

		private static void DeinitializeRiptide()
		{
			_riptideClient = null;
			_riptideServer = null;
		}

		public static void StartServer()
		{
			lock (_riptideClient)
			{
				lock (_riptideServer)
				{
					_riptideServer.Start((ushort)7777, (ushort)256, (byte)0, false);
					_riptideClient.Connected += OnConnect;
					_riptideClient.Connect("127.0.0.1:7777", 5, (byte)0, (Message)null, false);
				}
			}
			static void OnConnect(object sender, EventArgs args)
			{
				_riptideClient.Connected -= OnConnect;
				((Peer)_riptideClient).TimeoutTime = 30000;
				_riptideClient.Connection.CanQualityDisconnect = false;
				((Peer)_riptideServer).TimeoutTime = 30000;
				IsServerRunning = true;
				IsClientConnected = true;
				RiptideNetworkLayer.ActionQueue.Enqueue(delegate
				{
					PlayerIdManager.SetLongId((ulong)_riptideClient.Id);
					InternalServerHelpers.OnStartServer();
				});
			}
		}

		public static void StopServer()
		{
			lock (_riptideServer)
			{
				_riptideServer.Stop();
				IsServerRunning = false;
				IsClientConnected = false;
			}
		}

		public static void ConnectToServer(string serverCode)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			if (_isConnecting)
			{
				FusionNotifier.Send(new FusionNotification
				{
					Message = NotificationText.op_Implicit("Client is still connecting! Please wait until connection is finalized or failed."),
					PopupLength = 5f,
					SaveToMenu = false,
					Type = (NotificationType)1
				});
				return;
			}
			if (IsClientConnected)
			{
				FusionNotifier.Send(new FusionNotification
				{
					Message = NotificationText.op_Implicit("Disconnect from the current server before connecting to another!"),
					PopupLength = 5f,
					SaveToMenu = false,
					Type = (NotificationType)1
				});
				return;
			}
			string text;
			if (IPAddress.TryParse(serverCode, out IPAddress _))
			{
				text = serverCode;
			}
			else
			{
				if (!(IPUtils.DecodeIPAddress(serverCode) != string.Empty))
				{
					FusionNotifier.Send(new FusionNotification
					{
						Message = NotificationText.op_Implicit("Server Code or IP Address incorrect! Make sure you used the right code/IP!"),
						PopupLength = 5f,
						SaveToMenu = false,
						Type = (NotificationType)1
					});
					return;
				}
				text = IPUtils.DecodeIPAddress(serverCode);
			}
			lock (_riptideClient)
			{
				_riptideClient.Connected += OnConnect;
				_riptideClient.ConnectionFailed += OnConnectionFailed;
				_riptideClient.Connect(text + ":7777", 5, (byte)0, (Message)null, false);
				_isConnecting = true;
			}
			static void OnConnect(object sender, EventArgs args)
			{
				_riptideClient.Connected -= OnConnect;
				_riptideClient.ConnectionFailed -= OnConnectionFailed;
				_isConnecting = false;
				((Peer)_riptideClient).TimeoutTime = 30000;
				_riptideClient.Connection.CanQualityDisconnect = false;
				IsClientConnected = true;
				RiptideNetworkLayer.ActionQueue.Enqueue(delegate
				{
					PlayerIdManager.SetLongId((ulong)_riptideClient.Id);
					ConnectionSender.SendConnectionRequest();
				});
			}
			static void OnConnectionFailed(object sender, ConnectionFailedEventArgs args)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Expected O, but got Unknown
				_riptideClient.Connected -= OnConnect;
				_riptideClient.ConnectionFailed -= OnConnectionFailed;
				_isConnecting = false;
				FusionNotifier.Send(new FusionNotification
				{
					Title = NotificationText.op_Implicit("Failed to Connect!"),
					Message = NotificationText.op_Implicit($"REASON: {args.Reason}"),
					SaveToMenu = false,
					PopupLength = 5f,
					Type = (NotificationType)2
				});
			}
		}

		public static void Disconnect(string reason = "")
		{
			lock (_riptideClient)
			{
				lock (_riptideServer)
				{
					if (IsClientConnected)
					{
						_riptideServer.Stop();
						_riptideClient.Disconnect();
						IsClientConnected = false;
						IsServerRunning = false;
						InternalServerHelpers.OnDisconnect(reason);
					}
				}
			}
		}

		private static void OnServerReceives(object sender, MessageReceivedEventArgs e)
		{
			RiptideNetworkLayer.MessageQueue.Enqueue(new Tuple<byte[], bool>(e.Message.GetBytes(), item2: true));
		}

		private static void OnClientReceives(object sender, MessageReceivedEventArgs e)
		{
			RiptideNetworkLayer.MessageQueue.Enqueue(new Tuple<byte[], bool>(e.Message.GetBytes(), item2: false));
		}
	}
}