Decompiled source of SSMPEssentials v0.1.2

SSMPEssentials.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Timers;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using HarmonyLib;
using InControl;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SSMP.Api.Client;
using SSMP.Api.Client.Networking;
using SSMP.Api.Command;
using SSMP.Api.Command.Client;
using SSMP.Api.Command.Server;
using SSMP.Api.Server;
using SSMP.Api.Server.Networking;
using SSMP.Game;
using SSMP.Game.Settings;
using SSMP.Logging;
using SSMP.Math;
using SSMP.Networking.Packet;
using SSMP.Networking.Packet.Data;
using SSMPEssentials.Client;
using SSMPEssentials.Client.Commands;
using SSMPEssentials.Client.Modules;
using SSMPEssentials.Client.Packets;
using SSMPEssentials.Data;
using SSMPEssentials.Server;
using SSMPEssentials.Server.Commands;
using SSMPEssentials.Server.Modules;
using SSMPEssentials.Server.Packets;
using SSMPEssentials.Utils;
using SSMPEssentials.Utils.Tests;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SSMPEssentials")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2+3a63a082276d69e01bd49966d2e99cf58d479675")]
[assembly: AssemblyProduct("SSMPEssentials")]
[assembly: AssemblyTitle("SSMPEssentials")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/BobbyTheCatfish/SSMP.Utils")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.2.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace SSMPEssentials
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("io.github.bobbythecatfish.ssmp.essentials", "SSMPEssentials", "0.1.2")]
	public class SSMPEssentialsPlugin : BaseUnityPlugin
	{
		private TestManager testManager = new TestManager();

		public static readonly List<Action> NextFrames = new List<Action>();

		private List<Action> _nextFrames = new List<Action>();

		internal static SSMPEssentialsPlugin instance;

		public const string Id = "io.github.bobbythecatfish.ssmp.essentials";

		public static string Name => "SSMPEssentials";

		public static string Version => "0.1.2";

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			instance = this;
			ClientAddon.RegisterAddon((ClientAddon)(object)new SSMPEssentials.Client.Client());
			ServerAddon.RegisterAddon((ServerAddon)(object)new SSMPEssentials.Server.Server());
			Config.Init(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.bobbythecatfish.ssmp.essentials) has loaded!"));
			new Harmony("ssmp.essentials").PatchAll();
			HeroController.OnHeroInstanceSet += new HeroSetDelegate(InitializeHCModules);
		}

		private void InitializeHCModules(HeroController controller)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			HeroController.OnHeroInstanceSet -= new HeroSetDelegate(InitializeHCModules);
			Spectate.CreateFreecamUI();
			PlayerDeaths.Init();
			controller.OnDeath += PlayerDeaths.OnDeath;
			PlayerHealth.BlueHealthAddListener();
		}

		private void Update()
		{
			if (Config.TestsEnabled)
			{
				testManager.Update();
			}
			if (_nextFrames.Count > 0)
			{
				Action[] array = _nextFrames.ToArray();
				_nextFrames.Clear();
				Action[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i]();
				}
			}
			Inputs.Update();
		}

		private void LateUpdate()
		{
			if (NextFrames.Count > 0)
			{
				_nextFrames = NextFrames.ToList();
				NextFrames.Clear();
			}
			Spectate.Update();
		}
	}
}
namespace SSMPEssentials.Utils
{
	internal class Common
	{
		public static GameObject? HornetObject
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)HeroController.SilentInstance))
				{
					return null;
				}
				return ((Component)HeroController.SilentInstance).gameObject;
			}
		}

		public static string ServerTextColor(string text, Colors color)
		{
			return color switch
			{
				Colors.White => "&f", 
				Colors.Black => "&1", 
				Colors.Orange => "&6", 
				Colors.Purple => "&5", 
				Colors.Blue => "&b", 
				Colors.Green => "&2", 
				Colors.Red => "&4", 
				Colors.Yellow => "&e", 
				_ => "&f", 
			} + text + "&r";
		}

		public static string LocalTextColor(string text, Colors color)
		{
			string text2 = color switch
			{
				Colors.White => "#FFFFFF", 
				Colors.Black => "#000000", 
				Colors.Orange => "#FFAA00", 
				Colors.Purple => "#AA00AA", 
				Colors.Blue => "#55FFFF", 
				Colors.Green => "#00AA00", 
				Colors.Red => "#AA0000", 
				Colors.Yellow => "#FFFF55", 
				_ => "#FFFFFF", 
			};
			return "<color=" + text2 + ">" + text + "</color>";
		}

		public static string ColoredUsername(IServerPlayer? player, Colors defaultColor = Colors.White)
		{
			//IL_0017: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected I4, but got Unknown
			if (player == null)
			{
				return ServerTextColor("Unknown Player", defaultColor);
			}
			string username = player.Username;
			Team team = player.Team;
			return (team - 1) switch
			{
				3 => ServerTextColor(username, Colors.Blue), 
				0 => ServerTextColor(username, Colors.Green), 
				2 => ServerTextColor(username, Colors.Red), 
				1 => ServerTextColor(username, Colors.Orange), 
				_ => ServerTextColor(username, defaultColor), 
			};
		}

		public static string ColoredUsername(IClientPlayer? player, Colors defaultColor = Colors.White)
		{
			//IL_0017: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected I4, but got Unknown
			if (player == null)
			{
				return LocalTextColor("Unknown Player", defaultColor);
			}
			string username = player.Username;
			Team team = player.Team;
			return (team - 1) switch
			{
				3 => LocalTextColor(username, Colors.Blue), 
				0 => LocalTextColor(username, Colors.Green), 
				2 => LocalTextColor(username, Colors.Red), 
				1 => LocalTextColor(username, Colors.Orange), 
				_ => LocalTextColor(username, defaultColor), 
			};
		}
	}
	public class Packet : IPacketData
	{
		public virtual bool IsReliable => true;

		public virtual bool DropReliableDataIfNewerExists => true;

		public virtual void WriteData(IPacket packet)
		{
			Log.LogInfo("THIS SHOULD NOT RUN");
		}

		public virtual void ReadData(IPacket packet)
		{
			Log.LogInfo("THIS SHOULD NOT RUN");
		}
	}
	internal static class Config
	{
		public const uint SSMPApiVersion = 1u;

		public const string ModName = "SSMP Essentials";

		public const string Version = "0.1.2";

		private static ConfigEntry<bool>? _testsEnabled;

		private static ConfigEntry<KeyCode>? _spectateNext;

		private static ConfigEntry<KeyCode>? _spectatePrevious;

		private static ConfigEntry<KeyCode>? _exitSpectate;

		private static ConfigEntry<KeyCode>? _freecamToggle;

		public static bool TestsEnabled => _testsEnabled?.Value ?? false;

		public static KeyCode SpectateNext => (KeyCode)(((??)_spectateNext?.Value) ?? 0);

		public static KeyCode SpectatePrevious => (KeyCode)(((??)_spectatePrevious?.Value) ?? 0);

		public static KeyCode ExitSpectate => (KeyCode)(((??)_exitSpectate?.Value) ?? 0);

		public static KeyCode FreecamToggle => (KeyCode)(((??)_freecamToggle?.Value) ?? 0);

		public static void Init(ConfigFile config)
		{
			_spectatePrevious = config.Bind<KeyCode>("Keybinds", "Spectate Previous Player", (KeyCode)50, (ConfigDescription)null);
			_spectateNext = config.Bind<KeyCode>("Keybinds", "Spectate Next Player", (KeyCode)51, (ConfigDescription)null);
			_exitSpectate = config.Bind<KeyCode>("Keybinds", "Exit Spectate Mode", (KeyCode)52, (ConfigDescription)null);
			_freecamToggle = config.Bind<KeyCode>("Keybinds", "Toggle Freecam Mode", (KeyCode)53, (ConfigDescription)null);
		}
	}
	internal enum PacketIDs
	{
		Huddle,
		TeleportRequest,
		TeleportAccept,
		Message,
		PlayerDeath,
		PlayerHealth,
		Settings
	}
	internal enum Messages
	{
		TeleportDenied
	}
	internal enum CauseOfDeath
	{
		Generic,
		Player,
		Enemy,
		Spikes,
		Acid,
		Lava,
		Pit,
		Coal,
		Zap,
		Explosion,
		Sink,
		Steam,
		Frost
	}
	internal enum Colors
	{
		Black,
		White,
		Blue,
		Green,
		Orange,
		Purple,
		Red,
		Yellow
	}
	internal static class GameObjectUtils
	{
		public static GameObject? FindGameObjectInChildren(this GameObject parent, string path)
		{
			string[] array = path.Split('/');
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			for (int i = 0; i < array.Length; i++)
			{
				GameObject val = FindGameObjectLayer(array[i], parent);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
				parent = val;
			}
			return parent;
		}

		private static GameObject? FindGameObjectLayer(string name, GameObject parent)
		{
			int childCount = parent.transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				Transform child = parent.transform.GetChild(i);
				if (((Object)child).name == name)
				{
					return ((Component)child).gameObject;
				}
			}
			Log.LogWarning(name + " not found");
			return null;
		}
	}
	internal static class Inputs
	{
		private static float MovementAmount(PlayerAction action, PlayerAction inverseAction)
		{
			float num = 0.1f;
			if (((OneAxisInputControl)action).Value > num)
			{
				return ((OneAxisInputControl)action).Value;
			}
			if (OneAxisInputControl.op_Implicit((OneAxisInputControl)(object)inverseAction) > num)
			{
				return 0f - ((OneAxisInputControl)inverseAction).Value;
			}
			return 0f;
		}

		private static void FreecamMovement()
		{
			float num = 6f;
			HeroActions inputActions = ManagerSingleton<InputHandler>.Instance.inputActions;
			if (((OneAxisInputControl)inputActions.Dash).IsPressed)
			{
				num = 2f;
			}
			Spectate.FreecamMovementVector.x = MovementAmount(inputActions.Right, inputActions.Left) / num;
			Spectate.FreecamMovementVector.y = MovementAmount(inputActions.Up, inputActions.Down) / num;
		}

		public static void Update()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			IClientApi api = SSMPEssentials.Client.Client.api;
			if (api != null && api.UiManager.ChatBox.IsOpen)
			{
				return;
			}
			if (Input.GetKeyDown(Config.SpectateNext))
			{
				Spectate.FocusOnPlayer(Spectate.MoveDir.Next);
			}
			else if (Input.GetKeyDown(Config.SpectatePrevious))
			{
				Spectate.FocusOnPlayer(Spectate.MoveDir.Prev);
			}
			else if (Input.GetKeyDown(Config.ExitSpectate))
			{
				Spectate.ReturnToSelf();
			}
			else if (Input.GetKeyDown(Config.FreecamToggle))
			{
				if (Spectate.freecam)
				{
					Spectate.ReturnToSelf();
				}
				else
				{
					Spectate.Freecam();
				}
			}
			if (Spectate.freecam)
			{
				FreecamMovement();
			}
		}
	}
	internal class FakeLogger : ILogger
	{
		public void Debug(string message)
		{
		}

		public void Error(string message)
		{
		}

		public void Info(string message)
		{
		}

		public void Message(string message)
		{
		}

		public void Warn(string message)
		{
		}
	}
	internal static class Log
	{
		private static ILogger logger = (ILogger)(object)new FakeLogger();

		public static void SetLogger(ILogger log)
		{
			logger = log;
		}

		private static bool ShouldLog(LogEventArgs log)
		{
			if (log.Source.SourceName == "SSMP" && log.Data is string text && text.StartsWith("[SSMPEssentials"))
			{
				return true;
			}
			return false;
		}

		public static void LogInfo(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Info(obj.ToString());
			}
		}

		public static void LogWarning(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Warn(obj.ToString());
			}
		}

		public static void LogError(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Error(obj.ToString());
			}
		}

		public static void LogFatal(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Error(obj.ToString());
			}
		}

		public static void LogDebug(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Debug(obj.ToString());
			}
		}

		public static void LogMessage(params object[] data)
		{
			foreach (object obj in data)
			{
				logger.Message(obj.ToString());
			}
		}
	}
	internal class NoRepeat<T> : IEnumerable
	{
		private List<T> _unused = new List<T>();

		private List<T> _used = new List<T>();

		private readonly Random random = new Random();

		public void Add(T item)
		{
			_unused.Add(item);
		}

		public IEnumerator GetEnumerator()
		{
			return _unused.GetEnumerator();
		}

		public T GetRandom()
		{
			if (_used.Count == 0 && _unused.Count <= 1)
			{
				if (_unused.Count == 0)
				{
					throw new Exception("NoRepeat was empty, could not return a proper value.");
				}
				return _unused[0];
			}
			int index = random.Next(_unused.Count);
			T val = _unused[index];
			_unused.RemoveAt(index);
			if (_unused.Count == 0)
			{
				_unused.AddRange(_used);
				_used = new List<T>();
			}
			_used.Add(val);
			return val;
		}
	}
}
namespace SSMPEssentials.Utils.Tests
{
	internal class TestManager
	{
		private List<BaseTest> tests = new List<BaseTest>();

