Decompiled source of UFOAbduction v0.1.1

plugins/MuckUfoAbduction.dll

Decompiled 12 hours 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 HarmonyLib;
using Microsoft.CodeAnalysis;
using MuckShrineOfChance;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("MuckUfoAbduction")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Shrine of Chance outcome: a flying saucer abducts the player who spun and drops them far across the island.")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+5caa96df932c509d2f99e20681f4a02fa2d68991")]
[assembly: AssemblyProduct("UFO Abduction")]
[assembly: AssemblyTitle("MuckUfoAbduction")]
[assembly: InternalsVisibleTo("MuckUfoAbduction.Tests")]
[assembly: AssemblyVersion("0.1.1.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace MuckUfoAbduction
{
	internal static class PlayerNames
	{
		public static string Of(int clientId)
		{
			Dictionary<int, PlayerManager> players = GameManager.players;
			if (players != null && players.TryGetValue(clientId, out var value) && (Object)(object)value != (Object)null && !string.IsNullOrEmpty(value.username))
			{
				return value.username;
			}
			return "Someone";
		}
	}
	internal static class UfoArt
	{
		private const string Prefix = "MuckUfoAbduction.";

		public const string SaucerObj = "MuckUfoAbduction.ufo.obj";

		public const string SaucerJson = "MuckUfoAbduction.ufo.json";

		public const string BeamObj = "MuckUfoAbduction.ufo_beam.obj";

		public const string BeamJson = "MuckUfoAbduction.ufo_beam.json";

		internal static readonly string[] BodyShaders = new string[2] { "Standard", "Legacy Shaders/Diffuse" };

		internal static readonly string[] BeamShaders = new string[2] { "Legacy Shaders/Particles/Additive", "Sprites/Default" };

		private static bool built;

		private static Mesh saucerMesh;

		private static Material[] saucerMaterials;

		private static Mesh beamMesh;

		private static Material beamMaterial;

		private static readonly Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>();

		public static int LightsSubMesh { get; private set; } = -1;

		public static Color LightsEmission { get; private set; }

		public static bool TryGetSaucer(out Mesh mesh, out Material[] materials)
		{
			BuildOnce();
			mesh = saucerMesh;
			materials = saucerMaterials;
			if ((Object)(object)mesh != (Object)null)
			{
				return materials != null;
			}
			return false;
		}

		public static bool TryGetBeam(out Mesh mesh, out Material material)
		{
			BuildOnce();
			mesh = beamMesh;
			material = beamMaterial;
			if ((Object)(object)mesh != (Object)null)
			{
				return (Object)(object)material != (Object)null;
			}
			return false;
		}

		internal static UfoModel Load(string obj, string json)
		{
			return UfoModel.Parse(Text(obj), Text(json));
		}

		internal static string Choose(IList<string> wanted, Func<string, bool> available)
		{
			foreach (string item in wanted)
			{
				if (available(item))
				{
					return item;
				}
			}
			return null;
		}

		private static void BuildOnce()
		{
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			if (built)
			{
				return;
			}
			built = true;
			string text = Choose(BodyShaders, (string name) => (Object)(object)Shader.Find(name) != (Object)null);
			string text2 = Choose(BeamShaders, (string name) => (Object)(object)Shader.Find(name) != (Object)null);
			UfoPlugin.Log.LogInfo((object)("UFO shader: body '" + (text ?? "none") + "'" + ((text == "Standard") ? " (normal map, emission map, premultiplied glass)" : "") + ", beam '" + (text2 ?? "none") + "'."));
			try
			{
				UfoModel ufoModel = Load("MuckUfoAbduction.ufo.obj", "MuckUfoAbduction.ufo.json");
				if (text == null)
				{
					throw new InvalidOperationException("no body shader");
				}
				saucerMesh = ToMesh(ufoModel, "UFO saucer");
				saucerMaterials = (Material[])(object)new Material[ufoModel.SubMeshes.Count];
				for (int num = 0; num < ufoModel.SubMeshes.Count; num++)
				{
					string material = ufoModel.SubMeshes[num].Material;
					MaterialSpec materialSpec = ufoModel.Materials[material];
					saucerMaterials[num] = ((materialSpec.Alpha < 1f) ? Glass(text, materialSpec, material) : Body(text, materialSpec, material));
					if (LightsSubMesh < 0 && materialSpec.Emission > 0f)
					{
						LightsSubMesh = num;
						LightsEmission = Emission(materialSpec);
					}
				}
				UfoPlugin.Log.LogInfo((object)$"UFO saucer built: {ufoModel.TriangleCount} triangles, {ufoModel.Positions.Length} vertices, {ufoModel.SubMeshes.Count} materials, {Textures.Count} textures.");
			}
			catch (Exception ex)
			{
				saucerMesh = null;
				saucerMaterials = null;
				UfoPlugin.Log.LogWarning((object)("UFO saucer model was not built (" + ex.Message + "). The UFO shows as a light only."));
			}
			try
			{
				UfoModel ufoModel2 = Load("MuckUfoAbduction.ufo_beam.obj", "MuckUfoAbduction.ufo_beam.json");
				if (text2 == null)
				{
					throw new InvalidOperationException("no beam shader");
				}
				beamMesh = ToMesh(ufoModel2, "UFO beam");
				beamMaterial = Beam(text2, ufoModel2.Materials[ufoModel2.SubMeshes[0].Material]);
			}
			catch (Exception ex2)
			{
				beamMesh = null;
				beamMaterial = null;
				UfoPlugin.Log.LogWarning((object)("UFO beam was not built (" + ex2.Message + "). The UFO lifts without a visible beam."));
			}
		}

		private static Mesh ToMesh(UfoModel model, string name)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = new Mesh
			{
				name = name,
				hideFlags = (HideFlags)32
			};
			if (model.Positions.Length > 65000)
			{
				val.indexFormat = (IndexFormat)1;
			}
			List<Vector3> list = new List<Vector3>(model.Positions.Length);
			List<Vector3> list2 = new List<Vector3>(model.Positions.Length);
			List<Vector2> list3 = new List<Vector2>(model.Positions.Length);
			for (int i = 0; i < model.Positions.Length; i++)
			{
				list.Add(new Vector3(model.Positions[i].X, model.Positions[i].Y, model.Positions[i].Z));
				list2.Add(new Vector3(model.Normals[i].X, model.Normals[i].Y, model.Normals[i].Z));
				list3.Add(new Vector2(model.U[i], model.V[i]));
			}
			val.SetVertices(list);
			val.SetNormals(list2);
			val.SetUVs(0, list3);
			val.subMeshCount = model.SubMeshes.Count;
			for (int j = 0; j < model.SubMeshes.Count; j++)
			{
				val.SetTriangles(model.SubMeshes[j].Triangles, j);
			}
			val.RecalculateTangents();
			val.RecalculateBounds();
			return val;
		}

		private static Material Body(string shader, MaterialSpec spec, string name)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			Material val = New(shader, name);
			val.color = new Color(spec.R, spec.G, spec.B, 1f);
			if (spec.Albedo != null)
			{
				val.mainTexture = (Texture)(object)Texture(spec.Albedo, linear: false);
			}
			val.SetFloat("_Metallic", spec.Metallic);
			val.SetFloat("_Glossiness", spec.Smoothness);
			if (spec.Normal != null && val.HasProperty("_BumpMap"))
			{
				val.SetTexture("_BumpMap", (Texture)(object)Texture(spec.Normal, linear: true));
				val.SetFloat("_BumpScale", 1f);
				val.EnableKeyword("_NORMALMAP");
			}
			if (spec.Emission > 0f && val.HasProperty("_EmissionColor"))
			{
				if (spec.EmissionMap != null)
				{
					val.SetTexture("_EmissionMap", (Texture)(object)Texture(spec.EmissionMap, linear: false));
				}
				val.SetColor("_EmissionColor", Emission(spec));
				val.EnableKeyword("_EMISSION");
				val.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)1;
			}
			return val;
		}

		private static Material Glass(string shader, MaterialSpec spec, string name)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Material val = New(shader, name);
			val.color = new Color(spec.R, spec.G, spec.B, spec.Alpha);
			val.SetFloat("_Metallic", spec.Metallic);
			val.SetFloat("_Glossiness", spec.Smoothness);
			if (shader != "Standard")
			{
				return val;
			}
			val.SetFloat("_Mode", 3f);
			val.SetInt("_SrcBlend", 1);
			val.SetInt("_DstBlend", 10);
			val.SetInt("_ZWrite", 0);
			val.EnableKeyword("_ALPHAPREMULTIPLY_ON");
			val.renderQueue = 3000;
			return val;
		}

		private static Material Beam(string shader, MaterialSpec spec)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			Material val = New(shader, "UFO beam");
			if (spec.Albedo != null)
			{
				val.mainTexture = (Texture)(object)Texture(spec.Albedo, linear: false);
			}
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(spec.R, spec.G, spec.B, spec.Alpha);
			if (val.HasProperty("_TintColor"))
			{
				val.SetColor("_TintColor", new Color(val2.r * 0.5f, val2.g * 0.5f, val2.b * 0.5f, val2.a));
			}
			else
			{
				val.color = val2;
			}
			return val;
		}

		private static Material New(string shader, string name)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return new Material(Shader.Find(shader))
			{
				name = name,
				hideFlags = (HideFlags)32
			};
		}

		private static Color Emission(MaterialSpec spec)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			return new Color(spec.EmissionR * spec.Emission, spec.EmissionG * spec.Emission, spec.EmissionB * spec.Emission, 1f);
		}

		private static Texture2D Texture(string file, bool linear)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			if (Textures.TryGetValue(file, out var value))
			{
				return value;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			if (!ImageConversion.LoadImage(val, Bytes("MuckUfoAbduction." + file)))
			{
				throw new InvalidDataException(file + " is not an image");
			}
			Texture2D val2 = val;
			if (linear)
			{
				val2 = new Texture2D(((Texture)val).width, ((Texture)val).height, (TextureFormat)4, true, true);
				val2.SetPixels32(val.GetPixels32());
				Object.Destroy((Object)(object)val);
			}
			((Object)val2).name = file;
			((Texture)val2).wrapMode = (TextureWrapMode)0;
			((Texture)val2).anisoLevel = 4;
			((Object)val2).hideFlags = (HideFlags)32;
			val2.Apply(true, true);
			Textures.Add(file, val2);
			return val2;
		}

		private static byte[] Bytes(string name)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
			if (stream == null)
			{
				throw new FileNotFoundException(name);
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static string Text(string name)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
			if (stream == null)
			{
				throw new FileNotFoundException(name);
			}
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}
	}
	internal static class UfoDrop
	{
		public static void Aim(float px, float pz, float u, float v, float min, float max, out float x, out float z)
		{
			if (max < min)
			{
				max = min;
			}
			double num = (double)u * 2.0 * Math.PI;
			double num2 = Math.Sqrt((double)(min * min) + (double)(max * max - min * min) * (double)v);
			x = (float)((double)px + Math.Cos(num) * num2);
			z = (float)((double)pz + Math.Sin(num) * num2);
		}
	}
	internal static class UfoRules
	{
		public const float BossRadius = 50f;

		public static bool Abducts(bool alive, bool bossNear, bool dropFound)
		{
			return alive && !bossNear && dropFound;
		}

		public static bool BossNear(bool bossType, bool mobTypeBoss, float distance)
		{
			if (bossType || mobTypeBoss)
			{
				return distance <= 50f;
			}
			return false;
		}
	}
	internal static class UfoHost
	{
		private const int DropAttempts = 40;

		public static void Launch(int shrineId, int useIndex, int clientId, Vector3 shrinePos)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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_0097: 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_00a3: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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)
			PlayerManager value = null;
			GameManager.players?.TryGetValue(clientId, out value);
			bool flag = (Object)(object)value != (Object)null && !value.dead;
			Vector3 val = (((Object)(object)value != (Object)null) ? ((Component)value).transform.position : shrinePos);
			bool flag2 = BossNear(val);
			Vector3 drop = val;
			bool dropFound = flag && !flag2 && TryDrop(val, out drop);
			bool flag3 = UfoRules.Abducts(flag, flag2, dropFound);
			if (!flag3)
			{
				drop = val;
			}
			if (flag3)
			{
				UfoPlugin.Log.LogInfo((object)$"UFO abduction start: client {clientId} from {UfoText.Point(val.x, val.y, val.z)} to {UfoText.Point(drop.x, drop.y, drop.z)}, {UfoText.Metres(UfoText.FlatDistance(val.x, val.z, drop.x, drop.z))} m.");
			}
			else
			{
				UfoPlugin.Log.LogInfo((object)$"UFO flyby: client {clientId} ({UfoText.FlybyReason(flag, flag2, dropFound)}).");
			}
			string text = UfoWire.Encode(new UfoTrip(shrineId, useIndex, clientId, flag3, val.x, val.y, val.z, drop.x, drop.y, drop.z));
			ServerSend.SendChatMessage(-1, "", text);
			UfoShow.Present(text);
		}

		private static bool BossNear(Vector3 at)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			//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)
			MobManager instance = MobManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.mobs == null)
			{
				return false;
			}
			foreach (KeyValuePair<int, Mob> mob in instance.mobs)
			{
				Mob value = mob.Value;
				if (!((Object)(object)value == (Object)null))
				{
					bool mobTypeBoss = (Object)(object)value.mobType != (Object)null && value.mobType.boss;
					if (UfoRules.BossNear((int)value.bossType > 0, mobTypeBoss, Vector3.Distance(((Component)value).transform.position, at)))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool TryDrop(Vector3 from, out Vector3 drop)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_00a6: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			drop = from;
			float value = UfoPlugin.Cfg.MinDistance.Value;
			float value2 = UfoPlugin.Cfg.MaxDistance.Value;
			int mask = LayerMask.GetMask(new string[2] { "Ground", "Terrain" });
			RaycastHit val = default(RaycastHit);
			NavMeshHit val2 = default(NavMeshHit);
			for (int i = 0; i < 40; i++)
			{
				UfoDrop.Aim(from.x, from.z, Random.value, Random.value, value, value2, out var x, out var z);
				if (Physics.Raycast(new Vector3(x, from.y + 300f, z), Vector3.down, ref val, 800f, mask) && (int)WorldUtility.WorldHeightToBiome(((RaycastHit)(ref val)).point.y - 0.5f) != 0 && NavMesh.SamplePosition(((RaycastHit)(ref val)).point, ref val2, 3f, -1))
				{
					drop = ((NavMeshHit)(ref val2)).position;
					return true;
				}
			}
			return false;
		}
	}
	internal readonly struct Vec3
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public Vec3(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}
	}
	internal sealed class MaterialSpec
	{
		public float R = 1f;

		public float G = 1f;

		public float B = 1f;

		public float Alpha = 1f;

		public float Metallic;

		public float Smoothness;

		public float Emission;

		public float EmissionR = 1f;

		public float EmissionG = 1f;

		public float EmissionB = 1f;

		public string Albedo;

		public string Normal;

		public string EmissionMap;
	}
	internal sealed class SubMesh
	{
		public readonly string Material;

		public readonly int[] Triangles;

		public SubMesh(string material, int[] triangles)
		{
			Material = material;
			Triangles = triangles;
		}
	}
	internal sealed class UfoModel
	{
		public readonly string Name;

		public readonly Vec3[] Positions;

		public readonly Vec3[] Normals;

		public readonly float[] U;

		public readonly float[] V;

		public readonly IReadOnlyList<SubMesh> SubMeshes;

		public readonly IReadOnlyDictionary<string, MaterialSpec> Materials;

		public readonly int TriangleCount;

		private UfoModel(string name, Vec3[] positions, Vec3[] normals, float[] u, float[] v, IReadOnlyList<SubMesh> subMeshes, IReadOnlyDictionary<string, MaterialSpec> materials, int triangles)
		{
			Name = name;
			Positions = positions;
			Normals = normals;
			U = u;
			V = v;
			SubMeshes = subMeshes;
			Materials = materials;
			TriangleCount = triangles;
		}

		public static UfoModel Parse(string objText, string json)
		{
			if (!(JsonReader.Parse(json) is Dictionary<string, object> obj))
			{
				throw new FormatException("model json: top level is not an object.");
			}
			string text = Str(obj, "name");
			Dictionary<string, MaterialSpec> dictionary = ReadMaterials(Obj(obj, "materials"));
			if (objText == null)
			{
				throw new FormatException(text + ": OBJ text is null.");
			}
			List<Vec3> list = new List<Vec3>();
			List<Vec3> list2 = new List<Vec3>();
			List<float[]> list3 = new List<float[]>();
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			List<Vec3> list4 = new List<Vec3>();
			List<Vec3> list5 = new List<Vec3>();
			List<float> list6 = new List<float>();
			List<float> list7 = new List<float>();
			List<string> list8 = new List<string>();
			Dictionary<string, List<int>> dictionary3 = new Dictionary<string, List<int>>();
			int num = 0;
			int num2 = 0;
			string text2 = null;
			string[] array = objText.Split(new char[1] { '\n' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Trim().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries);
				if (array2.Length == 0)
				{
					continue;
				}
				switch (array2[0])
				{
				case "v":
				{
					Vec3 vec = ReadVec(array2, text, i);
					list.Add(new Vec3(0f - vec.X, vec.Y, vec.Z));
					break;
				}
				case "vn":
				{
					Vec3 vec2 = ReadVec(array2, text, i);
					list2.Add(new Vec3(0f - vec2.X, vec2.Y, vec2.Z));
					break;
				}
				case "vt":
					if (array2.Length < 3)
					{
						throw new FormatException($"{text}: OBJ line {i + 1} needs two numbers.");
					}
					list3.Add(new float[2]
					{
						Float(array2[1], text, i),
						Float(array2[2], text, i)
					});
					break;
				case "o":
					num++;
					break;
				case "usemtl":
					text2 = ((array2.Length > 1) ? array2[1] : null);
					if (text2 != null && !dictionary.ContainsKey(text2))
					{
						throw new FormatException(text + ": uses undefined material '" + text2 + "'.");
					}
					break;
				case "f":
				{
					if (text2 == null)
					{
						throw new FormatException($"{text}: OBJ line {i + 1} has a face outside a material.");
					}
					if (array2.Length != 4)
					{
						throw new FormatException($"{text}: OBJ line {i + 1} is not a triangle.");
					}
					if (!dictionary3.TryGetValue(text2, out var value))
					{
						value = new List<int>();
						dictionary3.Add(text2, value);
						list8.Add(text2);
					}
					int[] array3 = new int[3] { 1, 3, 2 };
					foreach (int num3 in array3)
					{
						if (!dictionary2.TryGetValue(array2[num3], out var value2))
						{
							string[] array4 = array2[num3].Split(new char[1] { '/' });
							if (array4.Length < 3 || array4[1].Length == 0 || array4[2].Length == 0)
							{
								throw new FormatException($"{text}: OBJ line {i + 1} has a corner without a UV or a normal.");
							}
							value2 = list4.Count;
							list4.Add(list[Index(array4[0], list.Count, text, i)]);
							float[] array5 = list3[Index(array4[1], list3.Count, text, i)];
							list6.Add(array5[0]);
							list7.Add(array5[1]);
							list5.Add(list2[Index(array4[2], list2.Count, text, i)]);
							dictionary2.Add(array2[num3], value2);
						}
						value.Add(value2);
					}
					num2++;
					break;
				}
				}
			}
			if (num != 1)
			{
				throw new FormatException($"{text}: the OBJ needs exactly one object, it has {num}.");
			}
			int num4 = (int)Num(obj, "tris");
			if (num2 != num4)
			{
				throw new FormatException($"{text}: OBJ has {num2} triangles, the json says {num4}.");
			}
			List<SubMesh> list9 = new List<SubMesh>();
			foreach (string item in list8)
			{
				list9.Add(new SubMesh(item, dictionary3[item].ToArray()));
			}
			return new UfoModel(text, list4.ToArray(), list5.ToArray(), list6.ToArray(), list7.ToArray(), list9, dictionary, num2);
		}

		private static Dictionary<string, MaterialSpec> ReadMaterials(Dictionary<string, object> raw)
		{
			Dictionary<string, MaterialSpec> dictionary = new Dictionary<string, MaterialSpec>();
			foreach (KeyValuePair<string, object> item in raw)
			{
				if (!(item.Value is Dictionary<string, object> dictionary2))
				{
					throw new FormatException("model json: material " + item.Key + " is not an object.");
				}
				MaterialSpec materialSpec = new MaterialSpec();
				if (dictionary2.ContainsKey("rgb"))
				{
					Vec3 vec = ReadVec3(dictionary2, "rgb");
					materialSpec.R = vec.X;
					materialSpec.G = vec.Y;
					materialSpec.B = vec.Z;
				}
				if (dictionary2.ContainsKey("emission_rgb"))
				{
					Vec3 vec2 = ReadVec3(dictionary2, "emission_rgb");
					materialSpec.EmissionR = vec2.X;
					materialSpec.EmissionG = vec2.Y;
					materialSpec.EmissionB = vec2.Z;
				}
				else
				{
					materialSpec.EmissionR = materialSpec.R;
					materialSpec.EmissionG = materialSpec.G;
					materialSpec.EmissionB = materialSpec.B;
				}
				materialSpec.Alpha = Optional(dictionary2, "alpha", 1f);
				materialSpec.Metallic = Optional(dictionary2, "metallic", 0f);
				materialSpec.Smoothness = Optional(dictionary2, "smoothness", 0f);
				materialSpec.Emission = Optional(dictionary2, "emission", 0f);
				if (dictionary2.TryGetValue("textures", out var value) && value is Dictionary<string, object> dictionary3)
				{
					materialSpec.Albedo = (dictionary3.TryGetValue("albedo", out var value2) ? (value2 as string) : null);
					materialSpec.Normal = (dictionary3.TryGetValue("normal", out var value3) ? (value3 as string) : null);
					materialSpec.EmissionMap = (dictionary3.TryGetValue("emission", out var value4) ? (value4 as string) : null);
				}
				dictionary.Add(item.Key, materialSpec);
			}
			return dictionary;
		}

		private static int Index(string raw, int count, string name, int line)
		{
			if (!int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result == 0)
			{
				throw new FormatException($"{name}: OBJ line {line + 1} has a bad index '{raw}'.");
			}
			int num = ((result > 0) ? (result - 1) : (count + result));
			if (num < 0 || num >= count)
			{
				throw new FormatException($"{name}: OBJ line {line + 1} index {raw} is out of range.");
			}
			return num;
		}

		private static Vec3 ReadVec(string[] tokens, string name, int line)
		{
			if (tokens.Length < 4)
			{
				throw new FormatException($"{name}: OBJ line {line + 1} needs three numbers.");
			}
			return new Vec3(Float(tokens[1], name, line), Float(tokens[2], name, line), Float(tokens[3], name, line));
		}

		private static float Float(string raw, string name, int line)
		{
			if (!float.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				throw new FormatException($"{name}: OBJ line {line + 1} has a bad number '{raw}'.");
			}
			return result;
		}

		private static Vec3 ReadVec3(Dictionary<string, object> obj, string key)
		{
			List<object> list = (Field(obj, key) as List<object>) ?? throw new FormatException("model json: '" + key + "' is not an array.");
			if (list.Count != 3 || !(list[0] is double num) || !(list[1] is double num2) || !(list[2] is double num3))
			{
				throw new FormatException("model json: '" + key + "' is not three numbers.");
			}
			return new Vec3((float)num, (float)num2, (float)num3);
		}

		private static float Optional(Dictionary<string, object> obj, string key, float fallback)
		{
			if (!obj.TryGetValue(key, out var value) || !(value is double num))
			{
				return fallback;
			}
			return (float)num;
		}

		private static object Field(Dictionary<string, object> obj, string key)
		{
			if (!obj.TryGetValue(key, out var value))
			{
				throw new FormatException("model json: missing '" + key + "'.");
			}
			return value;
		}

		private static string Str(Dictionary<string, object> obj, string key)
		{
			return (Field(obj, key) as string) ?? throw new FormatException("model json: '" + key + "' is not a string.");
		}

		private static double Num(Dictionary<string, object> obj, string key)
		{
			object obj2 = Field(obj, key);
			if (obj2 is double)
			{
				return (double)obj2;
			}
			throw new FormatException("model json: '" + key + "' is not a number.");
		}

		private static Dictionary<string, object> Obj(Dictionary<string, object> obj, string key)
		{
			return (Field(obj, key) as Dictionary<string, object>) ?? throw new FormatException("model json: '" + key + "' is not an object.");
		}
	}
	internal sealed class JsonReader
	{
		private readonly string text;

		private int pos;

		private JsonReader(string text)
		{
			this.text = text;
		}

		public static object Parse(string text)
		{
			if (text == null)
			{
				throw new FormatException("JSON text is null.");
			}
			JsonReader jsonReader = new JsonReader(text);
			object result = jsonReader.ReadValue();
			jsonReader.SkipWhitespace();
			if (jsonReader.pos != text.Length)
			{
				throw jsonReader.Error("trailing characters");
			}
			return result;
		}

		private object ReadValue()
		{
			SkipWhitespace();
			if (pos >= text.Length)
			{
				throw Error("unexpected end");
			}
			char c = text[pos];
			switch (c)
			{
			case '{':
				return ReadObject();
			case '[':
				return ReadArray();
			case '"':
				return ReadString();
			case 't':
				Expect("true");
				return true;
			case 'f':
				Expect("false");
				return false;
			case 'n':
				Expect("null");
				return null;
			default:
				switch (c)
				{
				case '-':
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					return ReadNumber();
				default:
					throw Error($"unexpected '{c}'");
				}
			}
		}

		private Dictionary<string, object> ReadObject()
		{
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			pos++;
			SkipWhitespace();
			if (Peek() == '}')
			{
				pos++;
				return dictionary;
			}
			while (true)
			{
				SkipWhitespace();
				if (Peek() != '"')
				{
					throw Error("expected a key");
				}
				string key = ReadString();
				SkipWhitespace();
				if (Peek() != ':')
				{
					break;
				}
				pos++;
				dictionary[key] = ReadValue();
				SkipWhitespace();
				char c = Peek();
				pos++;
				switch (c)
				{
				case ',':
					break;
				case '}':
					return dictionary;
				default:
					throw Error("expected ',' or '}'");
				}
			}
			throw Error("expected ':'");
		}

		private List<object> ReadArray()
		{
			List<object> list = new List<object>();
			pos++;
			SkipWhitespace();
			if (Peek() == ']')
			{
				pos++;
				return list;
			}
			while (true)
			{
				list.Add(ReadValue());
				SkipWhitespace();
				char c = Peek();
				pos++;
				switch (c)
				{
				case ',':
					break;
				case ']':
					return list;
				default:
					throw Error("expected ',' or ']'");
				}
			}
		}

		private string ReadString()
		{
			pos++;
			StringBuilder stringBuilder = new StringBuilder();
			while (pos < text.Length)
			{
				char c = text[pos++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					break;
				case '\\':
				{
					if (pos >= text.Length)
					{
						throw Error("unterminated escape");
					}
					char c2 = text[pos++];
					switch (c2)
					{
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					case 'b':
						stringBuilder.Append('\b');
						break;
					case 'f':
						stringBuilder.Append('\f');
						break;
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'u':
						if (pos + 4 > text.Length)
						{
							throw Error("short \\u escape");
						}
						stringBuilder.Append((char)int.Parse(text.Substring(pos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
						pos += 4;
						break;
					default:
						throw Error($"bad escape '\\{c2}'");
					}
					break;
				}
				}
			}
			throw Error("unterminated string");
		}

		private double ReadNumber()
		{
			int num = pos;
			while (pos < this.text.Length && "+-0123456789.eE".IndexOf(this.text[pos]) >= 0)
			{
				pos++;
			}
			string text = this.text.Substring(num, pos - num);
			if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				throw Error("bad number '" + text + "'");
			}
			return result;
		}

		private void Expect(string word)
		{
			if (string.CompareOrdinal(text, pos, word, 0, word.Length) != 0)
			{
				throw Error("expected '" + word + "'");
			}
			pos += word.Length;
		}

		private char Peek()
		{
			if (pos >= text.Length)
			{
				return '\0';
			}
			return text[pos];
		}

		private void SkipWhitespace()
		{
			while (pos < text.Length && char.IsWhiteSpace(text[pos]))
			{
				pos++;
			}
		}

		private FormatException Error(string what)
		{
			return new FormatException($"JSON: {what} at offset {pos}.");
		}
	}
	[HarmonyPatch(typeof(ChatBox), "AppendMessage")]
	internal static class UfoChatPatch
	{
		private static bool Prefix(int fromUser, string message)
		{
			if (!UfoWire.Hidden(message))
			{
				return true;
			}
			if (fromUser == -1)
			{
				UfoShow.Present(message);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerStatus), "Damage")]
	internal static class UfoDamagePatch
	{
		private static bool Prefix()
		{
			return !UfoShow.Shielded;
		}
	}
	[HarmonyPatch(typeof(PlayerStatus), "DealDamage")]
	internal static class UfoDealDamagePatch
	{
		private static bool Prefix()
		{
			return !UfoShow.Shielded;
		}
	}
	[BepInPlugin("evan.muck.ufoabduction", "UFO Abduction", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class UfoPlugin : BaseUnityPlugin
	{
		public const string Guid = "evan.muck.ufoabduction";

		public const string Name = "UFO Abduction";

		public const string Version = "0.1.1";

		public const string OutcomeId = "evan.muck.ufoabduction.ufo";

		internal static readonly Color Cyan = new Color(0.3f, 0.92f, 1f);

		internal static ManualLogSource Log;

		internal static UfoConfig Cfg;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new UfoConfig(((BaseUnityPlugin)this).Config);
			Harmony harmony = new Harmony("evan.muck.ufoabduction");
			if (!TryPatch(harmony, typeof(UfoChatPatch)))
			{
				Log.LogError((object)"UFO Abduction 0.1.1 could not hook ChatBox.AppendMessage, so no peer could see a UFO. The UFO stays out of the shrine's odds.");
				return;
			}
			if (!TryPatch(harmony, typeof(UfoDamagePatch)) || !TryPatch(harmony, typeof(UfoDealDamagePatch)))
			{
				Log.LogWarning((object)"UFO Abduction could not hook PlayerStatus damage. An abducted player can still be hurt.");
			}
			ShrineOutcomeRegistry.Register(new ShrineOutcomeSpec("evan.muck.ufoabduction.ufo", "UFO", "UFO", Cyan, "Three UFOs! Look up.", (Func<double>)(() => UfoText.Share(Cfg.Enabled.Value, Cfg.Chance.Value, Cfg.Force.Value)), (Action<ShrineOutcomeRoll>)delegate(ShrineOutcomeRoll roll)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				UfoHost.Launch(((ShrineOutcomeRoll)(ref roll)).ShrineId, ((ShrineOutcomeRoll)(ref roll)).UseIndex, ((ShrineOutcomeRoll)(ref roll)).ClientId, ((ShrineOutcomeRoll)(ref roll)).ShrinePosition);
			}));
			Log.LogInfo((object)string.Format("{0} {1} loaded. UFO share {2:0.##}% of every shrine roll. Every player must share this config.", "UFO Abduction", "0.1.1", UfoText.Share(Cfg.Enabled.Value, Cfg.Chance.Value, Cfg.Force.Value) * 100.0));
		}

		private static bool TryPatch(Harmony harmony, Type patchClass)
		{
			try
			{
				harmony.CreateClassProcessor(patchClass).Patch();
				return true;
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("{0} failed to patch {1}: {2}", "UFO Abduction", patchClass.Name, arg));
				return false;
			}
		}
	}
	internal sealed class UfoConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<float> Chance;

		public readonly ConfigEntry<float> MinDistance;

		public readonly ConfigEntry<float> MaxDistance;

		public readonly ConfigEntry<bool> Force;

		public readonly ConfigEntry<bool> VerboseLogging;

		public UfoConfig(ConfigFile cfg)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("UFO", "Enabled", true, "A Shrine of Chance roll can bring a flying saucer over the player who spun. It lifts them up its beam and drops them somewhere else on the island, unhurt. Every player must use the same value.");
			Chance = cfg.Bind<float>("UFO", "Chance", 10f, new ConfigDescription("Percent of every paid Shrine of Chance roll that brings the UFO. The six built-in tiers, Nuke included, share what is left, keeping their relative weights. Every player must use the same value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			MinDistance = cfg.Bind<float>("UFO", "MinDistance", 60f, new ConfigDescription("Fewest meters from the pickup spot to the drop spot. The host's value picks the spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 400f), Array.Empty<object>()));
			MaxDistance = cfg.Bind<float>("UFO", "MaxDistance", 150f, new ConfigDescription("Most meters from the pickup spot to the drop spot. Below MinDistance it is raised to MinDistance. The host's value picks the spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 400f), Array.Empty<object>()));
			Force = cfg.Bind<bool>("Debug", "ForceUfo", false, "Every paid shrine roll brings the UFO. Debug only. Every player must use the same value.");
			VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Logs each UFO decision's details and the hum clip.");
		}
	}
	internal sealed class UfoShow : MonoBehaviour
	{
		private const float Diameter = 9f;

		private const float BeamTopRadius = 0.12f;

		private const float BeamBottomRadius = 3f;

		private const float HoldBelow = 2.4f;

		private const float GraceSeconds = 1.5f;

		private const float SpinDegreesPerSecond = 40f;

		private const float BeamScrollPerSecond = 0.08f;

		private static readonly HashSet<string> Seen = new HashSet<string>();

		private static UfoShow holder;

		private static float shieldUntil = -1f;

		private UfoTrip trip;

		private float t;

		private Vector3 hover;

		private Vector3 dropHover;

		private Vector3 from;

		private Vector3 away;

		private Transform saucer;

		private Transform beam;

		private Light glow;

		private Material beamMat;

		private Renderer saucerRenderer;

		private MaterialPropertyBlock lightsBlock;

		private AudioSource hum;

		private bool holding;

		private bool refused;

		private Vector3 liftStart;

		private bool inputWasActive;

		private bool wasKinematic;

		public static bool Shielded
		{
			get
			{
				if (!((Object)(object)holder != (Object)null))
				{
					return Time.time < shieldUntil;
				}
				return true;
			}
		}

		public static void Present(string message)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (UfoWire.TryParse(message, out var visit))
			{
				HashSet<string> seen = Seen;
				string[] obj = new string[5]
				{
					GameManager.GetSeed().ToString(),
					":",
					null,
					null,
					null
				};
				int shrineId = visit.ShrineId;
				obj[2] = shrineId.ToString();
				obj[3] = ":";
				shrineId = visit.UseIndex;
				obj[4] = shrineId.ToString();
				if (seen.Add(string.Concat(obj)))
				{
					new GameObject("UfoAbduction").AddComponent<UfoShow>().Begin(visit);
				}
			}
		}

		private void Begin(UfoTrip visit)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_00e9: 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_00f5: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			trip = visit;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(trip.PickupX, trip.PickupY, trip.PickupZ);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(trip.DropX, trip.DropY, trip.DropZ);
			Vector3 val3 = val2 - val;
			val3.y = 0f;
			val3 = ((((Vector3)(ref val3)).sqrMagnitude > 1f) ? ((Vector3)(ref val3)).normalized : Vector3.forward);
			hover = val + Vector3.up * 15f;
			dropHover = val2 + Vector3.up * 15f;
			from = hover - val3 * 70f + Vector3.up * 50f;
			away = dropHover + val3 * 140f + Vector3.up * 90f;
			((Component)this).transform.position = from;
			Build();
			Say(UfoText.Line(PlayerNames.Of(trip.ClientId), trip.Abduct));
		}

		private void Build()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00d7: 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)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			if (UfoArt.TryGetSaucer(out var mesh, out var materials))
			{
				saucer = Part("Saucer", mesh, materials, Vector3.one * 9f);
				saucerRenderer = ((Component)saucer).GetComponent<Renderer>();
				lightsBlock = new MaterialPropertyBlock();
			}
			if (UfoArt.TryGetBeam(out var mesh2, out var material))
			{
				beam = Part("Beam", mesh2, (Material[])(object)new Material[1] { material }, Vector3.one);
				beamMat = material;
				beam.localPosition = Vector3.down * 9f * 0.2f;
				((Component)beam).gameObject.SetActive(false);
			}
			GameObject val = new GameObject("UfoGlow");
			val.transform.SetParent(((Component)this).transform, false);
			val.transform.localPosition = Vector3.down * 2.5f;
			glow = val.AddComponent<Light>();
			glow.type = (LightType)2;
			glow.color = UfoPlugin.Cyan;
			glow.range = 22f;
			glow.intensity = 2f;
			hum = UfoSound.Attach(((Component)this).gameObject);
		}

		private Transform Part(string name, Mesh mesh, Material[] materials, Vector3 scale)
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(((Component)this).transform, false);
			val.transform.localScale = scale;
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = materials;
			return val.transform;
		}

		private void Update()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			t += Time.deltaTime;
			UfoPhase ufoPhase = UfoTimeline.PhaseAt(t);
			if (ufoPhase == UfoPhase.Done)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			((Component)this).transform.position = UfoPosition(ufoPhase);
			if ((Object)(object)saucer != (Object)null)
			{
				saucer.Rotate(0f, 40f * Time.deltaTime, 0f, (Space)1);
			}
			float num = 0.5f + 0.5f * Mathf.Sin(t * 9f);
			if ((Object)(object)glow != (Object)null)
			{
				glow.intensity = 1.6f + 1.2f * num;
			}
			PulseLights(0.7f + 0.6f * num);
			if ((Object)(object)hum != (Object)null)
			{
				hum.volume = 0.8f * (1f - UfoTimeline.Progress(UfoPhase.Leave, t));
			}
			UpdateBeam();
			if (trip.Abduct && IsMine())
			{
				HoldPlayer(ufoPhase);
			}
		}

		private Vector3 UfoPosition(UfoPhase phase)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Sin(t * 2.2f) * 0.35f;
			switch (phase)
			{
			case UfoPhase.Arrive:
				return Vector3.Lerp(from, hover, UfoTimeline.Progress(UfoPhase.Arrive, t));
			case UfoPhase.Beam:
			case UfoPhase.Lift:
				return hover + Vector3.up * num;
			case UfoPhase.Carry:
			{
				float num2 = UfoTimeline.Progress(UfoPhase.Carry, t);
				return Vector3.Lerp(hover, dropHover, num2) + Vector3.up * (Mathf.Sin(num2 * MathF.PI) * 12f + num);
			}
			case UfoPhase.Lower:
				return dropHover + Vector3.up * num;
			default:
				return Vector3.Lerp(dropHover, away, UfoTimeline.Progress(UfoPhase.Leave, t));
			}
		}

		private void PulseLights(float gain)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			int lightsSubMesh = UfoArt.LightsSubMesh;
			if (!((Object)(object)saucerRenderer == (Object)null) && lightsSubMesh >= 0)
			{
				lightsBlock.SetColor("_EmissionColor", UfoArt.LightsEmission * gain);
				saucerRenderer.SetPropertyBlock(lightsBlock, lightsSubMesh);
			}
		}

		private void UpdateBeam()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)beam == (Object)null)
			{
				return;
			}
			if ((Object)(object)beamMat != (Object)null)
			{
				beamMat.mainTextureOffset = new Vector2(t * 0.08f, 0f);
			}
			bool flag = trip.Abduct && UfoTimeline.BeamOn(t);
			if (((Component)beam).gameObject.activeSelf != flag)
			{
				((Component)beam).gameObject.SetActive(flag);
			}
			if (flag)
			{
				float num = 16f;
				int mask = LayerMask.GetMask(new string[2] { "Ground", "Terrain" });
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(beam.position, Vector3.down, ref val, 60f, mask))
				{
					num = ((RaycastHit)(ref val)).distance;
				}
				float num2 = 6f;
				beam.localScale = new Vector3(num2, Mathf.Max(1f, num), num2);
			}
		}

		private bool IsMine()
		{
			if ((Object)(object)LocalClient.instance != (Object)null)
			{
				return LocalClient.instance.myId == trip.ClientId;
			}
			return false;
		}

		private void HoldPlayer(UfoPhase phase)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0082: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			if (refused)
			{
				return;
			}
			if (!UfoTimeline.Holding(t))
			{
				if (holding)
				{
					Release();
				}
				return;
			}
			PlayerMovement instance = PlayerMovement.Instance;
			if (!holding)
			{
				if ((Object)(object)instance == (Object)null || instance.IsDead())
				{
					refused = true;
					return;
				}
				Grab(instance);
			}
			if (!((Object)(object)instance == (Object)null))
			{
				Vector3 val = ((Component)this).transform.position + Vector3.down * 2.4f;
				Vector3 position = (Vector3)(phase switch
				{
					UfoPhase.Lift => Vector3.Lerp(liftStart, val, UfoTimeline.Progress(UfoPhase.Lift, t)), 
					UfoPhase.Lower => Vector3.Lerp(val, new Vector3(trip.DropX, trip.DropY + 1f, trip.DropZ), UfoTimeline.Progress(UfoPhase.Lower, t)), 
					_ => val, 
				});
				((Component)instance).transform.position = position;
			}
		}

		private void Grab(PlayerMovement pm)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			holding = true;
			holder = this;
			liftStart = ((Component)pm).transform.position;
			inputWasActive = (Object)(object)PlayerInput.Instance == (Object)null || PlayerInput.Instance.active;
			if ((Object)(object)PlayerInput.Instance != (Object)null)
			{
				PlayerInput.Instance.active = false;
			}
			Rigidbody rb = pm.GetRb();
			wasKinematic = (Object)(object)rb != (Object)null && rb.isKinematic;
			if ((Object)(object)rb != (Object)null)
			{
				rb.velocity = Vector3.zero;
				rb.isKinematic = true;
			}
		}

		private void Release()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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)
			holding = false;
			PlayerMovement instance = PlayerMovement.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				Vector3 position = ((Component)instance).transform.position;
				UfoPlugin.Log.LogInfo((object)$"UFO abduction drop: client {trip.ClientId} at {UfoText.Point(position.x, position.y, position.z)}, {UfoText.Metres(UfoText.FlatDistance(trip.PickupX, trip.PickupZ, position.x, position.z))} m from the pickup.");
			}
			if ((Object)(object)holder == (Object)(object)this)
			{
				holder = null;
			}
			shieldUntil = Time.time + 1.5f;
			PlayerMovement instance2 = PlayerMovement.Instance;
			if ((Object)(object)instance2 != (Object)null)
			{
				Rigidbody rb = instance2.GetRb();
				if ((Object)(object)rb != (Object)null)
				{
					rb.isKinematic = wasKinematic;
					rb.velocity = Vector3.zero;
				}
			}
			if ((Object)(object)PlayerInput.Instance != (Object)null)
			{
				PlayerInput.Instance.active = inputWasActive;
			}
		}

		private void OnDestroy()
		{
			if (holding)
			{
				Release();
			}
		}

		private static void Say(string message)
		{
			ChatBox instance = ChatBox.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.AppendMessage(-1, message, "");
			}
		}
	}
	internal static class UfoSound
	{
		internal static readonly string[] Preferred = new string[4] { "ChargeHold", "ZoneAmbience", "Charge", "WindFlyby" };

		public const float Volume = 0.8f;

		private const float Pitch = 0.45f;

		private static AudioClip clip;

		private static bool warned;

		public static int Pick(IList<string> names)
		{
			string[] preferred = Preferred;
			foreach (string text in preferred)
			{
				for (int j = 0; j < names.Count; j++)
				{
					if (names[j] == text)
					{
						return j;
					}
				}
			}
			return -1;
		}

		public static AudioSource Attach(GameObject saucer)
		{
			if ((Object)(object)clip == (Object)null)
			{
				clip = Find();
			}
			if ((Object)(object)clip == (Object)null)
			{
				if (!warned)
				{
					UfoPlugin.Log.LogWarning((object)"UFO hum: none of ChargeHold, ZoneAmbience, Charge or WindFlyby is loaded, so the UFO is silent.");
				}
				warned = true;
				return null;
			}
			AudioSource obj = saucer.AddComponent<AudioSource>();
			obj.clip = clip;
			obj.loop = true;
			obj.pitch = 0.45f;
			obj.volume = 0.8f;
			obj.spatialBlend = 1f;
			obj.rolloffMode = (AudioRolloffMode)1;
			obj.minDistance = 12f;
			obj.maxDistance = 160f;
			obj.dopplerLevel = 0f;
			obj.Play();
			if (UfoPlugin.Cfg.VerboseLogging.Value)
			{
				UfoPlugin.Log.LogInfo((object)("UFO hum '" + ((Object)clip).name + "' playing."));
			}
			return obj;
		}

		private static AudioClip Find()
		{
			AudioClip[] array = Resources.FindObjectsOfTypeAll<AudioClip>();
			string[] array2 = new string[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array2[i] = (((Object)(object)array[i] == (Object)null) ? null : ((Object)array[i]).name);
			}
			int num = Pick(array2);
			if (num >= 0)
			{
				return array[num];
			}
			return null;
		}
	}
	internal static class UfoText
	{
		public const string Label = "UFO";

		public const string WinMessage = "Three UFOs! Look up.";

		public static string Line(string playerName, bool abduct)
		{
			if (string.IsNullOrEmpty(playerName))
			{
				playerName = "Someone";
			}
			if (!abduct)
			{
				return "A UFO looks " + playerName + " over and leaves.";
			}
			return "A UFO is taking " + playerName + "!";
		}

		public static string FlybyReason(bool alive, bool bossNear, bool dropFound)
		{
			if (!alive)
			{
				return "player dead or missing";
			}
			if (bossNear)
			{
				return "boss within " + 50f.ToString(CultureInfo.InvariantCulture) + " m";
			}
			if (!dropFound)
			{
				return "no dry navmesh drop spot";
			}
			return "none";
		}

		public static double Share(bool enabled, float chancePercent, bool force)
		{
			if (force)
			{
				return 1.0;
			}
			if (!enabled || float.IsNaN(chancePercent) || chancePercent <= 0f)
			{
				return 0.0;
			}
			if (!(chancePercent >= 100f))
			{
				return (double)chancePercent / 100.0;
			}
			return 1.0;
		}

		public static string Point(float x, float y, float z)
		{
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			return "(" + x.ToString("0.0", invariantCulture) + ", " + y.ToString("0.0", invariantCulture) + ", " + z.ToString("0.0", invariantCulture) + ")";
		}

		public static string Metres(float metres)
		{
			return metres.ToString("0.0", CultureInfo.InvariantCulture);
		}

		public static float FlatDistance(float ax, float az, float bx, float bz)
		{
			float num = bx - ax;
			float num2 = bz - az;
			return (float)Math.Sqrt(num * num + num2 * num2);
		}
	}
	internal enum UfoPhase
	{
		Arrive,
		Beam,
		Lift,
		Carry,
		Lower,
		Leave,
		Done
	}
	internal static class UfoTimeline
	{
		public const float HoverHeight = 15f;

		private static readonly float[] Starts = new float[7] { 0f, 2f, 2.5f, 5.5f, 8f, 9.5f, 12f };

		public static UfoPhase PhaseAt(float t)
		{
			for (int num = Starts.Length - 1; num > 0; num--)
			{
				if (t >= Starts[num])
				{
					return (UfoPhase)num;
				}
			}
			return UfoPhase.Arrive;
		}

		public static float Progress(UfoPhase phase, float t)
		{
			if ((int)phase >= Starts.Length - 1)
			{
				if (!(t >= Starts[(int)phase]))
				{
					return 0f;
				}
				return 1f;
			}
			float num = (t - Starts[(int)phase]) / (Starts[(int)(phase + 1)] - Starts[(int)phase]);
			if (num <= 0f)
			{
				return 0f;
			}
			if (num >= 1f)
			{
				return 1f;
			}
			return num * num * (3f - 2f * num);
		}

		public static bool BeamOn(float t)
		{
			if (t >= Starts[1])
			{
				return t < Starts[5];
			}
			return false;
		}

		public static bool Holding(float t)
		{
			if (t >= Starts[2])
			{
				return t < Starts[5];
			}
			return false;
		}
	}
	internal readonly struct UfoTrip
	{
		public readonly int ShrineId;

		public readonly int UseIndex;

		public readonly int ClientId;

		public readonly bool Abduct;

		public readonly float PickupX;

		public readonly float PickupY;

		public readonly float PickupZ;

		public readonly float DropX;

		public readonly float DropY;

		public readonly float DropZ;

		public UfoTrip(int shrineId, int useIndex, int clientId, bool abduct, float pickupX, float pickupY, float pickupZ, float dropX, float dropY, float dropZ)
		{
			ShrineId = shrineId;
			UseIndex = useIndex;
			ClientId = clientId;
			Abduct = abduct;
			PickupX = pickupX;
			PickupY = pickupY;
			PickupZ = pickupZ;
			DropX = dropX;
			DropY = dropY;
			DropZ = dropZ;
		}
	}
	internal static class UfoWire
	{
		public const string Prefix = "~ufo";

		private const string Head = "~ufo1 trip";

		public static bool Hidden(string message)
		{
			return message?.StartsWith("~ufo", StringComparison.Ordinal) ?? false;
		}

		public static string Encode(UfoTrip trip)
		{
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			string[] obj = new string[11]
			{
				"~ufo1 trip", null, null, null, null, null, null, null, null, null,
				null
			};
			int shrineId = trip.ShrineId;
			obj[1] = shrineId.ToString(invariantCulture);
			shrineId = trip.UseIndex;
			obj[2] = shrineId.ToString(invariantCulture);
			shrineId = trip.ClientId;
			obj[3] = shrineId.ToString(invariantCulture);
			obj[4] = (trip.Abduct ? "a" : "f");
			obj[5] = Dm(trip.PickupX);
			obj[6] = Dm(trip.PickupY);
			obj[7] = Dm(trip.PickupZ);
			obj[8] = Dm(trip.DropX);
			obj[9] = Dm(trip.DropY);
			obj[10] = Dm(trip.DropZ);
			return string.Join(" ", obj);
		}

		public static bool TryParse(string message, out UfoTrip trip)
		{
			trip = default(UfoTrip);
			if (message == null || !message.StartsWith("~ufo1 trip ", StringComparison.Ordinal))
			{
				return false;
			}
			string[] array = message.Split(new char[1] { ' ' });
			if (array.Length != 12 || (array[5] != "a" && array[5] != "f"))
			{
				return false;
			}
			int[] array2 = new int[12];
			for (int i = 2; i < 12; i++)
			{
				if (i != 5 && !int.TryParse(array[i], NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out array2[i]))
				{
					return false;
				}
			}
			trip = new UfoTrip(array2[2], array2[3], array2[4], array[5] == "a", (float)array2[6] / 10f, (float)array2[7] / 10f, (float)array2[8] / 10f, (float)array2[9] / 10f, (float)array2[10] / 10f, (float)array2[11] / 10f);
			return true;
		}

		private static string Dm(float metres)
		{
			return ((int)Math.Round((double)metres * 10.0, MidpointRounding.AwayFromZero)).ToString(CultureInfo.InvariantCulture);
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "MuckUfoAbduction";

		public const string PLUGIN_NAME = "UFO Abduction";

		public const string PLUGIN_VERSION = "0.1.1";
	}
}