Decompiled source of ValheimEssentials v1.0.0

plugins/ValheimEssentials/ValheimEssentials.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("ValheimEssentials")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f84a7f7d29d31f2889ca36c8ca597670851b1e2e")]
[assembly: AssemblyProduct("ValheimEssentials")]
[assembly: AssemblyTitle("ValheimEssentials")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimEssentials
{
	public static class BackManager
	{
		public enum PositionType
		{
			Teleport,
			Death
		}

		private static readonly Dictionary<string, Vector3> LastPositions = new Dictionary<string, Vector3>();

		private static readonly Dictionary<string, PositionType> LastTypes = new Dictionary<string, PositionType>();

		public static void SavePosition(Player player, PositionType type = PositionType.Teleport)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			string key = player.GetPlayerID().ToString();
			LastPositions[key] = ((Component)player).transform.position;
			LastTypes[key] = type;
		}

		public static Vector3? GetLastPosition(Player player)
		{
			PositionType type;
			return GetLastPosition(player, out type);
		}

		public static Vector3? GetLastPosition(Player player, out PositionType type)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			type = PositionType.Teleport;
			string key = player.GetPlayerID().ToString();
			if (LastPositions.TryGetValue(key, out var value))
			{
				LastTypes.TryGetValue(key, out type);
				return value;
			}
			return null;
		}

		public static void Clear()
		{
			LastPositions.Clear();
			LastTypes.Clear();
		}
	}
	[HarmonyPatch(typeof(Chat), "InputText")]
	public static class CommandRouter
	{
		private static bool Prefix(Chat __instance)
		{
			string text = ((TMP_InputField)((Terminal)__instance).m_input).text;
			if (string.IsNullOrEmpty(text))
			{
				return true;
			}
			string value = Plugin.CommandPrefix.Value;
			if (!text.StartsWith(value, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			string text2 = text.Substring(value.Length);
			if (string.IsNullOrEmpty(text2))
			{
				return true;
			}
			string[] array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			string cmd = array[0].ToLowerInvariant();
			string[] array2;
			if (array.Length > 1)
			{
				array2 = new string[array.Length - 1];
				Array.Copy(array, 1, array2, 0, array.Length - 1);
			}
			else
			{
				array2 = Array.Empty<string>();
			}
			Dispatch(cmd, array2);
			return false;
		}

		private static void Dispatch(string cmd, string[] args)
		{
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			switch (cmd)
			{
			case "sethome":
			{
				Player localPlayer4 = Player.m_localPlayer;
				if (!((Object)(object)localPlayer4 == (Object)null))
				{
					if (args.Length == 0)
					{
						FeedbackHelper.SendError("Você precisa dar um nome! Ex: /sethome base");
						break;
					}
					if (HomeManager.SetHome(localPlayer4, args[0], ((Component)localPlayer4).transform.position))
					{
						FeedbackHelper.Send("Home '<color=yellow>" + args[0] + "</color>' salvo!");
						break;
					}
					int value = Plugin.MaxHomes.Value;
					FeedbackHelper.SendError($"Limite de homes atingido! ({value}/{value}). Delete um com /delhome <nome>");
				}
				break;
			}
			case "home":
			{
				Player localPlayer7 = Player.m_localPlayer;
				if ((Object)(object)localPlayer7 == (Object)null)
				{
					break;
				}
				if (args.Length == 0)
				{
					FeedbackHelper.SendError("Você precisa dar um nome! Ex: /home base");
					break;
				}
				Vector3? home = HomeManager.GetHome(localPlayer7, args[0]);
				if (!home.HasValue)
				{
					FeedbackHelper.SendError("Home '<color=yellow>" + args[0] + "</color>' não encontrado. Use /homes pra ver seus homes.");
					break;
				}
				TeleportHelper.Teleport(localPlayer7, home.Value);
				FeedbackHelper.Send("Teleportado para '<color=yellow>" + args[0] + "</color>'!");
				break;
			}
			case "delhome":
			{
				Player localPlayer2 = Player.m_localPlayer;
				if (!((Object)(object)localPlayer2 == (Object)null))
				{
					if (args.Length == 0)
					{
						FeedbackHelper.SendError("Você precisa dar um nome! Ex: /delhome base");
					}
					else if (HomeManager.RemoveHome(localPlayer2, args[0]))
					{
						FeedbackHelper.Send("Home '<color=yellow>" + args[0] + "</color>' deletado!");
					}
					else
					{
						FeedbackHelper.SendError("Home '<color=yellow>" + args[0] + "</color>' não encontrado. Use /homes pra ver seus homes.");
					}
				}
				break;
			}
			case "homes":
			{
				Player localPlayer8 = Player.m_localPlayer;
				if (!((Object)(object)localPlayer8 == (Object)null))
				{
					List<string> homeNames = HomeManager.GetHomeNames(localPlayer8);
					int value2 = Plugin.MaxHomes.Value;
					if (homeNames.Count == 0)
					{
						FeedbackHelper.Send("Você não tem homes salvos. Use /sethome <nome> pra criar um!");
						break;
					}
					homeNames.Sort(StringComparer.OrdinalIgnoreCase);
					string arg = string.Join(", ", homeNames);
					FeedbackHelper.Send($"Homes ({homeNames.Count}/{value2}): {arg}");
				}
				break;
			}
			case "back":
			{
				Player localPlayer6 = Player.m_localPlayer;
				if ((Object)(object)localPlayer6 == (Object)null)
				{
					break;
				}
				BackManager.PositionType type;
				Vector3? lastPosition = BackManager.GetLastPosition(localPlayer6, out type);
				if (!lastPosition.HasValue)
				{
					FeedbackHelper.SendError("Nenhuma posição anterior salva. Use um teleporte primeiro!");
					break;
				}
				TeleportHelper.Teleport(localPlayer6, lastPosition.Value);
				if (type == BackManager.PositionType.Death)
				{
					FeedbackHelper.Send("Teleportado para o local da sua morte!");
				}
				else
				{
					FeedbackHelper.Send("Teleportado para a posicao anterior!");
				}
				break;
			}
			case "tpa":
			{
				Player localPlayer5 = Player.m_localPlayer;
				if ((Object)(object)localPlayer5 == (Object)null)
				{
					break;
				}
				if (args.Length == 0)
				{
					FeedbackHelper.SendError("Uso: /tpa <jogador>");
					break;
				}
				string text = string.Join(" ", args);
				if (text.Equals(localPlayer5.GetPlayerName(), StringComparison.OrdinalIgnoreCase))
				{
					FeedbackHelper.SendError("Voce nao pode se teleportar para si mesmo!");
				}
				else
				{
					RpcChannels.SendTpaRequest(localPlayer5, text);
				}
				break;
			}
			case "tpaccept":
			{
				Player localPlayer3 = Player.m_localPlayer;
				if (!((Object)(object)localPlayer3 == (Object)null))
				{
					RpcChannels.SendTpaAccept();
				}
				break;
			}
			case "rtp":
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					float minRange = Plugin.RtpMinRange.Value;
					float maxRange = Plugin.RtpMaxRange.Value;
					RtpManager.StartSearch(localPlayer, minRange, maxRange);
				}
				break;
			}
			default:
				FeedbackHelper.Send("Comando desconhecido: <color=yellow>/" + cmd + "</color>. Use /ajuda para ver os comandos.");
				break;
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	public static class ZNet_Start_Patch
	{
		private static void Postfix()
		{
			HomeManager.Reset();
			RpcChannels.Register();
			Plugin.Log.LogInfo((object)"[ValheimEssentials] RPCs registrados. Homes serao carregados no primeiro uso.");
		}
	}
	[HarmonyPatch(typeof(Player), "CreateTombStone")]
	public static class Player_CreateTombStone_Patch
	{
		private static void Prefix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				BackManager.SavePosition(__instance, BackManager.PositionType.Death);
				FeedbackHelper.Send("Posição de morte salva. Use /back para voltar!");
			}
		}
	}
	public static class FeedbackHelper
	{
		private const string Prefix = "<color=orange>[Essentials]</color>";

		public static void Send(string message)
		{
			if (!((Object)(object)Chat.instance == (Object)null))
			{
				((Terminal)Chat.instance).AddString("<color=orange>[Essentials]</color> " + message);
			}
		}

		public static void SendError(string message)
		{
			if (!((Object)(object)Chat.instance == (Object)null))
			{
				((Terminal)Chat.instance).AddString("<color=orange>[Essentials]</color> <color=red>" + message + "</color>");
			}
		}
	}
	public static class HomeManager
	{
		private static readonly Dictionary<string, Dictionary<string, Vector3>> PlayerHomes = new Dictionary<string, Dictionary<string, Vector3>>();

		private static string _currentFile;

		private static bool _loaded = false;

		private static string GetSavePath()
		{
			string text = "default";
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					string worldName = ZNet.instance.GetWorldName();
					if (!string.IsNullOrEmpty(worldName) && worldName != "")
					{
						text = worldName;
					}
				}
			}
			catch
			{
			}
			string text2 = Path.Combine(Paths.ConfigPath, "ValheimEssentials");
			Directory.CreateDirectory(text2);
			return Path.Combine(text2, "homes_" + text + ".txt");
		}

		private static void EnsureLoaded()
		{
			if (!_loaded)
			{
				Load();
			}
		}

		public static void Reset()
		{
			_loaded = false;
			PlayerHomes.Clear();
		}

		public static void Load()
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			PlayerHomes.Clear();
			_currentFile = GetSavePath();
			_loaded = true;
			Plugin.Log.LogInfo((object)("[ValheimEssentials] Tentando carregar homes de: " + _currentFile));
			if (!File.Exists(_currentFile))
			{
				Plugin.Log.LogInfo((object)("[ValheimEssentials] Arquivo de homes nao encontrado: " + _currentFile));
				return;
			}
			string[] array = File.ReadAllLines(_currentFile);
			foreach (string text in array)
			{
				string[] array2 = text.Split(new char[1] { '|' });
				if (array2.Length != 5)
				{
					continue;
				}
				string key = array2[0];
				string key2 = array2[1];
				if (float.TryParse(array2[2], out var result) && float.TryParse(array2[3], out var result2) && float.TryParse(array2[4], out var result3))
				{
					if (!PlayerHomes.ContainsKey(key))
					{
						PlayerHomes[key] = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
					}
					PlayerHomes[key][key2] = new Vector3(result, result2, result3);
				}
			}
			Plugin.Log.LogInfo((object)$"Homes carregadas de {_currentFile}: {PlayerHomes.Values.Sum((Dictionary<string, Vector3> h) => h.Count)} total");
		}

		public static void Save()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			_currentFile = GetSavePath();
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, Dictionary<string, Vector3>> playerHome in PlayerHomes)
			{
				string key = playerHome.Key;
				foreach (KeyValuePair<string, Vector3> item in playerHome.Value)
				{
					Vector3 value = item.Value;
					list.Add($"{key}|{item.Key}|{value.x}|{value.y}|{value.z}");
				}
			}
			string text = _currentFile + ".tmp";
			File.WriteAllLines(text, list);
			if (File.Exists(_currentFile))
			{
				File.Replace(text, _currentFile, null);
			}
			else
			{
				File.Move(text, _currentFile);
			}
		}

		public static string GetPlayerId(Player player)
		{
			return player.GetPlayerID().ToString();
		}

		public static bool SetHome(Player player, string homeName, Vector3 position)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			EnsureLoaded();
			string playerId = GetPlayerId(player);
			if (!PlayerHomes.ContainsKey(playerId))
			{
				PlayerHomes[playerId] = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase);
			}
			Dictionary<string, Vector3> dictionary = PlayerHomes[playerId];
			if (dictionary.ContainsKey(homeName))
			{
				dictionary[homeName] = position;
				Save();
				return true;
			}
			if (dictionary.Count >= Plugin.MaxHomes.Value)
			{
				return false;
			}
			dictionary[homeName] = position;
			Save();
			return true;
		}

		public static bool RemoveHome(Player player, string homeName)
		{
			EnsureLoaded();
			string playerId = GetPlayerId(player);
			if (!PlayerHomes.ContainsKey(playerId))
			{
				return false;
			}
			bool flag = PlayerHomes[playerId].Remove(homeName);
			if (flag)
			{
				Save();
			}
			return flag;
		}

		public static Vector3? GetHome(Player player, string homeName)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			EnsureLoaded();
			string playerId = GetPlayerId(player);
			if (!PlayerHomes.ContainsKey(playerId))
			{
				return null;
			}
			if (PlayerHomes[playerId].TryGetValue(homeName, out var value))
			{
				return value;
			}
			return null;
		}

		public static List<string> GetHomeNames(Player player)
		{
			EnsureLoaded();
			string playerId = GetPlayerId(player);
			if (!PlayerHomes.ContainsKey(playerId))
			{
				return new List<string>();
			}
			return PlayerHomes[playerId].Keys.ToList();
		}
	}
	[BepInPlugin("com.jojo.valheimessentials", "ValheimEssentials", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.jojo.valheimessentials";

		public const string PluginName = "ValheimEssentials";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		public static ConfigEntry<int> RtpMinRange;

		public static ConfigEntry<int> RtpMaxRange;

		public static ConfigEntry<int> RtpCooldownSeconds;

		public static ConfigEntry<int> HomeCooldownSeconds;

		public static ConfigEntry<int> BackCooldownSeconds;

		public static ConfigEntry<int> MaxHomes;

		public static ConfigEntry<string> CommandPrefix;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CommandPrefix = ((BaseUnityPlugin)this).Config.Bind<string>("General", "CommandPrefix", "/", "Prefixo dos comandos no chat");
			RtpMinRange = ((BaseUnityPlugin)this).Config.Bind<int>("RTP", "MinRange", 1000, "Distância mínima do teleporte aleatório");
			RtpMaxRange = ((BaseUnityPlugin)this).Config.Bind<int>("RTP", "MaxRange", 8000, "Distância máxima do teleporte aleatório");
			RtpCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("RTP", "CooldownSeconds", 0, "Cooldown do /rtp em segundos (0 = desativado)");
			HomeCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Home", "CooldownSeconds", 0, "Cooldown do /home em segundos (0 = desativado)");
			MaxHomes = ((BaseUnityPlugin)this).Config.Bind<int>("Home", "MaxHomes", 5, "Número máximo de homes por jogador");
			BackCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Back", "CooldownSeconds", 0, "Cooldown do /back em segundos (0 = desativado)");
			_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.jojo.valheimessentials");
			if (typeof(Chat).GetMethod("InputText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) == null)
			{
				Log.LogError((object)"[ValheimEssentials] ERRO CRITICO: Chat.InputText nao encontrado! O mod pode nao funcionar apos uma atualizacao do Valheim.");
			}
			Log.LogInfo((object)"ValheimEssentials v1.0.0 carregado!");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class RpcChannels
	{
		public struct PlayerMatch
		{
			public long PeerUid;

			public string PlayerName;
		}

		public static void Register()
		{
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaRequest", (Action<long, ZPackage>)RPC_Server_TpaRequest);
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaNotify", (Action<long, ZPackage>)RPC_Client_TpaNotify);
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaAccept", (Action<long, ZPackage>)RPC_Server_TpaAccept);
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaExecute", (Action<long, ZPackage>)RPC_Client_TpaExecute);
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaExpireRequester", (Action<long, ZPackage>)RPC_Client_TpaExpireRequester);
			ZRoutedRpc.instance.Register<ZPackage>("VE_TpaExpireTarget", (Action<long, ZPackage>)RPC_Client_TpaExpireTarget);
			Plugin.Log.LogInfo((object)"[ValheimEssentials] RPCs de TPA registrados.");
		}

		public static void SendTpaRequest(Player player, string targetQuery)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(player.GetPlayerName());
			val.Write(targetQuery);
			long serverPeerUid = GetServerPeerUid();
			ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerUid, "VE_TpaRequest", new object[1] { val });
		}

		public static void SendTpaAccept()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			long serverPeerUid = GetServerPeerUid();
			ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerUid, "VE_TpaAccept", new object[1] { val });
		}

		private static long GetServerPeerUid()
		{
			if (ZNet.instance.IsServer())
			{
				return ZNet.GetUID();
			}
			ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
			if (serverPeer != null)
			{
				return serverPeer.m_uid;
			}
			Plugin.Log.LogWarning((object)"[ValheimEssentials] GetServerPeerUid: server peer nao encontrado, usando GetUID()");
			return ZNet.GetUID();
		}

		private static void RPC_Server_TpaRequest(long sender, ZPackage pkg)
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			string text = pkg.ReadString();
			string query = pkg.ReadString();
			List<PlayerMatch> list = FindByNameQuery(query);
			if (list.Count == 0)
			{
				SendNotifyError(sender, "Jogador nao encontrado ou offline");
				return;
			}
			if (list.Count > 1)
			{
				string text2 = string.Join(", ", list.Select((PlayerMatch p) => p.PlayerName));
				SendNotifyError(sender, "Multiplos jogadores encontrados: " + text2 + ". Seja mais especifico!");
				return;
			}
			PlayerMatch playerMatch = list[0];
			if (playerMatch.PeerUid == sender)
			{
				SendNotifyError(sender, "Voce nao pode se teleportar para si mesmo!");
				return;
			}
			if (TpaManager.HasPendingFromRequester(sender))
			{
				SendNotifyError(sender, "Voce ja tem um pedido pendente!");
				return;
			}
			TpaManager.PendingRequest pendingRequest = default(TpaManager.PendingRequest);
			pendingRequest.RequesterPeerUid = sender;
			pendingRequest.RequesterName = text;
			pendingRequest.TargetPeerUid = playerMatch.PeerUid;
			pendingRequest.TargetName = playerMatch.PlayerName;
			pendingRequest.ExpiresAt = DateTime.UtcNow.AddSeconds(60.0);
			TpaManager.PendingRequest req = pendingRequest;
			TpaManager.TryAddRequest(sender, req);
			ZPackage val = new ZPackage();
			val.Write((byte)2);
			val.Write(text);
			ZRoutedRpc.instance.InvokeRoutedRPC(playerMatch.PeerUid, "VE_TpaNotify", new object[1] { val });
			ZPackage val2 = new ZPackage();
			val2.Write((byte)1);
			val2.Write(playerMatch.PlayerName);
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VE_TpaNotify", new object[1] { val2 });
			((MonoBehaviour)Plugin.Instance).StartCoroutine(TpaManager.ExpireAfterDelay(sender, 60f));
		}

		private static void RPC_Server_TpaAccept(long sender, ZPackage pkg)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			if (!TpaManager.TryConsumeByTarget(sender, out var req))
			{
				SendNotifyError(sender, "Nenhum pedido de TP pendente para voce!");
				return;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(req.RequesterPeerUid);
			if (peer == null)
			{
				SendNotifyError(sender, "O jogador que fez o pedido se desconectou.");
				return;
			}
			ZNetPeer peer2 = ZNet.instance.GetPeer(sender);
			if (peer2 == null)
			{
				SendNotifyError(req.RequesterPeerUid, "Erro ao obter posicao. Tente novamente.");
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(peer2.m_characterID);
			if (zDO == null)
			{
				SendNotifyError(req.RequesterPeerUid, "Erro ao obter posicao. Tente novamente.");
				return;
			}
			Vector3 position = zDO.GetPosition();
			ZPackage val = new ZPackage();
			val.Write(position);
			val.Write(req.TargetName);
			ZRoutedRpc.instance.InvokeRoutedRPC(req.RequesterPeerUid, "VE_TpaExecute", new object[1] { val });
			ZPackage val2 = new ZPackage();
			val2.Write((byte)3);
			val2.Write(req.RequesterName);
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VE_TpaNotify", new object[1] { val2 });
		}

		private static void RPC_Client_TpaNotify(long sender, ZPackage pkg)
		{
			byte b = pkg.ReadByte();
			string text = pkg.ReadString();
			switch (b)
			{
			case 0:
				FeedbackHelper.SendError(text);
				break;
			case 1:
				FeedbackHelper.Send("Pedido de TP enviado para <color=yellow>" + text + "</color>!");
				break;
			case 2:
				FeedbackHelper.Send("<color=yellow>" + text + "</color> quer se teleportar para voce! Use /tpaccept");
				break;
			case 3:
				FeedbackHelper.Send("<color=yellow>" + text + "</color> foi teleportado para voce!");
				break;
			default:
				Plugin.Log.LogWarning((object)$"[ValheimEssentials] VE_TpaNotify: tipo desconhecido {b}");
				break;
			}
		}

		private static void RPC_Client_TpaExecute(long sender, ZPackage pkg)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Vector3 destination = pkg.ReadVector3();
			string text = pkg.ReadString();
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				TeleportHelper.Teleport(localPlayer, destination);
				FeedbackHelper.Send("Teleportado para <color=yellow>" + text + "</color>!");
			}
		}

		private static void RPC_Client_TpaExpireRequester(long sender, ZPackage pkg)
		{
			string text = pkg.ReadString();
			FeedbackHelper.Send("Pedido de TP para <color=yellow>" + text + "</color> expirou");
		}

		private static void RPC_Client_TpaExpireTarget(long sender, ZPackage pkg)
		{
			string text = pkg.ReadString();
			FeedbackHelper.Send("Pedido de TP de <color=yellow>" + text + "</color> expirou");
		}

		private static List<PlayerMatch> FindByNameQuery(string query)
		{
			string value = query.ToLowerInvariant();
			List<PlayerMatch> list = new List<PlayerMatch>();
			List<ZNetPeer> peers = ZNet.instance.GetPeers();
			foreach (ZNetPeer item in peers)
			{
				if (item.m_playerName != null && item.m_playerName.ToLowerInvariant().Contains(value))
				{
					list.Add(new PlayerMatch
					{
						PeerUid = item.m_uid,
						PlayerName = item.m_playerName
					});
				}
			}
			if (ZNet.instance.IsServer() && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				string playerName = Player.m_localPlayer.GetPlayerName();
				if (playerName != null && playerName.ToLowerInvariant().Contains(value))
				{
					list.Add(new PlayerMatch
					{
						PeerUid = ZNet.GetUID(),
						PlayerName = playerName
					});
				}
			}
			return list;
		}

		private static void SendNotifyError(long peerUid, string errorMessage)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write((byte)0);
			val.Write(errorMessage);
			ZRoutedRpc.instance.InvokeRoutedRPC(peerUid, "VE_TpaNotify", new object[1] { val });
		}
	}
	public static class RtpManager
	{
		private static bool _searching;

		public static void StartSearch(Player player, float minRange, float maxRange)
		{
			if (_searching)
			{
				FeedbackHelper.SendError("Já estamos buscando uma posição segura, espere!");
				return;
			}
			_searching = true;
			FeedbackHelper.Send("Buscando uma posição segura, espere...");
			((MonoBehaviour)Plugin.Instance).StartCoroutine(SearchCoroutine(player, minRange, maxRange));
		}

		private static IEnumerator SearchCoroutine(Player player, float minRange, float maxRange)
		{
			int totalAttempts = 0;
			int attemptsPerFrame = 100;
			int maxTotalAttempts = 10000;
			while (totalAttempts < maxTotalAttempts)
			{
				if ((Object)(object)player == (Object)null)
				{
					_searching = false;
					yield break;
				}
				for (int i = 0; i < attemptsPerFrame; i++)
				{
					totalAttempts++;
					Vector3 candidate = RandomRingPoint(((Component)player).transform.position, minRange, maxRange);
					if (IsSafePosition(candidate.x, candidate.z, out var groundY))
					{
						_searching = false;
						Vector3 safePos = new Vector3(candidate.x, groundY + 1f, candidate.z);
						TeleportHelper.Teleport(player, safePos);
						FeedbackHelper.Send("Teleportado para uma posição aleatória!");
						yield break;
					}
				}
				if (totalAttempts % 2000 == 0)
				{
					FeedbackHelper.Send($"Ainda buscando... ({totalAttempts} tentativas)");
				}
				yield return null;
			}
			_searching = false;
			FeedbackHelper.SendError("Não foi possível encontrar uma posição segura. Tente novamente!");
		}

		private static Vector3 RandomRingPoint(Vector3 center, float minR, float maxR)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			float num = Random.Range(0f, 360f) * ((float)Math.PI / 180f);
			float num2 = Random.Range(minR, maxR);
			float num3 = center.x + Mathf.Cos(num) * num2;
			float num4 = center.z + Mathf.Sin(num) * num2;
			return new Vector3(num3, 0f, num4);
		}

		private static bool IsSafePosition(float x, float z, out float groundY)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0039: Invalid comparison between Unknown and I4
			groundY = 0f;
			if (WorldGenerator.instance == null)
			{
				return false;
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(x, 0f, z);
			Biome biome = WorldGenerator.instance.GetBiome(val);
			if ((int)biome == 256)
			{
				return false;
			}
			groundY = WorldGenerator.instance.GetHeight(x, z);
			if (groundY < 30f)
			{
				return false;
			}
			float num = Mathf.Sqrt(x * x + z * z);
			if (num > 10000f)
			{
				return false;
			}
			return true;
		}
	}
	public static class TeleportHelper
	{
		public static void Teleport(Player player, Vector3 destination)
		{
			//IL_000a: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			BackManager.SavePosition(player);
			((Character)player).TeleportTo(destination, ((Component)player).transform.rotation, true);
			Plugin.Log.LogInfo((object)$"[TeleportHelper] {player.GetPlayerName()} teleportado para {destination}");
		}
	}
	public static class TpaManager
	{
		public struct PendingRequest
		{
			public long RequesterPeerUid;

			public string RequesterName;

			public long TargetPeerUid;

			public string TargetName;

			public DateTime ExpiresAt;
		}

		private static readonly Dictionary<long, PendingRequest> _pending = new Dictionary<long, PendingRequest>();

		public static bool TryAddRequest(long requesterKey, PendingRequest req)
		{
			if (_pending.ContainsKey(requesterKey))
			{
				return false;
			}
			_pending[requesterKey] = req;
			return true;
		}

		public static bool HasPendingFromRequester(long requesterKey)
		{
			return _pending.ContainsKey(requesterKey);
		}

		public static bool TryConsumeByTarget(long targetPeerUid, out PendingRequest req)
		{
			foreach (KeyValuePair<long, PendingRequest> item in _pending)
			{
				if (item.Value.TargetPeerUid == targetPeerUid)
				{
					req = item.Value;
					_pending.Remove(item.Key);
					return true;
				}
			}
			req = default(PendingRequest);
			return false;
		}

		public static bool TryGetPending(long requesterKey, out PendingRequest req)
		{
			return _pending.TryGetValue(requesterKey, out req);
		}

		public static void Remove(long requesterKey)
		{
			_pending.Remove(requesterKey);
		}

		public static void Clear()
		{
			_pending.Clear();
		}

		public static IEnumerator ExpireAfterDelay(long requesterKey, float delaySeconds)
		{
			yield return (object)new WaitForSeconds(delaySeconds);
			if (_pending.TryGetValue(requesterKey, out var req))
			{
				_pending.Remove(requesterKey);
				ZPackage pkgR = new ZPackage();
				pkgR.Write(req.TargetName);
				ZRoutedRpc.instance.InvokeRoutedRPC(req.RequesterPeerUid, "VE_TpaExpireRequester", new object[1] { pkgR });
				ZPackage pkgT = new ZPackage();
				pkgT.Write(req.RequesterName);
				ZRoutedRpc.instance.InvokeRoutedRPC(req.TargetPeerUid, "VE_TpaExpireTarget", new object[1] { pkgT });
			}
		}
	}
}