		public TestManager()
		{
			tests.Add(new WarpTest());
		}

		public void Update()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			foreach (BaseTest test in tests)
			{
				if (Input.GetKeyDown(test.KeyCode))
				{
					test.Execute();
				}
			}
		}
	}
	internal class WarpTest : BaseTest
	{
		public override KeyCode KeyCode => (KeyCode)49;

		public override void Execute()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			SSMPEssentials.Client.PacketReceiver.OnHuddle(new TeleportPacket
			{
				Scene = "Bonetown",
				Position = new Vector2(100f, 15f)
			});
		}
	}
	internal abstract class BaseTest
	{
		public abstract KeyCode KeyCode { get; }

		public abstract void Execute();
	}
}
namespace SSMPEssentials.Server
{
	internal static class PacketReceiver
	{
		public static void Init()
		{
			IServerAddonNetworkReceiver<PacketIDs> networkReceiver = Server.api.NetServer.GetNetworkReceiver<PacketIDs>((ServerAddon)(object)Server.instance, (Func<PacketIDs, IPacketData>)SSMPEssentials.Client.Packets.Packets.Instantiate);
			networkReceiver.RegisterPacketHandler<TeleportPacket>(PacketIDs.Huddle, (GenericServerPacketHandler<TeleportPacket>)OnHuddle);
			networkReceiver.RegisterPacketHandler<TeleportRequestPacket>(PacketIDs.TeleportRequest, (GenericServerPacketHandler<TeleportRequestPacket>)OnTeleportRequest);
			networkReceiver.RegisterPacketHandler<TeleportPacket>(PacketIDs.TeleportAccept, (GenericServerPacketHandler<TeleportPacket>)OnTeleportRequestAccept);
			networkReceiver.RegisterPacketHandler<MessagePacket>(PacketIDs.Message, (GenericServerPacketHandler<MessagePacket>)OnMessage);
			networkReceiver.RegisterPacketHandler<DeathPacket>(PacketIDs.PlayerDeath, (GenericServerPacketHandler<DeathPacket>)OnPlayerDeath);
			networkReceiver.RegisterPacketHandler<HealthPacket>(PacketIDs.PlayerHealth, (GenericServerPacketHandler<HealthPacket>)OnPlayerHealth);
		}

		public static void OnHuddle(ushort id, TeleportPacket data)
		{
			if (!Server.ServerSettings.HuddleEnabled)
			{
				Server.SendMessageToPlayer(id, "Huddles are currently disabled.");
				return;
			}
			IServerPlayer player = Server.GetPlayer(id);
			if (player == null || !player.IsAuthorized)
			{
				Server.SendMessageToPlayer(id, "You need to be authorized to use that command.");
				return;
			}
			if (data.Scene == "")
			{
				IServerPlayer player2 = Server.GetPlayer(data.PlayerId);
				if (player2 == null)
				{
					Server.SendMessageToPlayer(id, "I couldn't find that player.");
					return;
				}
				data.Scene = player2.CurrentScene;
				data.Position = player2.Position ?? Vector2.Zero;
			}
			else
			{
				data.PlayerId = id;
			}
			PacketSender.BroadcastWarp(data.Scene, data.Position, data.PlayerId);
		}

		public static void OnTeleportRequest(ushort id, TeleportRequestPacket data)
		{
			if (!Server.ServerSettings.TeleportsEnabled)
			{
				Server.SendMessageToPlayer(id, "Teleporting is currently disabled.");
			}
			else if (Server.GetPlayer(data.PlayerId) == null)
			{
				Server.SendMessageToPlayer(id, "I couldn't find that player.");
			}
			else
			{
				PacketSender.SendTeleportRequest(data.PlayerId, id);
			}
		}

		public static void OnTeleportRequestAccept(ushort id, TeleportPacket data)
		{
			if (!Server.ServerSettings.TeleportsEnabled)
			{
				Server.SendMessageToPlayer(id, "Teleporting is currently disabled.");
			}
			else if (Server.GetPlayer(data.PlayerId) == null)
			{
				Server.SendMessageToPlayer(id, "I couldn't find that player.");
			}
			else
			{
				PacketSender.SendTeleportAccepted(data.PlayerId, id, data.Scene, data.Position);
			}
		}

		public static void OnMessage(ushort id, MessagePacket data)
		{
			if (Server.GetPlayer(data.PlayerId) == null)
			{
				Server.SendMessageToPlayer(id, "I couldn't find that player.");
			}
			else
			{
				PacketSender.SendMessage(data.PlayerId, id, data.Message);
			}
		}

		public static void OnPlayerDeath(ushort id, DeathPacket data)
		{
			if (!Server.ServerSettings.DeathMessagesEnabled)
			{
				return;
			}
			IServerPlayer player = Server.GetPlayer(id);
			if (player != null)
			{
				IServerPlayer player2 = Server.GetPlayer(data.KillerID);
				string text = Common.ColoredUsername(player) + " " + DetermineDeathString(data.Cause, player2);
				if (data.Cause != CauseOfDeath.Player && data.RanAway)
				{
					text = text + " while fighting " + Common.ColoredUsername(player2);
				}
				Server.api.ServerManager.BroadcastMessage(text);
			}
		}

		private static string DetermineDeathString(CauseOfDeath cause, IServerPlayer? player)
		{
			if (!DeathMessages.Messages.TryGetValue(cause, out NoRepeat<string> value))
			{
				value = DeathMessages.Messages[CauseOfDeath.Generic];
			}
			string text = value.GetRandom();
			if (cause == CauseOfDeath.Player)
			{
				text = text + " " + Common.ColoredUsername(player);
			}
			return text;
		}

		private static void OnPlayerHealth(ushort id, HealthPacket data)
		{
			Log.LogDebug($"Received health from {id}: {data.Health}");
			StoredPlayerData player = PlayerDataTracker.ServerInstance.GetPlayer(id);
			player.Health = data.Health;
			PacketSender.BroadcastPlayerHealth(id, player.Health);
		}
	}
	internal static class PacketSender
	{
		private static IServerAddonNetworkSender<PacketIDs>? sender;

		internal static void Init()
		{
			sender = Server.api.NetServer.GetNetworkSender<PacketIDs>((ServerAddon)(object)Server.instance);
		}

		private static void Broadcast(PacketIDs id, Packet packet, ushort senderId, bool collection = true)
		{
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
				return;
			}
			foreach (IServerPlayer player in Server.api.ServerManager.Players)
			{
				if (player.Id != senderId)
				{
					if (collection)
					{
						sender.SendCollectionData<Packet>(id, packet, player.Id);
					}
					else
					{
						sender.SendSingleData(id, (IPacketData)(object)packet, player.Id);
					}
				}
			}
		}

		internal static void BroadcastWarp(string scene, Vector2 position, ushort destinationPlayerId)
		{
			TeleportPacket packet = new TeleportPacket
			{
				Scene = scene,
				Position = position
			};
			Broadcast(PacketIDs.Huddle, packet, destinationPlayerId, collection: false);
		}

