Decompiled source of TownPortal v1.0.40

plugins/TownPortal.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using TownPortal.Runic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("TownPortal")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Open a blue wood portal back to your bed.")]
[assembly: AssemblyFileVersion("1.0.40.0")]
[assembly: AssemblyInformationalVersion("1.0.40")]
[assembly: AssemblyProduct("TownPortal")]
[assembly: AssemblyTitle("TownPortal")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.40.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 TownPortal
{
	public class ArrivalGuard : MonoBehaviour
	{
		private Vector3 _pos;

		private Quaternion _rot;

		private float _correctAfter;

		private float _until;

		private string _totemKey;

		private bool _snapped;

		private float _totemSeen;

		private float _resnapUntil;

		private int _resnaps;

		public void Arm(Vector3 pos, float yaw)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Arm(pos, yaw, null);
		}

		public void Arm(Vector3 pos, float yaw, string totemKey)
		{
			//IL_0001: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			_pos = pos;
			_rot = Quaternion.Euler(0f, yaw, 0f);
			_correctAfter = Time.time + 2.2f;
			_until = Time.time + 12f;
			_totemKey = (string.IsNullOrEmpty(totemKey) ? null : totemKey);
			_snapped = false;
			_totemSeen = -1f;
			_resnaps = 0;
			if (_totemKey != null)
			{
				_until = Time.time + 30f;
			}
		}

		private void TotemStep()
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				if (((Character)localPlayer).IsTeleporting())
				{
					return;
				}
				if (!RunicApi.TryGetLoadedTotem(_totemKey, out var totem, out var attached))
				{
					_totemSeen = -1f;
					return;
				}
				if (_totemSeen < 0f)
				{
					_totemSeen = Time.time;
				}
				float num = Time.time - _totemSeen;
				if (!_snapped)
				{
					if (!(num < (attached ? 0.5f : 1.5f)))
					{
						if (RunicApi.TryGetDeckPoint(_totemKey, out var point))
						{
							Place(localPlayer, point);
						}
						_snapped = true;
						_resnapUntil = Time.time + 6f;
					}
				}
				else if (Time.time > _resnapUntil || _resnaps >= 3)
				{
					Object.Destroy((Object)(object)this);
				}
				else
				{
					Vector3 position = ((Component)localPlayer).transform.position;
					Vector3 position2 = totem.position;
					Vector2 val = new Vector2(position.x - position2.x, position.z - position2.z);
					if (((Vector2)(ref val)).sqrMagnitude < 400f && (((Character)localPlayer).InWater() || position.y < position2.y - 1.5f) && RunicApi.TryGetDeckPoint(_totemKey, out var point2))
					{
						Place(localPlayer, point2);
						_resnaps++;
					}
				}
			}
		}

		private static void Place(Player player, Vector3 point)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			((Component)player).transform.position = point;
			if ((Object)(object)((Character)player).m_body != (Object)null)
			{
				((Character)player).m_body.position = point;
				((Character)player).m_body.linearVelocity = Vector3.zero;
			}
		}

		private void LateUpdate()
		{
			//IL_0047: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time > _until)
			{
				Object.Destroy((Object)(object)this);
			}
			else if (_totemKey != null)
			{
				TotemStep();
			}
			else
			{
				if (Time.time < _correctAfter)
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				Vector3 position = ((Component)localPlayer).transform.position;
				bool num = position.y > 3000f && _pos.y < 3000f;
				bool flag = _pos.y < 3000f && position.y > _pos.y + 8f;
				if (num || flag)
				{
					((Component)localPlayer).transform.position = _pos;
					((Component)localPlayer).transform.rotation = _rot;
					if ((Object)(object)((Character)localPlayer).m_body != (Object)null)
					{
						((Character)localPlayer).m_body.linearVelocity = Vector3.zero;
					}
				}
			}
		}
	}
	internal static class BookArt
	{
		private sealed class Maps
		{
			public Texture2D Albedo;

			public Texture2D Normal;

			public Texture2D Metal;

			public Texture2D Emission;
		}

		private static Mesh _mesh;

		private static Material _blueMat;

		private static Material _greyMat;

		private static Sprite _blueIcon;

		private static Sprite _greyIcon;

		private static Maps _tomeMaps;

		private static Maps _mysteriousMaps;

		public static Sprite Icon(bool restored)
		{
			if (restored)
			{
				if ((Object)(object)_blueIcon == (Object)null)
				{
					_blueIcon = MakeIcon(restored: true);
				}
				return _blueIcon;
			}
			if ((Object)(object)_greyIcon == (Object)null)
			{
				_greyIcon = MakeIcon(restored: false);
			}
			return _greyIcon;
		}

		public static bool Attach(GameObject prefab, bool restored)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return false;
			}
			Mesh val = BookMesh();
			Material val2 = BookMaterial(restored);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return false;
			}
			Transform val3 = prefab.transform.Find("attach");
			if ((Object)(object)val3 == (Object)null)
			{
				GameObject val4 = new GameObject("attach");
				val4.transform.SetParent(prefab.transform, false);
				val3 = val4.transform;
			}
			Transform val5 = val3.Find("attachobj");
			GameObject val6 = (((Object)(object)val5 != (Object)null) ? ((Component)val5).gameObject : ((Component)val3).gameObject);
			val3.localPosition = Vector3.zero;
			val3.localRotation = Quaternion.identity;
			val3.localScale = Vector3.one;
			val6.transform.localPosition = Vector3.zero;
			val6.transform.localRotation = Quaternion.identity;
			val6.transform.localScale = Vector3.one;
			val6.layer = prefab.layer;
			MeshFilter val7 = val6.GetComponent<MeshFilter>();
			if ((Object)(object)val7 == (Object)null)
			{
				val7 = val6.AddComponent<MeshFilter>();
			}
			val7.sharedMesh = val;
			MeshRenderer val8 = val6.GetComponent<MeshRenderer>();
			if ((Object)(object)val8 == (Object)null)
			{
				val8 = val6.AddComponent<MeshRenderer>();
			}
			((Renderer)val8).sharedMaterial = val2;
			((Renderer)val8).enabled = true;
			((Renderer)val8).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)val8).receiveShadows = true;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val9 in componentsInChildren)
			{
				if (!((Object)(object)val9 == (Object)(object)val8))
				{
					val9.enabled = false;
				}
			}
			BoxCollider component = prefab.GetComponent<BoxCollider>();
			if ((Object)(object)component != (Object)null)
			{
				component.center = new Vector3(0f, 0.034f, 0f);
				component.size = new Vector3(0.185f, 0.068f, 0.252f);
			}
			return true;
		}

		private static Mesh BookMesh()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: 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_0183: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_mesh != (Object)null)
			{
				return _mesh;
			}
			byte[] array = Resource("TownPortal.BookArt.mesh.bin");
			if (array == null || array.Length < 12 || array[0] != 84 || array[1] != 77 || array[2] != 66 || array[3] != 49)
			{
				Plugin.Log.LogError((object)"The leather tome mesh is missing from the plugin.");
				return null;
			}
			int num = BitConverter.ToInt32(array, 4);
			int num2 = BitConverter.ToInt32(array, 8);
			int offset = 12;
			int num3 = offset + num * 32 + num2 * 2;
			if (num <= 0 || num2 <= 0 || array.Length < num3)
			{
				Plugin.Log.LogError((object)"The leather tome mesh is incomplete.");
				return null;
			}
			Vector3[] array2 = (Vector3[])(object)new Vector3[num];
			Vector3[] array3 = (Vector3[])(object)new Vector3[num];
			Vector2[] array4 = (Vector2[])(object)new Vector2[num];
			for (int i = 0; i < num; i++)
			{
				array2[i] = new Vector3(ReadFloat(array, ref offset), ReadFloat(array, ref offset), ReadFloat(array, ref offset));
			}
			for (int j = 0; j < num; j++)
			{
				array3[j] = new Vector3(ReadFloat(array, ref offset), ReadFloat(array, ref offset), ReadFloat(array, ref offset));
			}
			for (int k = 0; k < num; k++)
			{
				array4[k] = new Vector2(ReadFloat(array, ref offset), ReadFloat(array, ref offset));
			}
			int[] array5 = new int[num2];
			for (int l = 0; l < num2; l++)
			{
				array5[l] = BitConverter.ToUInt16(array, offset);
				offset += 2;
			}
			_mesh = new Mesh
			{
				name = "TownPortal_Tome"
			};
			_mesh.vertices = MirrorX(array2);
			_mesh.normals = MirrorX(array3);
			_mesh.uv = array4;
			_mesh.triangles = array5;
			_mesh.RecalculateTangents();
			Color32[] array6 = (Color32[])(object)new Color32[num];
			for (int m = 0; m < num; m++)
			{
				array6[m] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			}
			_mesh.colors32 = array6;
			return _mesh;
		}

		private static Material BookMaterial(bool restored)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			if (restored && (Object)(object)_blueMat != (Object)null)
			{
				return _blueMat;
			}
			if (!restored && (Object)(object)_greyMat != (Object)null)
			{
				return _greyMat;
			}
			Shader val = Shader.Find("Custom/Creature");
			if ((Object)(object)val == (Object)null)
			{
				val = Cache.GetPrefab<Shader>("Custom/Creature");
			}
			if ((Object)(object)val == (Object)null || ((Object)val).name.Contains("Error"))
			{
				Plugin.Log.LogError((object)"Custom/Creature was not available. The tome keeps the amber model.");
				return null;
			}
			if (!EnsureTextures(restored))
			{
				return null;
			}
			Maps maps = (restored ? _tomeMaps : _mysteriousMaps);
			Material val2 = new Material(val);
			((Object)val2).name = (restored ? "TownPortal_Tome_Mat" : "TownPortal_MysteriousTome_Mat");
			val2.shader = val;
			StripTint(val2);
			SetFloat(val2, "_Metallic", 0f);
			SetFloat(val2, "_MetalGloss", 0f);
			SetFloat(val2, "_Glossiness", 0.15f);
			SetFloat(val2, "_UseGlossmap", 1f);
			SetFloat(val2, "_BumpScale", 0.6f);
			SetFloat(val2, "_Cull", 0f);
			SetFloat(val2, "_TwoSidedNormals", 1f);
			if (val2.HasProperty("_Color"))
			{
				val2.SetColor("_Color", Color.white);
			}
			val2.SetTexture("_MainTex", (Texture)(object)maps.Albedo);
			val2.SetTexture("_BumpMap", (Texture)(object)maps.Normal);
			val2.EnableKeyword("_NORMALMAP");
			val2.EnableKeyword("_TWOSIDEDNORMALS_ON");
			val2.SetTexture("_MetallicGlossMap", (Texture)(object)maps.Metal);
			val2.EnableKeyword("_METALLICGLOSSMAP");
			val2.EnableKeyword("_USEGLOSSMAP_ON");
			val2.SetTexture("_EmissionMap", (Texture)(object)maps.Emission);
			if (restored)
			{
				if (val2.HasProperty("_EmissionColor"))
				{
					val2.SetColor("_EmissionColor", new Color(0.7f, 1.7f, 2f));
				}
				val2.EnableKeyword("_EMISSION");
			}
			else
			{
				if (val2.HasProperty("_EmissionColor"))
				{
					val2.SetColor("_EmissionColor", Color.black);
				}
				val2.DisableKeyword("_EMISSION");
			}
			Texture texture = val2.GetTexture("_MainTex");
			Plugin.Log.LogInfo((object)(((Object)val2).name + " shader=" + ((Object)val2.shader).name + " main=" + (((Object)(object)texture != (Object)null) ? ((Object)texture).name : "null") + " metallic=" + (val2.HasProperty("_Metallic") ? val2.GetFloat("_Metallic").ToString("0.00") : "?")));
			if (restored)
			{
				_blueMat = val2;
			}
			else
			{
				_greyMat = val2;
			}
			return val2;
		}

		private static void StripTint(Material mat)
		{
			Shader shader = mat.shader;
			int propertyCount = shader.GetPropertyCount();
			for (int i = 0; i < propertyCount; i++)
			{
				string propertyName = shader.GetPropertyName(i);
				switch (propertyName)
				{
				case "_Hue":
				case "_Saturation":
				case "_Value":
				case "_UseStyles":
				case "_Style":
				case "_NoiseGlowEnabled":
					mat.SetFloat(propertyName, 0f);
					break;
				}
			}
			mat.DisableKeyword("_USESTYLES_ON");
			mat.DisableKeyword("NOISEGLOW");
		}

		private static Sprite MakeIcon(bool restored)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture(restored ? "TownPortal.BookArt.tome_icon.png" : "TownPortal.BookArt.mysterious_icon.png", mipmap: false);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Object)val).name = (restored ? "TownPortal_Tome_icon" : "TownPortal_MysteriousTome_icon");
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width);
		}

		private static bool EnsureTextures(bool restored)
		{
			if (restored && _tomeMaps != null)
			{
				return true;
			}
			if (!restored && _mysteriousMaps != null)
			{
				return true;
			}
			string text = (restored ? "tome" : "mysterious");
			Texture2D val = LoadTexture("TownPortal.BookArt." + text + "_albedo.png", mipmap: true);
			Texture2D val2 = LoadTexture("TownPortal.BookArt." + text + "_normal.png", mipmap: true, linear: true);
			Texture2D val3 = LoadTexture("TownPortal.BookArt." + text + "_metal.png", mipmap: true, linear: true);
			Texture2D val4 = LoadTexture("TownPortal.BookArt." + text + "_emission.png", mipmap: true);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
			{
				Plugin.Log.LogError((object)("The " + text + " tome textures are missing from the plugin."));
				return false;
			}
			PackNormal(val2);
			Crisp((Texture)(object)val);
			Crisp((Texture)(object)val2);
			Crisp((Texture)(object)val3);
			Crisp((Texture)(object)val4);
			((Object)val).name = (restored ? "TownPortal_Tome_Albedo" : "TownPortal_MysteriousTome_Albedo");
			((Object)val2).name = (restored ? "TownPortal_Tome_Normal" : "TownPortal_MysteriousTome_Normal");
			((Object)val3).name = (restored ? "TownPortal_Tome_MetallicSmoothness" : "TownPortal_MysteriousTome_MetallicSmoothness");
			((Object)val4).name = (restored ? "TownPortal_Tome_Emission" : "TownPortal_MysteriousTome_Emission");
			Maps maps = new Maps
			{
				Albedo = val,
				Normal = val2,
				Metal = val3,
				Emission = val4
			};
			if (restored)
			{
				_tomeMaps = maps;
			}
			else
			{
				_mysteriousMaps = maps;
			}
			return true;
		}

		private static void SetFloat(Material mat, string name, float value)
		{
			if (mat.HasProperty(name))
			{
				mat.SetFloat(name, value);
			}
		}

		private static void PackNormal(Texture2D tex)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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)
			Color32[] pixels = tex.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				Color32 val = pixels[i];
				byte r = val.r;
				byte g = val.g;
				val.r = byte.MaxValue;
				val.g = g;
				val.b = byte.MaxValue;
				val.a = r;
				pixels[i] = val;
			}
			tex.SetPixels32(pixels);
			tex.Apply(true, false);
		}

		private static Texture2D LoadTexture(string resource, bool mipmap, bool linear = false)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			byte[] array = Resource(resource);
			if (array == null)
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, mipmap, linear);
			if (!LoadPng(val, array))
			{
				Object.Destroy((Object)(object)val);
				return null;
			}
			((Object)val).name = resource;
			return val;
		}

		private static bool LoadPng(Texture2D tex, byte[] bytes)
		{
			try
			{
				return ImageConversion.LoadImage(tex, bytes);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not decode the leather tome art. " + ex.Message));
				return false;
			}
		}

		private static float ReadFloat(byte[] bytes, ref int offset)
		{
			float result = BitConverter.ToSingle(bytes, offset);
			offset += 4;
			return result;
		}

		private static void Crisp(Texture tex)
		{
			if (!((Object)(object)tex == (Object)null))
			{
				tex.filterMode = (FilterMode)0;
				tex.wrapMode = (TextureWrapMode)1;
				tex.anisoLevel = 0;
			}
		}

		private static Vector3[] MirrorX(Vector3[] values)
		{
			for (int i = 0; i < values.Length; i++)
			{
				values[i].x = 0f - values[i].x;
			}
			return values;
		}

		private static byte[] Resource(string name)
		{
			Stream manifestResourceStream = typeof(BookArt).Assembly.GetManifestResourceStream(name);
			if (manifestResourceStream == null)
			{
				return null;
			}
			using (manifestResourceStream)
			{
				byte[] array = new byte[manifestResourceStream.Length];
				int i;
				int num;
				for (i = 0; i < array.Length; i += num)
				{
					num = manifestResourceStream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				return (i == array.Length) ? array : null;
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class ClearCommand
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Expected O, but got Unknown
				if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					args.Context.AddString("Not in a world.");
				}
				else if (ZNet.instance.IsServer())
				{
					int num = PortalService.ClearWorld();
					args.Context.AddString("Cleared " + num + " town portal objects and the old map markers. Save the world once so they stay gone.");
				}
				else if (!Net.EnsureReady())
				{
					args.Context.AddString("Not connected.");
				}
				else
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TownPortal_Clear", new object[1] { (object)new ZPackage() });
					args.Context.AddString("Asked the server to clear town portals and the old map markers. Save once after it finishes.");
				}
			}
		}

		private static void Postfix()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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)
			//IL_0029: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					//IL_0093: Unknown result type (might be due to invalid IL or missing references)
					//IL_0099: Expected O, but got Unknown
					if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
					{
						args.Context.AddString("Not in a world.");
					}
					else if (ZNet.instance.IsServer())
					{
						int num = PortalService.ClearWorld();
						args.Context.AddString("Cleared " + num + " town portal objects and the old map markers. Save the world once so they stay gone.");
					}
					else if (!Net.EnsureReady())
					{
						args.Context.AddString("Not connected.");
					}
					else
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TownPortal_Clear", new object[1] { (object)new ZPackage() });
						args.Context.AddString("Asked the server to clear town portals and the old map markers. Save once after it finishes.");
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("townportal_clear", "Destroy every town portal and clear the tome cooldown.", (ConsoleEvent)obj, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
	internal static class Content
	{
		public const string MysteriousName = "TownPortal_MysteriousTome";

		public const string TomeName = "TownPortal_Tome";

		public const string DoorName = "TownPortal_Door";

		public const string GateName = "TownPortal_ReturnGate";

		public const string SeHome = "SE_NowhereLikeHome";

		public const string SeRest = "SE_TomeRests";

		private static bool _built;

		private static SharedData _tomeShared;

		private static StatusEffect _seHome;

		private static StatusEffect _seRest;

		private static readonly Dictionary<string, bool> ChestLog = new Dictionary<string, bool>();

		public static void Build()
		{
			//IL_003f: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			if (!_built)
			{
				_built = true;
				PrefabManager.OnVanillaPrefabsAvailable -= Build;
				Sprite val = Icons.Book(new Color(0.45f, 0.28f, 0.16f), new Color(0.75f, 0.62f, 0.42f));
				Sprite val2 = Icons.Book(new Color(0.1f, 0.18f, 0.38f), new Color(0.45f, 0.75f, 1f));
				Sprite val3 = BookArt.Icon(restored: true);
				Sprite val4 = BookArt.Icon(restored: false);
				Sprite val5 = (((Object)(object)val3 != (Object)null) ? val3 : val2);
				Sprite val6 = (((Object)(object)val4 != (Object)null) ? val4 : val);
				ItemConfig val7 = new ItemConfig
				{
					Name = "Mysterious Tome",
					Description = "A ruined book. The way home is still written in it, for someone willing to make it whole.",
					Enabled = false
				};
				CustomItem val8 = new CustomItem("TownPortal_MysteriousTome", "Amber", val7);
				ItemManager.Instance.AddItem(val8);
				Tune(val8, 1, (ItemType)1, val6);
				if (!BookArt.Attach(val8.ItemPrefab, restored: false))
				{
					Plugin.Log.LogWarning((object)"The mysterious tome is still the amber stand-in.");
				}
				ItemConfig val9 = new ItemConfig
				{
					Name = "Tome of Town Portal",
					Description = TomeDescription(),
					CraftingStation = CraftingStations.Workbench,
					MinStationLevel = 1
				};
				val9.AddRequirement("TownPortal_MysteriousTome", 1, 0);
				val9.AddRequirement("SurtlingCore", 10, 0);
				val9.AddRequirement("GreydwarfEye", 25, 0);
				val9.AddRequirement("LeatherScraps", 15, 0);
				val9.AddRequirement("DeerHide", 5, 0);
				CustomItem val10 = new CustomItem("TownPortal_Tome", "Amber", val9);
				ItemManager.Instance.AddItem(val10);
				Tune(val10, 1, (ItemType)16, val5);
				_tomeShared = val10.ItemDrop.m_itemData.m_shared;
				if (!BookArt.Attach(val10.ItemPrefab, restored: true))
				{
					Plugin.Log.LogWarning((object)"The tome of town portal is still the amber stand-in.");
				}
				BuildEffects(val6, val5);
				BuildDoor();
				BuildGate();
			}
		}

		public static bool FirstChestLog(string prefab, bool accepted)
		{
			if (ChestLog.ContainsKey(prefab))
			{
				return false;
			}
			ChestLog[prefab] = accepted;
			return true;
		}

		private static void Tune(CustomItem item, int stack, ItemType type, Sprite icon)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Invalid comparison between Unknown and I4
			SharedData shared = item.ItemDrop.m_itemData.m_shared;
			shared.m_maxStackSize = stack;
			shared.m_weight = 1f;
			shared.m_maxQuality = 1;
			shared.m_itemType = type;
			shared.m_teleportable = true;
			shared.m_icons = (Sprite[])(object)new Sprite[1] { icon };
			item.ItemDrop.m_itemData.m_dropPrefab = item.ItemPrefab;
			if (item.ItemDrop.m_itemData.m_customData == null)
			{
				item.ItemDrop.m_itemData.m_customData = new Dictionary<string, string>();
			}
			item.ItemDrop.m_itemData.m_customData["TownPortal"] = (((int)type == 16) ? "tome" : "ruined");
		}

		private static void BuildEffects(Sprite ruined, Sprite restored)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			StatusEffect val = ScriptableObject.CreateInstance<StatusEffect>();
			((Object)val).name = "SE_NowhereLikeHome";
			val.m_name = "Nowhere Like Home";
			val.m_tooltip = "The way back is still open.";
			val.m_ttl = Mathf.Max(1f, Plugin.DurationSeconds.Value);
			val.m_icon = restored;
			val.m_flashIcon = false;
			val.m_cooldownIcon = false;
			val.m_startMessage = "";
			val.m_stopMessage = "";
			ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(val, false));
			_seHome = val;
			StatusEffect val2 = ScriptableObject.CreateInstance<StatusEffect>();
			((Object)val2).name = "SE_TomeRests";
			val2.m_name = "The Tome Rests";
			val2.m_tooltip = "The tome cannot open another door yet.";
			val2.m_ttl = Mathf.Max(1f, Plugin.CooldownSeconds.Value);
			val2.m_icon = ruined;
			val2.m_flashIcon = false;
			val2.m_cooldownIcon = false;
			val2.m_startMessage = "";
			val2.m_stopMessage = "";
			ItemManager.Instance.AddStatusEffect(new CustomStatusEffect(val2, false));
			_seRest = val2;
		}

		public static void ApplyTimers()
		{
			if ((Object)(object)_seHome != (Object)null)
			{
				_seHome.m_ttl = Mathf.Max(1f, Plugin.DurationSeconds.Value);
			}
			if ((Object)(object)_seRest != (Object)null)
			{
				_seRest.m_ttl = Mathf.Max(1f, Plugin.CooldownSeconds.Value);
			}
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_NowhereLikeHome"));
				if ((Object)(object)statusEffect != (Object)null)
				{
					statusEffect.m_ttl = Mathf.Max(1f, Plugin.DurationSeconds.Value);
				}
				StatusEffect statusEffect2 = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_TomeRests"));
				if ((Object)(object)statusEffect2 != (Object)null)
				{
					statusEffect2.m_ttl = Mathf.Max(1f, Plugin.CooldownSeconds.Value);
				}
			}
		}

		public static string TomeDescription()
		{
			//IL_0013: 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)
			string text = KeyText((Plugin.OpenKey != null) ? Plugin.OpenKey.Value : KeyboardShortcut.Empty);
			string text2 = ((text != null) ? (text + " or L2 + right stick") : "L2 + right stick");
			return "Restored to its former glory. While it is in your inventory, " + text2 + " opens a door home to your Runic Spawn Point, or to the bed you have claimed.";
		}

		public static void ApplyTomeText()
		{
			string description = TomeDescription();
			if (_tomeShared != null)
			{
				_tomeShared.m_description = description;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("TownPortal_Tome") : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null)
			{
				val2.m_itemData.m_shared.m_description = description;
			}
		}

		public static string KeyText(KeyboardShortcut key)
		{
			//IL_0002: 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)
			//IL_0026: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref key)).MainKey == 0)
			{
				return null;
			}
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref key)).Modifiers)
			{
				list.Add(KeyName(modifier));
			}
			list.Add(KeyName(((KeyboardShortcut)(ref key)).MainKey));
			return string.Join(" + ", list.ToArray());
		}

		private unsafe static string KeyName(KeyCode code)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0016: 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_0042: Expected I4, but got Unknown
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)code <= 27)
			{
				if ((int)code == 13)
				{
					return "Enter";
				}
				if ((int)code == 27)
				{
					return "Esc";
				}
			}
			else
			{
				if ((int)code == 96)
				{
					return "`";
				}
				switch (code - 303)
				{
				case 5:
					return "Left Alt";
				case 4:
					return "Right Alt";
				case 1:
					return "Left Shift";
				case 0:
					return "Right Shift";
				case 3:
					return "Left Ctrl";
				case 2:
					return "Right Ctrl";
				case 7:
					return "Left Cmd";
				case 6:
					return "Right Cmd";
				}
			}
			string text = ((object)(*(KeyCode*)(&code))/*cast due to .constrained prefix*/).ToString();
			if (text.Length == 6 && text.StartsWith("Alpha", StringComparison.Ordinal))
			{
				return text.Substring(5);
			}
			if (text.StartsWith("Keypad", StringComparison.Ordinal))
			{
				return "Numpad " + text.Substring(6);
			}
			if (text.StartsWith("Mouse", StringComparison.Ordinal))
			{
				return "Mouse " + text.Substring(5);
			}
			return text;
		}

		private static void BuildDoor()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("TownPortal_Door", "portal_wood");
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"portal_wood was not found. The town portal door was not registered.");
				return;
			}
			StripPortalLogic(val);
			RecolorBlue(val);
			ZNetView component = val.GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_persistent = true;
			}
			val.AddComponent<TownDoor>();
			GameObject val2 = new GameObject("TownPortalTrigger");
			val2.transform.SetParent(val.transform, false);
			int num = LayerMask.NameToLayer("character_trigger");
			val2.layer = ((num >= 0) ? num : 0);
			BoxCollider obj = val2.AddComponent<BoxCollider>();
			((Collider)obj).isTrigger = true;
			obj.size = new Vector3(1.4f, 2.4f, 1.2f);
			obj.center = new Vector3(0f, 1.3f, 0f);
			val2.AddComponent<DoorTrigger>();
			Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren)
			{
				if (!val3.isTrigger && !((Object)(object)((Component)val3).GetComponent<DoorLabel>() != (Object)null))
				{
					((Component)val3).gameObject.AddComponent<DoorLabel>();
				}
			}
			PrefabManager.Instance.AddPrefab(val);
		}

		private static void StripPortalLogic(GameObject door)
		{
			TeleportWorld[] componentsInChildren = door.GetComponentsInChildren<TeleportWorld>(true);
			foreach (TeleportWorld val in componentsInChildren)
			{
				PortalLook portalLook = door.GetComponent<PortalLook>();
				if ((Object)(object)portalLook == (Object)null)
				{
					portalLook = door.AddComponent<PortalLook>();
				}
				portalLook.Capture(val);
				Object.DestroyImmediate((Object)(object)val);
			}
			Piece[] componentsInChildren2 = door.GetComponentsInChildren<Piece>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[j]);
			}
			WearNTear[] componentsInChildren3 = door.GetComponentsInChildren<WearNTear>(true);
			for (int k = 0; k < componentsInChildren3.Length; k++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[k]);
			}
			HoverText[] componentsInChildren4 = door.GetComponentsInChildren<HoverText>(true);
			for (int l = 0; l < componentsInChildren4.Length; l++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[l]);
			}
		}

		private static void RecolorBlue(GameObject door)
		{
			//IL_0025: 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_0034: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(0.3f, 0.62f, 1f);
			Color val2 = new Color(0.55f, 0.82f, 1f) * 1.8f;
			Light[] componentsInChildren = door.GetComponentsInChildren<Light>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].color = val;
			}
			ParticleSystem[] componentsInChildren2 = door.GetComponentsInChildren<ParticleSystem>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				MainModule main = componentsInChildren2[j].main;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(val);
			}
			Renderer[] componentsInChildren3 = door.GetComponentsInChildren<Renderer>(true);
			for (int k = 0; k < componentsInChildren3.Length; k++)
			{
				Material[] materials = componentsInChildren3[k].materials;
				foreach (Material val3 in materials)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					string text = ((Object)val3).name.ToLowerInvariant();
					if (text.Contains("glow") || text.Contains("portal") || text.Contains("flare") || text.Contains("swirl") || text.Contains("light") || text.Contains("particle") || val3.IsKeywordEnabled("_EMISSION"))
					{
						if (val3.HasProperty("_EmissionColor"))
						{
							val3.EnableKeyword("_EMISSION");
							val3.SetColor("_EmissionColor", val2);
						}
						if (val3.HasProperty("_EmissiveColor"))
						{
							val3.SetColor("_EmissiveColor", val2);
						}
						if (val3.HasProperty("_Color"))
						{
							val3.color = val;
						}
					}
				}
			}
		}

		private static void BuildGate()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = PrefabManager.Instance.CreateEmptyPrefab("TownPortal_ReturnGate", true);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogError((object)"Could not create the return gate prefab.");
				return;
			}
			ZNetView component = val.GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_persistent = true;
			}
			MeshFilter component2 = val.GetComponent<MeshFilter>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component2);
			}
			MeshRenderer component3 = val.GetComponent<MeshRenderer>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component3);
			}
			BoxCollider component4 = val.GetComponent<BoxCollider>();
			if ((Object)(object)component4 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component4);
			}
			GameObject val2 = new GameObject("Field");
			val2.transform.SetParent(val.transform, false);
			val2.AddComponent<MeshFilter>().sharedMesh = OpenCylinder(0.55f, 1.55f, 24);
			MeshRenderer obj = val2.AddComponent<MeshRenderer>();
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			GameObject val3 = new GameObject("Use");
			val3.transform.SetParent(val.transform, false);
			int num = LayerMask.NameToLayer("piece_nonsolid");
			val3.layer = ((num >= 0) ? num : 0);
			CapsuleCollider obj2 = val3.AddComponent<CapsuleCollider>();
			obj2.height = 1.55f;
			obj2.radius = 0.55f;
			obj2.center = new Vector3(0f, 0.775f, 0f);
			((Collider)obj2).isTrigger = false;
			val3.AddComponent<GateInteract>();
			val.AddComponent<GateBody>();
			PrefabManager.Instance.AddPrefab(val);
		}

		private static Mesh OpenCylinder(float radius, float height, int segments)
		{
			//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_0011: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = new Mesh
			{
				name = "TownPortalField"
			};
			Vector3[] array = (Vector3[])(object)new Vector3[segments * 2];
			Vector3[] array2 = (Vector3[])(object)new Vector3[array.Length];
			Vector2[] array3 = (Vector2[])(object)new Vector2[array.Length];
			Color[] array4 = (Color[])(object)new Color[array.Length];
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.2f, 0.45f, 1f, 1f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.45f, 0.72f, 1f, 0.85f);
			for (int i = 0; i < segments; i++)
			{
				float num = (float)i / (float)segments * (float)Math.PI * 2f;
				float num2 = Mathf.Cos(num) * radius;
				float num3 = Mathf.Sin(num) * radius;
				array[i] = new Vector3(num2, 0f, num3);
				array[i + segments] = new Vector3(num2, height, num3);
				int num4 = i + segments;
				int num5 = i;
				Vector3 val4 = new Vector3(num2, 0f, num3);
				val4 = (array2[num4] = (array2[num5] = ((Vector3)(ref val4)).normalized));
				float num6 = (float)i / (float)segments;
				array3[i] = new Vector2(num6, 0f);
				array3[i + segments] = new Vector2(num6, 1f);
				array4[i] = val2;
				array4[i + segments] = val3;
			}
			int[] array5 = new int[segments * 12];
			int num7 = 0;
			for (int j = 0; j < segments; j++)
			{
				int num8 = (j + 1) % segments;
				int num9 = j;
				int num10 = num8;
				int num11 = j + segments;
				int num12 = num8 + segments;
				array5[num7++] = num9;
				array5[num7++] = num11;
				array5[num7++] = num10;
				array5[num7++] = num10;
				array5[num7++] = num11;
				array5[num7++] = num12;
				array5[num7++] = num9;
				array5[num7++] = num10;
				array5[num7++] = num11;
				array5[num7++] = num10;
				array5[num7++] = num12;
				array5[num7++] = num11;
			}
			val.vertices = array;
			val.normals = array2;
			val.uv = array3;
			val.colors = array4;
			val.triangles = array5;
			return val;
		}
	}
	public class DoorLabel : MonoBehaviour, Hoverable
	{
		private TownDoor _door;

		private void Awake()
		{
			_door = ((Component)this).GetComponentInParent<TownDoor>();
		}

		public string GetHoverName()
		{
			if (!((Object)(object)_door != (Object)null))
			{
				return "Town Portal";
			}
			return _door.HoverName();
		}

		public string GetHoverText()
		{
			if (!((Object)(object)_door != (Object)null))
			{
				return "Town Portal";
			}
			return _door.HoverText();
		}

		public float GetHoverOffset()
		{
			return 0f;
		}
	}
	public class DoorTrigger : MonoBehaviour
	{
		private TownDoor _door;

		private void Awake()
		{
			_door = ((Component)this).GetComponentInParent<TownDoor>();
		}

		private void OnTriggerEnter(Collider other)
		{
			if (!((Object)(object)_door == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Player val = ((Component)other).GetComponent<Player>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)other).GetComponentInParent<Player>();
				}
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					Net.RequestTraverse(((Component)_door).GetComponent<ZNetView>());
				}
			}
		}
	}
	internal static class Feedback
	{
		public static void ShowLocal(string message, bool denied)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !string.IsNullOrEmpty(message))
			{
				((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}

		public static void ToPeer(long peer, string message, bool denied)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (!string.IsNullOrEmpty(message))
			{
				if (peer == 0L || ZRoutedRpc.instance == null)
				{
					Plugin.Log.LogInfo((object)("Town portal: no one to tell: " + message));
					return;
				}
				if (peer == ZDOMan.GetSessionID())
				{
					ShowLocal(message, denied);
					return;
				}
				ZPackage val = new ZPackage();
				val.Write(denied);
				val.Write(message);
				ZRoutedRpc.instance.InvokeRoutedRPC(peer, "TownPortal_Deny", new object[1] { val });
			}
		}

		public static void ToPlayer(long playerId, string message, bool denied)
		{
			long num = Net.PeerOfPlayer(playerId);
			if (num != 0L)
			{
				ToPeer(num, message, denied);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class GameStartNet
	{
		private static void Postfix()
		{
			Net.Ensure();
		}
	}
	public class GateBody : MonoBehaviour
	{
		private ZNetView _net;

		private Material _material;

		private Color _color;

		private string _totemKey;

		private float _nextKeyCheck;

		private Transform _totem;

		private Vector3 _offset;

		private bool _offsetFinal;

		private int _offsetTries;

		private float _nextOffsetTry;

		private float _totemSeen;

		private float _nextSync;

		private static readonly Vector3[] Spots = (Vector3[])(object)new Vector3[6]
		{
			new Vector3(1.4f, 0f, 0f),
			new Vector3(-1.4f, 0f, 0f),
			new Vector3(0f, 0f, 1.4f),
			new Vector3(1.4f, 0f, -1.7f),
			new Vector3(-1.4f, 0f, -1.7f),
			new Vector3(0f, 0f, 2.6f)
		};

		private void Awake()
		{
			_net = ((Component)this).GetComponent<ZNetView>();
		}

		private void Start()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_net != (Object)null && _net.IsValid())
			{
				PortalService.Watch(_net);
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && PortalService.Expired(_net.GetZDO()))
				{
					ZNetScene.instance.Destroy(((Component)this).gameObject);
					return;
				}
			}
			MeshRenderer componentInChildren = ((Component)this).GetComponentInChildren<MeshRenderer>();
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				_material = BlueMaterial();
				if (!((Object)(object)_material == (Object)null))
				{
					_color = new Color(0.25f, 0.55f, 1f, 0.45f);
					ApplyColor(_color);
					((Renderer)componentInChildren).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)componentInChildren).receiveShadows = false;
					((Renderer)componentInChildren).material = _material;
				}
			}
			GateNameLabel.Attach(((Component)this).gameObject);
		}

		private static Material BlueMaterial()
		{
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			Material val = null;
			GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("portal_wood") : null);
			if ((Object)(object)val2 != (Object)null)
			{
				ParticleSystemRenderer[] componentsInChildren = val2.GetComponentsInChildren<ParticleSystemRenderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Material sharedMaterial = ((Renderer)componentsInChildren[i]).sharedMaterial;
					if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null) && !((Object)sharedMaterial.shader).name.Contains("Error"))
					{
						val = sharedMaterial;
						break;
					}
				}
			}
			Shader val3 = (((Object)(object)val != (Object)null) ? val.shader : null);
			if ((Object)(object)val3 == (Object)null)
			{
				string[] array = new string[3] { "Custom/Particle", "Custom/AlphaParticle", "Unlit/Color" };
				for (int j = 0; j < array.Length; j++)
				{
					Shader val4 = Shader.Find(array[j]);
					if ((Object)(object)val4 != (Object)null && !((Object)val4).name.Contains("Error"))
					{
						val3 = val4;
						break;
					}
				}
			}
			if ((Object)(object)val3 == (Object)null)
			{
				return null;
			}
			Material val5 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(val3));
			if (val5.HasProperty("_MainTex") && (Object)(object)val5.GetTexture("_MainTex") == (Object)null)
			{
				Texture2D val6 = new Texture2D(1, 1, (TextureFormat)4, false);
				val6.SetPixel(0, 0, Color.white);
				val6.Apply();
				val5.SetTexture("_MainTex", (Texture)(object)val6);
			}
			val5.renderQueue = 3000;
			return val5;
		}

		private void ApplyColor(Color color)
		{
			//IL_002b: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_material == (Object)null))
			{
				if (_material.HasProperty("_Color"))
				{
					_material.SetColor("_Color", color);
				}
				if (_material.HasProperty("_TintColor"))
				{
					_material.SetColor("_TintColor", color);
				}
				_material.color = color;
			}
		}

		private void Update()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_material != (Object)null)
			{
				float a = 0.38f + Mathf.Sin(Time.time * 1.6f) * 0.06f;
				Color color = _color;
				color.a = a;
				ApplyColor(color);
			}
		}

		private void LateUpdate()
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_net == (Object)null || !_net.IsValid())
			{
				return;
			}
			ZDO zDO = _net.GetZDO();
			if (Time.time >= _nextKeyCheck)
			{
				_nextKeyCheck = Time.time + 1f;
				string text = zDO.GetString("totem_key", "");
				text = (string.IsNullOrEmpty(text) ? null : text);
				if (text != _totemKey)
				{
					_totemKey = text;
					_totem = null;
				}
			}
			if (_totemKey == null)
			{
				return;
			}
			Vector3 val;
			if ((Object)(object)_totem == (Object)null)
			{
				if (!RunicApi.TryGetLoadedTotem(_totemKey, out var totem, out var _))
				{
					Vector3 position = zDO.GetPosition();
					val = ((Component)this).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude > 0.25f)
					{
						((Component)this).transform.position = position;
					}
					return;
				}
				_totem = totem;
				_offsetFinal = false;
				_offsetTries = 0;
				_nextOffsetTry = 0f;
				_totemSeen = Time.time;
				_offset = FallbackOffset();
			}
			if (!_offsetFinal && Time.time >= _nextOffsetTry)
			{
				_nextOffsetTry = Time.time + 0.5f;
				RunicApi.TryGetLoadedTotem(_totemKey, out var _, out var attached2);
				if (attached2 || Time.time - _totemSeen > 1.5f)
				{
					_offsetTries++;
					if (TryPickOffset(out var offset))
					{
						_offset = offset;
						_offsetFinal = true;
					}
					else if (_offsetTries >= 10)
					{
						_offsetFinal = true;
					}
				}
			}
			((Component)this).transform.position = _totem.TransformPoint(_offset);
			((Component)this).transform.rotation = _totem.rotation;
			if (_net.IsOwner() && Time.time >= _nextSync)
			{
				_nextSync = Time.time + 0.5f;
				val = zDO.GetPosition() - ((Component)this).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude > 1f)
				{
					zDO.SetPosition(((Component)this).transform.position);
				}
			}
		}

		private Vector3 FallbackOffset()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(0f, 0.05f, 0.85f);
			if (RunicApi.TryGetDeckPoint(_totemKey, out var point))
			{
				val = _totem.InverseTransformPoint(point);
			}
			return val + Spots[0];
		}

		private bool TryPickOffset(out Vector3 offset)
		{
			//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_0022: 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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			offset = Vector3.zero;
			if (!RunicApi.TryGetDeckPoint(_totemKey, out var point))
			{
				return false;
			}
			Vector3 val = _totem.InverseTransformPoint(point);
			int mask = LayerMask.GetMask(new string[5] { "terrain", "Default", "piece", "static_solid", "vehicle" });
			int mask2 = LayerMask.GetMask(new string[4] { "Default", "piece", "static_solid", "vehicle" });
			RaycastHit val2 = default(RaycastHit);
			for (int i = 0; i < Spots.Length; i++)
			{
				if (Physics.Raycast(_totem.TransformPoint(val + Spots[i]) + Vector3.up * 1.8f, Vector3.down, ref val2, 4f, mask, (QueryTriggerInteraction)1) && !(((RaycastHit)(ref val2)).normal.y < 0.6f) && !((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(_totem) && (!((Object)(object)ZoneSystem.instance != (Object)null) || !(((RaycastHit)(ref val2)).point.y < ZoneSystem.instance.m_waterLevel - 0.1f)) && !Physics.CheckCapsule(((RaycastHit)(ref val2)).point + Vector3.up * 0.4f, ((RaycastHit)(ref val2)).point + Vector3.up * 1.7f, 0.35f, mask2, (QueryTriggerInteraction)1))
				{
					offset = _totem.InverseTransformPoint(((RaycastHit)(ref val2)).point + Vector3.up * 0.02f);
					return true;
				}
			}
			return false;
		}

		private void OnDestroy()
		{
			PortalService.Forget(_net);
			if ((Object)(object)_material != (Object)null)
			{
				Object.Destroy((Object)(object)_material);
			}
		}

		public string HoverText()
		{
			string text = "Return";
			long num = (((Object)(object)_net != (Object)null && _net.IsValid()) ? _net.GetZDO().GetLong("owner", 0L) : 0);
			if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerID() == num)
			{
				text = "Return and close";
			}
			string text2 = HoverName() + "\n" + PortalService.Countdown(_net) + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text;
			if (Localization.instance == null)
			{
				return text2;
			}
			return Localization.instance.Localize(text2);
		}

		public string HoverName()
		{
			return (((Object)(object)_net != (Object)null && _net.IsValid()) ? GateNames.ReturnGate(_net.GetZDO()) : null) ?? "Return gate";
		}

		public void RequestReturn()
		{
			if (!((Object)(object)_net == (Object)null) && _net.IsValid())
			{
				Net.RequestReturn(_net);
			}
		}
	}
	public class GateInteract : MonoBehaviour, Hoverable, Interactable
	{
		private GateBody _body;

		private GateBody Body
		{
			get
			{
				if ((Object)(object)_body == (Object)null)
				{
					_body = ((Component)this).GetComponentInParent<GateBody>();
				}
				return _body;
			}
		}

		public string GetHoverName()
		{
			GateBody body = Body;
			if (!((Object)(object)body != (Object)null))
			{
				return "Return gate";
			}
			return body.HoverName();
		}

		public string GetHoverText()
		{
			GateBody body = Body;
			if (!((Object)(object)body != (Object)null))
			{
				return "Return gate";
			}
			return body.HoverText();
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || alt)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			GateBody body = Body;
			if ((Object)(object)body == (Object)null)
			{
				return false;
			}
			body.RequestReturn();
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	public class GateNameLabel : MonoBehaviour
	{
		private const float FadeFrom = 11f;

		private const float HideFrom = 15f;

		private const float MaxAlpha = 0.9f;

		private static TMP_FontAsset _font;

		private static bool _fontSearched;

		private ZNetView _net;

		private TextMeshPro _text;

		private MeshRenderer _renderer;

		private string _shown;

		private float _nextRead;

		private float _alpha = -1f;

		public static void Attach(GameObject gate)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0040: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)gate == (Object)null) && !((Object)(object)gate.GetComponentInChildren<GateNameLabel>(true) != (Object)null) && (int)SystemInfo.graphicsDeviceType != 4 && (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()))
			{
				GameObject val = new GameObject("OwnerName");
				val.transform.SetParent(gate.transform, false);
				val.transform.localPosition = new Vector3(0f, 2.05f, 0f);
				val.AddComponent<GateNameLabel>();
			}
		}

		private void Awake()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			_net = ((Component)this).GetComponentInParent<ZNetView>();
			_text = ((Component)this).gameObject.AddComponent<TextMeshPro>();
			TMP_FontAsset val = GameFont();
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)_text).font = val;
			}
			((TMP_Text)_text).fontSize = 2.2f;
			((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
			((TMP_Text)_text).richText = false;
			((TMP_Text)_text).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
			((TMP_Text)_text).rectTransform.sizeDelta = new Vector2(6f, 0.6f);
			((Graphic)_text).color = new Color(1f, 0.93f, 0.78f, 0f);
			((TMP_Text)_text).text = "";
			_renderer = ((Component)this).GetComponent<MeshRenderer>();
			if ((Object)(object)_renderer != (Object)null)
			{
				((Renderer)_renderer).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)_renderer).receiveShadows = false;
				((Renderer)_renderer).enabled = false;
			}
		}

		private static TMP_FontAsset GameFont()
		{
			if ((Object)(object)_font != (Object)null || _fontSearched)
			{
				return _font;
			}
			_fontSearched = true;
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("sign") : null);
			if ((Object)(object)val != (Object)null)
			{
				Sign componentInChildren = val.GetComponentInChildren<Sign>(true);
				if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.m_textWidget != (Object)null)
				{
					_font = ((TMP_Text)componentInChildren.m_textWidget).font;
				}
				if ((Object)(object)_font == (Object)null)
				{
					TextMeshProUGUI componentInChildren2 = val.GetComponentInChildren<TextMeshProUGUI>(true);
					if ((Object)(object)componentInChildren2 != (Object)null)
					{
						_font = ((TMP_Text)componentInChildren2).font;
					}
				}
			}
			return _font;
		}

		private void LateUpdate()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_text == (Object)null || (Object)(object)_renderer == (Object)null)
			{
				return;
			}
			if (Time.time >= _nextRead)
			{
				_nextRead = Time.time + 1f;
				string text = (((Object)(object)_net != (Object)null && _net.IsValid()) ? GateNames.ReturnGate(_net.GetZDO()) : null);
				if (text != _shown)
				{
					_shown = text;
					((TMP_Text)_text).text = text ?? "";
				}
			}
			Camera mainCamera = Utils.GetMainCamera();
			bool num = _shown != null && (Object)(object)mainCamera != (Object)null && (Plugin.ShowGateNames == null || Plugin.ShowGateNames.Value);
			float num2 = 0f;
			if (num)
			{
				float num3 = Vector3.Distance(((Component)mainCamera).transform.position, ((Component)this).transform.position);
				num2 = 0.9f * Mathf.Clamp01((15f - num3) / 4f);
			}
			if (num2 <= 0.01f)
			{
				if (((Renderer)_renderer).enabled)
				{
					((Renderer)_renderer).enabled = false;
				}
				_alpha = 0f;
				return;
			}
			Face(mainCamera);
			if (Mathf.Abs(num2 - _alpha) > 0.02f)
			{
				_alpha = num2;
				((TMP_Text)_text).alpha = num2;
			}
			if (!((Renderer)_renderer).enabled)
			{
				((Renderer)_renderer).enabled = true;
			}
		}

		private void OnWillRenderObject()
		{
			Face(Utils.GetMainCamera());
		}

		private void Face(Camera cam)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam != (Object)null)
			{
				((Component)this).transform.rotation = ((Component)cam).transform.rotation;
			}
		}
	}
	internal static class GateNames
	{
		public const string Key = "owner_name";

		private const string PinSuffix = "'s town portal";

		public static string Owner(ZDO zdo)
		{
			string text = ((zdo != null) ? zdo.GetString("owner_name", "") : null);
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			return text;
		}

		public static string FromDoor(ZDO door)
		{
			string text = Owner(door);
			if (text != null)
			{
				return text;
			}
			string text2 = ((door != null) ? door.GetString("pinName", "") : null);
			if (!string.IsNullOrEmpty(text2) && text2.Length > "'s town portal".Length && text2.EndsWith("'s town portal", StringComparison.Ordinal))
			{
				return text2.Substring(0, text2.Length - "'s town portal".Length);
			}
			return null;
		}

		public static string ReturnGate(ZDO gate)
		{
			string text = Owner(gate);
			if (text == null)
			{
				return null;
			}
			return text + "'s return gate";
		}

		public static string TownPortal(ZDO door)
		{
			string text = ((door != null) ? door.GetString("pinName", "") : null);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			string text2 = Owner(door);
			if (text2 == null)
			{
				return null;
			}
			return text2 + "'s town portal";
		}
	}
	internal static class Hotkey
	{
		public static void Poll()
		{
			if (!Pressed() || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead() || BlockedByUi())
			{
				return;
			}
			if (((Character)Player.m_localPlayer).InPlaceMode())
			{
				Net.Refuse("Put away your build tool first.");
				return;
			}
			PortalService.RepairTomes(Player.m_localPlayer);
			if (!PortalService.HasTome(Player.m_localPlayer))
			{
				if (PortalService.HasMysteriousTome(Player.m_localPlayer))
				{
					Net.Refuse("That is the ruined tome. Craft it into the Tome of Town Portal first.");
				}
				else
				{
					Net.Refuse("The Tome of Town Portal has to be in your inventory.");
				}
			}
			else if (((Character)Player.m_localPlayer).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_TomeRests")))
			{
				Net.Refuse("The tome is not ready.");
			}
			else
			{
				Net.RequestOpen();
			}
		}

		private static bool Pressed()
		{
			//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)
			if (Plugin.OpenKey != null)
			{
				KeyboardShortcut value = Plugin.OpenKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					return true;
				}
			}
			if (ZInput.instance != null && ZInput.GetButton("JoyLTrigger"))
			{
				return ZInput.GetButtonDown("JoyRStick");
			}
			return false;
		}

		private static bool BlockedByUi()
		{
			if (Console.IsVisible() || TextInput.IsVisible())
			{
				return true;
			}
			if (InventoryGui.IsVisible() || Menu.IsVisible() || StoreGui.IsVisible())
			{
				return true;
			}
			if (Minimap.IsOpen())
			{
				return true;
			}
			if (ChatFocused())
			{
				return true;
			}
			if (((Character)Player.m_localPlayer).InCutscene())
			{
				return true;
			}
			return false;
		}

		private static bool ChatFocused()
		{
			if ((Object)(object)Chat.instance == (Object)null)
			{
				return false;
			}
			return Chat.instance.HasFocus();
		}
	}
	internal static class Icons
	{
		public static Sprite Book(Color cover, Color page)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0041: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0f, 0f, 0f, 0f);
			Color[] array = (Color[])(object)new Color[4096];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val2;
			}
			FillRect(array, 64, 14, 10, 50, 54, cover);
			FillRect(array, 64, 18, 14, 46, 50, page);
			Color color = default(Color);
			((Color)(ref color))..ctor(page.r * 0.45f + 0.2f, page.g * 0.7f + 0.15f, 1f, 1f);
			FillRect(array, 64, 28, 22, 38, 44, color);
			FillRect(array, 64, 10, 12, 16, 52, cover * 0.7f);
			val.SetPixels(array);
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
		}

		private static void FillRect(Color[] pixels, int size, int x0, int y0, int x1, int y1, Color color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			for (int i = y0; i <= y1; i++)
			{
				for (int j = x0; j <= x1; j++)
				{
					pixels[i * size + j] = color;
				}
			}
		}
	}
	internal static class Loot
	{
		private static readonly HashSet<string> Logged = new HashSet<string>();

		public static bool TryRoll(Container container)
		{
			if (WorldGenerator.instance == null)
			{
				return false;
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO.GetBool("TownPortal_TomeRolled", false))
			{
				return true;
			}
			string prefabName = Utils.GetPrefabName(((Component)container).gameObject);
			if (!IsTomeChest(container, prefabName, out var reason))
			{
				if (reason == "no world")
				{
					return false;
				}
				Note(prefabName, accepted: false, reason);
				return true;
			}
			zDO.Set("TownPortal_TomeRolled", true);
			Note(prefabName, accepted: true, "rolled");
			float num = Mathf.Clamp01(Plugin.DropChance.Value);
			if (Random.value > num)
			{
				return true;
			}
			Inventory inventory = container.GetInventory();
			if (inventory == null)
			{
				return true;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("TownPortal_MysteriousTome") : null);
			if ((Object)(object)val == (Object)null || !inventory.AddItem(val, 1))
			{
				return true;
			}
			container.Save();
			return true;
		}

		private unsafe static bool IsTomeChest(Container container, string prefab, out string reason)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Invalid comparison between Unknown and I4
			reason = null;
			if (string.IsNullOrEmpty(prefab))
			{
				reason = "no name";
				return false;
			}
			string text = prefab.ToLowerInvariant();
			if (text.Contains("barrel"))
			{
				reason = "barrel";
				return false;
			}
			if (!text.Contains("chest"))
			{
				reason = "not a chest";
				return false;
			}
			if (container.m_defaultItems == null || container.m_defaultItems.m_drops == null || container.m_defaultItems.m_drops.Count == 0)
			{
				reason = "no default loot";
				return false;
			}
			if (container.m_nview.GetZDO().GetLong("creator", 0L) != 0L)
			{
				reason = "player placed";
				return false;
			}
			if (WorldGenerator.instance == null)
			{
				reason = "no world";
				return false;
			}
			Biome biome = WorldGenerator.instance.GetBiome(((Component)container).transform.position);
			if ((int)biome != 1 && (int)biome != 8)
			{
				reason = ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString();
				return false;
			}
			return true;
		}

		private static void Note(string prefab, bool accepted, string reason)
		{
			if (Plugin.LogChests != null && Plugin.LogChests.Value && Logged.Add(prefab + ":" + accepted))
			{
				Plugin.Log.LogInfo((object)("Tome chest " + prefab + " -> " + (accepted ? "eligible" : ("skip (" + reason + ")"))));
			}
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class LootPatch
	{
		private static void Postfix(Container __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent<TomeRoller>() != (Object)null))
			{
				((Component)__instance).gameObject.AddComponent<TomeRoller>();
			}
		}
	}
	internal static class MapPin
	{
		private static readonly Dictionary<string, PinData> Pins = new Dictionary<string, PinData>();

		private static Sprite _icon;

		private static bool _synced;

		private static float _refresh;

		private static string _signature = "";

		public static void Tick()
		{
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated())
			{
				if (Net.EnsureReady())
				{
					_refresh += Time.unscaledDeltaTime;
					if (!(_refresh < 2f))
					{
						_refresh = 0f;
						Refresh();
					}
				}
			}
			else if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				if (_synced || Pins.Count > 0)
				{
					Reset();
				}
			}
			else
			{
				if ((Object)(object)Minimap.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || !Net.EnsureReady())
				{
					return;
				}
				if (!_synced)
				{
					RemoveSavedTownPins();
					_synced = true;
					if (ZNet.instance.IsServer())
					{
						Refresh();
					}
					else
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "TownPortal_PinSync", new object[1] { (object)new ZPackage() });
					}
				}
				if (ZNet.instance.IsServer())
				{
					_refresh += Time.unscaledDeltaTime;
					if (!(_refresh < 2f))
					{
						_refresh = 0f;
						Refresh();
					}
				}
			}
		}

		public static void Show(long user, uint id, Vector3 pos, string label)
		{
			//IL_0021: 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: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Minimap.instance == (Object)null))
			{
				string key = Key(user, id);
				Hide(user, id);
				PinData val = Minimap.instance.AddPin(pos, (PinType)0, label ?? "Town portal", false, false, 0L, default(PlatformUserID));
				val.m_icon = Icon();
				Pins[key] = val;
			}
		}

		public static void Hide(long user, uint id)
		{
			string key = Key(user, id);
			if (Pins.TryGetValue(key, out var value))
			{
				Pins.Remove(key);
				if (value != null && (Object)(object)Minimap.instance != (Object)null)
				{
					Minimap.instance.RemovePin(value);
				}
			}
		}

		public static void HideAll()
		{
			RemoveSavedTownPins();
			CommitMap();
		}

		public static int RemoveSavedTownPins()
		{
			Pins.Clear();
			if ((Object)(object)Minimap.instance == (Object)null)
			{
				return 0;
			}
			List<PinData> pins = Minimap.instance.m_pins;
			int num = 0;
			bool flag = false;
			for (int num2 = pins.Count - 1; num2 >= 0; num2--)
			{
				PinData val = pins[num2];
				if (IsTownPin(val))
				{
					if (val.m_save)
					{
						flag = true;
					}
					Minimap.instance.RemovePin(val);
					num++;
				}
			}
			if (flag)
			{
				CommitMap();
			}
			return num;
		}

		private static void CommitMap()
		{
			if (!((Object)(object)Minimap.instance == (Object)null) && !((Object)(object)Game.instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.GetWorldUID() != 0L)
			{
				Minimap.instance.SaveMapData();
			}
		}

		public static void Reset()
		{
			HideAll();
			_synced = false;
			_refresh = 0f;
			_signature = "";
		}

		public static void Refresh()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			List<ZDO> list = Doors();
			string text = Signature(list);
			if (text == _signature)
			{
				return;
			}
			_signature = text;
			RemoveSavedTownPins();
			for (int i = 0; i < list.Count; i++)
			{
				ZDO val = list[i];
				string text2 = val.GetString("pinName", "");
				if (string.IsNullOrEmpty(text2))
				{
					text2 = "Town portal";
				}
				Show(((ZDOID)(ref val.m_uid)).UserID, ((ZDOID)(ref val.m_uid)).ID, val.GetPosition(), text2);
			}
			Fanout("TownPortal_PinList", PackAll().GetArray());
		}

		public static void BroadcastShow(ZDOID id, Vector3 pos, string label)
		{
			//IL_000e: 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)
			Show(((ZDOID)(ref id)).UserID, ((ZDOID)(ref id)).ID, pos, label);
			Fanout("TownPortal_Pin", PackOne(((ZDOID)(ref id)).UserID, ((ZDOID)(ref id)).ID, pos, label));
		}

		public static void BroadcastHide(ZDOID id)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Hide(((ZDOID)(ref id)).UserID, ((ZDOID)(ref id)).ID);
			ZPackage val = new ZPackage();
			val.Write(((ZDOID)(ref id)).UserID);
			val.Write((long)((ZDOID)(ref id)).ID);
			Fanout("TownPortal_Unpin", val.GetArray());
		}

		public static void BroadcastClear()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			HideAll();
			Fanout("TownPortal_PinClear", new ZPackage().GetArray());
		}

		public static void ShowAllFromWorld()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			foreach (ZDO item in Doors())
			{
				string text = item.GetString("pinName", "");
				if (string.IsNullOrEmpty(text))
				{
					text = "Town portal";
				}
				Show(((ZDOID)(ref item.m_uid)).UserID, ((ZDOID)(ref item.m_uid)).ID, item.GetPosition(), text);
			}
		}

		public static ZPackage PackAll()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			List<ZDO> list = Doors();
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			for (int i = 0; i < list.Count; i++)
			{
				ZDO val2 = list[i];
				string text = val2.GetString("pinName", "");
				if (string.IsNullOrEmpty(text))
				{
					text = "Town portal";
				}
				val.Write(((ZDOID)(ref val2.m_uid)).UserID);
				val.Write((long)((ZDOID)(ref val2.m_uid)).ID);
				val.Write(val2.GetPosition());
				val.Write(text);
			}
			return val;
		}

		public static void ApplyList(ZPackage pkg)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			RemoveSavedTownPins();
			int num = pkg.ReadInt();
			for (int i = 0; i < num; i++)
			{
				long user = pkg.ReadLong();
				uint id = (uint)pkg.ReadLong();
				Vector3 pos = pkg.ReadVector3();
				string label = pkg.ReadString();
				Show(user, id, pos, label);
			}
		}

		private static List<ZDO> Doors()
		{
			return PortalService.LiveDoors();
		}

		private static byte[] PackOne(long user, uint id, Vector3 pos, string label)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(user);
			val.Write((long)id);
			val.Write(pos);
			val.Write(label ?? "Town portal");
			return val.GetArray();
		}

		private static void Fanout(string method, byte[] data)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if (data == null || (Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				return;
			}
			List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers();
			if (connectedPeers == null)
			{
				return;
			}
			for (int i = 0; i < connectedPeers.Count; i++)
			{
				ZNetPeer val = connectedPeers[i];
				if (val != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC(val.m_uid, method, new object[1] { (object)new ZPackage(data) });
				}
			}
		}

		private static string Signature(List<ZDO> doors)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (doors.Count == 0)
			{
				return "";
			}
			string[] array = new string[doors.Count];
			for (int i = 0; i < doors.Count; i++)
			{
				ZDOID uid = doors[i].m_uid;
				array[i] = ((ZDOID)(ref uid)).UserID + ":" + ((ZDOID)(ref uid)).ID;
			}
			Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal);
			return string.Join("|", array);
		}

		private static bool IsTownPin(PinData pin)
		{
			if (pin == null)
			{
				return false;
			}
			if ((Object)(object)_icon != (Object)null && (Object)(object)pin.m_icon == (Object)(object)_icon)
			{
				return true;
			}
			string name = pin.m_name;
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf("town portal", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static string Key(long user, uint id)
		{
			return user + ":" + id;
		}

		private static Sprite Icon()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_icon != (Object)null)
			{
				return _icon;
			}
			Texture2D val = new Texture2D(48, 48, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			Color[] array = (Color[])(object)new Color[2304];
			float num = 23.5f;
			float num2 = 20.16f;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.22f, 0.48f, 1f, 0.95f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.78f, 0.9f, 1f, 1f);
			for (int i = 0; i < 48; i++)
			{
				for (int j = 0; j < 48; j++)
				{
					float num3 = (float)j - num;
					float num4 = (float)i - num;
					float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
					if (!(num5 > num2))
					{
						float num6 = num5 / num2;
						array[i * 48 + j] = ((num5 > num2 - 2.2f) ? val3 : Color.Lerp(val2, val3, num6 * num6));
					}
				}
			}
			val.SetPixels(array);
			val.Apply();
			_icon = Sprite.Create(val, new Rect(0f, 0f, 48f, 48f), new Vector2(0.5f, 0.5f), 48f);
			return _icon;
		}
	}
	internal static class Net
	{
		private static ZRoutedRpc _hooked;

		private const int TotemTag = 1;

		private const float AnswerTimeout = 12f;

		private static bool _totemPending;

		private static float _totemPendingSince;

		private static int _openPending;

		private static float _openPendingSince;

		private static int _openSerial;

		private static float _travelPendingUntil;

		public static void Ensure()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && _hooked != instance)
			{
				_hooked = instance;
				_totemPending = false;
				_openPending = 0;
				_travelPendingUntil = 0f;
				instance.Register<ZPackage>("TownPortal_Request", (Action<long, ZPackage>)OnRequest);
				instance.Register<ZPackage>("TownPortal_Opened", (Action<long, ZPackage>)OnOpened);
				instance.Register<ZPackage>("TownPortal_Traverse", (Action<long, ZPackage>)OnTraverse);
				instance.Register<ZPackage>("TownPortal_Return", (Action<long, ZPackage>)OnReturn);
				instance.Register<ZPackage>("TownPortal_Closed", (Action<long, ZPackage>)OnClosed);
				instance.Register<ZPackage>("TownPortal_Reset", (Action<long, ZPackage>)OnReset);
				instance.Register<ZPackage>("TownPortal_Deny", (Action<long, ZPackage>)OnDeny);
				instance.Register<ZPackage>("TownPortal_Go", (Action<long, ZPackage>)OnGo);
				instance.Register<ZPackage>("TownPortal_Clear", (Action<long, ZPackage>)OnClear);
				instance.Register<ZPackage>("TownPortal_Pin", (Action<long, ZPackage>)OnPin);
				instance.Register<ZPackage>("TownPortal_Unpin", (Action<long, ZPackage>)OnUnpin);
				instance.Register<ZPackage>("TownPortal_PinClear", (Action<long, ZPackage>)OnPinClear);
				instance.Register<ZPackage>("TownPortal_PinSync", (Action<long, ZPackage>)OnPinSync);
				instance.Register<ZPackage>("TownPortal_PinList", (Action<long, ZPackage>)OnPinList);
				SpawnPointCommand.Register(instance);
			}
		}

		internal static bool EnsureReady()
		{
			Ensure();
			return ZRoutedRpc.instance != null;
		}

		private static long ServerPeer()
		{
			return ZRoutedRpc.instance.GetServerPeerID();
		}

		public static void RequestOpen()
		{
			//IL_00d7: 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)
			if (!EnsureReady())
			{
				Refuse("You are not connected to a world.");
				return;
			}
			if (_openPending != 0 && Time.time - _openPendingSince < 12f)
			{
				Feedback.ShowLocal("The door is already opening...", denied: false);
				Plugin.Log.LogInfo((object)"Town portal: open ignored, the server has not answered the last request yet.");
				return;
			}
			if (_totemPending && Time.time - _totemPendingSince < 75f)
			{
				Feedback.ShowLocal("Still looking for your Runic Spawn Point...", denied: false);
				Plugin.Log.LogInfo((object)"Town portal: open ignored, still waiting for the Runic Spawn Point lookup.");
				return;
			}
			_totemPending = false;
			_openPending = 0;
			if (RunicApi.HasSpawnPoint)
			{
				_totemPending = true;
				_totemPendingSince = Time.time;
				Plugin.Log.LogInfo((object)"Town portal: open requested, asking the server where the Runic Spawn Point is.");
				RunicApi.RequestSpawnPointInfo(delegate(bool found, Vector3 pos, string key, ZDOID id, bool onVehicle)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0003: Unknown result type (might be due to invalid IL or missing references)
					OnTotemAnswer(found, pos, key, id);
				});
			}
			else
			{
				SendOpen(Player.m_localPlayer, null, ZDOID.None, Vector3.zero);
			}
		}

		private static void OnTotemAnswer(bool found, Vector3 pos, string key, ZDOID id)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (_totemPending)
			{
				_totemPending = false;
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
				{
					Plugin.Log.LogInfo((object)"Town portal: open dropped, the player died or left while the spawn point was looked up.");
				}
				else if (!EnsureReady())
				{
					Refuse("You are not connected to a world.");
				}
				else if (!PortalService.HasTome(localPlayer))
				{
					Refuse("The Tome of Town Portal has to be in your inventory.");
				}
				else if (!found || string.IsNullOrEmpty(key))
				{
					Rules.Destination(localPlayer, out var worldStart);
					((Character)localPlayer).Message((MessageType)1, worldStart ? "Couldn't find your Runic Spawn Point. The door opens toward the starting stones." : "Couldn't find your Runic Spawn Point. The door opens to your bed instead.", 0, (Sprite)null, false);
					SendOpen(localPlayer, null, ZDOID.None, Vector3.zero);
				}
				else
				{
					SendOpen(localPlayer, key, id, pos);
				}
			}
		}

		private static void SendOpen(Player player, string totemKey, ZDOID totemId, Vector3 totemPos)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || ((Character)player).IsDead())
			{
				Plugin.Log.LogInfo((object)"Town portal: open dropped, no living local player.");
				return;
			}
			if (((Character)player).InPlaceMode())
			{
				Refuse("Put away your build tool first.");
				return;
			}
			if (((Character)player).GetSEMan().HaveStatusEffect(StringExtensionMethods.GetStableHashCode("SE_TomeRests")))
			{
				Refuse("The tome is not ready.");
				return;
			}
			if (!Rules.PortalsAllowed(out var deny))
			{
				Refuse(deny);
				return;
			}
			float yawOffset = ((Plugin.PortalYawOffset != null) ? Plugin.PortalYawOffset.Value : 0f);
			float radius = ((Plugin.SearchRadius != null) ? Plugin.SearchRadius.Value : 6f);
			if (!Placement.TryFind(player, radius, yawOffset, out var pos, out var rot))
			{
				Refuse("The door has nowhere to open.");
				return;
			}
			Vector3 val = pos + rot * Vector3.forward * 1.8f;
			val.y = Rules.FloorNear(val, pos.y);
			bool worldStart;
			Vector3 val2 = Rules.Destination(player, out worldStart);
			bool flag = !string.IsNullOrEmpty(totemKey);
			ZPackage val3 = new ZPackage();
			val3.Write(++_openSerial);
			val3.Write(player.GetPlayerID());
			val3.Write(player.GetPlayerName() ?? "");
			val3.Write(pos);
			val3.Write(rot);
			val3.Write(val);
			val3.Write(((Quaternion)(ref rot)).eulerAngles.y + 180f);
			val3.Write(val2);
			val3.Write(worldStart);
			val3.Write(flag ? 1 : 0);
			if (flag)
			{
				val3.Write(totemKey);
				val3.Write(totemId);
				val3.Write(totemPos);
			}
			_openPending = _openSerial;
			_openPendingSince = Time.time;
			Plugin.Log.LogInfo((object)("Town portal: open request sent to the server. Door at " + Fmt(pos) + ", leads to " + (flag ? "the Runic Spawn Point" : (worldStart ? "the starting stones" : "the bed")) + "."));
			ZRoutedRpc.instance.InvokeRoutedRPC(ServerPeer(), "TownPortal_Request", new object[1] { val3 });
			if (_openPending == _openSerial && (Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(OpenTimeout(_openSerial));
			}
		}

		private static IEnumerator OpenTimeout(int serial)
		{
			yield return (object)new WaitForSecondsRealtime(12f);
			if (_openPending == serial)
			{
				_openPending = 0;
				Refuse("The server did not answer. Try again in a moment.");
			}
		}

		internal static void Refuse(string message)
		{
			Feedback.ShowLocal(message, denied: true);
			Plugin.Log.LogInfo((object)("Town portal: open refused: " +