Decompiled source of Heimfor v0.1.1

plugins/Heimfor.dll

Decompiled a week ago
using System;
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.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GBV.Skeid;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Guys Being Vikings")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+0d91a9fc5cbcdc93045265f692b14a4a994bdfb6")]
[assembly: AssemblyProduct("Heimfor")]
[assembly: AssemblyTitle("Heimfor")]
[assembly: AssemblyVersion("0.1.1.0")]
[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 GBV.Skeid
{
	internal sealed class ObjModel
	{
		internal sealed class Part
		{
			public string Name;

			public string Material;

			public float[] Vertices;

			public float[] Normals;

			public float[] Uvs;

			public int[] Triangles;

			public float MinX;

			public float MinY;

			public float MinZ;

			public float MaxX;

			public float MaxY;

			public float MaxZ;

			public int VertexCount
			{
				get
				{
					if (Vertices == null)
					{
						return 0;
					}
					return Vertices.Length / 3;
				}
			}

			public int TriangleCount
			{
				get
				{
					if (Triangles == null)
					{
						return 0;
					}
					return Triangles.Length / 3;
				}
			}

			public float CentreX => (MinX + MaxX) * 0.5f;

			public float CentreY => (MinY + MaxY) * 0.5f;

			public float CentreZ => (MinZ + MaxZ) * 0.5f;

			public float SizeX => MaxX - MinX;

			public float SizeY => MaxY - MinY;

			public float SizeZ => MaxZ - MinZ;

			public static void Tangent(float nx, float ny, float nz, float[] into, int at)
			{
				float num = 0f;
				float num2 = 0f;
				float num3 = 0f;
				float num4 = Math.Abs(nx);
				float num5 = Math.Abs(ny);
				float num6 = Math.Abs(nz);
				if (num4 <= num5 && num4 <= num6)
				{
					num = 1f;
				}
				else if (num5 <= num6)
				{
					num2 = 1f;
				}
				else
				{
					num3 = 1f;
				}
				float num7 = ny * num3 - nz * num2;
				float num8 = nz * num - nx * num3;
				float num9 = nx * num2 - ny * num;
				float num10 = (float)Math.Sqrt(num7 * num7 + num8 * num8 + num9 * num9);
				if (num10 < 1E-06f || float.IsNaN(num10) || float.IsInfinity(num10))
				{
					num7 = 1f;
					num8 = 0f;
					num9 = 0f;
					num10 = 1f;
				}
				into[at] = num7 / num10;
				into[at + 1] = num8 / num10;
				into[at + 2] = num9 / num10;
				into[at + 3] = 1f;
			}

			public bool LooksLikeAWheel()
			{
				if (!IsWheelWord(Name))
				{
					return IsWheelWord(Material);
				}
				return true;
			}

			public Part SideOf(bool negative)
			{
				if (Triangles == null || Vertices == null)
				{
					return null;
				}
				Dictionary<int, int> remap = new Dictionary<int, int>();
				List<float> list = new List<float>();
				List<float> list2 = ((Normals != null) ? new List<float>() : null);
				List<float> list3 = ((Uvs != null) ? new List<float>() : null);
				List<int> list4 = new List<int>();
				for (int i = 0; i + 2 < Triangles.Length; i += 3)
				{
					int num = Triangles[i];
					int num2 = Triangles[i + 1];
					int num3 = Triangles[i + 2];
					if ((Vertices[num * 3] + Vertices[num2 * 3] + Vertices[num3 * 3]) / 3f < 0f == negative)
					{
						list4.Add(Copy(num, remap, list, list2, list3));
						list4.Add(Copy(num2, remap, list, list2, list3));
						list4.Add(Copy(num3, remap, list, list2, list3));
					}
				}
				if (list4.Count == 0)
				{
					return null;
				}
				Part part = new Part();
				part.Name = Name + (negative ? "_L" : "_R");
				part.Material = Material;
				part.Vertices = list.ToArray();
				part.Normals = list2?.ToArray();
				part.Uvs = list3?.ToArray();
				part.Triangles = list4.ToArray();
				part.Recalculate();
				return part;
			}

			private int Copy(int index, Dictionary<int, int> remap, List<float> vs, List<float> ns, List<float> uvs)
			{
				if (remap.TryGetValue(index, out var value))
				{
					return value;
				}
				int result = (remap[index] = vs.Count / 3);
				vs.Add(Vertices[index * 3]);
				vs.Add(Vertices[index * 3 + 1]);
				vs.Add(Vertices[index * 3 + 2]);
				if (ns != null)
				{
					ns.Add(Normals[index * 3]);
					ns.Add(Normals[index * 3 + 1]);
					ns.Add(Normals[index * 3 + 2]);
				}
				if (uvs != null)
				{
					uvs.Add(Uvs[index * 2]);
					uvs.Add(Uvs[index * 2 + 1]);
				}
				return result;
			}

			internal void Recalculate()
			{
				MinX = (MinY = (MinZ = float.MaxValue));
				MaxX = (MaxY = (MaxZ = float.MinValue));
				for (int i = 0; i + 2 < Vertices.Length; i += 3)
				{
					float num = Vertices[i];
					float num2 = Vertices[i + 1];
					float num3 = Vertices[i + 2];
					if (num < MinX)
					{
						MinX = num;
					}
					if (num2 < MinY)
					{
						MinY = num2;
					}
					if (num3 < MinZ)
					{
						MinZ = num3;
					}
					if (num > MaxX)
					{
						MaxX = num;
					}
					if (num2 > MaxY)
					{
						MaxY = num2;
					}
					if (num3 > MaxZ)
					{
						MaxZ = num3;
					}
				}
			}

			private static bool IsWheelWord(string s)
			{
				if (string.IsNullOrEmpty(s))
				{
					return false;
				}
				string text = s.ToLowerInvariant();
				if (text.Contains("steer") || text.Contains("ster"))
				{
					return false;
				}
				if (!text.Contains("wheel") && !text.Contains("tyre") && !text.Contains("tire") && !text.Contains("rim"))
				{
					return text.Contains("hubcap");
				}
				return true;
			}
		}

		private sealed class Builder
		{
			public readonly string Name;

			public string Material;

			public readonly List<int> Triangles = new List<int>();

			private readonly Dictionary<long, int> _map = new Dictionary<long, int>();

			private readonly List<float> _vs = new List<float>();

			private readonly List<float> _vns = new List<float>();

			private readonly List<float> _vts = new List<float>();

			private bool _anyNormals;

			private bool _anyUvs;

			public Builder(string name)
			{
				Name = name;
			}

			public int Resolve(string text, int from, int stop, List<float> vs, List<float> vns, List<float> vts, int lineNumber)
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				int num5 = from;
				while (num5 <= stop)
				{
					int i;
					for (i = num5; i < stop && text[i] != '/'; i++)
					{
					}
					if (i > num5)
					{
						if (!int.TryParse(text.Substring(num5, i - num5), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
						{
							throw new ObjException("line " + lineNumber + " has a face corner that is not a number");
						}
						switch (num4)
						{
						case 0:
							num = result;
							break;
						case 1:
							num2 = result;
							break;
						case 2:
							num3 = result;
							break;
						}
					}
					num4++;
					if (i >= stop)
					{
						break;
					}
					num5 = i + 1;
				}
				int num6 = vs.Count / 3;
				int num7 = vts.Count / 2;
				int num8 = vns.Count / 3;
				num = ((num < 0) ? (num6 + num) : (num - 1));
				num2 = ((num2 < 0) ? (num7 + num2) : (num2 - 1));
				num3 = ((num3 < 0) ? (num8 + num3) : (num3 - 1));
				if (num < 0 || num >= num6)
				{
					throw new ObjException("line " + lineNumber + " refers to vertex " + (num + 1) + ", and the file only has " + num6);
				}
				bool flag = num2 >= 0 && num2 < num7;
				bool flag2 = num3 >= 0 && num3 < num8;
				long key = ((long)(num & 0x1FFFFF) << 42) | ((long)((flag ? num2 : 2097151) & 0x1FFFFF) << 21) | ((flag2 ? num3 : 2097151) & 0x1FFFFF);
				if (_map.TryGetValue(key, out var value))
				{
					return value;
				}
				value = _vs.Count / 3;
				_map[key] = value;
				_vs.Add(vs[num * 3]);
				_vs.Add(vs[num * 3 + 1]);
				_vs.Add(vs[num * 3 + 2]);
				if (flag2)
				{
					_anyNormals = true;
					_vns.Add(vns[num3 * 3]);
					_vns.Add(vns[num3 * 3 + 1]);
					_vns.Add(vns[num3 * 3 + 2]);
				}
				else
				{
					_vns.Add(0f);
					_vns.Add(1f);
					_vns.Add(0f);
				}
				if (flag)
				{
					_anyUvs = true;
					_vts.Add(vts[num2 * 2]);
					_vts.Add(vts[num2 * 2 + 1]);
				}
				else
				{
					_vts.Add(0f);
					_vts.Add(0f);
				}
				return value;
			}

			public Part Build()
			{
				Part part = new Part();
				part.Name = Name;
				part.Material = Material;
				part.Vertices = _vs.ToArray();
				part.Triangles = Triangles.ToArray();
				part.Normals = (_anyNormals ? _vns.ToArray() : null);
				part.Uvs = (_anyUvs ? _vts.ToArray() : null);
				part.Recalculate();
				return part;
			}
		}

		public float MinX;

		public float MinY;

		public float MinZ;

		public float MaxX;

		public float MaxY;

		public float MaxZ;

		internal const int MaxTriangles = 200000;

		private const int MaxCorners = 64;

		private static readonly int[] FaceBuffer = new int[64];

		internal List<Part> Parts { get; } = new List<Part>();

		public float SizeX => MaxX - MinX;

		public float SizeY => MaxY - MinY;

		public float SizeZ => MaxZ - MinZ;

		public int VertexCount
		{
			get
			{
				int num = 0;
				for (int i = 0; i < Parts.Count; i++)
				{
					num += Parts[i].VertexCount;
				}
				return num;
			}
		}

		public int TriangleCount
		{
			get
			{
				int num = 0;
				for (int i = 0; i < Parts.Count; i++)
				{
					num += Parts[i].TriangleCount;
				}
				return num;
			}
		}

		internal List<Part> Wheels()
		{
			List<Part> list = new List<Part>();
			for (int i = 0; i < Parts.Count; i++)
			{
				if (Parts[i].LooksLikeAWheel())
				{
					list.Add(Parts[i]);
				}
			}
			return list;
		}

		internal List<Part> Body()
		{
			List<Part> list = new List<Part>();
			for (int i = 0; i < Parts.Count; i++)
			{
				if (!Parts[i].LooksLikeAWheel())
				{
					list.Add(Parts[i]);
				}
			}
			return list;
		}

		internal static ObjModel Parse(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				throw new ObjException("the file is empty");
			}
			ObjModel objModel = new ObjModel();
			List<float> vs = new List<float>();
			List<float> vns = new List<float>();
			List<float> vts = new List<float>();
			Builder current = null;
			string pendingMaterial = null;
			int num = 0;
			int totalTriangles = 0;
			int num2 = 0;
			while (num2 <= text.Length)
			{
				int num3 = text.IndexOf('\n', num2);
				if (num3 < 0)
				{
					num3 = text.Length;
				}
				int num4 = num3;
				if (num4 > num2 && text[num4 - 1] == '\r')
				{
					num4--;
				}
				num++;
				ReadLine(text, num2, num4, vs, vns, vts, ref current, ref pendingMaterial, ref totalTriangles, objModel, num);
				if (num3 >= text.Length)
				{
					break;
				}
				num2 = num3 + 1;
			}
			Flush(current, objModel);
			if (objModel.Parts.Count == 0 || objModel.TriangleCount == 0)
			{
				throw new ObjException("it has no triangles. Faces are the f lines in an OBJ; a file with only v lines is a point cloud, not a model");
			}
			objModel.Recalculate();
			return objModel;
		}

		private static void ReadLine(string text, int start, int stop, List<float> vs, List<float> vns, List<float> vts, ref Builder current, ref string pendingMaterial, ref int totalTriangles, ObjModel model, int lineNumber)
		{
			while (start < stop && (text[start] == ' ' || text[start] == '\t'))
			{
				start++;
			}
			if (start >= stop || text[start] == '#')
			{
				return;
			}
			int i;
			for (i = start; i < stop && text[i] != ' ' && text[i] != '\t'; i++)
			{
			}
			int num = i - start;
			if (num == 1 && text[start] == 'v')
			{
				ReadFloats(text, i, stop, vs, 3, lineNumber, "v", negateThird: true);
			}
			else if (num == 2 && text[start] == 'v' && text[start + 1] == 'n')
			{
				ReadFloats(text, i, stop, vns, 3, lineNumber, "vn", negateThird: true);
			}
			else if (num == 2 && text[start] == 'v' && text[start + 1] == 't')
			{
				ReadFloats(text, i, stop, vts, 2, lineNumber, "vt", negateThird: false);
			}
			else if (num == 1 && text[start] == 'f')
			{
				if (current == null)
				{
					current = new Builder("car");
					current.Material = pendingMaterial;
				}
				AddFace(text, i, stop, vs, vns, vts, current, ref totalTriangles, lineNumber);
			}
			else if (num == 1 && (text[start] == 'o' || text[start] == 'g'))
			{
				string text2 = Trimmed(text, i, stop);
				if (text2.Length != 0)
				{
					Flush(current, model);
					current = new Builder(text2)
					{
						Material = pendingMaterial
					};
				}
			}
			else
			{
				if (num != 6 || string.CompareOrdinal(text, start, "usemtl", 0, 6) != 0)
				{
					return;
				}
				string text3 = Trimmed(text, i, stop);
				if (!(text3 == pendingMaterial))
				{
					pendingMaterial = text3;
					if (current != null && current.Triangles.Count > 0)
					{
						Flush(current, model);
						current = new Builder(current.Name)
						{
							Material = text3
						};
					}
					else if (current != null)
					{
						current.Material = text3;
					}
				}
			}
		}

		private static void ReadFloats(string text, int from, int stop, List<float> into, int count, int lineNumber, string what, bool negateThird)
		{
			int num = 0;
			int i = from;
			while (num < count)
			{
				for (; i < stop && (text[i] == ' ' || text[i] == '\t'); i++)
				{
				}
				if (i >= stop)
				{
					break;
				}
				int j;
				for (j = i; j < stop && text[j] != ' ' && text[j] != '\t'; j++)
				{
				}
				if (!float.TryParse(text.Substring(i, j - i), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					throw new ObjException("line " + lineNumber + " is a " + what + " with something that is not a number in it");
				}
				if (float.IsNaN(result))
				{
					result = 0f;
				}
				into.Add(result);
				num++;
				i = j;
			}
			if (num < count)
			{
				throw new ObjException("line " + lineNumber + " is a " + what + " with only " + num + " numbers; " + count + " are needed");
			}
			if (negateThird && count == 3)
			{
				into[into.Count - 1] = 0f - into[into.Count - 1];
			}
			if (count == 2)
			{
				into[into.Count - 1] = 1f - into[into.Count - 1];
			}
		}

		private static void AddFace(string text, int from, int stop, List<float> vs, List<float> vns, List<float> vts, Builder part, ref int totalTriangles, int lineNumber)
		{
			int[] faceBuffer = FaceBuffer;
			int num = 0;
			int i = from;
			while (i < stop && num < 64)
			{
				for (; i < stop && (text[i] == ' ' || text[i] == '\t'); i++)
				{
				}
				if (i >= stop)
				{
					break;
				}
				int j;
				for (j = i; j < stop && text[j] != ' ' && text[j] != '\t'; j++)
				{
				}
				faceBuffer[num++] = part.Resolve(text, i, j, vs, vns, vts, lineNumber);
				i = j;
			}
			if (num < 3)
			{
				return;
			}
			for (int k = 1; k + 1 < num; k++)
			{
				if (++totalTriangles > 200000)
				{
					throw new ObjException("it has more than " + 200000 + " triangles, which is far more than a car needs and more than this loads");
				}
				part.Triangles.Add(faceBuffer[0]);
				part.Triangles.Add(faceBuffer[k + 1]);
				part.Triangles.Add(faceBuffer[k]);
			}
		}

		private static void Flush(Builder builder, ObjModel model)
		{
			if (builder != null && builder.Triangles.Count != 0)
			{
				model.Parts.Add(builder.Build());
			}
		}

		private static string Trimmed(string text, int from, int stop)
		{
			while (from < stop && (text[from] == ' ' || text[from] == '\t'))
			{
				from++;
			}
			while (stop > from && (text[stop - 1] == ' ' || text[stop - 1] == '\t'))
			{
				stop--;
			}
			if (from >= stop)
			{
				return string.Empty;
			}
			return text.Substring(from, stop - from);
		}

		internal void Recalculate()
		{
			MinX = (MinY = (MinZ = float.MaxValue));
			MaxX = (MaxY = (MaxZ = float.MinValue));
			for (int i = 0; i < Parts.Count; i++)
			{
				Part part = Parts[i];
				if (part.MinX < MinX)
				{
					MinX = part.MinX;
				}
				if (part.MinY < MinY)
				{
					MinY = part.MinY;
				}
				if (part.MinZ < MinZ)
				{
					MinZ = part.MinZ;
				}
				if (part.MaxX > MaxX)
				{
					MaxX = part.MaxX;
				}
				if (part.MaxY > MaxY)
				{
					MaxY = part.MaxY;
				}
				if (part.MaxZ > MaxZ)
				{
					MaxZ = part.MaxZ;
				}
			}
		}
	}
	internal sealed class ObjException : Exception
	{
		internal ObjException(string message)
			: base(message)
		{
		}
	}
}
namespace GBV.Heimfor
{
	internal static class Aura
	{
		private static Shader _additive;

		private static bool _shaderSearched;

		private static string _shaderName = "not resolved yet";

		private static Texture2D _moteTexture;

		private static Texture2D _bandTexture;

		private static AuraDriver _current;

		private static AuraDriver Current
		{
			get
			{
				if (!((Object)(object)_current != (Object)null))
				{
					return null;
				}
				return _current;
			}
		}

		internal static string Describe()
		{
			if (Icons.Headless())
			{
				return "not built (headless)";
			}
			ConfigEntry<bool> showEffect = HeimforPlugin.ShowEffect;
			if (showEffect != null && !showEffect.Value)
			{
				return "switched off in the settings";
			}
			return "shader '" + _shaderName + "'" + ((_shaderName.IndexOf("dditive", StringComparison.Ordinal) < 0) ? "  <-- NOT ADDITIVE, the effect will look flat and pasted on" : "");
		}

		internal static void Begin(Player player)
		{
			End();
			if (!((Object)(object)player == (Object)null) && !Icons.Headless())
			{
				ConfigEntry<bool> showEffect = HeimforPlugin.ShowEffect;
				if (showEffect == null || showEffect.Value)
				{
					GameObject val = Build(player, HeimforPlugin.ChannelSeconds?.Value ?? 10f);
					_current = (((Object)(object)val == (Object)null) ? null : val.GetComponent<AuraDriver>());
				}
			}
		}

		internal static GameObject Build(Player player, float duration, float startedAt = 0f)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Shader val = ResolveAdditive();
				if ((Object)(object)val == (Object)null)
				{
					Safety.Warn("Aura.NoShader", "no particle shader could be found, so the cast has no effect. The stone still works.");
					return null;
				}
				Color val2 = ParseColour(HeimforPlugin.EffectColour?.Value);
				float intensity = Mathf.Clamp(HeimforPlugin.EffectIntensity?.Value ?? 1f, 0f, 2f);
				float radius = Mathf.Clamp(HeimforPlugin.RingRadius?.Value ?? 2.2f, 0.5f, 6f);
				float maxLightRange = Mathf.Clamp(HeimforPlugin.LightRange?.Value ?? 6f, 0f, 20f);
				GameObject val3 = new GameObject("HF_Aura");
				val3.transform.SetParent(((Component)player).transform, false);
				val3.transform.localPosition = Vector3.zero;
				ConfigEntry<bool> showRing = HeimforPlugin.ShowRing;
				GameObject val4 = ((showRing == null || showRing.Value) ? BuildRing(val3, val, val2, player) : null);
				ParticleSystem motes = BuildMotes(val3, val, val2, intensity);
				ParticleSystem column = BuildColumn(val3, val, val2, intensity);
				ConfigEntry<bool> showLight = HeimforPlugin.ShowLight;
				Light glow = ((showLight == null || showLight.Value) ? BuildLight(val3, val2) : null);
				AuraDriver auraDriver = val3.AddComponent<AuraDriver>();
				auraDriver.Duration = Mathf.Max(0.1f, duration);
				auraDriver.Elapsed = Mathf.Max(0f, startedAt);
				auraDriver.Ring = (((Object)(object)val4 == (Object)null) ? null : val4.transform);
				auraDriver.RingRenderer = (((Object)(object)val4 == (Object)null) ? null : val4.GetComponent<MeshRenderer>());
				auraDriver.Motes = motes;
				auraDriver.Column = column;
				auraDriver.Glow = glow;
				auraDriver.Radius = radius;
				auraDriver.Intensity = intensity;
				auraDriver.MaxLightRange = maxLightRange;
				auraDriver.Tint = val2;
				auraDriver.GroundY = GroundUnder(player, out var sensible);
				auraDriver.HasGround = sensible;
				return val3;
			}
			catch (Exception ex)
			{
				Safety.Failed("Aura.Build", ex);
				return null;
			}
		}

		internal static void Release()
		{
			AuraDriver current = Current;
			if (!((Object)(object)current == (Object)null))
			{
				current.Release();
				_current = null;
			}
		}

		internal static void End()
		{
			AuraDriver current = Current;
			if (!((Object)(object)current == (Object)null))
			{
				if ((Object)(object)((Component)current).gameObject != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)current).gameObject);
				}
				_current = null;
			}
		}

		private static GameObject BuildRing(GameObject host, Shader shader, Color colour, Player player)
		{
			//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_007c: 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_0096: 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_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_00c4: 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)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: 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)
			//IL_01a9: Expected O, but got Unknown
			Mesh val = new Mesh
			{
				name = "HF_RingMesh"
			};
			Vector3[] array = (Vector3[])(object)new Vector3[194];
			Vector2[] array2 = (Vector2[])(object)new Vector2[194];
			int[] array3 = new int[576];
			for (int i = 0; i <= 96; i++)
			{
				float num = (float)i / 96f;
				float num2 = num * MathF.PI * 2f;
				float num3 = Mathf.Sin(num2);
				float num4 = Mathf.Cos(num2);
				array[i * 2] = new Vector3(num4 * 0.8f, 0f, num3 * 0.8f);
				array[i * 2 + 1] = new Vector3(num4, 0f, num3);
				array2[i * 2] = new Vector2(num, 0f);
				array2[i * 2 + 1] = new Vector2(num, 1f);
			}
			for (int j = 0; j < 96; j++)
			{
				int num5 = j * 2;
				int num6 = j * 6;
				array3[num6] = num5;
				array3[num6 + 1] = num5 + 1;
				array3[num6 + 2] = num5 + 2;
				array3[num6 + 3] = num5 + 1;
				array3[num6 + 4] = num5 + 3;
				array3[num6 + 5] = num5 + 2;
			}
			val.vertices = array;
			val.uv = array2;
			val.triangles = array3;
			val.RecalculateBounds();
			GameObject val2 = new GameObject("HF_Ring");
			val2.transform.SetParent(host.transform, false);
			val2.AddComponent<MeshFilter>().sharedMesh = val;
			MeshRenderer obj = val2.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = MakeMaterial(shader, (Texture)(object)BandTexture(), colour);
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			((Renderer)obj).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)obj).reflectionProbeUsage = (ReflectionProbeUsage)0;
			return val2;
		}

		private static ParticleSystem BuildMotes(GameObject host, Shader shader, Color colour, float intensity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_005b: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("HF_Motes");
			val.transform.SetParent(host.transform, false);
			ParticleSystem obj = Fresh(val);
			MainModule main = obj.main;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.7f);
			((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.7f, 1.3f);
			((MainModule)(ref main)).startSize = new MinMaxCurve(0.1f, 0.26f);
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.06f);
			((MainModule)(ref main)).maxParticles = 400;
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(colour);
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			ShapeModule shape = obj.shape;
			((ShapeModule)(ref shape)).enabled = true;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)17;
			((ShapeModule)(ref shape)).radius = 1f;
			((ShapeModule)(ref shape)).donutRadius = 0.08f;
			((ShapeModule)(ref shape)).radiusThickness = 1f;
			((ShapeModule)(ref shape)).rotation = new Vector3(90f, 0f, 0f);
			ApplyRamp(obj, colour);
			EmissionModule emission = obj.emission;
			((EmissionModule)(ref emission)).enabled = true;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
			Renderer(obj, shader, (Texture)(object)MoteTexture(), (ParticleSystemRenderMode)0);
			return obj;
		}

		private static ParticleSystem BuildColumn(GameObject host, Shader shader, Color colour, float intensity)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_005b: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_009d: 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)
			//IL_00e3: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("HF_Column");
			val.transform.SetParent(host.transform, false);
			ParticleSystem obj = Fresh(val);
			MainModule main = obj.main;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.9f);
			((MainModule)(ref main)).startSpeed = new MinMaxCurve(3.5f, 6f);
			((MainModule)(ref main)).startSize = new MinMaxCurve(0.06f, 0.14f);
			((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f);
			((MainModule)(ref main)).maxParticles = 200;
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(colour);
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1;
			ShapeModule shape = obj.shape;
			((ShapeModule)(ref shape)).enabled = true;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)10;
			((ShapeModule)(ref shape)).radius = 0.32f;
			((ShapeModule)(ref shape)).radiusThickness = 1f;
			((ShapeModule)(ref shape)).rotation = new Vector3(90f, 0f, 0f);
			ApplyRamp(obj, colour);
			EmissionModule emission = obj.emission;
			((EmissionModule)(ref emission)).enabled = true;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f);
			ParticleSystemRenderer obj2 = Renderer(obj, shader, (Texture)(object)MoteTexture(), (ParticleSystemRenderMode)1);
			obj2.lengthScale = 2.5f;
			obj2.velocityScale = 0.08f;
			return obj;
		}

		private static Light BuildLight(GameObject host, Color colour)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("HF_Light");
			val.transform.SetParent(host.transform, false);
			val.transform.localPosition = new Vector3(0f, 1.1f, 0f);
			Light obj = val.AddComponent<Light>();
			obj.type = (LightType)2;
			obj.color = colour;
			obj.intensity = 0f;
			obj.range = 2f;
			obj.shadows = (LightShadows)0;
			obj.renderMode = (LightRenderMode)2;
			return obj;
		}

		private static ParticleSystem Fresh(GameObject go)
		{
			ParticleSystem obj = go.AddComponent<ParticleSystem>();
			obj.Stop(true, (ParticleSystemStopBehavior)0);
			return obj;
		}

		private static void ApplyRamp(ParticleSystem system, Color colour)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0030: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			Gradient val = new Gradient();
			GradientColorKey[] array = (GradientColorKey[])(object)new GradientColorKey[8];
			GradientAlphaKey[] array2 = (GradientAlphaKey[])(object)new GradientAlphaKey[8];
			for (int i = 0; i < 8; i++)
			{
				float num = AuraPlan.RampAt(i);
				AuraPlan.ColourAt(num, out var warm, out var alpha);
				array[i] = new GradientColorKey(Color.Lerp(colour, Color.white, warm), num);
				array2[i] = new GradientAlphaKey(alpha, num);
			}
			val.SetKeys(array, array2);
			ColorOverLifetimeModule colorOverLifetime = system.colorOverLifetime;
			((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true;
			((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val);
		}

		private static ParticleSystemRenderer Renderer(ParticleSystem system, Shader shader, Texture texture, ParticleSystemRenderMode mode)
		{
			//IL_0007: 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)
			ParticleSystemRenderer component = ((Component)system).GetComponent<ParticleSystemRenderer>();
			component.renderMode = mode;
			((Renderer)component).sharedMaterial = MakeMaterial(shader, texture, Color.white);
			((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)component).receiveShadows = false;
			((Renderer)component).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)component).reflectionProbeUsage = (ReflectionProbeUsage)0;
			return component;
		}

		private static Material MakeMaterial(Shader shader, Texture texture, Color tint)
		{
			//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_0012: Expected O, but got Unknown
			//IL_0035: 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)
			Material val = new Material(shader)
			{
				name = "HF_Additive"
			};
			if ((Object)(object)texture != (Object)null)
			{
				val.mainTexture = texture;
			}
			if (val.HasProperty("_TintColor"))
			{
				val.SetColor("_TintColor", tint);
			}
			if (val.HasProperty("_Color"))
			{
				val.SetColor("_Color", tint);
			}
			return val;
		}

		private static Shader ResolveAdditive()
		{
			if (_shaderSearched)
			{
				return _additive;
			}
			_shaderSearched = true;
			string[] array = new string[5] { "portal_wood", "Torch", "TorchMist", "FireWorkRocket", "Firestaff" };
			foreach (string text in array)
			{
				try
				{
					ZNetScene instance = ZNetScene.instance;
					GameObject val = ((instance != null) ? instance.GetPrefab(text) : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					ParticleSystemRenderer[] componentsInChildren = val.GetComponentsInChildren<ParticleSystemRenderer>(true);
					foreach (ParticleSystemRenderer obj in componentsInChildren)
					{
						object obj2;
						if (obj == null)
						{
							obj2 = null;
						}
						else
						{
							Material sharedMaterial = ((Renderer)obj).sharedMaterial;
							obj2 = ((sharedMaterial != null) ? sharedMaterial.shader : null);
						}
						Shader val2 = (Shader)obj2;
						if (!((Object)(object)val2 == (Object)null) && ((Object)val2).name.IndexOf("additive", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							_additive = val2;
							_shaderName = ((Object)val2).name + " (from " + text + ")";
							return _additive;
						}
					}
				}
				catch (Exception ex)
				{
					Safety.Failed("Aura.ResolveAdditive " + text, ex);
				}
			}
			array = new string[4] { "Legacy Shaders/Particles/Additive", "Particles/Additive", "Legacy Shaders/Particles/Alpha Blended Premultiply", "Sprites/Default" };
			for (int i = 0; i < array.Length; i++)
			{
				Shader val3 = Shader.Find(array[i]);
				if (!((Object)(object)val3 == (Object)null))
				{
					_additive = val3;
					_shaderName = ((Object)val3).name + " (by name)";
					return _additive;
				}
			}
			_shaderName = "none";
			return null;
		}

		internal static void Reset()
		{
			_shaderSearched = false;
			_additive = null;
			_shaderName = "not resolved yet";
		}

		private static Texture2D MoteTexture()
		{
			if ((Object)(object)_moteTexture == (Object)null)
			{
				_moteTexture = Icons.MoteTexture();
			}
			return _moteTexture;
		}

		private static Texture2D BandTexture()
		{
			if ((Object)(object)_bandTexture == (Object)null)
			{
				_bandTexture = Icons.BandTexture();
			}
			return _bandTexture;
		}

		private static float GroundUnder(Player player, out bool sensible)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			sensible = false;
			if ((Object)(object)player == (Object)null)
			{
				return 0f;
			}
			float y = ((Component)player).transform.position.y;
			try
			{
				if ((Object)(object)ZoneSystem.instance == (Object)null)
				{
					return y;
				}
				float solidHeight = ZoneSystem.instance.GetSolidHeight(((Component)player).transform.position);
				if (Mathf.Abs(solidHeight - y) > 1.5f)
				{
					return y;
				}
				sensible = true;
				return solidHeight + 0.03f;
			}
			catch (Exception ex)
			{
				Safety.Failed("Aura.GroundUnder", ex);
				return y;
			}
		}

		private static Color ParseColour(string text)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			Color result = default(Color);
			((Color)(ref result))..ctor(0.5f, 0.78f, 1f, 1f);
			if (string.IsNullOrEmpty(text))
			{
				return result;
			}
			Color result2 = default(Color);
			if (!ColorUtility.TryParseHtmlString(text.Trim(), ref result2))
			{
				Safety.Warn("Aura.BadColour", "'" + text + "' is not a colour like #7FC8FF, so the default is being used.");
				return result;
			}
			result2.a = 1f;
			return result2;
		}
	}
	internal sealed class AuraDriver : MonoBehaviour
	{
		internal float Duration = 10f;

		internal float Elapsed;

		internal Transform Ring;

		internal MeshRenderer RingRenderer;

		internal ParticleSystem Motes;

		internal ParticleSystem Column;

		internal Light Glow;

		internal float Radius = 2.2f;

		internal float Intensity = 1f;

		internal float MaxLightRange = 6f;

		internal Color Tint = Color.white;

		internal float GroundY;

		internal bool HasGround;

		private float _spin;

		private bool _released;

		private float _releasedAt;

		private float _releaseFrom;

		private float _phase;

		private bool _started;

		private void Start()
		{
			_phase = Random.Range(0f, 360f);
			_started = true;
			if ((Object)(object)Motes != (Object)null)
			{
				Motes.Play(true);
			}
			if ((Object)(object)Column != (Object)null)
			{
				Column.Play(true);
			}
			if ((Object)(object)Ring != (Object)null && !HasGround)
			{
				((Component)Ring).gameObject.SetActive(false);
			}
		}

		internal void Release()
		{
			if (!_released)
			{
				_released = true;
				_releasedAt = Time.time;
				_releaseFrom = (((Object)(object)Glow == (Object)null) ? 0f : Glow.intensity);
				if ((Object)(object)Motes != (Object)null)
				{
					Motes.Stop(true, (ParticleSystemStopBehavior)1);
				}
				if ((Object)(object)Column != (Object)null)
				{
					Column.Stop(true, (ParticleSystemStopBehavior)1);
				}
				if ((Object)(object)Ring != (Object)null)
				{
					((Component)Ring).gameObject.SetActive(false);
				}
				Object.Destroy((Object)(object)((Component)this).gameObject, 2.5f);
			}
		}

		private void Update()
		{
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: 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_020b: 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_00d8: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!_started)
				{
					return;
				}
				if (_released)
				{
					FadeOut();
					return;
				}
				Elapsed += Time.deltaTime;
				float t = ((Duration <= 0f) ? 1f : Mathf.Clamp01(Elapsed / Duration));
				_spin += AuraPlan.RingSpin(t) * Time.deltaTime;
				if (_spin > 360f)
				{
					_spin -= 360f;
				}
				if ((Object)(object)Ring != (Object)null && HasGround)
				{
					float num = Radius * AuraPlan.RingRadius(t);
					Ring.localScale = new Vector3(num, 1f, num);
					Vector3 position = ((Component)this).transform.position;
					Ring.position = new Vector3(position.x, GroundY, position.z);
					Ring.rotation = Quaternion.Euler(0f, _spin, 0f);
					if ((Object)(object)RingRenderer != (Object)null && (Object)(object)((Renderer)RingRenderer).material != (Object)null)
					{
						Color val = Tint * AuraPlan.RingAlpha(t) * Intensity;
						val.a = 1f;
						if (((Renderer)RingRenderer).material.HasProperty("_TintColor"))
						{
							((Renderer)RingRenderer).material.SetColor("_TintColor", val);
						}
						else if (((Renderer)RingRenderer).material.HasProperty("_Color"))
						{
							((Renderer)RingRenderer).material.SetColor("_Color", val);
						}
					}
				}
				if ((Object)(object)Motes != (Object)null)
				{
					EmissionModule emission = Motes.emission;
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(AuraPlan.MoteRate(t) * Intensity);
					ShapeModule shape = Motes.shape;
					((ShapeModule)(ref shape)).radius = Radius * AuraPlan.RingRadius(t);
				}
				if ((Object)(object)Column != (Object)null)
				{
					EmissionModule emission2 = Column.emission;
					((EmissionModule)(ref emission2)).rateOverTime = MinMaxCurve.op_Implicit(AuraPlan.ColumnRate(t) * Intensity);
				}
				if ((Object)(object)Glow != (Object)null)
				{
					float num2 = 1f + 0.06f * Mathf.Sin(Time.time * 7.3f + _phase);
					Glow.intensity = AuraPlan.LightIntensity(t) * Intensity * num2;
					Glow.range = AuraPlan.LightRange(t, MaxLightRange);
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("AuraDriver.Update", ex);
				((Behaviour)this).enabled = false;
			}
		}

		private void FadeOut()
		{
			if (!((Object)(object)Glow == (Object)null))
			{
				float num = Time.time - _releasedAt;
				float num2 = 1f - Mathf.Clamp01(num / 0.4f);
				Glow.intensity = _releaseFrom * num2;
			}
		}
	}
	internal static class AuraPlan
	{
		internal const float MoteLifetime = 1.7f;

		internal const float MoteSpeedMin = 0.7f;

		internal const float MoteSpeedMax = 1.3f;

		internal const float MoteSizeMin = 0.1f;

		internal const float MoteSizeMax = 0.26f;

		internal const float MoteGravity = -0.06f;

		internal const float ColumnLifetime = 0.9f;

		internal const float ColumnSpeedMin = 3.5f;

		internal const float ColumnSpeedMax = 6f;

		internal const float ColumnSizeMin = 0.06f;

		internal const float ColumnSizeMax = 0.14f;

		internal const float ColumnRadius = 0.32f;

		internal const float ReleaseFade = 0.4f;

		internal const float ReleaseLinger = 2.5f;

		internal const int RampKeys = 8;

		internal static float RingRadius(float t)
		{
			return 0.27f + 0.73f * SmoothStep(0f, 0.5f, t);
		}

		internal static float RingSpin(float t)
		{
			return 20f + 160f * Pow(Clamp01(t), 1.3f);
		}

		internal static float RingAlpha(float t)
		{
			return SmoothStep(0f, 0.25f, t) * (1f + 0.6f * SmoothStep(0.6f, 1f, t));
		}

		internal static float MoteRate(float t)
		{
			return 6f + 54f * Pow(Clamp01(t), 1.5f);
		}

		internal static float ColumnRate(float t)
		{
			return 40f * SmoothStep(0.6f, 1f, t);
		}

		internal static float LightIntensity(float t)
		{
			return 0.2f + 2.8f * Pow(Clamp01(t), 1.4f);
		}

		internal static float LightRange(float t, float max)
		{
			float num = 2f;
			if (max < num)
			{
				return max;
			}
			return num + (max - num) * Clamp01(t);
		}

		internal static void ColourAt(float life, out float warm, out float alpha)
		{
			life = Clamp01(life);
			warm = Lerp(0f, 1f, SmoothStep(0.05f, 0.55f, life)) * (1f - 0.35f * SmoothStep(0.7f, 1f, life));
			if (life < 0.12f)
			{
				alpha = SmoothStep(0f, 0.12f, life);
			}
			else
			{
				alpha = 1f - SmoothStep(0.45f, 1f, life);
			}
		}

		internal static float RampAt(int index)
		{
			return (float)index / 7f;
		}

		internal static float SmoothStep(float edge0, float edge1, float x)
		{
			if (edge0 == edge1)
			{
				if (!(x < edge0))
				{
					return 1f;
				}
				return 0f;
			}
			float num = Clamp01((x - edge0) / (edge1 - edge0));
			return num * num * (3f - 2f * num);
		}

		internal static float Lerp(float from, float to, float t)
		{
			return from + (to - from) * Clamp01(t);
		}

		internal static float Clamp01(float x)
		{
			if (float.IsNaN(x))
			{
				return 0f;
			}
			if (x < 0f)
			{
				return 0f;
			}
			if (!(x > 1f))
			{
				return x;
			}
			return 1f;
		}

		private static float Pow(float x, float p)
		{
			return (float)Math.Pow(x, p);
		}
	}
	internal enum ChannelState
	{
		Idle,
		Casting,
		Firing,
		Spent
	}
	internal enum CancelReason
	{
		None,
		Moved,
		Damaged,
		Menu,
		Died,
		Teleported,
		PlayerGone,
		ByHand,
		Refused
	}
	internal sealed class ChannelRules
	{
		internal float Duration = 10f;

		internal bool CancelOnMove = true;

		internal bool CancelOnDamage = true;

		internal bool CancelOnMenu = true;

		internal float DriftBudget = 0.5f;

		internal float MaxDt = 0.5f;

		internal float FireTimeout = 5f;
	}
	internal struct ChannelTick
	{
		internal float Dt;

		internal bool InputMoving;

		internal float DriftMetres;

		internal bool Hit;

		internal float HealthLost;

		internal bool MenuOpen;

		internal bool Dead;

		internal bool Teleporting;

		internal bool PlayerGone;

		internal bool ByHand;
	}
	internal sealed class Channel
	{
		internal const float DamageFloor = 0.1f;

		private ChannelRules _rules = new ChannelRules();

		private float _fireElapsed;

		private bool _menuGrace;

		internal ChannelState State { get; private set; }

		internal CancelReason Reason { get; private set; }

		internal float Elapsed { get; private set; }

		internal float Drift { get; private set; }

		internal ChannelRules Rules => _rules;

		internal float Progress
		{
			get
			{
				if (State == ChannelState.Firing || State == ChannelState.Spent)
				{
					return 1f;
				}
				if (State != ChannelState.Casting)
				{
					return 0f;
				}
				if (_rules.Duration <= 0f)
				{
					return 1f;
				}
				float num = Elapsed / _rules.Duration;
				if (num < 0f)
				{
					return 0f;
				}
				if (!(num > 1f))
				{
					return num;
				}
				return 1f;
			}
		}

		internal bool Running
		{
			get
			{
				if (State != ChannelState.Casting)
				{
					return State == ChannelState.Firing;
				}
				return true;
			}
		}

		internal void Begin(ChannelRules rules)
		{
			_rules = rules ?? new ChannelRules();
			_fireElapsed = 0f;
			Elapsed = 0f;
			Drift = 0f;
			Reason = CancelReason.None;
			_menuGrace = true;
			State = ChannelState.Casting;
		}

		internal ChannelState Advance(in ChannelTick t)
		{
			if (State != ChannelState.Casting && State != ChannelState.Firing)
			{
				return State;
			}
			if (float.IsNaN(t.Dt) || float.IsInfinity(t.Dt) || t.Dt <= 0f)
			{
				return State;
			}
			float num = ((t.Dt > _rules.MaxDt) ? _rules.MaxDt : t.Dt);
			if (t.PlayerGone)
			{
				return Abort(CancelReason.PlayerGone);
			}
			if (t.Dead)
			{
				return Abort(CancelReason.Died);
			}
			if (t.ByHand)
			{
				return Abort(CancelReason.ByHand);
			}
			if (State == ChannelState.Firing)
			{
				_fireElapsed += num;
				if (_fireElapsed >= _rules.FireTimeout)
				{
					return Abort(CancelReason.Refused);
				}
				return State;
			}
			if (t.Teleporting)
			{
				return Abort(CancelReason.Teleported);
			}
			if (!t.MenuOpen)
			{
				_menuGrace = false;
			}
			else if (_rules.CancelOnMenu && !_menuGrace)
			{
				return Abort(CancelReason.Menu);
			}
			if (_rules.CancelOnDamage && (t.Hit || t.HealthLost > 0.1f))
			{
				return Abort(CancelReason.Damaged);
			}
			if (_rules.CancelOnMove)
			{
				if (t.InputMoving)
				{
					return Abort(CancelReason.Moved);
				}
				if (t.DriftMetres > 0f)
				{
					Drift += t.DriftMetres;
				}
				if (Drift > _rules.DriftBudget)
				{
					return Abort(CancelReason.Moved);
				}
			}
			Elapsed += num;
			if (Elapsed >= _rules.Duration)
			{
				_fireElapsed = 0f;
				State = ChannelState.Firing;
			}
			return State;
		}

		internal static float NetHealthLost(float lastHealth, float health, float maxHealth)
		{
			if (NotANumber(lastHealth) || NotANumber(health) || NotANumber(maxHealth))
			{
				return 0f;
			}
			float num = lastHealth - health;
			if (num <= 0f)
			{
				return 0f;
			}
			float num2 = lastHealth - maxHealth;
			if (num2 <= 0f)
			{
				return num;
			}
			float num3 = num - num2;
			if (!(num3 > 0f))
			{
				return 0f;
			}
			return num3;
		}

		private static bool NotANumber(float f)
		{
			if (!float.IsNaN(f))
			{
				return float.IsInfinity(f);
			}
			return true;
		}

		internal bool Accept()
		{
			if (State != ChannelState.Firing)
			{
				return false;
			}
			State = ChannelState.Spent;
			Reason = CancelReason.None;
			return true;
		}

		internal ChannelState Abort(CancelReason why)
		{
			if (State == ChannelState.Spent)
			{
				return State;
			}
			State = ChannelState.Idle;
			Reason = why;
			_fireElapsed = 0f;
			return State;
		}

		internal void Reset()
		{
			State = ChannelState.Idle;
			Reason = CancelReason.None;
			Elapsed = 0f;
			Drift = 0f;
			_fireElapsed = 0f;
		}

		internal static string Explain(CancelReason why)
		{
			return why switch
			{
				CancelReason.Moved => "You have to stand still.", 
				CancelReason.Damaged => "The way home slips away as you are struck.", 
				CancelReason.Menu => "The way home slips away.", 
				CancelReason.Died => "", 
				CancelReason.Teleported => "", 
				CancelReason.PlayerGone => "", 
				CancelReason.ByHand => "You let the stone go cold.", 
				CancelReason.Refused => "The way home will not open yet. Try again.", 
				_ => "", 
			};
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static class Commands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__2_0;

			internal void <Register>b__2_0(ConsoleEventArgs args)
			{
				try
				{
					string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "");
					switch (text)
					{
					default:
					{
						if (text.Length != 0)
						{
							break;
						}
						Terminal context2 = args.Context;
						if (context2 != null)
						{
							context2.AddString(Status());
						}
						return;
					}
					case "give":
					{
						Terminal context4 = args.Context;
						if (context4 != null)
						{
							context4.AddString(Give());
						}
						return;
					}
					case "probe":
					{
						Terminal context5 = args.Context;
						if (context5 != null)
						{
							context5.AddString(Probe());
						}
						return;
					}
					case "where":
					{
						Terminal context3 = args.Context;
						if (context3 != null)
						{
							context3.AddString(Where());
						}
						return;
					}
					case "reset":
					{
						Terminal context = args.Context;
						if (context != null)
						{
							context.AddString(Reset());
						}
						return;
					}
					case null:
						break;
					}
					Terminal context6 = args.Context;
					if (context6 != null)
					{
						context6.AddString("heimfor: no such verb '" + text + "'. Try give, probe, where or reset.");
					}
				}
				catch (Exception ex)
				{
					Safety.Failed("heimfor", ex);
				}
			}
		}

		private static bool _registered;

		[HarmonyPostfix]
		public static void Postfix()
		{
			try
			{
				Register();
			}
			catch (Exception ex)
			{
				Safety.Failed("Terminal.InitTerminal command registration", ex);
			}
		}

		internal static void Register()
		{
			//IL_0041: 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)
			//IL_0037: Expected O, but got Unknown
			if (_registered)
			{
				return;
			}
			_registered = true;
			object obj = <>c.<>9__2_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					try
					{
						string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "");
						switch (text)
						{
						default:
							if (text.Length == 0)
							{
								Terminal context2 = args.Context;
								if (context2 != null)
								{
									context2.AddString(Status());
								}
								return;
							}
							break;
						case "give":
						{
							Terminal context4 = args.Context;
							if (context4 != null)
							{
								context4.AddString(Give());
							}
							return;
						}
						case "probe":
						{
							Terminal context5 = args.Context;
							if (context5 != null)
							{
								context5.AddString(Probe());
							}
							return;
						}
						case "where":
						{
							Terminal context3 = args.Context;
							if (context3 != null)
							{
								context3.AddString(Where());
							}
							return;
						}
						case "reset":
						{
							Terminal context = args.Context;
							if (context != null)
							{
								context.AddString(Reset());
							}
							return;
						}
						case null:
							break;
						}
						Terminal context6 = args.Context;
						if (context6 != null)
						{
							context6.AddString("heimfor: no such verb '" + text + "'. Try give, probe, where or reset.");
						}
					}
					catch (Exception ex)
					{
						Safety.Failed("heimfor", ex);
					}
				};
				<>c.<>9__2_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("heimfor", "heimfor - say whether your stone is ready, and where it would take you. Also: heimfor give, heimfor probe, heimfor where, heimfor reset.", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static string Status()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return "Heimfor: you are not in a world.";
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("Heimfor ").Append("0.1.1");
			ConfigEntry<bool> enabled = HeimforPlugin.Enabled;
			if (enabled != null && !enabled.Value)
			{
				stringBuilder.Append(" - switched off in the settings.");
				return stringBuilder.ToString();
			}
			stringBuilder.Append(" - ").Append(Hearth.CooldownText(localPlayer)).AppendLine();
			bool flag = StoneItem.FindIn(((Humanoid)localPlayer).GetInventory()) != null;
			stringBuilder.Append(flag ? "You are carrying a stone." : "You are not carrying a stone.").AppendLine();
			stringBuilder.Append(Hearth.DestinationText());
			return stringBuilder.ToString();
		}

		private static string Give()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return "Heimfor: you are not in a world.";
			}
			if ((Object)(object)StoneItem.Prefab == (Object)null)
			{
				return "Heimfor: the stone does not exist in this session. Run 'heimfor probe'.";
			}
			if (!StoneItem.Give(localPlayer))
			{
				return "Heimfor: could not add it - your pack is probably full.";
			}
			return "Heimfor: one Heimfor Stone added to your pack.";
		}

		private static string Probe()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("Heimfor ").Append("0.1.1").AppendLine(" probe");
			GameObject prefab = StoneItem.Prefab;
			stringBuilder.Append("  prefab:     ").AppendLine(((Object)(object)prefab == (Object)null) ? "NOT BUILT - no donor in the CloneFrom list resolved" : (((Object)prefab).name + ", cloned from " + StoneItem.ClonedFrom));
			if ((Object)(object)prefab != (Object)null)
			{
				ObjectDB instance = ObjectDB.instance;
				bool flag = instance?.m_items != null && instance.m_items.Contains(prefab);
				bool flag2 = (Object)(object)((instance != null) ? instance.GetItemPrefab("HF_HeimforStone") : null) != (Object)null;
				stringBuilder.Append("  ObjectDB:   ").AppendLine((!flag) ? "NOT REGISTERED - it cannot be crafted or spawned" : (flag2 ? "registered and findable by name" : "IN THE LIST BUT NOT FINDABLE - UpdateRegisters did not run"));
				ZNetScene instance2 = ZNetScene.instance;
				bool flag3 = instance2?.m_prefabs != null && instance2.m_prefabs.Contains(prefab);
				bool flag4 = (Object)(object)((instance2 != null) ? instance2.GetPrefab("HF_HeimforStone") : null) != (Object)null;
				stringBuilder.Append("  ZNetScene:  ").AppendLine((!flag3) ? "NOT REGISTERED - A DROPPED STONE WILL VANISH ON THE NEXT ZONE RELOAD" : (flag4 ? "registered - a dropped stone survives a reload" : "IN THE LIST BUT NOT NAMED - A DROPPED STONE WILL VANISH"));
				int value = prefab.GetComponentsInChildren<Collider>(true).Length;
				int value2 = prefab.GetComponentsInChildren<Renderer>(true).Length;
				bool flag5 = (Object)(object)prefab.GetComponent<ZNetView>() != (Object)null;
				stringBuilder.Append("  components: ").Append(value2).Append(" renderer(s), ")
					.Append(value)
					.Append(" collider(s), ZNetView ")
					.AppendLine(flag5 ? "present" : "MISSING - a dropped stone cannot exist");
				stringBuilder.Append("  mesh:       ").AppendLine(StoneModel.MeshReport);
				stringBuilder.Append("  material:   ").AppendLine(StoneModel.MaterialReport);
				stringBuilder.Append("  icon:       ").AppendLine(Icons.Source);
			}
			stringBuilder.Append("  recipe:     ").AppendLine(Recipes.Describe());
			stringBuilder.Append("  effect:     ").AppendLine(Aura.Describe());
			stringBuilder.Append("  others:     ").Append(Watch.Drawing).AppendLine(" other player(s) being drawn casting right now");
			stringBuilder.Append("  cooldown:   ").Append(HeimforPlugin.CooldownMinutes?.Value.ToString("0.#", CultureInfo.InvariantCulture)).Append(" minutes on the ")
				.Append(HeimforPlugin.CooldownClock?.Value)
				.AppendLine(" clock");
			return stringBuilder.ToString();
		}

		private static string Where()
		{
			return Hearth.DestinationReport();
		}

		private static string Reset()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return "Heimfor: you are not in a world.";
			}
			Hearth.ClearCooldown(localPlayer);
			return "Heimfor: your stone is ready again.";
		}
	}
	internal static class Cooldown
	{
		internal const string KeyPrefix = "gbv_heimfor_ready_";

		internal static readonly TimeSpan StaleAfter = TimeSpan.FromHours(24.0);

		internal static string KeyFor(long worldUid, bool shareAcrossWorlds)
		{
			if (shareAcrossWorlds)
			{
				return "gbv_heimfor_ready_all";
			}
			return "gbv_heimfor_ready_" + worldUid.ToString(CultureInfo.InvariantCulture);
		}

		internal static string Encode(long readyAtTicks)
		{
			return readyAtTicks.ToString(CultureInfo.InvariantCulture);
		}

		internal static bool TryParse(string stored, out long readyAtTicks)
		{
			readyAtTicks = 0L;
			if (string.IsNullOrEmpty(stored))
			{
				return false;
			}
			return long.TryParse(stored.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out readyAtTicks);
		}

		internal static long ReadyAtFrom(long nowTicks, float minutes)
		{
			if (minutes <= 0f)
			{
				return nowTicks;
			}
			return nowTicks + TicksFor(minutes);
		}

		internal static long TicksFor(float minutes)
		{
			if (minutes <= 0f)
			{
				return 0L;
			}
			double num = (double)minutes * 60.0 * 10000000.0;
			if (num >= 9.223372036854776E+18)
			{
				return long.MaxValue;
			}
			return (long)num;
		}

		internal static bool IsCorrupt(long readyAtTicks, long nowTicks, float cooldownMinutes)
		{
			if (readyAtTicks <= nowTicks)
			{
				return false;
			}
			return Diff(readyAtTicks, nowTicks) > TicksFor(cooldownMinutes);
		}

		internal static bool IsReady(long readyAtTicks, long nowTicks)
		{
			return nowTicks >= readyAtTicks;
		}

		internal static TimeSpan Remaining(long readyAtTicks, long nowTicks)
		{
			if (readyAtTicks <= nowTicks)
			{
				return TimeSpan.Zero;
			}
			long num = Diff(readyAtTicks, nowTicks);
			if (num >= TimeSpan.MaxValue.Ticks)
			{
				return TimeSpan.MaxValue;
			}
			return TimeSpan.FromTicks(num);
		}

		internal static bool IsStale(long readyAtTicks, long nowTicks)
		{
			return Diff(nowTicks, readyAtTicks) > StaleAfter.Ticks;
		}

		private static long Diff(long a, long b)
		{
			try
			{
				return checked(a - b);
			}
			catch (OverflowException)
			{
				return (a > b) ? long.MaxValue : long.MinValue;
			}
		}

		internal static string Format(TimeSpan remaining)
		{
			if (remaining <= TimeSpan.Zero)
			{
				return "ready";
			}
			double totalSeconds = remaining.TotalSeconds;
			if (totalSeconds < 60.0)
			{
				return (int)Math.Ceiling(totalSeconds) + "s";
			}
			int num = (int)Math.Ceiling(totalSeconds / 60.0);
			if (num < 60)
			{
				return num + "m";
			}
			int num2 = num / 60;
			int num3 = num % 60;
			if (num3 == 0)
			{
				return num2 + "h";
			}
			return num2 + "h " + num3 + "m";
		}
	}
	internal readonly struct CostLine
	{
		internal readonly string Item;

		internal readonly int Count;

		internal CostLine(string item, int count)
		{
			Item = item;
			Count = count;
		}

		public override string ToString()
		{
			return Item + ":" + Count.ToString(CultureInfo.InvariantCulture);
		}
	}
	internal static class Cost
	{
		internal const int MaxCount = 999;

		internal static List<CostLine> Parse(string text, List<string> problems)
		{
			List<CostLine> list = new List<CostLine>();
			if (string.IsNullOrEmpty(text))
			{
				return list;
			}
			string[] array = text.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				int num = text2.IndexOf(':');
				if (num < 0)
				{
					problems?.Add("'" + text2 + "' has no count, so it was read as one.");
					list.Add(new CostLine(text2, 1));
					continue;
				}
				string text3 = text2.Substring(0, num).Trim();
				string s = text2.Substring(num + 1).Trim();
				if (text3.Length == 0)
				{
					problems?.Add("'" + text2 + "' has no ingredient name, so it was skipped.");
					continue;
				}
				if (!int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
				{
					problems?.Add("'" + text2 + "' does not have a whole number after the colon, so it was skipped.");
					continue;
				}
				if (result <= 0)
				{
					problems?.Add("'" + text2 + "' asks for " + result + ", so it was skipped.");
					continue;
				}
				if (result > 999)
				{
					problems?.Add("'" + text2 + "' was capped at " + 999 + ".");
					result = 999;
				}
				int num2 = IndexOf(list, text3);
				if (num2 >= 0)
				{
					long num3 = (long)list[num2].Count + (long)result;
					if (num3 > 999)
					{
						num3 = 999L;
					}
					list[num2] = new CostLine(list[num2].Item, (int)num3);
					problems?.Add("'" + text3 + "' was listed more than once, so the counts were added up.");
				}
				else
				{
					list.Add(new CostLine(text3, result));
				}
			}
			return list;
		}

		internal static string Format(IEnumerable<CostLine> lines)
		{
			if (lines == null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (CostLine line in lines)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append(line.Item).Append(':').Append(line.Count.ToString(CultureInfo.InvariantCulture));
			}
			return stringBuilder.ToString();
		}

		private static int IndexOf(List<CostLine> lines, string name)
		{
			for (int i = 0; i < lines.Count; i++)
			{
				if (string.Equals(lines[i].Item, name, StringComparison.OrdinalIgnoreCase))
				{
					return i;
				}
			}
			return -1;
		}
	}
	internal static class Hearth
	{
		private static readonly Channel Cast = new Channel();

		private static Player _caster;

		private static Vector3 _target;

		private static Quaternion _targetRot = Quaternion.identity;

		private static Vector3 _lastPosition;

		private static float _lastHealth;

		private static bool _haveLast;

		internal static bool HitFlag;

		private static FieldInfo _moveDirField;

		private static bool _moveDirChecked;

		private const int MaxSitAttempts = 3;

		private static float _nextSit;

		private static int _sitAttempts;

		private static bool _weSatThem;

		internal static bool Running => Cast.Running;

		internal static bool Use(Player player, ItemData item)
		{
			//IL_006e: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			ConfigEntry<bool> enabled = HeimforPlugin.Enabled;
			if (enabled != null && !enabled.Value)
			{
				Say(player, "The stone is quiet. Heimfor is switched off on this server.");
				return true;
			}
			if (Cast.Running)
			{
				Stop(CancelReason.ByHand);
				return true;
			}
			if (!Ready(player, out var why))
			{
				Say(player, why);
				return true;
			}
			if (!Destination(out var point, out var rot, out var refusal))
			{
				Say(player, refusal);
				return true;
			}
			_caster = player;
			_target = point;
			_targetRot = rot;
			_lastPosition = ((Component)player).transform.position;
			_lastHealth = ((Character)player).GetHealth();
			_haveLast = true;
			HitFlag = false;
			_sitAttempts = 0;
			_nextSit = 0f;
			Cast.Begin(RulesFromConfig());
			CloseInventory();
			Sit(player);
			Aura.Begin(player);
			Watch.Broadcast(player, casting: true);
			Say(player, "The stone warms. Stand still.");
			HeimforPlugin.Verbose("cast started, destination " + ((Vector3)(ref _target)).ToString("0.0") + ".");
			return true;
		}

		private static bool Ready(Player player, out string why)
		{
			why = null;
			if (((Character)player).IsDead())
			{
				why = "";
				return false;
			}
			if (((Character)player).IsTeleporting())
			{
				why = "You are already on your way somewhere.";
				return false;
			}
			if (((Character)player).InCutscene() || player.IsSleeping())
			{
				why = "Not now.";
				return false;
			}
			if (((Character)player).IsAttached())
			{
				why = "Stand up first.";
				return false;
			}
			ConfigEntry<bool> respectNoPortals = HeimforPlugin.RespectNoPortals;
			if ((respectNoPortals == null || respectNoPortals.Value) && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)32))
			{
				why = "The ways are closed on this server.";
				return false;
			}
			ConfigEntry<bool> respectBossBlock = HeimforPlugin.RespectBossBlock;
			if ((respectBossBlock == null || respectBossBlock.Value) && BossFightOn())
			{
				why = "Something is awake that will not let you leave.";
				return false;
			}
			long num = NowTicks();
			long readyAtTicks = ReadyAt(player, num);
			if (!Cooldown.IsReady(readyAtTicks, num))
			{
				why = "The stone is still cold. " + Cooldown.Format(Cooldown.Remaining(readyAtTicks, num)) + " to go.";
				return false;
			}
			return true;
		}

		private static bool BossFightOn()
		{
			try
			{
				if ((Object)(object)ZoneSystem.instance == (Object)null)
				{
					return false;
				}
				if (!ZoneSystem.instance.GetGlobalKey((GlobalKeys)33))
				{
					return false;
				}
				if ((Object)(object)RandEventSystem.instance != (Object)null && RandEventSystem.instance.GetBossEvent() != null)
				{
					return true;
				}
				float num = default(float);
				return ZoneSystem.instance.GetGlobalKey((GlobalKeys)47, ref num) && num > 0f;
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.BossFightOn", ex);
				return false;
			}
		}

		internal static void Tick()
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_00ba: 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_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			if (!Cast.Running)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			ChannelTick t = new ChannelTick
			{
				Dt = Time.deltaTime,
				PlayerGone = ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer != (Object)(object)_caster),
				MenuOpen = MenuOpen()
			};
			if (!t.PlayerGone && (Object)(object)localPlayer != (Object)null)
			{
				t.Dead = ((Character)localPlayer).IsDead();
				t.Teleporting = ((Character)localPlayer).IsTeleporting() && Cast.State == ChannelState.Casting;
				t.InputMoving = AskingToMove(localPlayer);
				Vector3 position = ((Component)localPlayer).transform.position;
				if (_haveLast)
				{
					Vector3 val = default(Vector3);
					((Vector3)(ref val))..ctor(position.x - _lastPosition.x, 0f, position.z - _lastPosition.z);
					t.DriftMetres = ((Vector3)(ref val)).magnitude;
				}
				_lastPosition = position;
				float health = ((Character)localPlayer).GetHealth();
				t.HealthLost = (_haveLast ? Channel.NetHealthLost(_lastHealth, health, ((Character)localPlayer).GetMaxHealth()) : 0f);
				_lastHealth = health;
				_haveLast = true;
				t.ByHand = StoneItem.FindIn(((Humanoid)localPlayer).GetInventory()) == null;
			}
			t.Hit = HitFlag;
			HitFlag = false;
			ChannelState state = Cast.State;
			ChannelState channelState = Cast.Advance(in t);
			switch (channelState)
			{
			case ChannelState.Idle:
				Finish(localPlayer, Cast.Reason);
				return;
			case ChannelState.Casting:
				Sit(localPlayer);
				break;
			}
			if (state == ChannelState.Casting && channelState == ChannelState.Firing)
			{
				Stand(localPlayer);
				HeimforPlugin.Verbose("channel complete, asking for the teleport.");
			}
			if (channelState == ChannelState.Firing && !((Object)(object)localPlayer == (Object)null))
			{
				bool flag;
				try
				{
					flag = ((Character)localPlayer).TeleportTo(_target, _targetRot, true);
				}
				catch (Exception ex)
				{
					Safety.Failed("Hearth.TeleportTo", ex);
					Cast.Abort(CancelReason.Refused);
					Finish(localPlayer, CancelReason.Refused);
					return;
				}
				if (flag && Cast.Accept())
				{
					Remember(localPlayer);
					Aura.Release();
					Watch.Broadcast(localPlayer, casting: false);
					Cast.Reset();
					_caster = null;
					_haveLast = false;
					HeimforPlugin.Verbose("teleport accepted, cooldown stored.");
				}
			}
		}

		private static void Finish(Player player, CancelReason why)
		{
			Aura.End();
			Stand(player);
			if ((Object)(object)player != (Object)null)
			{
				Watch.Broadcast(player, casting: false);
			}
			else if ((Object)(object)_caster != (Object)null)
			{
				Watch.Broadcast(_caster, casting: false);
			}
			string text = Channel.Explain(why);
			if ((Object)(object)player != (Object)null && !string.IsNullOrEmpty(text))
			{
				Say(player, text);
			}
			HeimforPlugin.Verbose("cast ended: " + why.ToString() + ".");
			Cast.Reset();
			_caster = null;
			_haveLast = false;
			HitFlag = false;
		}

		internal static void Stop(CancelReason why)
		{
			if (Cast.Running)
			{
				Cast.Abort(why);
				Finish(Player.m_localPlayer ?? _caster, why);
			}
		}

		internal static void Abandon()
		{
			try
			{
				if ((Object)(object)_caster != (Object)null)
				{
					Watch.Broadcast(_caster, casting: false);
				}
				Aura.End();
				Cast.Reset();
				_caster = null;
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Abandon", ex);
			}
		}

		private static bool AskingToMove(Player player)
		{
			//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)
			if (!_moveDirChecked)
			{
				_moveDirChecked = true;
				_moveDirField = AccessTools.Field(typeof(Character), "m_moveDir");
				if (_moveDirField == null)
				{
					Safety.Warn("Hearth.NoMoveDir", "Character.m_moveDir could not be found, so a cast is interrupted by how far you actually move rather than by pressing a movement key. Casts still work.");
				}
			}
			if (_moveDirField == null)
			{
				return false;
			}
			try
			{
				Vector3 val = (Vector3)_moveDirField.GetValue(player);
				return ((Vector3)(ref val)).sqrMagnitude > 0.0001f;
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.AskingToMove", ex);
				_moveDirField = null;
				return false;
			}
		}

		private static void Sit(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			string text = HeimforPlugin.ChannelEmote?.Value;
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			try
			{
				if (!((Character)player).InEmote() && _sitAttempts < 3 && !(Time.time < _nextSit) && !Held())
				{
					_nextSit = Time.time + 1.2f;
					_sitAttempts++;
					if (player.StartEmote(text, false))
					{
						_weSatThem = true;
					}
					else
					{
						HeimforPlugin.Verbose("the game refused the channel emote, attempt " + _sitAttempts + ".");
					}
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Sit", ex);
			}
		}

		private static bool Held()
		{
			try
			{
				return Input.GetMouseButton(0) || Input.GetMouseButton(1) || Input.GetKey((KeyCode)32) || Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)99);
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Held", ex);
				return false;
			}
		}

		private static void Stand(Player player)
		{
			bool weSatThem = _weSatThem;
			_weSatThem = false;
			if (!weSatThem || (Object)(object)player == (Object)null)
			{
				return;
			}
			try
			{
				if (((Character)player).InEmote())
				{
					player.StartEmote("", true);
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Stand", ex);
			}
		}

		private static void CloseInventory()
		{
			try
			{
				if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible())
				{
					InventoryGui.instance.Hide();
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.CloseInventory", ex);
			}
		}

		private static bool MenuOpen()
		{
			try
			{
				if (InventoryGui.IsVisible())
				{
					return true;
				}
				if (Menu.IsVisible())
				{
					return true;
				}
				if (Console.IsVisible())
				{
					return true;
				}
				if (StoreGui.IsVisible())
				{
					return true;
				}
				if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
				{
					return true;
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.MenuOpen", ex);
			}
			return false;
		}

		private static ChannelRules RulesFromConfig()
		{
			return new ChannelRules
			{
				Duration = Mathf.Max(0.1f, HeimforPlugin.ChannelSeconds?.Value ?? 10f),
				CancelOnMove = (HeimforPlugin.CancelOnMove?.Value ?? true),
				CancelOnDamage = (HeimforPlugin.CancelOnDamage?.Value ?? true),
				CancelOnMenu = (HeimforPlugin.CancelOnMenu?.Value ?? true),
				DriftBudget = Mathf.Max(0f, HeimforPlugin.DriftTolerance?.Value ?? 0.5f),
				MaxDt = 0.5f,
				FireTimeout = 5f
			};
		}

		private static bool Destination(out Vector3 point, out Quaternion rot, out string refusal)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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)
			point = Vector3.zero;
			rot = Quaternion.identity;
			refusal = null;
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (val == null)
			{
				refusal = "Something is wrong - there is no character loaded.";
				return false;
			}
			if (!val.HaveCustomSpawnPoint())
			{
				refusal = "You have no bed to go back to. Claim one first.";
				return false;
			}
			Vector3 customSpawnPoint = val.GetCustomSpawnPoint();
			if (((Vector3)(ref customSpawnPoint)).sqrMagnitude < 1f)
			{
				refusal = "You have no bed to go back to. Claim one first.";
				return false;
			}
			Bed val2 = LiveBed();
			if ((Object)(object)val2 != (Object)null)
			{
				rot = ((Component)val2).transform.rotation;
			}
			point = customSpawnPoint + Vector3.up * 0.25f;
			return true;
		}

		private static Bed LiveBed()
		{
			try
			{
				Bed[] array = Object.FindObjectsOfType<Bed>();
				if (array == null)
				{
					return null;
				}
				Bed[] array2 = array;
				foreach (Bed val in array2)
				{
					if ((Object)(object)val != (Object)null && val.IsCurrent())
					{
						return val;
					}
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.LiveBed", ex);
			}
			return null;
		}

		internal static string DestinationText()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (val == null || !val.HaveCustomSpawnPoint())
			{
				return "You have no bed claimed, so the stone has nowhere to take you.";
			}
			Vector3 customSpawnPoint = val.GetCustomSpawnPoint();
			Player localPlayer = Player.m_localPlayer;
			string text = (((Object)(object)localPlayer == (Object)null) ? "" : (" (" + Mathf.RoundToInt(Vector3.Distance(((Component)localPlayer).transform.position, customSpawnPoint)) + "m away)"));
			return "Your bed is at " + Mathf.RoundToInt(customSpawnPoint.x) + ", " + Mathf.RoundToInt(customSpawnPoint.z) + text + ".";
		}

		internal static string DestinationReport()
		{
			//IL_002a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (val == null)
			{
				return "Heimfor: there is no character loaded.";
			}
			if (!val.HaveCustomSpawnPoint())
			{
				return "Heimfor: you have not claimed a bed in this world, so the stone has nowhere to take you. Press E on a bed you have built.";
			}
			Vector3 customSpawnPoint = val.GetCustomSpawnPoint();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("Heimfor: your bed is at ").Append(Mathf.RoundToInt(customSpawnPoint.x)).Append(", ")
				.Append(Mathf.RoundToInt(customSpawnPoint.y))
				.Append(", ")
				.Append(Mathf.RoundToInt(customSpawnPoint.z))
				.AppendLine();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				stringBuilder.Append("  distance:  ").Append(Mathf.RoundToInt(Vector3.Distance(((Component)localPlayer).transform.position, customSpawnPoint))).AppendLine("m");
			}
			bool flag = false;
			try
			{
				flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.IsZoneLoaded(ZoneSystem.GetZone(customSpawnPoint));
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.DestinationReport zone", ex);
			}
			stringBuilder.Append("  zone:      ").AppendLine(flag ? "loaded" : "not loaded (normal)");
			if (!flag)
			{
				stringBuilder.AppendLine("  bed:       cannot tell from here - the zone is not loaded, which is not a problem");
			}
			else
			{
				stringBuilder.Append("  bed:       ").AppendLine(((Object)(object)LiveBed() != (Object)null) ? "found, and it is yours" : "NOT FOUND although the zone is loaded - the bed may have been destroyed. Claim another one.");
			}
			long num = NowTicks();
			long readyAtTicks = ReadyAt(localPlayer, num);
			stringBuilder.Append("  stone:     ").AppendLine(Cooldown.IsReady(readyAtTicks, num) ? "ready" : ("cold for another " + Cooldown.Format(Cooldown.Remaining(readyAtTicks, num))));
			return stringBuilder.ToString();
		}

		private static long NowTicks()
		{
			try
			{
				if (string.Equals(HeimforPlugin.CooldownClock?.Value, "WorldTime", StringComparison.OrdinalIgnoreCase))
				{
					return (long)((((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0) * 10000000.0);
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.NowTicks", ex);
			}
			return DateTime.UtcNow.Ticks;
		}

		private static string CooldownKey()
		{
			long worldUid = 0L;
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					worldUid = ZNet.instance.GetWorldUID();
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.CooldownKey", ex);
			}
			return Cooldown.KeyFor(worldUid, HeimforPlugin.ShareAcrossWorlds?.Value ?? false);
		}

		private static long ReadyAt(Player player, long now)
		{
			if ((Object)(object)player == (Object)null)
			{
				return now;
			}
			if (!Cooldown.TryParse(Store.Read(player, CooldownKey()), out var readyAtTicks))
			{
				return now;
			}
			float cooldownMinutes = HeimforPlugin.CooldownMinutes?.Value ?? 60f;
			if (Cooldown.IsCorrupt(readyAtTicks, now, cooldownMinutes))
			{
				Safety.Warn("Hearth.CorruptCooldown", "the stored cooldown was further away than a whole cooldown could put it, so it has been cleared. Usually this means the Clock setting changed or the system clock moved.");
				Store.Write(player, CooldownKey(), null);
				return now;
			}
			return readyAtTicks;
		}

		private static void Remember(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				float num = HeimforPlugin.CooldownMinutes?.Value ?? 60f;
				if (!(num <= 0f))
				{
					long num2 = NowTicks();
					Store.Write(player, CooldownKey(), Cooldown.Encode(Cooldown.ReadyAtFrom(num2, num)));
					Prune(player, num2);
				}
			}
		}

		private static void Prune(Player player, long now)
		{
			try
			{
				string b = CooldownKey();
				foreach (string item in Store.Keys(player, "gbv_heimfor_ready_"))
				{
					if (!string.Equals(item, b, StringComparison.Ordinal) && Cooldown.TryParse(Store.Read(player, item), out var readyAtTicks) && Cooldown.IsStale(readyAtTicks, now))
					{
						Store.Write(player, item, null);
						HeimforPlugin.Verbose("pruned a stale cooldown for another world.");
					}
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Prune", ex);
			}
		}

		internal static void ClearCooldown(Player player)
		{
			Store.Write(player, CooldownKey(), null);
		}

		internal static string CooldownText(Player player)
		{
			long num = NowTicks();
			long readyAtTicks = ReadyAt(player, num);
			if (Cooldown.IsReady(readyAtTicks, num))
			{
				return "your stone is ready.";
			}
			return "your stone is cold for another " + Cooldown.Format(Cooldown.Remaining(readyAtTicks, num)) + ".";
		}

		private static void Say(Player player, string message)
		{
			if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(message))
			{
				return;
			}
			try
			{
				((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
			catch (Exception ex)
			{
				Safety.Failed("Hearth.Say", ex);
			}
		}
	}
	internal static class Icons
	{
		internal const string IconFile = "heimfor_stone.png";

		internal static string Override => Path.Combine(Paths.ConfigPath, "Heimfor");

		internal static string Source { get; private set; } = "not built yet";

		internal static void Apply(SharedData shared, bool generate)
		{
			if (shared == null)
			{
				return;
			}
			if (Headless())
			{
				Source = "none (headless)";
				return;
			}
			try
			{
				Sprite val = FromOverride();
				if ((Object)(object)val != (Object)null)
				{
					shared.m_icons = (Sprite[])(object)new Sprite[1] { val };
					Source = "the heimfor_stone.png found on disk";
					return;
				}
				if (generate)
				{
					Sprite val2 = Draw();
					if ((Object)(object)val2 != (Object)null)
					{
						shared.m_icons = (Sprite[])(object)new Sprite[1] { val2 };
						Source = "generated";
						return;
					}
				}
				Source = "the prefab it was cloned from";
			}
			catch (Exception ex)
			{
				Safety.Failed("Icons.Apply", ex);
				Source = "the prefab it was cloned from (after an error)";
			}
		}

		private static Sprite Draw()
		{
			//IL_0096: 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)
			float[] rgba = Render.Draw(StoneMesh.Build().Model, 128, -0.38f, 0.3f, StoneMesh.Paint, 3, 0.14f, StoneMesh.Finish, 1.1f);
			Texture2D val = ToTexture(128, 128, rgba, "HF_HeimforStoneIcon");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f));
			((Object)obj).name = "HF_HeimforStoneIcon";
			return obj;
		}

		internal static Texture2D ToTexture(int width, int height, float[] rgba, string name)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Texture2D val = new Texture2D(width, height, (TextureFormat)4, false)
				{
					name = name,
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				Color[] array = (Color[])(object)new Color[width * height];
				for (int i = 0; i < height; i++)
				{
					int num = (height - 1 - i) * width;
					int num2 = i * width;
					for (int j = 0; j < width; j++)
					{
						int num3 = (num + j) * 4;
						array[num2 + j] = new Color(rgba[num3], rgba[num3 + 1], rgba[num3 + 2], rgba[num3 + 3]);
					}
				}
				val.SetPixels(array);
				val.Apply(false);
				return val;
			}
			catch (Exception ex)
			{
				Safety.Failed("Icons.ToTexture", ex);
				return null;
			}
		}

		internal static Texture2D BandTexture()
		{
			float[] rgba = new float[RuneSprite.Floats(256, 32)];
			RuneSprite.Render(256, 32, Glyph.Ring, rgba);
			Texture2D val = ToTexture(256, 32, rgba, "HF_HeimforBand");
			if ((Object)(object)val != (Object)null)
			{
				((Texture)val).wrapMode = (TextureWrapMode)0;
			}
			return val;
		}

		internal static Texture2D MoteTexture()
		{
			float[] rgba = new float[RuneSprite.Floats(64, 64)];
			RuneSprite.Render(64, 64, Glyph.Mote, rgba);
			return ToTexture(64, 64, rgba, "HF_HeimforMote");
		}

		private static Sprite FromOverride()
		{
			//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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			string text = Find("heimfor_stone.png");
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			try
			{
				byte[] array = File.ReadAllBytes(text);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					name = "HF_HeimforStoneIcon",
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1
				};
				if (!ImageConversion.LoadImage(val, array))
				{
					Object.Destroy((Object)(object)val);
					Safety.Warn("Icons.Decode", "'" + text + "' could not be decoded, so the generated icon is being used instead. It has to be a PNG.");
					return null;
				}
				Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
				((Object)obj).name = "HF_HeimforStoneIcon";
				return obj;
			}
			catch (Exception ex)
			{
				Safety.Failed("Icons.FromOverride", ex);
				return null;
			}
		}

		private static string Find(string file)
		{
			try
			{
				string text = Path.Combine(Override, file);
				if (File.Exists(text))
				{
					return text;
				}
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				if (!string.IsNullOrEmpty(directoryName))
				{
					string text2 = Path.Combine(directoryName, file);
					if (File.Exists(text2))
					{
						return text2;
					}
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Icons.Find", ex);
			}
			return null;
		}

		internal static bool Headless()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			try
			{
				return (int)SystemInfo.graphicsDeviceType == 4;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class Nursery
	{
		private static Transform _host;

		internal static Transform Transform()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			if ((Object)(object)_host != (Object)null)
			{
				return _host;
			}
			GameObject val = new GameObject("HeimforStone");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)val);
			_host = val.transform;
			return _host;
		}
	}
	internal static class Patches
	{
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	public static class Humanoid_UseItem_Patch
	{
		private static bool Prefix(Humanoid __instance, ItemData item)
		{
			try
			{
				if (!StoneItem.Is(item))
				{
					return true;
				}
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
				{
					return true;
				}
				return !Hearth.Use(val, item);
			}
			catch (Exception ex)
			{
				Safety.Failed("Humanoid.UseItem", ex);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDamaged")]
	public static class Player_OnDamaged_Patch
	{
		private static void Postfix(Player __instance)
		{
			try
			{
				if (Hearth.Running && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					Hearth.HitFlag = true;
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Player.OnDamaged", ex);
			}
		}
	}
	internal static class Hotkey
	{
		internal static void Tick()
		{
			try
			{
				if (!Pressed())
				{
					return;
				}
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !((Character)localPlayer).InCutscene() && !Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()))
				{
					ItemData val = StoneItem.FindIn(((Humanoid)localPlayer).GetInventory());
					if (val == null)
					{
						((Character)localPlayer).Message((MessageType)2, "You have no Heimfor Stone.", 0, (Sprite)null, false);
					}
					else
					{
						Hearth.Use(localPlayer, val);
					}
				}
			}
			catch (Exception ex)
			{
				Safety.Failed("Hotkey.Tick", ex);
			}
		}

		private static bool Pressed()
		{
			//IL_000e: 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_0016: 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)
			if (HeimforPlugin.CastHotkey == null)
			{
				return false;
			}
			KeyboardShortcut value = HeimforPlugin.CastHotkey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0)
			{
				return false;
			}
			if (!HasAny(((KeyboardShortcut)(ref value)).Modifiers))
			{
				return Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey);
			}
			return ((KeyboardShortcut)(ref value)).IsDown();
		}

		private static bool HasAny(IEnumerable<KeyCode> modifiers)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (modifiers == null)
			{
				return false;
			}
			using (IEnumerator<KeyCode> enumerator = modifiers.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					_ = enumerator.Current;
					return true;
				}
			}
			return false;
		}
	}
	[BepInPlugin("gbv.valheim.heimfor", "Heimfor", "0.1.1")]
	public class HeimforPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "gbv.valheim.heimfor";

		public const string PluginName = "Heimfor";

		public const string PluginVersion = "0.1.1";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> CooldownMinutes;

		internal static ConfigEntry<string> CooldownClock;

		internal static ConfigEntry<bool> ShareAcrossWorlds;

		internal static ConfigEntry<float> ChannelSeconds;

		internal static ConfigEntry<bool> CancelOnMove;

		internal static ConfigEntry<bool> CancelOnDamage;

		internal static ConfigEntry<bool> CancelOnMenu;

		internal static ConfigEntry<float> DriftTolerance;

		internal static ConfigEntry<string> ChannelEmote;

		internal static ConfigEntry<KeyboardShortcut> CastHotkey;

		internal static ConfigEntry<bool> RespectNoPortals;

		internal static ConfigEntry<bool> RespectBossBlock;

		internal static ConfigEntry<float> ItemWeight;

		internal static ConfigEntry<string> CloneFrom;

		internal static ConfigEntry<bool> GeneratedIcon;

		internal static ConfigEntry<bool> FlipWinding;

		internal static ConfigEntry<bool> ItemGlow;

		internal static ConfigEntry<bool> Craftable;

		internal static ConfigEntry<string> RecipeStation;

		internal static ConfigEntry<int> RecipeStationLevel;

		internal static ConfigEntry<string> RecipeCost;

		internal static ConfigEntry<int> RecipeRevision;

		internal static ConfigEntry<bool> ShowEffect;

		internal static ConfigEntry<bool> ShowOthers;

		internal static ConfigEntry<bool> ShowRing;

		internal static ConfigEntry<bool> ShowLight;

		internal static ConfigEntry<string> EffectColour;

		internal static ConfigEntry<float> EffectIntensity;

		internal static ConfigEntry<float> RingRadius;

		internal static ConfigEntry<float> LightRange;

		internal static ConfigEntry<bool> VerboseLog;

		internal const string DefaultCost = "Stone:1,GreydwarfEye:5,SurtlingCore:2,Coal:10";

		internal const string DefaultDonors = "SurtlingCore,GreydwarfEye,Ruby,Amber,Stone,Wood";

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Expected O, but got Unknown
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Expected O, but got Unknown
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Expected O, but got Unknown
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cc: Expected O, but got Unknown
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Expected O, but got Unknown
			//IL_0534: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Off means the stone can still be carried, crafted and traded, but using it does nothing. The item itself is always registered, because a prefab that stops existing is a stone that vanishes out of somebody's chest.");
				CooldownMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Cooldown", "Minutes", 60f, new ConfigDescription("How long before the stone can be used again. 0 means no cooldown at all.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1440f), Array.Empty<object>()));
				CooldownClock = ((BaseUnityPlugin)this).Config.Bind<string>("Cooldown", "Clock", "Wallclock", new ConfigDescription("Which clock the cooldown counts on. Wallclock is real time and keeps ticking while you are logged out, so an hour means an hour of your life. WorldTime counts game time, which stops when the server is empty, jumps forward when somebody s