		internal static void SendTeleportRequest(ushort targetPlayerId, ushort senderId)
		{
			TeleportRequestPacket teleportRequestPacket = new TeleportRequestPacket
			{
				PlayerId = senderId
			};
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
			}
			else
			{
				sender.SendCollectionData<TeleportRequestPacket>(PacketIDs.TeleportRequest, teleportRequestPacket, targetPlayerId);
			}
		}

		internal static void SendTeleportAccepted(ushort playerToTeleportId, ushort destinationPlayerId, string scene, Vector2 position)
		{
			TeleportPacket teleportPacket = new TeleportPacket
			{
				PlayerId = destinationPlayerId,
				Position = position,
				Scene = scene
			};
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
			}
			else
			{
				sender.SendSingleData(PacketIDs.TeleportAccept, (IPacketData)(object)teleportPacket, playerToTeleportId);
			}
		}

		internal static void SendMessage(ushort recipientId, ushort senderId, Messages message)
		{
			MessagePacket messagePacket = new MessagePacket
			{
				Message = message,
				PlayerId = senderId
			};
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
			}
			else
			{
				sender.SendCollectionData<MessagePacket>(PacketIDs.Message, messagePacket, recipientId);
			}
		}

		internal static void BroadcastPlayerHealth(ushort playerId, HealthData health)
		{
			PlayerHealthPacket packet = new PlayerHealthPacket
			{
				PlayerId = playerId,
				Health = health
			};
			Broadcast(PacketIDs.PlayerHealth, packet, playerId);
		}

		internal static void SendAllPlayerHealth(ushort recipientId)
		{
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
				return;
			}
			foreach (StoredPlayerData allDatum in PlayerDataTracker.ServerInstance.GetAllData())
			{
				PlayerHealthPacket playerHealthPacket = new PlayerHealthPacket
				{
					PlayerId = allDatum.Id,
					Health = allDatum.Health
				};
				sender.SendCollectionData<PlayerHealthPacket>(PacketIDs.PlayerHealth, playerHealthPacket, recipientId);
			}
		}

		internal static void BroadcastSettingsUpdate()
		{
			SettingsPacket settingsPacket = new SettingsPacket
			{
				ServerSettings = Server.ServerSettings
			};
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
			}
			else
			{
				sender.BroadcastSingleData(PacketIDs.Settings, (IPacketData)(object)settingsPacket);
			}
		}

		internal static void SendSettingsUpdate(ushort id)
		{
			SettingsPacket settingsPacket = new SettingsPacket
			{
				ServerSettings = Server.ServerSettings
			};
			if (sender == null)
			{
				Log.LogError("Unable to send packet, packet sender is null.");
			}
			else
			{
				sender.SendSingleData(PacketIDs.Settings, (IPacketData)(object)settingsPacket, id);
			}
		}
	}
	internal class Server : ServerAddon
	{
		internal static IServerApi api;

		internal static Server instance;

		internal static ServerSettings ServerSettings = new ServerSettings(client: false);

		protected override string Name => "SSMP Essentials";

		protected override string Version => "0.1.2";

		public override uint ApiVersion => 1u;

		public override bool NeedsNetwork => true;

		public override void Initialize(IServerApi serverApi)
		{
			instance = this;
			api = serverApi;
			Log.SetLogger(((ServerAddon)this).Logger);
			serverApi.ServerManager.PlayerConnectEvent += SendJoinInfo;
			((ICommandManager<IServerCommand>)(object)serverApi.CommandManager).RegisterCommand((IServerCommand)(object)new SettingsCommand());
			ServerSettings = SSMPEssentials.Server.Modules.ServerSettings.ReadFromFile();
			PacketReceiver.Init();
			PacketSender.Init();
			Log.LogInfo("SSMP Essentials Server Initialized");
		}

		public static IServerPlayer? GetPlayer(ushort id)
		{
			return api.ServerManager.GetPlayer(id);
		}

		public static void SendMessageToPlayer(ushort id, string message)
		{
			api.ServerManager.SendMessage(id, message);
		}

		public static void BroadcastMessage(string message)
		{
			api.ServerManager.BroadcastMessage(message);
		}

		private static void SendJoinInfo(IServerPlayer player)
		{
			PacketSender.SendSettingsUpdate(player.Id);
			PacketSender.SendAllPlayerHealth(player.Id);
		}
	}
}
namespace SSMPEssentials.Server.Packets
{
	internal class PlayerHealthPacket : HealthPacket
	{
		public ushort PlayerId;

		public override void WriteData(IPacket packet)
		{
			base.WriteData(packet);
			packet.Write(PlayerId);
		}

		public override void ReadData(IPacket packet)
		{
			base.ReadData(packet);
			PlayerId = packet.ReadUShort();
		}
	}
	internal class SettingsPacket : Packet
	{
		public ServerSettings ServerSettings;

		public override void WriteData(IPacket packet)
		{
			foreach (PropertyInfo prop in ServerSettings.GetProps())
			{
				if (prop.CanRead)
				{
					packet.Write((bool)prop.GetValue(ServerSettings, null));
				}
			}
		}

		public override void ReadData(IPacket packet)
		{
			ServerSettings = new ServerSettings(client: false);
			foreach (PropertyInfo prop in ServerSettings.GetProps())
			{
				if (prop.CanWrite)
				{
					prop.SetValue(ServerSettings, packet.ReadBool(), null);
				}
			}
		}
	}
	public static class Packets
	{
		internal class ErrorThrowingPacket : Packet
		{
			public ErrorThrowingPacket(PacketIDs id, bool server)
			{
				Log.LogError(id.ToString(), server);
				throw new NotImplementedException(id.ToString());
			}
		}

		internal static IPacketData Instantiate(PacketIDs packetID)
		{
			return (IPacketData)(packetID switch
			{
				PacketIDs.Huddle => new TeleportPacket(), 
				PacketIDs.TeleportRequest => new PacketDataCollection<TeleportRequestPacket>(), 
				PacketIDs.TeleportAccept => new TeleportPacket(), 
				PacketIDs.Message => new PacketDataCollection<MessagePacket>(), 
				PacketIDs.PlayerHealth => new PacketDataCollection<PlayerHealthPacket>(), 
				PacketIDs.Settings => new SettingsPacket(), 
				_ => new ErrorThrowingPacket(packetID, server: true), 
			});
		}
	}
}
namespace SSMPEssentials.Server.Modules
{
	internal class ServerSettings
	{
		[CompilerGenerated]
		private sealed class <GetProps>d__39 : IEnumerable<PropertyInfo>, IEnumerable, IEnumerator<PropertyInfo>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private PropertyInfo <>2__current;

			private int <>l__initialThreadId;

			private PropertyInfo[] <>7__wrap1;

			private int <>7__wrap2;

			PropertyInfo IEnumerator<PropertyInfo>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetProps>d__39(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>7__wrap1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					PropertyInfo[] properties = typeof(ServerSettings).GetProperties();
					<>7__wrap1 = properties;
					<>7__wrap2 = 0;
					break;
				}
				case 1:
					<>1__state = -1;
					<>7__wrap2++;
					break;
				}
				if (<>7__wrap2 < <>7__wrap1.Length)
				{
					PropertyInfo propertyInfo = <>7__wrap1[<>7__wrap2];
					<>2__current = propertyInfo;
					<>1__state = 1;
					return true;
				}
				<>7__wrap1 = null;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<PropertyInfo> IEnumerable<PropertyInfo>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <GetProps>d__39(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<PropertyInfo>)this).GetEnumerator();
			}
		}

		[JsonProperty("huddle")]
		[SettingAlias(new string[] { "huddle" })]
		public bool HuddleEnabled { get; set; } = true;


		[JsonProperty("teleport")]
		[SettingAlias(new string[] { "tp", "teleport" })]
		public bool TeleportsEnabled { get; set; } = true;


		[JsonProperty("back")]
		[SettingAlias(new string[] { "back", "tpback" })]
		public bool BackEnabled { get; set; } = true;


		[JsonProperty("teleport_requests")]
		[SettingAlias(new string[] { "tprequests", "tpa", "tpd", "tpr", "tpreq" })]
		public bool TeleportsNeedRequests { get; set; } = true;


		[JsonProperty("death_messages")]
		[SettingAlias(new string[] { "deathmessages", "death" })]
		public bool DeathMessagesEnabled { get; set; } = true;


		[JsonProperty("healthbars")]
		[SettingAlias(new string[] { "healthbars", "health" })]
		public bool HealthbarsEnabled { get; set; } = true;


		[JsonProperty("spectate")]
		[SettingAlias(new string[] { "spectate" })]
		public bool SpectateEnabled { get; set; } = true;


		[JsonProperty("spectate_team")]
		[SettingAlias(new string[] { "spectateteam" })]
		public bool SpectateTeamOnly { get; set; }

		[JsonProperty("freecam")]
		[SettingAlias(new string[] { "freecam" })]
		public bool FreecamEnabled { get; set; } = true;


		private static string Filepath()
		{
			return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ServerSettings.json");
		}

		public static ServerSettings ReadFromFile()
		{
			string text = Filepath();
			if (!File.Exists(text))
			{
				Log.LogWarning(text + " doesn't exist");
				new ServerSettings(client: false).WriteToFile();
				return new ServerSettings(client: false);
			}
			try
			{
				return JsonConvert.DeserializeObject<ServerSettings>(File.ReadAllText(text)) ?? new ServerSettings(client: false);
			}
			catch (Exception arg)
			{
				Log.LogError($"Could not load server settings from file:\n{arg}");
				return new ServerSettings(client: false);
			}
		}

		public void WriteToFile()
		{
			string text = Filepath();
			if (!Directory.Exists(Path.GetDirectoryName(text)))
			{
				Log.LogWarning(text + " directory doesn't exist");
				return;
			}
			string text2 = JsonConvert.SerializeObject((object)this, (Formatting)1);
			if (text2 == null)
			{
				return;
			}
			try
			{
				File.WriteAllText(text, text2);
			}
			catch (Exception arg)
			{
				Log.LogError($"Could not write server settings to file:\n{arg}");
			}
		}

		[IteratorStateMachine(typeof(<GetProps>d__39))]
		public IEnumerable<PropertyInfo> GetProps()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetProps>d__39(-2);
		}

		public ServerSettings(bool client)
		{
			foreach (PropertyInfo prop in GetProps())
			{
				prop.SetValue(this, !client);
			}
		}
	}
}
namespace SSMPEssentials.Server.Commands
{
	internal class SettingsCommand : IServerCommand, ICommand
	{
		private const string SETTING_SUB = "set";

		public bool AuthorizedOnly => true;

		public string Trigger => "/essentials";

		public string[] Aliases => new string[3] { "/essential", "/ess", "/e" };

		public void Execute(ICommandSender sender, string[] arguments)
		{
			string text = "Invalid Syntax. " + Trigger + " set <setting> <true/false>";
			if (arguments.Length < 2)
			{
				sender.SendMessage(text);
				return;
			}
			IEnumerable<PropertyInfo> props = Server.ServerSettings.GetProps();
			List<string> list = new List<string>();
			Dictionary<string, PropertyInfo> dictionary = new Dictionary<string, PropertyInfo>();
			foreach (PropertyInfo item in props)
			{
				SettingAliasAttribute customAttribute = ((MemberInfo)item).GetCustomAttribute<SettingAliasAttribute>();
				dictionary.Add(item.Name, item);
				if (customAttribute == null || customAttribute.Aliases.Length == 0)
				{
					list.Add(item.Name);
					continue;
				}
				list.Add(customAttribute.Aliases[0]);
				string[] aliases = customAttribute.Aliases;
				foreach (string key in aliases)
				{
					dictionary.Add(key, item);
				}
			}
			string text2 = "Valid settings are " + string.Join(", ", list);
			if (arguments.Length == 2)
			{
				sender.SendMessage(text2);
				return;
			}
			string key2 = arguments[2].ToLower().Replace("_", "");
			if (!dictionary.TryGetValue(key2, out var value))
			{
				sender.SendMessage(text2);
				return;
			}
			if (arguments.Length == 3)
			{
				object value2 = value.GetValue(Server.ServerSettings);
				sender.SendMessage($"Setting '{value.Name}' currently has value: {value2}");
				return;
			}
			string text3 = arguments[3].ToLower();
			if (text3 != "true" && text3 != "false")
			{
				sender.SendMessage(text);
				return;
			}
			bool flag = text3 == "true";
			value.SetValue(Server.ServerSettings, flag);
			Server.BroadcastMessage($"Changed setting '{value.Name}' to: {flag}");
			Server.ServerSettings.WriteToFile();
			PacketSender.BroadcastSettingsUpdate();
		}
	}
}
namespace SSMPEssentials.Data
{
	internal static class DeathMessages
	{
		public static readonly Dictionary<CauseOfDeath, NoRepeat<string>> Messages = new Dictionary<CauseOfDeath, NoRepeat<string>>
		{
			{
				CauseOfDeath.Generic,
				new NoRepeat<string> { "died of unnatural causes", "unalived", "was killed", "decided to set up a Cocoon Skip", "took damage equal to or more than their current HP" }
			},
			{
				CauseOfDeath.Player,
				new NoRepeat<string> { "lost a duel to", "made masterful use of their vulnerability frames while fighting", "failed to negotiate with", "regrettably ended their encounter with", "fell to one of the classic blunders while fighting" }
			},
			{
				CauseOfDeath.Enemy,
				new NoRepeat<string> { "had an intimate encounter with an enemy", "made masterful use of their vulnerability frames", "didn't see the enemy's final form", "mistook an enemy hitbox for a wall", "was squashed by a common bug" }
			},
			{
				CauseOfDeath.Spikes,
				new NoRepeat<string> { "got impaled by spikes", "didn't see the sharp things", "fought the spikes and lost", "attempted rudimentary acupuncture", "was pricked to death" }
			},
			{
				CauseOfDeath.Acid,
				new NoRepeat<string> { "forgot to equip Isma's Tear before hopping in acid", "mistook sulfuric acid for water", "tried to swim in acid", "got into a fight with a pool of liquid" }
			},
			{
				CauseOfDeath.Lava,
				new NoRepeat<string> { "discovered what the sun feels like", "had a charring revelation", "tried to swim in lava", "went up in flames", "discovered the floor was lava" }
			},
			{
				CauseOfDeath.Pit,
				new NoRepeat<string> { "fell down a hole", "never hit the bottom", "saw a giant ravine and decided to jump", "hit the ground too hard", "was doomed to fall" }
			},
			{
				CauseOfDeath.Coal,
				new NoRepeat<string> { "got hit in the head by a lump of coal", "shouldn't have collected all those hot rocks", "was burned to a crisp by a chunk of rock", "discovered that coals are hot" }
			},
			{
				CauseOfDeath.Zap,
				new NoRepeat<string> { "was electrocuted to death", "was utterly shocked", "became one with the Voltvyrm" }
			},
			{
				CauseOfDeath.Explosion,
				new NoRepeat<string> { "went Last Judge mode and blew up", "was blown to fluff", "looked back at the explosion", "went out with a bang" }
			},
			{
				CauseOfDeath.Sink,
				new NoRepeat<string> { "sunk so low that they couldn't get out", "fell out of the world" }
			},
			{
				CauseOfDeath.Steam,
				new NoRepeat<string> { "took a ride in a tea kettle", "fell into a pressure cooker", "got a face full of hot air", "was caught venting", "was blown away by the amount of steam in the organ" }
			},
			{
				CauseOfDeath.Frost,
				new NoRepeat<string> { "chilled out a little too hard", "froze up", "froze to death", "forgot to wear a coat", "became an icicle" }
			}
		};
	}
	internal class PlayerDataTracker
	{
		internal static PlayerDataTracker ClientInstance = new PlayerDataTracker();

		internal static PlayerDataTracker ServerInstance = new PlayerDataTracker();

		private readonly Dictionary<ushort, StoredPlayerData> data = new Dictionary<ushort, StoredPlayerData>();

		public StoredPlayerData GetPlayer(ushort id)
		{
			if (data.TryGetValue(id, out StoredPlayerData value))
			{
				return value;
			}
			value = new StoredPlayerData(id);
			data.Add(id, value);
			return value;
		}

		public List<StoredPlayerData> GetAllData()
		{
			return data.Values.ToList();
		}
	}
	internal class StoredPlayerData
	{
		public ushort Id;

		public HealthData Health = new HealthData();

		public StoredPlayerData(ushort id)
		{
			Id = id;
		}
	}
	public class HealthData
	{
		public int Health = 5;

		public int MaxHealth = 5;

		public int BlueHealth;

		public bool LifebloodState;

		public override string ToString()
		{
			return $"{Health}/{MaxHealth} + {BlueHealth} ({LifebloodState})";
		}
	}
}
namespace SSMPEssentials.Client
{
	internal class Client : ClientAddon
	{
		internal static IClientApi api;

		internal static Client instance;

		internal static ServerSettings ServerSettings = new ServerSettings(client: true);

		internal static Action OnServerSettingsUpdate = delegate
		{
		};

		internal static Action<ServerSettings>? OnSSMPSettingsUpdate;

		protected override string Name => "SSMP Essentials";

		protected override string Version => "0.1.2";

		public override uint ApiVersion => 1u;

		public override bool NeedsNetwork => true;

		public override void Initialize(IClientApi clientApi)
		{
			instance = this;
			api = clientApi;
			Log.SetLogger(((ClientAddon)this).Logger);
			PacketReceiver.Init();
			PacketSender.Init();
			((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new Huddle());
			((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new TeleportRequest());
			((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new TeleportAccept());
			((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new TeleportDeny());
			((ICommandManager<IClientCommand>)(object)api.CommandManager).RegisterCommand((IClientCommand)(object)new TeleportBack());
			api.ClientManager.DisconnectEvent += delegate
			{
				Spectate.ReturnToSelf();
			};
			api.ClientManager.PlayerEnterSceneEvent += PlayerHealth.OnPlayerEnter;
			Spectate.Init();
			Log.LogInfo("SSMP Essentials Client Initialized");
		}

		public static void LocalChat(string message)
		{
			string message2 = message;
			SSMPEssentialsPlugin.NextFrames.Add(delegate
			{
				api.UiManager.ChatBox.AddMessage(message2);
			});
		}

		public static IClientPlayer? GetPlayerByName(string username)
		{
			string username2 = username;
			return ((IEnumerable<IClientPlayer>)api.ClientManager.Players).FirstOrDefault((Func<IClientPlayer, bool>)((IClientPlayer p) => p.Username.Equals(username2, StringComparison.CurrentCultureIgnoreCase)));
		}

		public static IClientPlayer? GetPlayer(ushort id)
		{
			return api.ClientManager.GetPlayer(id);
		}

		public static ServerSettings GetClientServerSettings()
		{
			IClientManager clientManager = api.ClientManager;
			((object)clientManager).GetType();
			return Traverse.Create((object)clientManager).Field("_modSettings").Property("ServerSettings", (object[])null)
				.GetValue<ServerSettings>();
		}
	}
	internal static class PacketReceiver
	{
		public static void Init()
		{
			IClientAddonNetworkReceiver<PacketIDs> networkReceiver = Client.api.NetClient.GetNetworkReceiver<PacketIDs>((ClientAddon)(object)Client.instance, (Func<PacketIDs, IPacketData>)SSMPEssentials.Server.Packets.Packets.Instantiate);
			networkReceiver.RegisterPacketHandler<TeleportPacket>(PacketIDs.Huddle, (GenericClientPacketHandler<TeleportPacket>)OnHuddle);
			networkReceiver.RegisterPacketHandler<TeleportRequestPacket>(PacketIDs.TeleportRequest, (GenericClientPacketHandler<TeleportRequestPacket>)OnTeleportRequest);
			networkReceiver.RegisterPacketHandler<TeleportPacket>(PacketIDs.TeleportAccept, (GenericClientPacketHandler<TeleportPacket>)OnTeleportAccepted);
			networkReceiver.RegisterPacketHandler<MessagePacket>(PacketIDs.Message, (GenericClientPacketHandler<MessagePacket>)OnMessage);
			networkReceiver.RegisterPacketHandler<PlayerHealthPacket>(PacketIDs.PlayerHealth, (GenericClientPacketHandler<PlayerHealthPacket>)OnHealth);
			networkReceiver.RegisterPacketHandler<SettingsPacket>(PacketIDs.Settings, (GenericClientPacketHandler<SettingsPacket>)OnSettings);
		}

		public static void OnHuddle(TeleportPacket data)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			new Warp(data.Scene, (Vector2)data.Position).WarpToPosition();
		}

		public static void OnTeleportRequest(TeleportRequestPacket data)
		{
			IClientPlayer player = Client.GetPlayer(data.PlayerId);
			if (player == null)
			{
				Client.LocalChat("Received teleport request from unknown player. Ignoring.");
			}
			else if (!Client.ServerSettings.TeleportsNeedRequests)
			{
				PacketSender.SendTeleportAccept(new TeleportRequests.Request(data.PlayerId));
			}
			else
			{
				TeleportRequests.AddRequest(player);
			}
		}

		public static void OnTeleportAccepted(TeleportPacket data)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			IClientPlayer player = Client.GetPlayer(data.PlayerId);
			Client.LocalChat("Teleport request accepted. Teleporting to " + Common.ColoredUsername(player) + " now...");
			new Warp(data.Scene, (Vector2)data.Position).WarpToPosition();
		}

		public static void OnMessage(MessagePacket data)
		{
			IClientPlayer player = Client.GetPlayer(data.PlayerId);
			if (data.Message == Messages.TeleportDenied)
			{
				string message = Common.ColoredUsername(player) + " denied your teleport request.";
				Client.LocalChat(message);
				return;
			}
			throw new NotImplementedException();
		}

		public static void OnHealth(PlayerHealthPacket data)
		{
			IClientPlayer player = Client.GetPlayer(data.PlayerId);
			if (player != null)
			{
				PlayerHealth.SetPlayerHealth(player, data.Health);
			}
		}

		public static void OnSettings(SettingsPacket data)
		{
			Client.ServerSettings = data.ServerSettings;
			Client.OnServerSettingsUpdate();
		}
	}
	internal static class PacketSender
	{
		private static IClientAddonNetworkSender<PacketIDs>? sender;

		internal static void Init()
		{
			sender = Client.api.NetClient.GetNetworkSender<PacketIDs>((ClientAddon)(object)Client.instance);
		}

		private static void SendData(PacketIDs packetId, IPacketData data)
		{
			if (Client.api.NetClient.IsConnected && sender != null)
			{
				sender.SendSingleData(packetId, data);
			}
		}

		internal static void SendMessage(ushort id, Messages message)
		{
			MessagePacket data = new MessagePacket
			{
				Message = message,
				PlayerId = id
			};
			SendData(PacketIDs.Message, (IPacketData)(object)data);
		}

		internal static void SendHuddle()
		{
			if (Warp.GetHornetScenePosition(out string scene, out Vector2 position))
			{
				Log.LogDebug($"Sending huddle packet for scene {scene} at location {position}");
				SendData(PacketIDs.Huddle, (IPacketData)(object)new TeleportPacket
				{
					Scene = scene,
					Position = position
				});
			}
		}

		internal static void SendHuddle(ushort id)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if ((Object)(object)GameManager.SilentInstance == (Object)null || (int)GameManager.SilentInstance.GameState != 4)
			{
				Client.LocalChat("Resume the game first!");
				return;
			}
			Log.LogDebug($"Sending huddle packet for user {id}");
			SendData(PacketIDs.Huddle, (IPacketData)(object)new TeleportPacket
			{
				Scene = "",
				Position = Vector2.Zero,
				PlayerId = id
			});
		}

		internal static void SendTeleportAccept(TeleportRequests.Request request)
		{
			if (Warp.GetHornetScenePosition(out string scene, out Vector2 position))
			{
				request.Responded = true;
				Log.LogDebug($"Sending teleport accept to {request.PlayerId}");
				SendData(PacketIDs.TeleportAccept, (IPacketData)(object)new TeleportPacket
				{
					Scene = scene,
					Position = position,
					PlayerId = request.PlayerId
				});
			}
		}

		internal static void SendTeleportRequest(ushort playerId)
		{
			TeleportRequestPacket data = new TeleportRequestPacket
			{
				PlayerId = playerId
			};
			SendData(PacketIDs.TeleportRequest, (IPacketData)(object)data);
		}

		internal static void SendDeath(CauseOfDeath cause, ushort killerId = 0, bool ranAway = false)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			SceneTeleportMap.GetTeleportMap().TryGetValue(name, out var value);
			string scene = name;
			if (value != null)
			{
				string str = ((object)(MapZone)(ref value.MapZone)).ToString().Replace('_', ' ');
				scene = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str);
			}
			DeathPacket data = new DeathPacket
			{
				Scene = scene,
				KillerID = killerId,
				Cause = cause,
				RanAway = ranAway
			};
			SendData(PacketIDs.PlayerDeath, (IPacketData)(object)data);
		}

		internal static void SendHealth(HealthData healthData)
		{
			Log.LogDebug($"Sending health: {healthData}");
			HealthPacket data = new HealthPacket
			{
				Health = healthData
			};
			SendData(PacketIDs.PlayerHealth, (IPacketData)(object)data);
		}
	}
}
namespace SSMPEssentials.Client.Packets
{
	internal class TeleportPacket : Packet
	{
		public ushort PlayerId;

		public string Scene = "";

		public Vector2 Position = Vector2.Zero;

		public override void WriteData(IPacket packet)
		{
			packet.Write(PlayerId);
			packet.Write(Scene);
			packet.Write(Position);
		}

		public override void ReadData(IPacket packet)
		{
			PlayerId = packet.ReadUShort();
			Scene = packet.ReadString();
			Position = packet.ReadVector2();
		}
	}
	internal class MessagePacket : IPacketData
	{
		public ushort PlayerId;

		public Messages Message;

		public bool IsReliable => true;

		public bool DropReliableDataIfNewerExists => true;

		public void WriteData(IPacket packet)
		{
			packet.Write(PlayerId);
			packet.Write((ushort)Message);
		}

		public void ReadData(IPacket packet)
		{
			PlayerId = packet.ReadUShort();
			Message = (Messages)packet.ReadUShort();
		}
	}
	internal class TeleportRequestPacket : IPacketData
	{
		public ushort PlayerId;

		public bool IsReliable => true;

		public bool DropReliableDataIfNewerExists => true;

		public void WriteData(IPacket packet)
		{
			packet.Write(PlayerId);
		}

		public void ReadData(IPacket packet)
		{
			PlayerId = packet.ReadUShort();
		}
	}
	internal class DeathPacket : IPacketData
	{
		public ushort KillerID;

		public CauseOfDeath Cause;

		public bool RanAway;

		public string Scene = "";

		public bool IsReliable => true;

		public bool DropReliableDataIfNewerExists => true;

		public virtual void WriteData(IPacket packet)
		{
			packet.Write(KillerID);
			packet.Write((ushort)Cause);
			packet.Write(RanAway);
			packet.Write(Scene);
		}

		public virtual void ReadData(IPacket packet)
		{
			KillerID = packet.ReadUShort();
			Cause = (CauseOfDeath)packet.ReadUShort();
			RanAway = packet.ReadBool();
			Scene = packet.ReadString();
		}
	}
	public class HealthPacket : Packet
	{
		public HealthData Health = new HealthData();

		public override void WriteData(IPacket packet)
		{
			packet.Write(Health.Health);
			packet.Write(Health.MaxHealth);
			packet.Write(Health.BlueHealth);
			packet.Write(Health.LifebloodState);
		}

		public override void ReadData(IPacket packet)
		{
			Health = new HealthData();
			Health.Health = packet.ReadInt();
			Health.MaxHealth = packet.ReadInt();
			Health.BlueHealth = packet.ReadInt();
			Health.LifebloodState = packet.ReadBool();
		}
	}
	public static class Packets
	{
		internal static IPacketData Instantiate(PacketIDs packetID)
		{
			return (IPacketData)(packetID switch
			{
				PacketIDs.Huddle => new TeleportPacket(), 
				PacketIDs.TeleportRequest => new TeleportRequestPacket(), 
				PacketIDs.TeleportAccept => new TeleportPacket(), 
				PacketIDs.Message => new MessagePacket(), 
				PacketIDs.PlayerDeath => new DeathPacket(), 
				PacketIDs.PlayerHealth => new HealthPacket(), 
				_ => new SSMPEssentials.Server.Packets.Packets.ErrorThrowingPacket(packetID, server: false), 
			});
		}
	}
}
namespace SSMPEssentials.Client.Modules
{
	internal static class PlayerDeaths
	{
		public static CauseOfDeath LatestCause = CauseOfDeath.Generic;

		public static ushort LatestPlayerAttack = 0;

		public static DateTime LastDamageTime = DateTime.Now;

		public static DateTime PlayerAttackTime = DateTime.MinValue;

		public static void Init()
		{
			EventRegister val = ((IEnumerable<EventRegister>)((Component)HeroController.instance).gameObject.GetComponents<EventRegister>()).FirstOrDefault((Func<EventRegister, bool>)((EventRegister r) => r.subscribedEvent == "HERO DAMAGED"));
			if ((Object)(object)val != (Object)null)
			{
				((EventBase)val).ReceivedEvent += LastDitchEffort;
			}
		}

		private static void LastDitchEffort()
		{
			if (LastDamageTime.AddSeconds(1.0) < DateTime.Now)
			{
				LastDamageTime = DateTime.Now;
				LatestCause = CauseOfDeath.Generic;
			}
		}

		public static void OnDeath()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0076: 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)
			if (Client.ServerSettings.DeathMessagesEnabled)
			{
				bool ranAway = PlayerAttackTime.AddSeconds(15.0) > DateTime.Now;
				PacketSender.SendDeath(LatestCause, LatestPlayerAttack, ranAway);
				Scene activeScene = SceneManager.GetActiveScene();
				string name = ((Scene)(ref activeScene)).name;
				GameObject hornetObject = Common.HornetObject;
				if (!((Object)(object)hornetObject == (Object)null))
				{
					LatestCause = CauseOfDeath.Generic;
					LatestPlayerAttack = 0;
					TeleportBack.PreviousScene = name;
					TeleportBack.PreviousLocation = Vector2.op_Implicit(hornetObject.transform.position);
				}
			}
		}

		public static void DetermineCauseOfDamage(DamageHero damager)
		{
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			LastDamageTime = DateTime.Now;
			if (Object.op_Implicit((Object)(object)((Component)damager).GetComponentInParent<FireballProjectile>()))
			{
				LatestCause = CauseOfDeath.Coal;
				return;
			}
			if (((Component)damager).CompareTag("Explosion"))
			{
				LatestCause = CauseOfDeath.Explosion;
				return;
			}
			bool flag = false;
			Transform parent = ((Component)damager).transform;
			while ((Object)(object)parent != (Object)null && !flag)
			{
				if (((Object)parent).name == "Player Prefab")
				{
					flag = true;
				}
				else
				{
					parent = parent.parent;
				}
			}
			Log.LogDebug(flag, ((Object)damager).name);
			if (flag && Object.op_Implicit((Object)(object)parent))
			{
				LatestCause = CauseOfDeath.Player;
				IClientPlayer val = ((IEnumerable<IClientPlayer>)Client.api.ClientManager.Players).FirstOrDefault((Func<IClientPlayer, bool>)((IClientPlayer p) => (Object)(object)p.PlayerObject == (Object)(object)((Component)parent).gameObject));
				if (val == null)
				{
					Log.LogWarning("Attacked by unknown player");
				}
				else
				{
					LatestPlayerAttack = (ushort)((val != null) ? val.Id : 0);
					PlayerAttackTime = DateTime.Now;
				}
			}
			else
			{
				LatestCause = DetermineHazardType(damager.hazardType);
			}
		}

		private static CauseOfDeath DetermineHazardType(HazardType hazardType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected I4, but got Unknown
			return (hazardType - 1) switch
			{
				0 => CauseOfDeath.Enemy, 
				1 => CauseOfDeath.Spikes, 
				2 => CauseOfDeath.Acid, 
				3 => CauseOfDeath.Lava, 
				4 => CauseOfDeath.Pit, 
				5 => CauseOfDeath.Coal, 
				6 => CauseOfDeath.Zap, 
				7 => CauseOfDeath.Explosion, 
				8 => CauseOfDeath.Sink, 
				9 => CauseOfDeath.Steam, 
				10 => CauseOfDeath.Generic, 
				_ => CauseOfDeath.Generic, 
			};
		}
	}
	internal static class PlayerHealth
	{
		private static GameObject? maskPrefab;

		public const int MAX_HEALTH = 10;

		public const int MAX_BLUE_MASKS = 8;

		public const int MAX_TOTAL_HEALTH = 18;

		public const int NORMAL_MASK_ID = 9;

		public const int MISSING_MASK_ID = 0;

		public const int BLUE_MASK_ID = 50;

		public const int HIVE_MASK_ID = 194;

		public static void OnHealthChange()
		{
			PlayerData playerData = HeroController.instance.playerData;
			PacketSender.SendHealth(new HealthData
			{
				Health = playerData.health,
				MaxHealth = playerData.maxHealth,
				BlueHealth = playerData.healthBlue,
				LifebloodState = HeroController.instance.IsInLifebloodState
			});
		}

		public static void BlueHealthAddListener()
		{
			string path = "In-game/Anchor TL/Hud Canvas Offset/Hud Canvas/Health";
			GameObject val = ((Component)GameCameras.instance.hudCamera).gameObject.FindGameObjectInChildren(path);
			if ((Object)(object)val != (Object)null)
			{
				EventRegister val2 = ((IEnumerable<EventRegister>)val.GetComponents<EventRegister>()).FirstOrDefault((Func<EventRegister, bool>)((EventRegister r) => r.SubscribedEvent == "ADD BLUE HEALTH"));
				if ((Object)(object)val2 == (Object)null)
				{
					Log.LogError("Unable to hook Lifeblood Health Updates");
				}
				else
				{
					((EventBase)val2).ReceivedEvent += OnHealthChange;
				}
			}
		}

		public static void OnPlayerEnter(IClientPlayer player)
		{
			GameObject playerContainer = player.PlayerContainer;
			if (!((Object)(object)playerContainer == (Object)null))
			{
				FindOrCreateHealthBar(playerContainer, player.Id).Refresh();
			}
		}

		public static void SetPlayerHealth(IClientPlayer player, HealthData healthData)
		{
			int health = Math.Clamp(healthData.Health, 0, 10);
			int maxHealth = Math.Clamp(healthData.MaxHealth, 0, 10);
			int blueHealth = Math.Clamp(healthData.BlueHealth, 0, 8);
			HealthData health2 = PlayerDataTracker.ClientInstance.GetPlayer(player.Id).Health;
			health2.Health = health;
			health2.MaxHealth = maxHealth;
			health2.BlueHealth = blueHealth;
			health2.LifebloodState = healthData.LifebloodState;
			GameObject playerContainer = player.PlayerContainer;
			if (!((Object)(object)playerContainer == (Object)null))
			{
				FindOrCreateHealthBar(playerContainer, player.Id).Refresh();
			}
		}

		public static HealthDisplay FindOrCreateHealthBar(GameObject playerContainer, ushort id)
		{
			//IL_0028: 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)
			HealthDisplay healthDisplay = playerContainer.GetComponentInChildren<HealthDisplay>();
			if ((Object)(object)healthDisplay == (Object)null)
			{
				Log.LogDebug("Creating display");
				GameObject val = new GameObject("Player Health Display");
				Extensions.SetParentReset(val.transform, playerContainer.transform);
				healthDisplay = val.AddComponent<HealthDisplay>();
			}
			else
			{
				Log.LogDebug("Display found");
			}
			healthDisplay.Owner = id;
			return healthDisplay;
		}

		private static GameObject GetMask()
		{
			if ((Object)(object)maskPrefab != (Object)null)
			{
				return maskPrefab;
			}
			string path = "In-game/Anchor TL/Hud Canvas Offset/Hud Canvas/Health/Health 2+/Idle";
			GameObject? obj = ((Component)GameCameras.instance.hudCamera).gameObject.FindGameObjectInChildren(path);
			if ((Object)(object)obj == (Object)null)
			{
				throw new Exception("Couldn't find health icon");
			}
			GameObject obj2 = Object.Instantiate<GameObject>(obj);
			SpriteFlash val = default(SpriteFlash);
			if (obj2.TryGetComponent<SpriteFlash>(ref val))
			{
				Object.DestroyImmediate((Object)(object)val);
			}
			SteelSoulAnimProxy val2 = default(SteelSoulAnimProxy);
			if (obj2.TryGetComponent<SteelSoulAnimProxy>(ref val2))
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
			obj2.layer = 0;
			obj2.SetActive(false);
			maskPrefab = obj2;
			return maskPrefab;
		}

		public static void CreateHealthBar(GameObject healthBar)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			healthBar.layer = 5;
			Vector2 spacing = default(Vector2);
			((Vector2)(ref spacing))..ctor(-0.3f, 0.4f);
			float num = 0.2f;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 2f);
			int constraintCount = 6;
			Vector2 cellSize = default(Vector2);
			((Vector2)(ref cellSize))..ctor(1.76f, 1.55f);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(1.43f, 1.43f);
			int num2 = 15;
			int num3 = 9;
			healthBar.AddComponent<KeepWorldScalePositive>();
			healthBar.AddComponent<Canvas>().renderMode = (RenderMode)2;
			GridLayoutGroup obj = healthBar.AddComponent<GridLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)7;
			obj.startCorner = (Corner)0;
			obj.startAxis = (Axis)0;
			obj.cellSize = cellSize;
			obj.spacing = spacing;
			obj.constraint = (Constraint)1;
			obj.constraintCount = constraintCount;
			healthBar.AddComponent<ContentSizeFitter>();
			RectTransform component = healthBar.GetComponent<RectTransform>();
			component.pivot = new Vector2(0.5f, 0f);
			component.SetSizeWithCurrentAnchors((Axis)0, (float)num2);
			component.SetSizeWithCurrentAnchors((Axis)1, (float)num3);
			Extensions.SetLocalPosition2D((Transform)(object)component, val);
			Extensions.SetScale2D((Transform)(object)component, new Vector2(num, num));
			GameObject mask = GetMask();
			tk2dSpriteAnimator val3 = default(tk2dSpriteAnimator);
			for (int i = 0; i < 18; i++)
			{
				GameObject obj2 = Object.Instantiate<GameObject>(mask);
				Extensions.SetParentReset(obj2.transform, healthBar.transform);
				Extensions.SetScale2D((Transform)(object)Extensions.AddComponentIfNotPresent<RectTransform>(obj2), val2);
				if (obj2.TryGetComponent<tk2dSpriteAnimator>(ref val3))
				{
					Object.Destroy((Object)(object)val3);
				}
			}
		}
	}
	public class HealthDisplay : MonoBehaviour
	{
		public ushort Owner;

		public HealthData Health = new HealthData();

		private void Awake()
		{
			Log.LogDebug("Health display awoke");
			Extensions.Reset(((Component)this).transform);
			PlayerHealth.CreateHealthBar(((Component)this).gameObject);
			Client.OnServerSettingsUpdate = (Action)Delegate.Combine(Client.OnServerSettingsUpdate, new Action(OnSettingsChange));
			OnSettingsChange();
		}

		private void OnSettingsChange()
		{
			if (Client.ServerSettings.HealthbarsEnabled)
			{
				Log.LogDebug("Settings changed, enabling");
				((Component)this).gameObject.SetActive(true);
				Refresh();
			}
			else
			{
				Log.LogDebug("Settings changed, disabling");
				((Component)this).gameObject.SetActive(false);
			}
		}

		public void Refresh()
		{
			StoredPlayerData player = PlayerDataTracker.ClientInstance.GetPlayer(Owner);
			Health = player.Health;
			int num = Health.MaxHealth + Health.BlueHealth;
			for (int i = 0; i < 18; i++)
			{
				Transform child = ((Component)this).transform.GetChild(i);
				int num2 = i + 1;
				if (num2 > num)
				{
					((Component)child).gameObject.SetActive(false);
					continue;
				}
				((Component)child).gameObject.SetActive(true);
				tk2dSprite component = ((Component)child).GetComponent<tk2dSprite>();
				if (num2 <= Health.Health)
				{
					if (Health.LifebloodState)
					{
						((tk2dBaseSprite)component).SetSprite(50);
					}
					else
					{
						((tk2dBaseSprite)component).SetSprite(9);
					}
				}
				else if (num2 <= Health.MaxHealth)
				{
					((tk2dBaseSprite)component).SetSprite(0);
				}
				else
				{
					((tk2dBaseSprite)component).SetSprite(50);
				}
			}
			((Component)this).gameObject.SetActive(Client.ServerSettings.HealthbarsEnabled);
		}
	}
	internal static class Spectate
	{
		internal enum MoveDir
		{
			Prev,
			Next
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Action<IClientPlayer> <0>__AddPlayer;

			public static Action<IClientPlayer> <1>__RemovePlayer;

			public static PausedEvent <2>__OnPauseChange;
		}

		private static List<IClientPlayer> InScene = new List<IClientPlayer>();

		public static GameObject? FollowedPlayer;

		private static int FollowedPlayerIndex = -1;

		public static bool freecam = false;

		public static Vector2 FreecamMovementVector = Vector2.zero;

		private static GameObject? arrows;

		private static GameObject? LeftArrow;

		private static GameObject? RightArrow;

		private static GameObject? UpArrow;

		private static GameObject? DownArrow;

		private static bool Following => FollowedPlayerIndex != -1;

		public static void Init()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			Client.api.ClientManager.PlayerEnterSceneEvent += AddPlayer;
			Client.api.ClientManager.PlayerLeaveSceneEvent += RemovePlayer;
			Client.api.ClientManager.PlayerDisconnectEvent += RemovePlayer;
			SceneManager.activeSceneChanged += delegate
			{
				ReturnToSelf(wasSceneChange: true);
			};
			GameManager instance = GameManager.instance;
			object obj = <>O.<2>__OnPauseChange;
			if (obj == null)
			{
				PausedEvent val = OnPauseChange;
				<>O.<2>__OnPauseChange = val;
				obj = (object)val;
			}
			instance.GamePausedChange += (PausedEvent)obj;
			Client.OnServerSettingsUpdate = (Action)Delegate.Combine(Client.OnServerSettingsUpdate, (Action)delegate
			{
				if (!Client.ServerSettings.FreecamEnabled && freecam)
				{
					ReturnToSelf();
				}
				if (!Client.ServerSettings.SpectateEnabled && Following)
				{
					ReturnToSelf();
				}
				InScene = GetPlayersInScene();
			});
			Client.OnSSMPSettingsUpdate = (Action<ServerSettings>)Delegate.Combine(Client.OnSSMPSettingsUpdate, (Action<ServerSettings>)delegate(ServerSettings s)
			{
				InScene = GetPlayersInScene(s);
			});
		}

		public static void Unload()
		{
			Client.api.ClientManager.PlayerEnterSceneEvent -= AddPlayer;
			Client.api.ClientManager.PlayerLeaveSceneEvent -= RemovePlayer;
		}

		public static void FocusOnPlayer(MoveDir dir)
		{
			if (InScene.Count == 0)
			{
				Client.LocalChat("There isn't anyone to spectate in this room.");
				return;
			}
			if (!Client.ServerSettings.SpectateEnabled)
			{
				Client.LocalChat("Spectating is currently disabled.");
				ReturnToSelf();
				return;
			}
			int followedPlayerIndex = FollowedPlayerIndex;
			EndPreviousMode();
			ToggleVignette(status: false);
			FollowedPlayerIndex = followedPlayerIndex;
			if (dir == MoveDir.Prev)
			{
				if (FollowedPlayerIndex <= 0)
				{
					FollowedPlayerIndex = InScene.Count - 1;
				}
				else
				{
					FollowedPlayerIndex--;
				}
			}
			else if (FollowedPlayerIndex == -1 || FollowedPlayerIndex == InScene.Count - 1)
			{
				FollowedPlayerIndex = 0;
			}
			else
			{
				FollowedPlayerIndex++;
			}
			FollowedPlayer = InScene[FollowedPlayerIndex].PlayerObject;
			if (!((Object)(object)FollowedPlayer == (Object)null))
			{
				Transform transform = FollowedPlayer.transform;
				ImmobilizePlayer();
				GameManager.instance.cameraCtrl.camTarget.heroTransform = transform;
				FixMasks(FollowedPlayer);
				if ((Object)(object)arrows != (Object)null)
				{
					arrows.SetActive(true);
				}
				ToggleUpDownArrows(status: false);
			}
		}

		public static void Update()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			CameraController val = (((Object)(object)GameManager.SilentInstance != (Object)null) ? GameManager.SilentInstance.cameraCtrl : null);
			if (!((Object)(object)val == (Object)null))
			{
				if (freecam)
				{
					Vector3 position = ((Component)val.cam).transform.position;
					Vector2 val2 = FreecamMovementVector + Vector2.op_Implicit(position);
					SetFreecamBoundsArrows(val2);
					val.SnapTo(val2.x, val2.y);
				}
				else if (Following)
				{
					val.camTarget.ExitLockZone();
				}
			}
		}

		private static void SetFreecamBoundsArrows(Vector2 position)
		{
			//IL_000b: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			CameraController cameraCtrl = GameManager.instance.cameraCtrl;
			bool flag = position.x <= 14.8f;
			bool flag2 = position.x >= cameraCtrl.xLimit - 0.2f;
			bool flag3 = position.y <= 8.5f;
			bool flag4 = position.y >= cameraCtrl.yLimit - 0.2f;
			if ((Object)(object)LeftArrow != (Object)null)
			{
				LeftArrow.SetActive(!flag);
			}
			if ((Object)(object)RightArrow != (Object)null)
			{
				RightArrow.SetActive(!flag2);
			}
			if ((Object)(object)DownArrow != (Object)null)
			{
				DownArrow.SetActive(!flag3);
			}
			if ((Object)(object)UpArrow != (Object)null)
			{
				UpArrow.SetActive(!flag4);
			}
		}

		private static void EndPreviousMode()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			FreecamMovementVector = Vector2.zero;
			freecam = false;
			FollowedPlayerIndex = -1;
			FollowedPlayer = null;
			ToggleUpDownArrows(status: true);
			ToggleVignette(status: true);
			GameManager.instance.cameraCtrl.camTarget.heroTransform = HeroController.instance.transform;
			FixMasks(((Component)HeroController.instance).gameObject);
		}

		public static void ReturnToSelf(bool wasSceneChange = false)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			FollowedPlayerIndex = -1;
			FollowedPlayer = null;
			FreecamMovementVector = Vector2.zero;
			freecam = false;
			ToggleVignette(status: true);
			if ((Object)(object)HeroController.instance != (Object)null)
			{
				RestoreControl();
				GameManager.instance.cameraCtrl.camTarget.heroTransform = HeroController.instance.transform;
				if (!wasSceneChange)
				{
					FixMasks(((Component)HeroController.instance).gameObject);
				}
			}
			if ((Object)(object)arrows != (Object)null)
			{
				arrows.SetActive(false);
			}
		}

		private static void ToggleVignette(bool status)
		{
			GameObject val = (((Object)(object)HeroController.SilentInstance != (Object)null) ? ((Component)HeroController.SilentInstance).gameObject : null);
			if ((Object)(object)val != (Object)null)
			{
				GameObject val2 = val.FindGameObjectInChildren("Vignette");
				if ((Object)(object)val2 != (Object)null)
				{
					val2.SetActive(status);
				}
			}
		}

		private static void FixMasks(GameObject playerObject)
		{
			Remasker[] array = Resources.FindObjectsOfTypeAll<Remasker>();
			Collider2D component = playerObject.GetComponent<Collider2D>();
			Remasker[] array2 = array;
			foreach (Remasker val in array2)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Collider2D component2 = ((Component)val).GetComponent<Collider2D>();
					if ((Object)(object)component2 != (Object)null && component2.IsTouching(component))
					{
						val.Entered();
					}
					else
					{
						val.Exited(false);
					}
				}
			}
		}

		public static void Freecam()
		{
			if (freecam)
			{
				return;
			}
			if (!Client.ServerSettings.FreecamEnabled)
			{
				Client.LocalChat("Freecam is currently disabled.");
				ReturnToSelf();
				return;
			}
			EndPreviousMode();
			ToggleVignette(status: false);
			freecam = true;
			ImmobilizePlayer();
			FixMasks(((Component)HeroController.instance).gameObject);
			if ((Object)(object)arrows != (Object)null)
			{
				arrows.SetActive(true);
			}
			ToggleUpDownArrows(status: true);
		}

		private static void ImmobilizePlayer()
		{
			HeroController.instance.IgnoreInput();
			HeroController.instance.ResetMotion(true);
		}

		private static void RestoreControl()
		{
			HeroController.instance.UnPauseInput();
		}

		public static void CreateFreecamUI()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			Transform child = ((Component)GameManager.instance.gameCams.hudCamera).transform.GetChild(0);
			GameObject obj = Object.Instantiate<GameObject>(((Component)child.GetChild(4).GetChild(2).GetChild(1)
				.GetChild(0)).gameObject, child);
			obj.SetActive(false);
			DownArrow = ((Component)obj.transform.GetChild(0)).gameObject;
			LeftArrow = ((Component)obj.transform.GetChild(1)).gameObject;
			RightArrow = ((Component)obj.transform.GetChild(2)).gameObject;
			UpArrow = ((Component)obj.transform.GetChild(3)).gameObject;
			DownArrow.transform.localPosition = new Vector3(0f, -7.5f, 45f);
			LeftArrow.transform.localPosition = new Vector3(-13.5f, 0f, 45f);
			RightArrow.transform.localPosition = new Vector3(13.5f, 0f, 45f);
			UpArrow.transform.localPosition = new Vector3(0f, 7.5f, 45f);
			arrows = obj;
		}

		private static void ToggleUpDownArrows(bool status)
		{
			if (!((Object)(object)arrows == (Object)null))
			{
				if (Object.op_Implicit((Object)(object)DownArrow))
				{
					DownArrow.SetActive(status);
				}
				if (Object.op_Implicit((Object)(object)UpArrow))
				{
					UpArrow.SetActive(status);
				}
			}
		}

		private static void OnPauseChange(bool isPaused)
		{
			if (!isPaused && (freecam || Following))
			{
				ReturnToSelf();
			}
		}

		private static bool CanSpectatePlayer(IClientPlayer player)
		{
			ServerSettings clientServerSettings = Client.GetClientServerSettings();
			return CanSpectatePlayer(player, clientServerSettings);
		}

		private static bool CanSpectatePlayer(IClientPlayer player, ServerSettings settings)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (!Client.ServerSettings.SpectateTeamOnly)
			{
				return true;
			}
			if (!settings.TeamsEnabled)
			{
				return true;
			}
			return player.Team == Client.api.ClientManager.Team;
		}

		public static void AddPlayer(IClientPlayer player)
		{
			if (CanSpectatePlayer(player) && !InScene.Contains(player))
			{
				InScene.Add(player);
			}
		}

		public static void RemovePlayer(IClientPlayer player)
		{
			IClientPlayer player2 = player;
			int num = InScene.FindIndex((IClientPlayer p) => p.Id == player2.Id);
			if (num == -1)
			{
				return;
			}
			InScene.RemoveAt(num);
			if (Following)
			{
				if (InScene.Count == 0)
				{
					ReturnToSelf();
				}
				else if (num == InScene.Count - 1)
				{
					FocusOnPlayer(MoveDir.Prev);
				}
			}
		}

		private static List<IClientPlayer> GetPlayersInScene()
		{
			return (from p in Client.api.ClientManager.Players.ToList()
				where p.IsInLocalScene && CanSpectatePlayer(p)
				select p).ToList();
		}

		private static List<IClientPlayer> GetPlayersInScene(ServerSettings settings)
		{
			ServerSettings settings2 = settings;
			return (from p in Client.api.ClientManager.Players.ToList()
				where p.IsInLocalScene && CanSpectatePlayer(p, settings2)
				select p).ToList();
		}
	}
	internal static class TeleportRequests
	{
		internal class Request
		{
			private static ushort requestId;

			public ushort RequestId;

			public ushort PlayerId;

			public bool Responded;

			public Request(ushort id)
			{
				PlayerId = id;
				RequestId = requestId++;
			}
		}

		private static readonly List<Request> requests = new List<Request>();

		public static void AddRequest(IClientPlayer player)
		{
			IClientPlayer player2 = player;
			requests.RemoveAll((Request r) => r.PlayerId == player2.Id);
			Request request = new Request(player2.Id);
			requests.Add(request);
			Client.LocalChat(Common.ColoredUsername(player2) + " has requested to teleport to you. Use /tpaccept or /tpdeny within 30 seconds to respond.");
			Timer timer = new Timer(30000.0);
			timer.Elapsed += delegate
			{
				timer.Stop();
				if (requests.Contains(request))
				{
					requests.Remove(request);
					request.Responded = true;
					Client.LocalChat("Teleport from " + Common.ColoredUsername(player2) + " expired.");
				}
			};
			timer.AutoReset = false;
			timer.Start();
		}

		public static void RespondToRequest(bool accepted, string username = "")
		{
			Request request = null;
			if (username != "")
			{
				IClientPlayer player = Client.GetPlayerByName(username);
				if (player == null)
				{
					Client.LocalChat("Player '" + username + "' not found.");
					return;
				}
				request = requests.LastOrDefault((Request r) => r.PlayerId == player.Id);
				if (request == null)
				{
					Client.LocalChat(Common.ColoredUsername(player) + " hasn't sent you a request.");
					return;
				}
			}
			else
			{
				if (requests.Count == 0)
				{
					Client.LocalChat("You don't have any pending teleport requests.");
					return;
				}
				request = requests.Last();
				requests.RemoveAt(requests.Count - 1);
			}
			if (request.Responded)
			{
				if (!string.IsNullOrEmpty(username))
				{
					Client.LocalChat("That teleport request expired.");
				}
				else
				{
					Client.LocalChat("You don't have any active teleport requests.");
				}
				return;
			}
			request.Responded = true;
			if (!accepted)
			{
				PacketSender.SendMessage(request.PlayerId, Messages.TeleportDenied);
				Client.LocalChat("Teleport request denied.");
			}
			else
			{
				Client.LocalChat("Teleport request accepted.");
				PacketSender.SendTeleportAccept(request);
			}
		}
	}
	internal class Warp
	{
		private static bool teleporting;

		private string scene;

		private Vector2 position;

		public Warp(string scene, Vector2 position)
		{
			//IL_000e: 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)
			this.scene = scene;
			this.position = position;
		}

		private void SetHornetPosition()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			GameManager.instance.OnFinishedEnteringScene -= new EnterSceneEvent(SetHornetPosition);
			Log.LogDebug("Setting hornet position");
			GameObject hornetObject = Common.HornetObject;
			if ((Object)(object)hornetObject != (Object)null)
			{
				Extensions.SetPosition2D(hornetObject.transform, position);
			}
			teleporting = false;
		}

		public void WarpToPosition()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			GameObject hornetObject = Common.HornetObject;
			if ((Object)(object)hornetObject == (Object)null || teleporting)
			{
				FailedWarp(scene);
				return;
			}
			TeleportBack.PreviousScene = name;
			TeleportBack.PreviousLocation = Vector2.op_Implicit(hornetObject.transform.position);
			teleporting = true;
			if (scene == name)
			{
				SetHornetPosition();
			}
			else
			{
				WarpToScene();
			}
		}

		private void WarpToScene()
		{
			//IL_0022: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			SceneTeleportMap.GetTeleportMap().TryGetValue(scene, out var value);
			if (value == null)
			{
				FailedWarp(scene);
				return;
			}
			SceneLoadInfo val = new SceneLoadInfo
			{
				SceneName = scene,
				EntryGateName = value.TransitionGates[0],
				PreventCameraFadeOut = true,
				WaitForSceneTransitionCameraFade = false,
				AlwaysUnloadUnusedAssets = true,
				IsFirstLevelForPlayer = false
			};
			GameManager.instance.BeginSceneTransition(val);
			GameManager.instance.OnFinishedEnteringScene += new EnterSceneEvent(SetHornetPosition);
		}

		private static void FailedWarp(string scene)
		{
			Client.LocalChat("I couldn't warp you. Please join the rest of the server in " + scene + ".");
		}

		public static bool GetHornetScenePosition(out string scene, out Vector2 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			scene = ((Scene)(ref activeScene)).name;
			position = Vector2.Zero;
			if ((Object)(object)GameManager.SilentInstance == (Object)null || (int)GameManager.SilentInstance.GameState != 4)
			{
				Client.LocalChat("Resume the game first!");
				return false;
			}
			if (scene == null)
			{
				Client.LocalChat("I couldn't find the current scene!");
				Log.LogError("ACTUAL ERROR: Unable to find current scene.");
				return false;
			}
			GameObject hornetObject = Common.HornetObject;
			if ((Object)(object)hornetObject == (Object)null)
			{
				Client.LocalChat("I couldn't find your position. Uh oh!");
				Log.LogError("ACTUAL ERROR: Unable to find hornet object");
				return false;
			}
			position = (Vector2)Vector2.op_Implicit(hornetObject.transform.position);
			return true;
		}
	}
}
namespace SSMPEssentials.Client.Modules.Patches
{
	[HarmonyPatch]
	internal class DamageHeroPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(DamageHero), "OnAwake")]
		public static void DamageHeroAwake(DamageHero __instance)
		{
			DamageHero __instance2 = __instance;
			__instance2.HeroDamaged += delegate
			{
				PlayerDeaths.DetermineCauseOfDamage(__instance2);
				Log.LogDebug(PlayerDeaths.LatestCause);
			};
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HeroController), "DoSpecialDamage")]
		public static void DoSpecialDamage(HeroController __instance, bool isFrostDamage)
		{
			//IL_0008: 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)
			//IL_0015: Invalid comparison between Unknown and I4
			if (!__instance.takeNoDamage && (int)CheatManager.Invincibility == 0 && (int)ToolItemManager.ActiveState != 1 && !__instance.cState.transitioning)
			{
				PlayerDeaths.LastDamageTime = DateTime.Now;
				if (isFrostDamage)
				{
					Log.LogInfo("Froze");
					PlayerDeaths.LatestCause = CauseOfDeath.Frost;
				}
				else
				{
					Log.LogInfo("Generic Damage Type");
					PlayerDeaths.LatestCause = CauseOfDeath.Generic;
				}
			}
		}
	}
	[HarmonyPatch]
	internal class HealthPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerData), "AddHealth")]
		public static void AddHealth(PlayerData __instance)
		{
			PlayerHealth.OnHealthChange();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerData), "TakeHealth")]
		public static void TakeHealth(PlayerData __instance)
		{
			PlayerHealth.OnHealthChange();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerData), "AddToMaxHealth")]
		public static void AddToMaxHealth(PlayerData __instance)
		{
			PlayerHealth.OnHealthChange();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerData), "MaxHealth")]
		public static void MaxHealth(PlayerData __instance)
		{
			PlayerHealth.OnHealthChange();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HeroController), "UpdateBlueHealth")]
		public static void UpdateBlueHealth(PlayerData __instance)
		{
			PlayerHealth.OnHealthChange();
		}
	}
	[HarmonyPatch]
	internal class MaskerPatch
	{
		[HarmonyPatch(typeof(Remasker), "OnTriggerEnter2D")]
		[HarmonyPrefix]
		public static bool OnTriggerEnter2D(Remasker __instance, Collider2D collision)
		{
			if ((Object)(object)Spectate.FollowedPlayer != (Object)null && (Object)(object)((Component)collision).gameObject == (Object)(object)Spectate.FollowedPlayer)
			{
				__instance.Entered();
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(Remasker), "OnTriggerExit2D")]
		[HarmonyPrefix]
		public static bool OnTriggerExit2D(Remasker __instance, Collider2D collision)
		{
			if ((Object)(object)Spectate.FollowedPlayer != (Object)null && (Object)(object)((Component)collision).gameObject == (Object)(object)Spectate.FollowedPlayer)
			{
				__instance.Exited(false);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal class SSMPServerSettingUpdate
	{
		[HarmonyTargetMethod]
		public static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("SSMP.Networking.Packet.Data.ServerSettingsUpdate");
			if (type == null)
			{
				Log.LogError("Unable to receive SSMP server setting updates (type)");
				return null;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "ReadData", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogError("Unable to receive SSMP server setting updates (method)");
				return null;
			}
			return methodInfo;
		}

		[HarmonyPostfix]
		private static void Postfix(object __instance)
		{
			ServerSettings value = Traverse.Create(__instance).Property("ServerSettings", (object[])null).GetValue<ServerSettings>();
			Client.OnSSMPSettingsUpdate?.Invoke(value);
		}
	}
	[HarmonyPatch]
	internal class SSMPTeamUpdate
	{
		[HarmonyTargetMethod]
		public static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("SSMP.Game.Client.ClientPlayerData");
			if (type == null)
			{
				Log.LogError("Unable to receive SSMP team updates (type)");
				return null;
			}
			MethodInfo methodInfo = AccessTools.PropertySetter(type, "Team");
			if (methodInfo == null)
			{
				Log.LogError("Unable to receive SSMP team updates (method)");
				return null;
			}
			return methodInfo;
		}

		[HarmonyPostfix]
		public static void Postfix(IClientPlayer __instance)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.IsInLocalScene)
			{
				Team team = __instance.Team;
				if (Client.api.ClientManager.Team == team)
				{
					Spectate.AddPlayer(__instance);
				}
				else
				{
					Spectate.RemovePlayer(__instance);
				}
			}
		}
	}
}
namespace SSMPEssentials.Client.Commands
{
	internal class Huddle : IClientCommand, ICommand
	{
		public bool AuthorizedOnly => false;

		public string Trigger => "/huddle";

		public string[] Aliases => new string[1] { "/tpall" };

		public void Execute(string[] arguments)
		{
			List<string> list = arguments.ToList();
			list.RemoveAt(0);
			string text = string.Join(" ", list);
			if (list.Count <= 0)
			{
				PacketSender.SendHuddle();
				return;
			}
			IClientPlayer playerByName = Client.GetPlayerByName(text);
			if (playerByName != null)
			{
				PacketSender.SendHuddle(playerByName.Id);
			}
			else
			{
				Client.LocalChat("Player '" + text + "' not found.");
			}
		}
	}
	internal class TeleportAccept : IClientCommand, ICommand
	{
		public string Trigger => "/tpaccept";

		public string[] Aliases => new string[1] { "/tpa" };

		public void Execute(string[] arguments)
		{
			string usernameFromArgs = TeleportRequest.GetUsernameFromArgs(arguments, required: false);
			TeleportRequests.RespondToRequest(accepted: true, usernameFromArgs);
		}
	}
	internal class TeleportDeny : IClientCommand, ICommand
	{
		public string Trigger => "/tpdeny";

		public string[] Aliases => new string[1] { "/tpd" };

		public void Execute(string[] arguments)
		{
			string usernameFromArgs = TeleportRequest.GetUsernameFromArgs(arguments, required: false);
			TeleportRequests.RespondToRequest(accepted: false, usernameFromArgs);
		}
	}
	internal class TeleportBack : IClientCommand, ICommand
	{
		public static string PreviousScene = "";

		public static Vector2 PreviousLocation = Vector2.zero;

		public string Trigger => "/back";

		public string[] Aliases => Array.Empty<string>();

		public void Execute(string[] arguments)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (!Client.ServerSettings.BackEnabled)
			{
				Client.LocalChat("/back is currently disabled.");
			}
			else if (PreviousScene == "")
			{
				Client.LocalChat("I don't have your previous location.");
			}
			else
			{
				new Warp(PreviousScene, PreviousLocation).WarpToPosition();
			}
		}
	}
	internal class TeleportRequest : IClientCommand, ICommand
	{
		public string Trigger => "/tp";

		public string[] Aliases => new string[1] { "/teleport" };

		public void Execute(string[] arguments)
		{
			IClientPlayer userFromArgs = GetUserFromArgs(arguments, required: true);
			if (userFromArgs != null)
			{
				Client.LocalChat("Teleport request sent to " + Common.ColoredUsername(userFromArgs) + ".");
				PacketSender.SendTeleportRequest(userFromArgs.Id);
			}
		}

		public static string GetUsernameFromArgs(string[] arguments, bool required)
		{
			if (arguments.Length < 2)
			{
				if (required)
				{
					Client.LocalChat("You need to specify a user.");
				}
				return "";
			}
			List<string> list = arguments.ToList();
			list.RemoveAt(0);
			string text = string.Join(" ", list);
			if (string.IsNullOrEmpty(text))
			{
				if (required)
				{
					Client.LocalChat("You need to specify a user.");
				}
				return "";
			}
			return text;
		}

		public static IClientPlayer? GetUserFromArgs(string[] arguments, bool required)
		{
			string usernameFromArgs = GetUsernameFromArgs(arguments, required);
			if (usernameFromArgs == "")
			{
				return null;
			}
			IClientPlayer playerByName = Client.GetPlayerByName(usernameFromArgs);
			if (playerByName != null)
			{
				return playerByName;
			}
			Client.LocalChat("Player '" + usernameFromArgs + "' not found.");
			return null;
		}
	}
}