Decompiled source of HamudHabob v1.0.0

HamudHabob.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HamudHabob
{
	public class GlbModel
	{
		public GameObject Root;

		public SkinnedMeshRenderer Renderer;

		public Texture2D Texture;

		public Texture2D Emission;

		public Color EmissionColor = Color.black;

		public Bounds MeshBounds;

		public readonly Dictionary<string, AnimationClip> Clips = new Dictionary<string, AnimationClip>();
	}
	public static class GlbLoader
	{
		private class Ctx
		{
			public JObject Json;

			public byte[] Data;

			public int BinStart;
		}

		public static GlbModel Load(string path, Transform templateParent)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Expected O, but got Unknown
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_054b: Unknown result type (might be due to invalid IL or missing references)
			//IL_054d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Unknown result type (might be due to invalid IL or missing references)
			byte[] array = File.ReadAllBytes(path);
			if (BitConverter.ToUInt32(array, 0) != 1179937895)
			{
				throw new InvalidDataException(path + " is not a .glb file");
			}
			int num = BitConverter.ToInt32(array, 12);
			Ctx ctx = new Ctx
			{
				Json = JObject.Parse(Encoding.UTF8.GetString(array, 20, num)),
				Data = array,
				BinStart = 20 + num + 8
			};
			JObject json = ctx.Json;
			GlbModel glbModel = new GlbModel();
			glbModel.Root = new GameObject(Path.GetFileNameWithoutExtension(path));
			glbModel.Root.transform.SetParent(templateParent, false);
			JArray val = (JArray)json["nodes"];
			Transform[] nodes = (Transform[])(object)new Transform[((JContainer)val).Count];
			for (int i = 0; i < nodes.Length; i++)
			{
				GameObject val2 = new GameObject(((string)val[i][(object)"name"]) ?? ("node_" + i));
				nodes[i] = val2.transform;
			}
			for (int j = 0; j < nodes.Length; j++)
			{
				JToken val3 = val[j];
				JToken obj = val3[(object)"children"];
				JArray val4 = (JArray)(object)((obj is JArray) ? obj : null);
				if (val4 != null)
				{
					foreach (JToken item in val4)
					{
						nodes[(int)item].SetParent(nodes[j], false);
					}
				}
				ApplyTrs(nodes[j], val3);
			}
			int valueOrDefault = ((int?)json["scene"]).GetValueOrDefault();
			foreach (JToken item2 in (IEnumerable<JToken>)json["scenes"][(object)valueOrDefault][(object)"nodes"])
			{
				nodes[(int)item2].SetParent(glbModel.Root.transform, false);
			}
			JToken obj2 = json["materials"];
			JToken val5 = ((IEnumerable<JToken>)((obj2 is JArray) ? obj2 : null))?.FirstOrDefault();
			object textureInfo;
			if (val5 == null)
			{
				textureInfo = null;
			}
			else
			{
				JToken obj3 = val5[(object)"pbrMetallicRoughness"];
				textureInfo = ((obj3 != null) ? obj3[(object)"baseColorTexture"] : null);
			}
			int? num2 = ImageOf(json, (JToken)textureInfo);
			int? num3 = ImageOf(json, (val5 != null) ? val5[(object)"emissiveTexture"] : null);
			if (!num2.HasValue)
			{
				JToken obj4 = json["images"];
				JArray val6 = (JArray)(object)((obj4 is JArray) ? obj4 : null);
				if (val6 != null && ((JContainer)val6).Count > 0)
				{
					num2 = 0;
				}
			}
			if (num2.HasValue)
			{
				glbModel.Texture = LoadImage(ctx, num2.Value, ((Object)glbModel.Root).name + "_texture");
			}
			if (num3.HasValue)
			{
				glbModel.Emission = LoadImage(ctx, num3.Value, ((Object)glbModel.Root).name + "_emission");
				object obj5;
				if (val5 == null)
				{
					obj5 = null;
				}
				else
				{
					JToken obj6 = val5[(object)"extensions"];
					if (obj6 == null)
					{
						obj5 = null;
					}
					else
					{
						JToken obj7 = obj6[(object)"KHR_materials_emissive_strength"];
						obj5 = ((obj7 != null) ? obj7[(object)"emissiveStrength"] : null);
					}
				}
				float num4 = ((float?)(JToken)obj5) ?? 1f;
				JToken obj8 = ((val5 != null) ? val5[(object)"emissiveFactor"] : null);
				JArray val7 = (JArray)(object)((obj8 is JArray) ? obj8 : null);
				glbModel.EmissionColor = (Color)((val7 != null) ? new Color((float)val7[0], (float)val7[1], (float)val7[2]) : Color.white) * num4;
			}
			for (int k = 0; k < nodes.Length; k++)
			{
				JToken val8 = val[k];
				if (val8[(object)"mesh"] == null)
				{
					continue;
				}
				Mesh val9 = BuildMesh(ctx, json["meshes"][(object)(int)val8[(object)"mesh"]]);
				SkinnedMeshRenderer val10 = ((Component)nodes[k]).gameObject.AddComponent<SkinnedMeshRenderer>();
				if (val8[(object)"skin"] != null)
				{
					JToken val11 = json["skins"][(object)(int)val8[(object)"skin"]];
					Transform[] joints = ((IEnumerable<JToken>)(JArray)val11[(object)"joints"]).Select((JToken val14) => nodes[(int)val14]).ToArray();
					int count;
					float[] array2 = ReadFloats(ctx, (int)val11[(object)"inverseBindMatrices"], out count);
					Matrix4x4[] array3 = (Matrix4x4[])(object)new Matrix4x4[joints.Length];
					for (int num5 = 0; num5 < joints.Length; num5++)
					{
						Matrix4x4 m = default(Matrix4x4);
						for (int num6 = 0; num6 < 4; num6++)
						{
							for (int num7 = 0; num7 < 4; num7++)
							{
								((Matrix4x4)(ref m))[num7, num6] = array2[num5 * 16 + num6 * 4 + num7];
							}
						}
						array3[num5] = MirrorX(m);
					}
					val9.bindposes = array3;
					val10.bones = joints;
					val10.rootBone = joints.First((Transform t) => !joints.Contains(t.parent));
				}
				val10.sharedMesh = val9;
				val10.updateWhenOffscreen = true;
				glbModel.Renderer = val10;
				glbModel.MeshBounds = val9.bounds;
			}
			JToken obj9 = json["animations"];
			JArray val12 = (JArray)(object)((obj9 is JArray) ? obj9 : null);
			if (val12 != null)
			{
				foreach (JToken item3 in val12)
				{
					AnimationClip val13 = BuildClip(ctx, item3, nodes, glbModel.Root.transform);
					glbModel.Clips[((Object)val13).name] = val13;
				}
			}
			return glbModel;
		}

		private static int? ImageOf(JObject json, JToken textureInfo)
		{
			if (((textureInfo != null) ? textureInfo[(object)"index"] : null) == null)
			{
				return null;
			}
			JToken obj = json["textures"];
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				JToken obj3 = obj[(object)(int)textureInfo[(object)"index"]];
				obj2 = ((obj3 != null) ? obj3[(object)"source"] : null);
			}
			return (int?)(JToken)obj2;
		}

		private static Texture2D LoadImage(Ctx ctx, int image, string name)
		{
			//IL_0091: 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_009d: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			JToken val = ctx.Json["bufferViews"][(object)(int)ctx.Json["images"][(object)image][(object)"bufferView"]];
			int srcOffset = ctx.BinStart + ((int?)val[(object)"byteOffset"]).GetValueOrDefault();
			int num = (int)val[(object)"byteLength"];
			byte[] array = new byte[num];
			Buffer.BlockCopy(ctx.Data, srcOffset, array, 0, num);
			Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, true);
			ImageConversion.LoadImage(val2, array);
			((Object)val2).name = name;
			((Texture)val2).wrapMode = (TextureWrapMode)1;
			((Texture)val2).filterMode = (FilterMode)0;
			return val2;
		}

		private static Vector3 ConvPos(float x, float y, float z)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(0f - x, y, z);
		}

		private static Quaternion ConvRot(float x, float y, float z, float w)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(x, 0f - y, 0f - z, w);
		}

		private static Matrix4x4 MirrorX(Matrix4x4 m)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 val = Matrix4x4.Scale(new Vector3(-1f, 1f, 1f));
			return val * m * val;
		}

		private static void ApplyTrs(Transform t, JToken n)
		{
			//IL_0016: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0067: 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_0079: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			JToken obj = n[(object)"matrix"];
			JArray val = (JArray)(object)((obj is JArray) ? obj : null);
			if (val != null)
			{
				Matrix4x4 m = default(Matrix4x4);
				for (int i = 0; i < 4; i++)
				{
					for (int j = 0; j < 4; j++)
					{
						((Matrix4x4)(ref m))[j, i] = (float)val[i * 4 + j];
					}
				}
				m = MirrorX(m);
				t.localPosition = Vector4.op_Implicit(((Matrix4x4)(ref m)).GetColumn(3));
				t.localRotation = ((Matrix4x4)(ref m)).rotation;
				t.localScale = ((Matrix4x4)(ref m)).lossyScale;
				return;
			}
			JToken obj2 = n[(object)"translation"];
			JArray val2 = (JArray)(object)((obj2 is JArray) ? obj2 : null);
			if (val2 != null)
			{
				t.localPosition = ConvPos((float)val2[0], (float)val2[1], (float)val2[2]);
			}
			JToken obj3 = n[(object)"rotation"];
			JArray val3 = (JArray)(object)((obj3 is JArray) ? obj3 : null);
			if (val3 != null)
			{
				t.localRotation = ConvRot((float)val3[0], (float)val3[1], (float)val3[2], (float)val3[3]);
			}
			JToken obj4 = n[(object)"scale"];
			JArray val4 = (JArray)(object)((obj4 is JArray) ? obj4 : null);
			if (val4 != null)
			{
				t.localScale = new Vector3((float)val4[0], (float)val4[1], (float)val4[2]);
			}
		}

		private static Mesh BuildMesh(Ctx ctx, JToken meshJson)
		{
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Expected O, but got Unknown
			//IL_00ed: 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_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			List<BoneWeight> list4 = new List<BoneWeight>();
			List<int[]> list5 = new List<int[]>();
			foreach (JToken item2 in (IEnumerable<JToken>)meshJson[(object)"primitives"])
			{
				JToken val = item2[(object)"attributes"];
				int count = list.Count;
				int count2;
				float[] array = ReadFloats(ctx, (int)val[(object)"POSITION"], out count2);
				for (int i = 0; i < count2; i++)
				{
					list.Add(ConvPos(array[i * 3], array[i * 3 + 1], array[i * 3 + 2]));
				}
				int count3;
				if (val[(object)"NORMAL"] != null)
				{
					float[] array2 = ReadFloats(ctx, (int)val[(object)"NORMAL"], out count3);
					for (int j = 0; j < count2; j++)
					{
						list2.Add(ConvPos(array2[j * 3], array2[j * 3 + 1], array2[j * 3 + 2]));
					}
				}
				if (val[(object)"TEXCOORD_0"] != null)
				{
					float[] array3 = ReadFloats(ctx, (int)val[(object)"TEXCOORD_0"], out count3);
					for (int k = 0; k < count2; k++)
					{
						list3.Add(new Vector2(array3[k * 2], 1f - array3[k * 2 + 1]));
					}
				}
				if (val[(object)"JOINTS_0"] != null && val[(object)"WEIGHTS_0"] != null)
				{
					int[] array4 = ReadInts(ctx, (int)val[(object)"JOINTS_0"]);
					float[] array5 = ReadFloats(ctx, (int)val[(object)"WEIGHTS_0"], out count3);
					for (int l = 0; l < count2; l++)
					{
						float num = array5[l * 4] + array5[l * 4 + 1] + array5[l * 4 + 2] + array5[l * 4 + 3];
						if (num <= 0f)
						{
							num = 1f;
						}
						BoneWeight item = default(BoneWeight);
						((BoneWeight)(ref item)).boneIndex0 = array4[l * 4];
						((BoneWeight)(ref item)).weight0 = array5[l * 4] / num;
						((BoneWeight)(ref item)).boneIndex1 = array4[l * 4 + 1];
						((BoneWeight)(ref item)).weight1 = array5[l * 4 + 1] / num;
						((BoneWeight)(ref item)).boneIndex2 = array4[l * 4 + 2];
						((BoneWeight)(ref item)).weight2 = array5[l * 4 + 2] / num;
						((BoneWeight)(ref item)).boneIndex3 = array4[l * 4 + 3];
						((BoneWeight)(ref item)).weight3 = array5[l * 4 + 3] / num;
						list4.Add(item);
					}
				}
				int[] array6 = ((item2[(object)"indices"] != null) ? ReadInts(ctx, (int)item2[(object)"indices"]) : Enumerable.Range(0, count2).ToArray());
				int[] array7 = new int[array6.Length];
				for (int m = 0; m + 2 < array6.Length; m += 3)
				{
					array7[m] = array6[m] + count;
					array7[m + 1] = array6[m + 2] + count;
					array7[m + 2] = array6[m + 1] + count;
				}
				list5.Add(array7);
			}
			Mesh val2 = new Mesh
			{
				name = (((string)meshJson[(object)"name"]) ?? "glb_mesh")
			};
			if (list.Count > 65535)
			{
				val2.indexFormat = (IndexFormat)1;
			}
			val2.SetVertices(list);
			if (list2.Count == list.Count)
			{
				val2.SetNormals(list2);
			}
			if (list3.Count == list.Count)
			{
				val2.SetUVs(0, list3);
			}
			if (list4.Count == list.Count)
			{
				val2.boneWeights = list4.ToArray();
			}
			val2.subMeshCount = list5.Count;
			for (int n = 0; n < list5.Count; n++)
			{
				val2.SetTriangles(list5[n], n);
			}
			if (list2.Count != list.Count)
			{
				val2.RecalculateNormals();
			}
			val2.RecalculateBounds();
			return val2;
		}

		private static AnimationClip BuildClip(Ctx ctx, JToken anim, Transform[] nodes, Transform root)
		{
			//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_002c: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0123: 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_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: 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_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Expected O, but got Unknown
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			AnimationClip val = new AnimationClip
			{
				legacy = true,
				name = (((string)anim[(object)"name"]) ?? "anim")
			};
			JArray val2 = (JArray)anim[(object)"samplers"];
			foreach (JToken item in (IEnumerable<JToken>)anim[(object)"channels"])
			{
				JToken val3 = item[(object)"target"];
				if (val3[(object)"node"] == null)
				{
					continue;
				}
				string text = (string)val3[(object)"path"];
				JToken val4 = val2[(int)item[(object)"sampler"]];
				string text2 = ((string)val4[(object)"interpolation"]) ?? "LINEAR";
				int count;
				float[] array = ReadFloats(ctx, (int)val4[(object)"input"], out count);
				int count2;
				float[] array2 = ReadFloats(ctx, (int)val4[(object)"output"], out count2);
				int num = ((text == "rotation") ? 4 : 3);
				if (text == "weights")
				{
					continue;
				}
				float[][] array3 = new float[count][];
				Quaternion val5 = Quaternion.identity;
				for (int i = 0; i < count; i++)
				{
					int num2 = ((text2 == "CUBICSPLINE") ? ((i * 3 + 1) * num) : (i * num));
					if (!(text == "translation"))
					{
						if (text == "rotation")
						{
							Quaternion val6 = ConvRot(array2[num2], array2[num2 + 1], array2[num2 + 2], array2[num2 + 3]);
							if (i > 0 && Quaternion.Dot(val5, val6) < 0f)
							{
								((Quaternion)(ref val6))..ctor(0f - val6.x, 0f - val6.y, 0f - val6.z, 0f - val6.w);
							}
							val5 = val6;
							array3[i] = new float[4] { val6.x, val6.y, val6.z, val6.w };
						}
						else
						{
							array3[i] = new float[3]
							{
								array2[num2],
								array2[num2 + 1],
								array2[num2 + 2]
							};
						}
					}
					else
					{
						Vector3 val7 = ConvPos(array2[num2], array2[num2 + 1], array2[num2 + 2]);
						array3[i] = new float[3] { val7.x, val7.y, val7.z };
					}
				}
				string text3 = ((text == "translation") ? "localPosition" : ((text == "rotation") ? "localRotation" : "localScale"));
				string[] array4 = new string[4] { "x", "y", "z", "w" };
				string text4 = PathTo(nodes[(int)val3[(object)"node"]], root);
				for (int j = 0; j < num; j++)
				{
					Keyframe[] array5 = (Keyframe[])(object)new Keyframe[count];
					for (int k = 0; k < count; k++)
					{
						float num3 = array3[k][j];
						float num4 = 0f;
						float num5 = 0f;
						if (text2 == "STEP")
						{
							num4 = (num5 = float.PositiveInfinity);
						}
						else
						{
							if (k > 0)
							{
								num4 = (num3 - array3[k - 1][j]) / Mathf.Max(1E-05f, array[k] - array[k - 1]);
							}
							if (k < count - 1)
							{
								num5 = (array3[k + 1][j] - num3) / Mathf.Max(1E-05f, array[k + 1] - array[k]);
							}
							if (k == 0)
							{
								num4 = num5;
							}
							if (k == count - 1)
							{
								num5 = num4;
							}
						}
						array5[k] = new Keyframe(array[k], num3, num4, num5);
					}
					val.SetCurve(text4, typeof(Transform), text3 + "." + array4[j], new AnimationCurve(array5));
				}
			}
			val.EnsureQuaternionContinuity();
			return val;
		}

		private static string PathTo(Transform t, Transform root)
		{
			List<string> list = new List<string>();
			Transform val = t;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		private static int ComponentCount(string type)
		{
			return type switch
			{
				"SCALAR" => 1, 
				"VEC2" => 2, 
				"VEC3" => 3, 
				"VEC4" => 4, 
				"MAT4" => 16, 
				_ => throw new NotSupportedException("accessor type " + type), 
			};
		}

		private static float[] ReadFloats(Ctx ctx, int accessor, out int count)
		{
			JToken val = ctx.Json["accessors"][(object)accessor];
			count = (int)val[(object)"count"];
			int num = ComponentCount((string)val[(object)"type"]);
			int num2 = (int)val[(object)"componentType"];
			bool valueOrDefault = (bool?)val[(object)"normalized"] == true;
			GetLayout(ctx, val, num2, num, out var start, out var stride);
			float[] array = new float[count * num];
			int num3 = ComponentSize(num2);
			for (int i = 0; i < count; i++)
			{
				for (int j = 0; j < num; j++)
				{
					int num4 = start + i * stride + j * num3;
					float num5;
					switch (num2)
					{
					case 5126:
						num5 = BitConverter.ToSingle(ctx.Data, num4);
						break;
					case 5121:
						num5 = (int)ctx.Data[num4];
						if (valueOrDefault)
						{
							num5 /= 255f;
						}
						break;
					case 5123:
						num5 = (int)BitConverter.ToUInt16(ctx.Data, num4);
						if (valueOrDefault)
						{
							num5 /= 65535f;
						}
						break;
					case 5120:
						num5 = (sbyte)ctx.Data[num4];
						if (valueOrDefault)
						{
							num5 = Mathf.Max(num5 / 127f, -1f);
						}
						break;
					case 5122:
						num5 = BitConverter.ToInt16(ctx.Data, num4);
						if (valueOrDefault)
						{
							num5 = Mathf.Max(num5 / 32767f, -1f);
						}
						break;
					case 5125:
						num5 = BitConverter.ToUInt32(ctx.Data, num4);
						break;
					default:
						throw new NotSupportedException("componentType " + num2);
					}
					array[i * num + j] = num5;
				}
			}
			return array;
		}

		private static int[] ReadInts(Ctx ctx, int accessor)
		{
			JToken val = ctx.Json["accessors"][(object)accessor];
			int num = (int)val[(object)"count"];
			int num2 = ComponentCount((string)val[(object)"type"]);
			int num3 = (int)val[(object)"componentType"];
			GetLayout(ctx, val, num3, num2, out var start, out var stride);
			int num4 = ComponentSize(num3);
			int[] array = new int[num * num2];
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num2; j++)
				{
					int num5 = start + i * stride + j * num4;
					switch (num3)
					{
					case 5121:
						array[i * num2 + j] = ctx.Data[num5];
						break;
					case 5123:
						array[i * num2 + j] = BitConverter.ToUInt16(ctx.Data, num5);
						break;
					case 5125:
						array[i * num2 + j] = (int)BitConverter.ToUInt32(ctx.Data, num5);
						break;
					default:
						throw new NotSupportedException("index componentType " + num3);
					}
				}
			}
			return array;
		}

		private static int ComponentSize(int ctype)
		{
			switch (ctype)
			{
			default:
				return 1;
			case 5122:
			case 5123:
				return 2;
			case 5125:
			case 5126:
				return 4;
			}
		}

		private static void GetLayout(Ctx ctx, JToken a, int ctype, int n, out int start, out int stride)
		{
			JToken val = ctx.Json["bufferViews"][(object)(int)a[(object)"bufferView"]];
			start = ctx.BinStart + ((int?)val[(object)"byteOffset"]).GetValueOrDefault() + ((int?)a[(object)"byteOffset"]).GetValueOrDefault();
			stride = ((int?)val[(object)"byteStride"]) ?? (ComponentSize(ctype) * n);
		}
	}
	public static class HamudSounds
	{
		internal static AudioClip[] Voices = (AudioClip[])(object)new AudioClip[0];

		internal static AudioClip[] Laughs = (AudioClip[])(object)new AudioClip[0];

		internal static AudioClip[] Pop = (AudioClip[])(object)new AudioClip[0];

		internal static void Load(string dir)
		{
			Voices = LoadAll("hamud_voice");
			Laughs = LoadAll("hamud_laugh");
			Pop = LoadAll("hamud_pop");
			Plugin.Log.LogInfo((object)($"Sounds: {Voices.Length} voice, {Laughs.Length} laugh, {Pop.Length} pop " + "[" + string.Join(", ", from c in Voices.Concat(Laughs).Concat(Pop)
				select $"{((Object)c).name} {c.length:0.00}s") + "]"));
			AudioClip[] LoadAll(string prefix)
			{
				return (from f in Directory.GetFiles(dir, prefix + "*.wav")
					orderby f
					select f).Select(delegate(string f)
				{
					AudioClip obj = WavLoader.Load(f);
					((Object)obj).name = Path.GetFileNameWithoutExtension(f);
					return obj;
				}).ToArray();
			}
		}

		internal static GameObject MakeSfx(string name, GameObject template, AudioClip[] clips, string caption, bool throttle = true)
		{
			if (clips.Length == 0)
			{
				return null;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, template);
			ZSFX component = val.GetComponent<ZSFX>();
			component.m_audioClips = clips;
			component.m_minPitch = 0.97f;
			component.m_maxPitch = 1.03f;
			component.m_minVol = (component.m_maxVol = Plugin.VoiceVolume.Value);
			component.m_closedCaptionToken = caption;
			component.m_secondaryCaptionToken = "";
			component.m_maxConcurrentSources = 0;
			if (throttle)
			{
				val.AddComponent<HamudVoiceThrottle>();
			}
			ZNetView[] componentsInChildren = val.GetComponentsInChildren<ZNetView>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			TimedDestruction obj = val.GetComponent<TimedDestruction>() ?? val.AddComponent<TimedDestruction>();
			obj.m_timeout = clips.Max((AudioClip c) => c.length) + 1f;
			obj.m_triggerOnAwake = true;
			AudioSource component2 = val.GetComponent<AudioSource>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.loop = false;
				component2.maxDistance = Mathf.Max(component2.maxDistance, 35f);
			}
			return val;
		}

		internal static void Play(GameObject sfx, Vector3 pos)
		{
			//IL_000a: 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)
			if ((Object)(object)sfx != (Object)null)
			{
				Object.Instantiate<GameObject>(sfx, pos, Quaternion.identity);
			}
		}
	}
	public class HamudVoiceThrottle : MonoBehaviour
	{
		private const float Radius = 10f;

		private static readonly List<HamudVoiceThrottle> s_active = new List<HamudVoiceThrottle>();

		private float m_until;

		private void Awake()
		{
			//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)
			s_active.RemoveAll((HamudVoiceThrottle s) => (Object)(object)s == (Object)null || Time.time >= s.m_until);
			Vector3 pos = ((Component)this).transform.position;
			if (s_active.Any(delegate(HamudVoiceThrottle s)
			{
				//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_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)s).transform.position - pos;
				return ((Vector3)(ref val)).sqrMagnitude < 100f;
			}))
			{
				((Component)this).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			float num = 2f;
			((Component)this).GetComponent<AudioSource>();
			ZSFX component = ((Component)this).GetComponent<ZSFX>();
			if ((Object)(object)component != (Object)null && component.m_audioClips.Length != 0)
			{
				num = component.m_audioClips.Max((AudioClip c) => c.length);
			}
			m_until = Time.time + num + 0.3f;
			s_active.Add(this);
		}

		private void OnDestroy()
		{
			s_active.Remove(this);
		}
	}
	public class HamudThief : MonoBehaviour
	{
		internal const string ZLoot = "hamud_loot";

		internal const string ZLootCount = "hamud_lootcount";

		internal const string ZHeld = "hamud_held";

		internal const string ZFleeUntil = "hamud_flee_until";

		internal const string ZLaughs = "hamud_laughs";

		internal const string ZVictim = "hamud_victim";

		internal const string ZStealable = "hamud_stealable";

		internal const string ZSnatches = "hamud_snatches";

		private const string RpcLoot = "Hamud_Loot";

		private const string RpcSnatch = "Hamud_Snatch";

		private const float SnatchCooldown = 1.2f;

		private const float FullSackFleeRange = 16f;

		private const float GiveUpRange = 45f;

		private ZNetView m_nview;

		private Character m_character;

		private MonsterAI m_ai;

		private bool m_aiFleeing;

		private float m_nextIdleLaugh;

		private float m_nextSnatch;

		private float m_nextNotice;

		private float m_nextNoticeDebug;

		private static readonly bool s_debug = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SAHUR_TEST_OUT"));

		private static float s_nextFlagUpdate;

		private static int s_sightMask;

		private ZDO Zdo
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return null;
				}
				return m_nview.GetZDO();
			}
		}

		internal int LootCount
		{
			get
			{
				ZDO zdo = Zdo;
				if (zdo == null)
				{
					return 0;
				}
				return zdo.GetInt("hamud_lootcount", 0);
			}
		}

		internal string LootString
		{
			get
			{
				ZDO zdo = Zdo;
				return ((zdo != null) ? zdo.GetString("hamud_loot", "") : null) ?? "";
			}
		}

		internal static double Now
		{
			get
			{
				if (!((Object)(object)ZNet.instance != (Object)null))
				{
					return Time.time;
				}
				return ZNet.instance.GetTimeSeconds();
			}
		}

		internal bool IsFleeing
		{
			get
			{
				if (Zdo != null)
				{
					return Now < (double)Zdo.GetFloat("hamud_flee_until", 0f);
				}
				return false;
			}
		}

		internal bool CanSteal
		{
			get
			{
				if (Zdo != null && !m_character.IsDead())
				{
					return LootCount < Plugin.MaxLoot.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			m_character = ((Component)this).GetComponent<Character>();
			m_ai = ((Component)this).GetComponent<MonsterAI>();
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
			{
				m_nview.Register<ZPackage, ZDOID>("Hamud_Loot", (Action<long, ZPackage, ZDOID>)RPC_Loot);
				m_nview.Register<ZDOID>("Hamud_Snatch", (Action<long, ZDOID>)RPC_Snatch);
			}
			m_nextIdleLaugh = Time.time + Random.Range(8f, 16f);
		}

		internal static List<ItemData> Stealables(Inventory inv)
		{
			return (from i in inv.GetAllItems()
				where (Object)(object)i.m_dropPrefab != (Object)null && (Plugin.StealEquipped.Value || !i.m_equipped) && (Plugin.StealFromHotbar.Value || i.m_gridPos.y > 0)
				select i).ToList();
		}

		internal static void UpdateStealableFlag(Player player)
		{
			if (!(Time.time < s_nextFlagUpdate) && !((Object)(object)((Character)player).m_nview == (Object)null) && ((Character)player).m_nview.IsValid() && ((Character)player).m_nview.IsOwner())
			{
				s_nextFlagUpdate = Time.time + 1f;
				bool flag = Stealables(((Humanoid)player).GetInventory()).Count > 0;
				ZDO zDO = ((Character)player).m_nview.GetZDO();
				if (zDO.GetBool("hamud_stealable", true) != flag)
				{
					zDO.Set("hamud_stealable", flag);
				}
			}
		}

		internal bool WantsTarget(Character other)
		{
			Player val = (Player)(object)((other is Player) ? other : null);
			if (val == null)
			{
				return false;
			}
			if (IsFleeing || LootCount >= Plugin.MaxLoot.Value)
			{
				return true;
			}
			ZNetView nview = ((Character)val).m_nview;
			if (!((Object)(object)nview == (Object)null) && nview.IsValid())
			{
				return nview.GetZDO().GetBool("hamud_stealable", true);
			}
			return true;
		}

		internal static Inventory ParseLoot(string data)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			Inventory val = new Inventory("HamudLoot", (Sprite)null, 8, 4);
			if (!string.IsNullOrEmpty(data))
			{
				val.Load(new ZPackage(data));
			}
			return val;
		}

		internal static void StealFrom(Player victim, HamudThief thief)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)victim).GetInventory();
			List<ItemData> list = Stealables(inventory);
			if (list.Count == 0)
			{
				Debug(victim.GetPlayerName() + " has nothing to steal");
				return;
			}
			ItemData val = list[Random.Range(0, list.Count)];
			if (val.m_equipped)
			{
				((Humanoid)victim).UnequipItem(val, true);
			}
			ItemData val2 = val.Clone();
			val2.m_equipped = false;
			Inventory val3 = new Inventory("HamudSwag", (Sprite)null, 1, 1);
			val3.AddItem(val2);
			ZPackage val4 = new ZPackage();
			val3.Save(val4);
			inventory.RemoveItem(val);
			thief.m_nview.InvokeRPC("Hamud_Loot", new object[2]
			{
				val4,
				((Character)victim).GetZDOID()
			});
			string arg = Localization.instance.Localize(val.m_shared.m_name);
			MessageHud instance = MessageHud.instance;
			if (instance != null)
			{
				instance.ShowMessage((MessageType)2, string.Format(Localization.instance.Localize("$hamud_stole"), arg, val.m_stack), 0, (Sprite)null, false, true);
			}
			Debug($"STOLE {((Object)val.m_dropPrefab).name} x{val.m_stack} from {victim.GetPlayerName()}");
		}

		private void RPC_Snatch(long sender, ZDOID victim)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0069: 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_007d: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).GetZDOID() != victim || ((Character)localPlayer).IsDead() || !CanSteal)
			{
				return;
			}
			if (((Character)localPlayer).IsDodgeInvincible())
			{
				Debug("snatch dodged");
				return;
			}
			Vector3 val = Vector3.ProjectOnPlane(((Component)this).transform.position - ((Component)localPlayer).transform.position, Vector3.up);
			Vector3 normalized = ((Vector3)(ref val)).normalized;
			if (((Character)localPlayer).IsBlocking() && Vector3.Dot(((Component)localPlayer).transform.forward, normalized) > 0.5f)
			{
				Debug("snatch blocked");
			}
			else
			{
				StealFrom(localPlayer, this);
			}
		}

		private void TrySnatch()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_00fa: 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)
			if (Time.time < m_nextSnatch || !CanSteal)
			{
				return;
			}
			Character targetCreature = ((BaseAI)m_ai).GetTargetCreature();
			Player val = (Player)(object)((targetCreature is Player) ? targetCreature : null);
			if (val == null || ((Character)val).IsDead() || !WantsTarget((Character)(object)val))
			{
				return;
			}
			Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position;
			if (!(Mathf.Abs(val2.y) > 1.5f))
			{
				val2.y = 0f;
				if (!(((Vector3)(ref val2)).magnitude > Plugin.SnatchRange.Value))
				{
					m_nextSnatch = Time.time + 1.2f;
					Zdo.Set("hamud_snatches", Zdo.GetInt("hamud_snatches", 0) + 1);
					m_nview.InvokeRPC(ZNetView.Everybody, "Hamud_Snatch", new object[1] { ((Character)val).GetZDOID() });
					object arg = ((Vector3)(ref val2)).magnitude;
					Vector3 velocity = ((Character)val).GetVelocity();
					Debug($"snatch at {arg:0.0}m (target speed {((Vector3)(ref velocity)).magnitude:0.0})");
				}
			}
		}

		private void NoticeMarks()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < m_nextNotice || (Object)(object)((BaseAI)m_ai).GetTargetCreature() != (Object)null)
			{
				return;
			}
			m_nextNotice = Time.time + 0.5f;
			Player val = null;
			float num = Plugin.NoticeRange.Value;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!((Object)(object)allPlayer == (Object)null) && !((Character)allPlayer).IsDead() && !((Character)allPlayer).InGhostMode() && !((Character)allPlayer).IsDebugFlying() && WantsTarget((Character)(object)allPlayer))
				{
					float num2 = Vector3.Distance(((Component)allPlayer).transform.position, ((Component)this).transform.position);
					if (s_debug && Time.time > m_nextNoticeDebug)
					{
						m_nextNoticeDebug = Time.time + 5f;
						object[] obj = new object[5]
						{
							num2,
							HasLineOfSight(allPlayer),
							Plugin.NoticeRange.Value,
							null,
							null
						};
						Character targetCreature = ((BaseAI)m_ai).GetTargetCreature();
						obj[3] = ((targetCreature != null) ? ((Object)targetCreature).name : null);
						obj[4] = ((BaseAI)m_ai).IsAlerted();
						Debug(string.Format("notice check: {0:0}m los={1} range={2} target={3} alerted={4}", obj));
					}
					if (num2 < num && (num2 < 8f || HasLineOfSight(allPlayer)))
					{
						val = allPlayer;
						num = num2;
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				m_ai.m_targetCreature = (Character)(object)val;
				((BaseAI)m_ai).SetAlerted(true);
				Debug($"noticed {val.GetPlayerName()} at {num:0.0}m");
			}
		}

		private bool HasLineOfSight(Player p)
		{
			//IL_0045: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (s_sightMask == 0)
			{
				s_sightMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "terrain", "piece", "viewblock" });
			}
			Vector3 eyePoint = m_character.GetEyePoint();
			Vector3 eyePoint2 = ((Character)p).GetEyePoint();
			return !Physics.Linecast(eyePoint, eyePoint2, s_sightMask, (QueryTriggerInteraction)1);
		}

		private void RPC_Loot(long sender, ZPackage pkg, ZDOID victim)
		{
			//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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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)
			if (!m_nview.IsOwner())
			{
				return;
			}
			Inventory val = ParseLoot(LootString);
			Inventory val2 = new Inventory("HamudSwag", (Sprite)null, 1, 1);
			val2.Load(pkg);
			string text = "";
			foreach (ItemData item in val2.GetAllItems().ToList())
			{
				item.m_equipped = false;
				text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : text);
				if (!val.AddItem(item))
				{
					ItemDrop.DropItem(item, item.m_stack, ((Component)this).transform.position + Vector3.up, Quaternion.identity);
				}
			}
			SaveLoot(val);
			ZDO zdo = Zdo;
			zdo.Set("hamud_held", text);
			zdo.Set("hamud_victim", victim);
			zdo.Set("hamud_flee_until", (float)(Now + (double)Plugin.FleeSeconds.Value));
			zdo.Set("hamud_laughs", zdo.GetInt("hamud_laughs", 0) + 1);
			Debug(string.Format("loot now {0} stacks [{1}], fleeing for {2}s", LootCount, string.Join(", ", val.GetAllItems().Select(delegate(ItemData i)
			{
				GameObject dropPrefab = i.m_dropPrefab;
				return ((dropPrefab != null) ? ((Object)dropPrefab).name : null) + " x" + i.m_stack;
			})), Plugin.FleeSeconds.Value));
		}

		private void SaveLoot(Inventory loot)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			loot.Save(val);
			Zdo.Set("hamud_loot", val.GetBase64());
			Zdo.Set("hamud_lootcount", loot.GetAllItems().Count);
		}

		private void Update()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0072: 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_00c5: 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)
			if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.IsOwner() || (Object)(object)m_ai == (Object)null || m_character.IsDead())
			{
				return;
			}
			Character val = null;
			bool flag = IsFleeing;
			if (flag)
			{
				ZDOID zDOID = Zdo.GetZDOID("hamud_victim");
				GameObject val2 = (((ZDOID)(ref zDOID)).IsNone() ? null : ZNetScene.instance.FindInstance(zDOID));
				val = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Character>() : null);
				if ((Object)(object)val == (Object)null || val.IsDead())
				{
					val = (Character)(object)Player.GetClosestPlayer(((Component)this).transform.position, 45f);
				}
				if ((Object)(object)val == (Object)null || Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > 45f)
				{
					Zdo.Set("hamud_flee_until", 0f);
					flag = false;
					val = null;
				}
			}
			else if (LootCount >= Plugin.MaxLoot.Value)
			{
				val = (Character)(object)Player.GetClosestPlayer(((Component)this).transform.position, 16f);
				flag = (Object)(object)val != (Object)null;
			}
			if (flag)
			{
				m_ai.m_fleeIfLowHealth = 10f;
				m_ai.m_fleeTimeSinceHurt = 1E+09f;
				((BaseAI)m_ai).m_timeSinceHurt = 0f;
				m_ai.m_targetCreature = val;
				((BaseAI)m_ai).SetAlerted(true);
				m_aiFleeing = true;
			}
			else if (m_aiFleeing)
			{
				m_ai.m_fleeIfLowHealth = 0f;
				m_ai.m_fleeTimeSinceHurt = 20f;
				m_aiFleeing = false;
				Zdo.Set("hamud_laughs", Zdo.GetInt("hamud_laughs", 0) + 1);
			}
			if (!flag)
			{
				NoticeMarks();
				TrySnatch();
			}
			if (LootCount > 0 && !flag && Time.time > m_nextIdleLaugh)
			{
				m_nextIdleLaugh = Time.time + Random.Range(10f, 20f);
				if (Random.value < 0.35f)
				{
					Zdo.Set("hamud_laughs", Zdo.GetInt("hamud_laughs", 0) + 1);
				}
			}
		}

		internal static void Debug(string msg)
		{
			if (s_debug)
			{
				Plugin.Log.LogInfo((object)("[HamudThief] " + msg));
			}
		}
	}
	public class HamudVisual : MonoBehaviour
	{
		public const string ModelName = "HamudModel";

		internal static readonly HashSet<string> LoopingClips = new HashSet<string> { "idle", "sneak", "run", "flee", "laugh" };

		private const float RunThreshold = 2.6f;

		private const float LaughShowSeconds = 1.6f;

		private Character m_character;

		private ZNetView m_nview;

		private Transform m_model;

		private Transform m_sack;

		private Transform m_hand;

		private Animation m_anim;

		private Animator m_baseAnimator;

		private Vector3 m_lastPos;

		private float m_speed;

		private bool m_wasAttacking;

		private float m_nextHideCheck;

		private int m_seenLaughs = -1;

		private int m_seenSnatches = -1;

		private float m_snatchUntil;

		private const float SnatchSeconds = 0.4f;

		private float m_laughUntil;

		private string m_heldName = "";

		private GameObject m_held;

		private float m_sackScale = 1f;

		private static readonly int s_attackTag = Animator.StringToHash("attack");

		private void Awake()
		{
			//IL_00b6: 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)
			m_character = ((Component)this).GetComponent<Character>();
			m_nview = ((Component)this).GetComponent<ZNetView>();
			m_model = ((Component)this).transform.Find("HamudModel");
			m_anim = ((Component)m_model).GetComponent<Animation>();
			m_sack = FindBone("Sack");
			m_hand = FindBone("Hand.R");
			m_baseAnimator = ((IEnumerable<Animator>)((Component)this).GetComponentsInChildren<Animator>(true)).FirstOrDefault((Func<Animator, bool>)((Animator a) => !((Component)a).transform.IsChildOf(m_model)));
			Animator[] componentsInChildren = ((Component)this).GetComponentsInChildren<Animator>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].cullingMode = (AnimatorCullingMode)0;
			}
			HideVanillaRenderers(((Component)this).gameObject, m_model);
			m_lastPos = ((Component)this).transform.position;
			m_anim.Play("idle");
		}

		private Transform FindBone(string name)
		{
			return ((IEnumerable<Transform>)((Component)m_model).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == name));
		}

		internal static void HideVanillaRenderers(GameObject root, Transform keep)
		{
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)keep == (Object)null || !((Component)val).transform.IsChildOf(keep))
				{
					val.forceRenderingOff = true;
				}
			}
			Light[] componentsInChildren2 = root.GetComponentsInChildren<Light>(true);
			foreach (Light val2 in componentsInChildren2)
			{
				if ((Object)(object)keep == (Object)null || !((Component)val2).transform.IsChildOf(keep))
				{
					((Behaviour)val2).enabled = false;
				}
			}
		}

		private bool BaseAttacking(out float length)
		{
			//IL_0038: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			length = 1f;
			if ((Object)(object)m_baseAnimator != (Object)null)
			{
				AnimatorStateInfo val = (m_baseAnimator.IsInTransition(0) ? m_baseAnimator.GetNextAnimatorStateInfo(0) : m_baseAnimator.GetCurrentAnimatorStateInfo(0));
				if (((AnimatorStateInfo)(ref val)).tagHash == s_attackTag)
				{
					length = Mathf.Max(0.3f, ((AnimatorStateInfo)(ref val)).length);
					return true;
				}
			}
			if ((Object)(object)m_character != (Object)null)
			{
				return m_character.InAttack();
			}
			return false;
		}

		private void Update()
		{
			//IL_0052: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			float deltaTime = Time.deltaTime;
			if (deltaTime <= 0f || (Object)(object)m_character == (Object)null)
			{
				return;
			}
			if (Time.time >= m_nextHideCheck)
			{
				HideVanillaRenderers(((Component)this).gameObject, m_model);
				m_nextHideCheck = Time.time + 0.5f;
			}
			Vector3 val = ((Component)this).transform.position - m_lastPos;
			val.y = 0f;
			m_lastPos = ((Component)this).transform.position;
			m_speed = Mathf.Lerp(m_speed, ((Vector3)(ref val)).magnitude / deltaTime, 1f - Mathf.Exp((0f - deltaTime) * 8f));
			ZDO val2 = (((Object)(object)m_nview != (Object)null && m_nview.IsValid()) ? m_nview.GetZDO() : null);
			int num = ((val2 != null) ? val2.GetInt("hamud_lootcount", 0) : 0);
			bool flag = val2 != null && HamudThief.Now < (double)val2.GetFloat("hamud_flee_until", 0f);
			int num2 = ((val2 != null) ? val2.GetInt("hamud_laughs", 0) : 0);
			if (m_seenLaughs < 0)
			{
				m_seenLaughs = num2;
			}
			if (num2 != m_seenLaughs)
			{
				m_seenLaughs = num2;
				m_laughUntil = Time.time + 1.6f;
				HamudSounds.Play((((num2 * -1640531535 >>> 16) & 1) == 0) ? Plugin.LaughSfx : Plugin.VoiceSfx, ((Component)this).transform.position);
			}
			int num3 = ((val2 != null) ? val2.GetInt("hamud_snatches", 0) : 0);
			if (m_seenSnatches < 0)
			{
				m_seenSnatches = num3;
			}
			if (num3 != m_seenSnatches)
			{
				m_seenSnatches = num3;
				m_snatchUntil = Time.time + 0.4f;
				AnimationState obj = m_anim["steal"];
				obj.speed = obj.length / 0.4f;
				m_anim.CrossFade("steal", 0.05f);
				obj.time = 0f;
			}
			UpdateHeld(((val2 != null) ? val2.GetString("hamud_held", "") : null) ?? "");
			m_sackScale = Mathf.MoveTowards(m_sackScale, 1f + 0.1f * (float)Mathf.Min(num, 6), deltaTime * 0.8f);
			if (BaseAttacking(out var length))
			{
				if (!m_wasAttacking)
				{
					AnimationState obj2 = m_anim["steal"];
					obj2.speed = obj2.length / length;
					m_anim.CrossFade("steal", 0.08f);
					obj2.time = 0f;
					Player localPlayer = Player.m_localPlayer;
					HamudThief.Debug($"swing ({length:0.00}s) dist to player {(((Object)(object)localPlayer != (Object)null) ? Vector3.Distance(((Component)localPlayer).transform.position, ((Component)this).transform.position) : (-1f)):0.0}");
				}
				m_wasAttacking = true;
				if ((Object)(object)m_held != (Object)null)
				{
					m_held.SetActive(false);
				}
				return;
			}
			m_wasAttacking = false;
			if (Time.time < m_snatchUntil)
			{
				if ((Object)(object)m_held != (Object)null)
				{
					m_held.SetActive(false);
				}
				return;
			}
			float speed = 1f;
			float num4 = Mathf.Max(0.01f, m_model.localScale.y);
			string text;
			if (m_speed < 0.25f)
			{
				text = ((Time.time < m_laughUntil) ? "laugh" : "idle");
			}
			else if (m_speed < 2.6f)
			{
				text = "sneak";
				speed = Mathf.Clamp(m_speed / (Plugin.WalkStride.Value * num4), 0.5f, 2f);
			}
			else
			{
				text = ((flag && m_heldName.Length > 0) ? "flee" : "run");
				speed = Mathf.Clamp(m_speed / (Plugin.RunStride.Value * num4), 0.6f, 2.2f);
			}
			if ((Object)(object)m_held != (Object)null)
			{
				m_held.SetActive(text == "flee");
			}
			m_anim[text].speed = speed;
			if (!m_anim.IsPlaying(text))
			{
				m_anim.CrossFade(text, 0.15f);
			}
		}

		private void LateUpdate()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)m_sack != (Object)null && m_sackScale != 1f)
			{
				Transform sack = m_sack;
				sack.localScale *= m_sackScale;
			}
		}

		private void UpdateHeld(string name)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			if (name == m_heldName)
			{
				return;
			}
			m_heldName = name;
			if ((Object)(object)m_held != (Object)null)
			{
				Object.Destroy((Object)(object)m_held);
			}
			m_held = null;
			if (name.Length == 0 || (Object)(object)m_hand == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
			if (!((Object)(object)itemPrefab == (Object)null))
			{
				m_held = MakeProp(itemPrefab, m_hand);
				if ((Object)(object)m_held != (Object)null)
				{
					m_held.transform.localPosition = new Vector3(0f, 0.06f, 0f);
					m_held.SetActive(false);
				}
			}
		}

		internal static GameObject MakeProp(GameObject itemPrefab, Transform parent)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			Transform val = itemPrefab.transform.Find("attach") ?? itemPrefab.transform;
			ZNetView.m_forceDisableInit = true;
			GameObject val2;
			try
			{
				val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false);
			}
			finally
			{
				ZNetView.m_forceDisableInit = false;
			}
			((Object)val2).name = "HamudHeld_" + ((Object)itemPrefab).name;
			Collider[] componentsInChildren = val2.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			Rigidbody[] componentsInChildren2 = val2.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren2)
			{
				obj.isKinematic = true;
				obj.detectCollisions = false;
			}
			MonoBehaviour[] componentsInChildren3 = val2.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour obj2 in componentsInChildren3)
			{
				((Behaviour)obj2).enabled = false;
				Object.Destroy((Object)(object)obj2);
			}
			componentsInChildren2 = val2.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren2[i]);
			}
			val2.transform.localRotation = Quaternion.identity;
			Vector3 lossyScale = parent.lossyScale;
			Vector3 val3 = val.localScale * 0.9f;
			val2.transform.localScale = new Vector3(val3.x / lossyScale.x, val3.y / lossyScale.y, val3.z / lossyScale.z);
			return val2;
		}
	}
	public class HamudCorpse : MonoBehaviour
	{
		internal const float BurstDelay = 1.2f;

		internal static string s_pendingLoot;

		internal static int s_pendingLevel = 1;

		private const string ZBurst = "hamud_burst";

		private const string ZLevel = "hamud_level";

		private ZNetView m_nview;

		private Transform m_model;

		private Transform m_sack;

		private float m_start;

		private bool m_burst;

		private void Awake()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			if (s_pendingLoot != null && (Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner())
			{
				m_nview.GetZDO().Set("hamud_loot", s_pendingLoot);
				m_nview.GetZDO().Set("hamud_level", s_pendingLevel);
			}
		}

		private void Start()
		{
			m_model = ((Component)this).transform.Find("HamudModel");
			HamudVisual.HideVanillaRenderers(((Component)this).gameObject, m_model);
			m_sack = ((IEnumerable<Transform>)((Component)m_model).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "Sack"));
			Animation component = ((Component)m_model).GetComponent<Animation>();
			component["death"].wrapMode = (WrapMode)8;
			component.Play("death");
			m_start = Time.time;
		}

		private void Update()
		{
			if (!m_burst && !(Time.time - m_start < 1.2f))
			{
				m_burst = true;
				Burst();
			}
		}

		private Vector3 SackPoint()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)m_sack != (Object)null) ? m_sack.position : (((Component)this).transform.position + ((Component)this).transform.rotation * new Vector3(0f, 0.2f, -0.7f)));
			float num = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val, ref num, 1000) && val.y < num + 0.15f)
			{
				val.y = num + 0.15f;
			}
			return val;
		}

		private void Burst()
		{
			//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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_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)
			//IL_006d: 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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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)
			Vector3 val = SackPoint();
			HamudSounds.Play(Plugin.PopSfx, val);
			ZNetView.m_forceDisableInit = true;
			try
			{
				if ((Object)(object)Plugin.PuffVfx != (Object)null)
				{
					Object.Instantiate<GameObject>(Plugin.PuffVfx, val, Quaternion.identity);
				}
				if ((Object)(object)Plugin.CoinSfx != (Object)null)
				{
					Object.Instantiate<GameObject>(Plugin.CoinSfx, val, Quaternion.identity);
				}
			}
			finally
			{
				ZNetView.m_forceDisableInit = false;
			}
			GameObject val2 = new GameObject("HamudFlash");
			val2.transform.position = val + Vector3.up * 0.4f;
			val2.AddComponent<HamudFlash>();
			if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid() && m_nview.IsOwner())
			{
				ZDO zDO = m_nview.GetZDO();
				if (!zDO.GetBool("hamud_burst", false))
				{
					zDO.Set("hamud_burst", true);
					DropLoot(val, zDO);
				}
			}
		}

		private static void Fling(ItemDrop drop, float speed)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody val = (((Object)(object)drop != (Object)null) ? ((Component)drop).GetComponent<Rigidbody>() : null);
			if (!((Object)(object)val == (Object)null))
			{
				Vector2 insideUnitCircle = Random.insideUnitCircle;
				Vector2 normalized = ((Vector2)(ref insideUnitCircle)).normalized;
				val.linearVelocity = new Vector3(normalized.x * speed, Random.Range(3.5f, 6f), normalized.y * speed);
				val.angularVelocity = Random.insideUnitSphere * 8f;
			}
		}

		private void DropLoot(Vector3 p, ZDO zdo)
		{
			//IL_004e: 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_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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			Inventory obj = HamudThief.ParseLoot(zdo.GetString("hamud_loot", ""));
			int num = 0;
			foreach (ItemData allItem in obj.GetAllItems())
			{
				if (!((Object)(object)allItem.m_dropPrefab == (Object)null))
				{
					allItem.m_equipped = false;
					Fling(ItemDrop.DropItem(allItem, allItem.m_stack, p + Vector3.up * 0.3f, Random.rotation), Random.Range(1.2f, 2.5f));
					num++;
				}
			}
			int num2 = Mathf.Max(1, zdo.GetInt("hamud_level", 1));
			int num3 = Random.Range(Plugin.CoinsMin.Value, Plugin.CoinsMax.Value + 1) * num2;
			ObjectDB instance = ObjectDB.instance;
			GameObject val = ((instance != null) ? instance.GetItemPrefab("Coins") : null);
			int num4 = 0;
			if ((Object)(object)val != (Object)null && num3 > 0)
			{
				ItemData val2 = val.GetComponent<ItemDrop>().m_itemData.Clone();
				val2.m_dropPrefab = val;
				int num5 = num3;
				while (num5 > 0)
				{
					int num6 = Mathf.Min(num5, Random.Range(2, 6));
					num5 -= num6;
					Fling(ItemDrop.DropItem(val2, num6, p + Vector3.up * 0.3f, Random.rotation), Random.Range(1.5f, 3.2f));
					num4++;
				}
			}
			HamudThief.Debug($"BURST at {p}: {num} stolen stacks, {num3} coins in {num4} piles (level {num2})");
		}
	}
	public class HamudFlash : MonoBehaviour
	{
		private Light m_light;

		private float m_t;

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			m_light = ((Component)this).gameObject.AddComponent<Light>();
			m_light.type = (LightType)2;
			m_light.color = new Color(1f, 0.75f, 0.3f);
			m_light.range = 6f;
			m_light.intensity = 3f;
		}

		private void Update()
		{
			m_t += Time.deltaTime;
			m_light.intensity = Mathf.Lerp(3f, 0f, m_t / 0.35f);
			if (m_t > 0.4f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	public static class HamudStealPatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead() || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsOwner())
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			HamudThief hamudThief = (((Object)(object)attacker != (Object)null) ? ((Component)attacker).GetComponent<HamudThief>() : null);
			if ((Object)(object)hamudThief == (Object)null)
			{
				return;
			}
			HamudThief.Debug($"grab hit {val.GetPlayerName()}: canSteal={hamudThief.CanSteal} loot={hamudThief.LootCount}");
			if (hamudThief.CanSteal)
			{
				if (hit.m_blockable && ((Character)val).IsBlocking())
				{
					HamudThief.Debug("grab blocked");
				}
				else if (hit.m_dodgeable && ((Character)val).IsDodgeInvincible())
				{
					HamudThief.Debug("grab dodged");
				}
				else
				{
					HamudThief.StealFrom(val, hamudThief);
				}
			}
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
	{
		typeof(Character),
		typeof(Character)
	})]
	public static class HamudHostilityPatch
	{
		private static void Postfix(Character a, Character b, ref bool __result)
		{
			if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
			{
				return;
			}
			bool flag = (Object)(object)((Component)a).GetComponent<HamudThief>() != (Object)null;
			bool flag2 = (Object)(object)((Component)b).GetComponent<HamudThief>() != (Object)null;
			if (flag || flag2)
			{
				if (flag && flag2)
				{
					__result = false;
				}
				else
				{
					__result = (flag ? ((Component)a).GetComponent<HamudThief>().WantsTarget(b) : a.IsPlayer());
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	public static class HamudStealableFlagPatch
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				HamudThief.UpdateStealableFlag(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "OnDeath")]
	public static class HamudDeathPatch
	{
		private static void Prefix(Character __instance)
		{
			HamudThief component = ((Component)__instance).GetComponent<HamudThief>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsOwner())
			{
				HamudCorpse.s_pendingLoot = component.LootString;
				HamudCorpse.s_pendingLevel = __instance.GetLevel();
			}
		}

		private static void Finalizer()
		{
			HamudCorpse.s_pendingLoot = null;
			HamudCorpse.s_pendingLevel = 1;
		}
	}
	[BepInPlugin("wleee.hamudhabob", "Hamud Habob", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "wleee.hamudhabob";

		public const string Version = "1.0.0";

		public const string PrefabName = "HamudHabob";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<string> BaseCreature;

		internal static ConfigEntry<float> ModelScale;

		internal static ConfigEntry<float> ModelYaw;

		internal static ConfigEntry<float> Health;

		internal static ConfigEntry<float> StealDamage;

		internal static ConfigEntry<float> RunSpeed;

		internal static ConfigEntry<float> WalkSpeed;

		internal static ConfigEntry<float> FleeSeconds;

		internal static ConfigEntry<int> MaxLoot;

		internal static ConfigEntry<bool> StealFromHotbar;

		internal static ConfigEntry<bool> StealEquipped;

		internal static ConfigEntry<int> CoinsMin;

		internal static ConfigEntry<int> CoinsMax;

		internal static ConfigEntry<string> SpawnBiomes;

		internal static ConfigEntry<bool> SpawnEnabled;

		internal static ConfigEntry<float> SpawnChance;

		internal static ConfigEntry<float> SpawnInterval;

		internal static ConfigEntry<int> MaxSpawned;

		internal static ConfigEntry<int> MaxLevel;

		internal static ConfigEntry<bool> SpawnAtNight;

		internal static ConfigEntry<float> SnatchRange;

		internal static ConfigEntry<float> NoticeRange;

		internal static ConfigEntry<bool> VoiceEnabled;

		internal static ConfigEntry<float> VoiceVolume;

		internal static ConfigEntry<float> IdleVoiceInterval;

		internal static ConfigEntry<float> IdleVoiceChance;

		internal static ConfigEntry<float> CorpseSeconds;

		internal static ConfigEntry<float> WalkStride;

		internal static ConfigEntry<float> RunStride;

		internal static GlbModel Model;

		internal static Material ModelMaterial;

		internal static GameObject VoiceSfx;

		internal static GameObject LaughSfx;

		internal static GameObject PopSfx;

		internal static GameObject PuffVfx;

		internal static GameObject CoinSfx;

		private void Awake()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			BindConfig();
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			GameObject val = new GameObject("Hamud_Templates");
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			Model = GlbLoader.Load(Path.Combine(directoryName, "hamud.glb"), val.transform);
			Animation val2 = Model.Root.AddComponent<Animation>();
			val2.playAutomatically = false;
			val2.cullingType = (AnimationCullingType)0;
			foreach (KeyValuePair<string, AnimationClip> clip in Model.Clips)
			{
				clip.Value.wrapMode = (WrapMode)(HamudVisual.LoopingClips.Contains(clip.Key) ? 2 : 8);
				val2.AddClip(clip.Value, clip.Key);
			}
			Log.LogInfo((object)($"Loaded model: {((Bounds)(ref Model.MeshBounds)).size} bind-pose size, {Model.Renderer.sharedMesh.vertexCount} verts, " + string.Format("emission={0}, anims [{1}]", (Object)(object)Model.Emission != (Object)null, string.Join(", ", Model.Clips.Keys))));
			HamudSounds.Load(directoryName);
			AddLocalization();
			Harmony val3 = new Harmony("wleee.hamudhabob");
			val3.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)("Harmony patches: " + string.Join(", ", from m in val3.GetPatchedMethods()
				select m.DeclaringType?.Name + "." + m.Name)));
			CreatureManager.OnVanillaCreaturesAvailable += CreateHamud;
		}

		private void BindConfig()
		{
			BaseCreature = ((BaseUnityPlugin)this).Config.Bind<string>("Model", "BaseCreature", "Greyling", "Vanilla creature whose AI, attack and collider Hamud reuses (its model is hidden).");
			ModelScale = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "Scale", 1f, "Model scale (1 = about 1.35 m with the cap).");
			ModelYaw = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "ModelYaw", 0f, "Extra rotation of the model around the vertical axis, degrees.");
			WalkStride = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "WalkStride", 1.2f, "Speed (m/s) at which the sneak animation plays at 1x.");
			RunStride = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "RunStride", 4f, "Speed (m/s) at which the run animation plays at 1x.");
			CorpseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "CorpseSeconds", 5f, "How long the fallen Hamud stays before disappearing.");
			Health = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "Health", 25f, "Base health (a Surtling has 20): easy to kill, so you can get your stuff back.");
			StealDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "StealDamage", 4f, "Damage of the grab. The point of the grab is the theft, not the damage.");
			RunSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "RunSpeed", 6.5f, "Running speed, m/s (a sprinting player is about 7).");
			WalkSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Stats", "WalkSpeed", 1.6f, "Sneaking speed, m/s.");
			FleeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Theft", "FleeSeconds", 18f, "How long Hamud runs away after a successful theft.");
			MaxLoot = ((BaseUnityPlugin)this).Config.Bind<int>("Theft", "MaxLoot", 5, "Stolen stacks the sack holds. A full Hamud only runs from players.");
			StealFromHotbar = ((BaseUnityPlugin)this).Config.Bind<bool>("Theft", "StealFromHotbar", true, "Allow stealing from the hotbar (top inventory row).");
			StealEquipped = ((BaseUnityPlugin)this).Config.Bind<bool>("Theft", "StealEquipped", true, "Allow stealing equipped items (he pulls them off you).");
			CoinsMin = ((BaseUnityPlugin)this).Config.Bind<int>("Drops", "CoinsMin", 8, "Minimum coins that burst out of the sack (per star level).");
			CoinsMax = ((BaseUnityPlugin)this).Config.Bind<int>("Drops", "CoinsMax", 25, "Maximum coins that burst out of the sack (per star level).");
			SpawnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "Enabled", true, "Spawn Hamud naturally.");
			SpawnBiomes = ((BaseUnityPlugin)this).Config.Bind<string>("Spawn", "Biomes", "Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth", "Comma separated biomes he spawns in: Meadows, BlackForest, Swamp, Mountain, Plains, Mistlands, AshLands, DeepNorth.");
			SpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnChance", 15f, "Chance in percent per spawn interval.");
			SpawnInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "SpawnInterval", 400f, "Seconds between spawn attempts per spawner zone.");
			MaxSpawned = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "MaxSpawned", 1, "Max Hamuds alive near a player from this spawner.");
			MaxLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "MaxLevel", 3, "Max level (1 = no stars, 3 = two stars).");
			SpawnAtNight = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawn", "SpawnAtNight", true, "Also spawn at night.");
			SnatchRange = ((BaseUnityPlugin)this).Config.Bind<float>("Theft", "SnatchRange", 1.7f, "How close (m) Hamud has to get to snatch an item on the run.");
			NoticeRange = ((BaseUnityPlugin)this).Config.Bind<float>("Theft", "NoticeRange", 50f, "Hamud spots players with something to steal within this range (m), if nothing blocks the view.");
			VoiceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "VoiceEnabled", true, "Hamud shouts his name and giggles. The sack pop always plays.");
			VoiceVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "Volume", 1f, "Volume of Hamud's voice and laugh (0-1).");
			IdleVoiceInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "IdleVoiceInterval", 8f, "Seconds between random idle mutters.");
			IdleVoiceChance = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "IdleVoiceChance", 0.3f, "Chance (0-1) of an idle mutter each interval.");
		}

		private static void AddLocalization()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "enemy_hamudhabob", "Hamud Habob" },
				{ "hamud_stole", "Hamud Habob stole: {0} x{1}!" },
				{ "hamud_grab", "Hamud's grabby hand" }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "enemy_hamudhabob", "Хамуд Хабоб" },
				{ "hamud_stole", "Хамуд Хабоб украл: {0} x{1}!" },
				{ "hamud_grab", "Загребущая рука Хамуда" }
			});
		}

		private void CreateHamud()
		{
			//IL_0011: 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_0022: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_005f: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_009d: 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_00b4: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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_00f1: Expected O, but got Unknown
			CreatureManager.OnVanillaCreaturesAvailable -= CreateHamud;
			try
			{
				CreatureConfig val = new CreatureConfig
				{
					Name = "$enemy_hamudhabob"
				};
				if (SpawnEnabled.Value)
				{
					Biome val2 = ParseBiomes(SpawnBiomes.Value);
					if ((int)val2 != 0)
					{
						val.AddSpawnConfig(new SpawnConfig
						{
							Name = "HamudHabob_spawn",
							Biome = val2,
							SpawnChance = SpawnChance.Value,
							SpawnInterval = SpawnInterval.Value,
							MaxSpawned = MaxSpawned.Value,
							MinGroupSize = 1,
							MaxGroupSize = 1,
							MinLevel = 1,
							MaxLevel = MaxLevel.Value,
							SpawnAtDay = true,
							SpawnAtNight = SpawnAtNight.Value,
							GroundOffset = 0.5f,
							MinAltitude = 1f,
							MaxAltitude = 1000f
						});
					}
				}
				CustomCreature val3 = new CustomCreature("HamudHabob", BaseCreature.Value, val);
				GameObject prefab = val3.Prefab;
				SetupCharacter(prefab);
				SetupModel(prefab);
				SetupSounds(prefab);
				SetupWeapons(prefab);
				SetupDeath(prefab);
				PuffVfx = new string[2] { "vfx_coin_pile_destroyed", "vfx_coin_stack_destroyed" }.Select((string n) => PrefabManager.Instance.GetPrefab(n)).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null));
				CoinSfx = PrefabManager.Instance.GetPrefab("sfx_coins_pile_destroyed");
				prefab.AddComponent<HamudThief>();
				prefab.AddComponent<HamudVisual>();
				CreatureManager.Instance.AddCreature(val3);
				Log.LogInfo((object)("Registered HamudHabob (base " + BaseCreature.Value + "), puff vfx: " + (Object.op_Implicit((Object)(object)PuffVfx) ? ((Object)PuffVfx).name : "none")));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to create Hamud Habob: " + ex));
			}
		}

		private static Biome ParseBiomes(string list)
		{
			//IL_0001: 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_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_0070: 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)
			Biome val = (Biome)0;
			foreach (string item in from s in list.Split(',')
				select s.Trim() into s
				where s.Length > 0
				select s)
			{
				if (Enum.TryParse<Biome>(item, ignoreCase: true, out Biome result))
				{
					val |= result;
				}
				else
				{
					Log.LogWarning((object)("Unknown biome in config: " + item));
				}
			}
			return val;
		}

		private static void SetupCharacter(GameObject prefab)
		{
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			Character component = prefab.GetComponent<Character>();
			component.m_name = "$enemy_hamudhabob";
			component.m_health = Health.Value;
			component.m_defeatSetGlobalKey = "";
			component.m_runSpeed = RunSpeed.Value;
			component.m_walkSpeed = WalkSpeed.Value;
			component.m_speed = WalkSpeed.Value;
			Log.LogInfo((object)$"Base turn speed {component.m_turnSpeed}/{component.m_runTurnSpeed}");
			component.m_turnSpeed = 720f;
			component.m_runTurnSpeed = 720f;
			CharacterDrop component2 = prefab.GetComponent<CharacterDrop>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_drops = new List<Drop>();
			}
			MonsterAI component3 = prefab.GetComponent<MonsterAI>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.m_fleeIfLowHealth = 0f;
				component3.m_fleeIfHurtWhenTargetCantBeReached = true;
				component3.m_circleTargetInterval = 0f;
				component3.m_enableHuntPlayer = false;
				Log.LogInfo((object)$"Base senses: view {((BaseAI)component3).m_viewRange}m/{((BaseAI)component3).m_viewAngle}deg, hear {((BaseAI)component3).m_hearRange}m, alert {component3.m_alertRange}m");
				((BaseAI)component3).m_viewRange = Mathf.Max(((BaseAI)component3).m_viewRange, 30f);
				((BaseAI)component3).m_viewAngle = Mathf.Max(((BaseAI)component3).m_viewAngle, 120f);
				((BaseAI)component3).m_hearRange = Mathf.Max(((BaseAI)component3).m_hearRange, 25f);
				component3.m_alertRange = Mathf.Max(component3.m_alertRange, 15f);
				((BaseAI)component3).m_smoothMovement = true;
				((BaseAI)component3).m_moveMinAngle = 25f;
			}
			ManualLogSource log = Log;
			string text = $"Character: hp={component.m_health} run={component.m_runSpeed} walk={component.m_walkSpeed} ";
			object arg = component.m_faction;
			CapsuleCollider component4 = prefab.GetComponent<CapsuleCollider>();
			log.LogInfo((object)(text + $"faction={arg} collider={((component4 != null) ? new float?(component4.height) : ((float?)null))}"));
		}

		private static Material CreateMaterial(GameObject basePrefab)
		{
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			SkinnedMeshRenderer val = ((IEnumerable<SkinnedMeshRenderer>)basePrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true)).FirstOrDefault((Func<SkinnedMeshRenderer, bool>)((SkinnedMeshRenderer r) => (Object)(object)((Renderer)r).sharedMaterial != (Object)null));
			Material val2;
			if ((Object)(object)val != (Object)null)
			{
				val2 = new Material(((Renderer)val).sharedMaterial);
				Log.LogInfo((object)("Base material shader '" + ((Object)val2.shader).name + "', textures [" + string.Join(", ", val2.GetTexturePropertyNames()) + "], keywords [" + string.Join(", ", val2.shaderKeywords) + "]"));
				string[] texturePropertyNames = val2.GetTexturePropertyNames();
				foreach (string text in texturePropertyNames)
				{
					if (text != "_MainTex")
					{
						val2.SetTexture(text, (Texture)null);
					}
				}
				texturePropertyNames = val2.shaderKeywords;
				foreach (string text2 in texturePropertyNames)
				{
					val2.DisableKeyword(text2);
				}
				if (val2.HasProperty("_Glossiness"))
				{
					val2.SetFloat("_Glossiness", 0.1f);
				}
				if (val2.HasProperty("_Metallic"))
				{
					val2.SetFloat("_Metallic", 0f);
				}
				if (val2.HasProperty("_NoiseGlowEnabled"))
				{
					val2.SetFloat("_NoiseGlowEnabled", 0f);
				}
			}
			else
			{
				val2 = new Material(Shader.Find("Standard"));
			}
			((Object)val2).name = "Hamud_mat";
			val2.mainTexture = (Texture)(object)Model.Texture;
			val2.color = Color.white;
			if ((Object)(object)Model.Emission != (Object)null && val2.HasProperty("_EmissionMap"))
			{
				val2.SetTexture("_EmissionMap", (Texture)(object)Model.Emission);
				val2.SetColor("_EmissionColor", Model.EmissionColor);
				val2.EnableKeyword("_EMISSION");
				val2.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)1;
			}
			else if (val2.HasProperty("_EmissionColor"))
			{
				val2.SetColor("_EmissionColor", Color.black);
			}
			Log.LogInfo((object)("Hamud material: emission=" + (val2.HasProperty("_EmissionColor") ? ((object)val2.GetColor("_EmissionColor")/*cast due to .constrained prefix*/).ToString() : "n/a") + " keywords=[" + string.Join(", ", val2.shaderKeywords) + "]"));
			return val2;
		}

		internal static GameObject AttachModel(GameObject parent)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0085: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			((Renderer)Model.Renderer).sharedMaterial = ModelMaterial;
			GameObject obj = Object.Instantiate<GameObject>(Model.Root, parent.transform, false);
			((Object)obj).name = "HamudModel";
			obj.transform.localPosition = Vector3.zero;
			obj.transform.localRotation = Quaternion.Euler(0f, ModelYaw.Value, 0f);
			Vector3 lossyScale = parent.transform.lossyScale;
			obj.transform.localScale = new Vector3(ModelScale.Value / lossyScale.x, ModelScale.Value / lossyScale.y, ModelScale.Value / lossyScale.z);
			return obj;
		}

		private static void SetupModel(GameObject prefab)
		{
			ModelMaterial = CreateMaterial(prefab);
			AttachModel(prefab);
			HamudVisual.HideVanillaRenderers(prefab, prefab.transform.Find("HamudModel"));
		}

		private static void SetupSounds(GameObject prefab)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			MonsterAI component = prefab.GetComponent<MonsterAI>();
			GameObject val = FindSfx(((BaseAI)component).m_alertedEffects) ?? FindSfx(((BaseAI)component).m_idleSound) ?? FindSfx(prefab.GetComponent<Character>().m_hitEffects);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"No sfx template on the base creature, Hamud will be silent");
				return;
			}
			PopSfx = HamudSounds.MakeSfx("sfx_hamud_pop", val, HamudSounds.Pop, "", throttle: false);
			Character component2 = prefab.GetComponent<Character>();
			StripSfx(component2.m_hitEffects);
			StripSfx(component2.m_critHitEffects);
			StripSfx(component2.m_deathEffects);
			((BaseAI)component).m_alertedEffects = new EffectList();
			((BaseAI)component).m_idleSound = new EffectList();
			if (!VoiceEnabled.Value || HamudSounds.Voices.Length + HamudSounds.Laughs.Length == 0)
			{
				Log.LogInfo((object)"Voice disabled: Hamud is silent apart from the sack pop");
				return;
			}
			VoiceSfx = HamudSounds.MakeSfx("sfx_hamud_voice", val, (HamudSounds.Voices.Length != 0) ? HamudSounds.Voices : HamudSounds.Laughs, "$enemy_hamudhabob");
			LaughSfx = HamudSounds.MakeSfx("sfx_hamud_laugh", val, HamudSounds.Laughs, "$enemy_hamudhabob");
			GameObject sfx = HamudSounds.MakeSfx("sfx_hamud_mutter", val, HamudSounds.Voices.Concat(HamudSounds.Laughs).ToArray(), "$enemy_hamudhabob");
			((BaseAI)component).m_alertedEffects = Effect(VoiceSfx);
			((BaseAI)component).m_idleSound = Effect(sfx);
			((BaseAI)component).m_idleSoundInterval = IdleVoiceInterval.Value;
			((BaseAI)component).m_idleSoundChance = IdleVoiceChance.Value;
			Log.LogInfo((object)("Sounds cloned from '" + ((Object)val).name + "'"));
			static EffectList Effect(GameObject prefab2)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Expected O, but got Unknown
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Expected O, but got Unknown
				EffectList val2 = new EffectList();
				val2.m_effectPrefabs = (EffectData[])(object)new EffectData[1]
				{
					new EffectData
					{
						m_prefab = prefab2,
						m_enabled = true
					}
				};
				return val2;
			}
		}

		internal static void StripSfx(EffectList list)
		{
			if (list?.m_effectPrefabs != null)
			{
				list.m_effectPrefabs = list.m_effectPrefabs.Where((EffectData e) => (Object)(object)e.m_prefab == (Object)null || (Object)(object)e.m_prefab.GetComponent<ZSFX>() == (Object)null).ToArray();
			}
		}

		private static GameObject FindSfx(EffectList list)
		{
			return list?.m_effectPrefabs?.Select((EffectData e) => e.m_prefab).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => (Object)(object)p != (Object)null && (Object)(object)p.GetComponent<ZSFX>() != (Object)null && (Object)(object)p.GetComponent<AudioSource>() != (Object)null));
		}

		private static void SetupWeapons(GameObject prefab)
		{
			Humanoid component = prefab.GetComponent<Humanoid>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			Dictionary<GameObject, GameObject> cache = new Dictionary<GameObject, GameObject>();
			component.m_defaultItems = ConvertAll(component.m_defaultItems);
			component.m_randomWeapon = ConvertAll(component.m_randomWeapon);
			if (component.m_randomSets != null)
			{
				ItemSet[] randomSets = component.m_randomSets;
				foreach (ItemSet val in randomSets)
				{
					val.m_items = ConvertAll(val.m_items);
				}
			}
			if (component.m_randomItems != null)
			{
				RandomItem[] randomItems = component.m_randomItems;
				foreach (RandomItem val2 in randomItems)
				{
					val2.m_prefab = Convert(val2.m_prefab);
				}
			}
			GameObject Convert(GameObject item)
			{
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: 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_01ef: Expected O, but got Unknown
				//IL_0214: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)item == (Object)null)
				{
					return null;
				}
				if (cache.TryGetValue(item, out var value))
				{
					return value;
				}
				ItemDrop component2 = item.GetComponent<ItemDrop>();
				if ((Object)(object)component2 == (Object)null || !component2.m_itemData.IsWeapon())
				{
					return cache[item] = item;
				}
				GameObject val4 = PrefabManager.Instance.CreateClonedPrefab("Hamud_" + ((Object)item).name, item);
				SharedData shared = val4.GetComponent<ItemDrop>().m_itemData.m_shared;
				shared.m_name = "$hamud_grab";
				Renderer[] componentsInChildren = val4.GetComponentsInChildren<Renderer>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren[j]);
				}
				MeshFilter[] componentsInChildren2 = val4.GetComponentsInChildren<MeshFilter>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren2[j]);
				}
				DamageTypes val5 = (shared.m_damages = new DamageTypes
				{
					m_blunt = StealDamage.Value
				});
				shared.m_attackStatusEffect = null;
				shared.m_attackForce = 5f;
				Attack attack = shared.m_attack;
				Log.LogInfo((object)$"Base grab: range {attack.m_attackRange}, angle {attack.m_attackAngle}, ray {attack.m_attackRayWidth}, height {attack.m_attackHeight}, type {attack.m_attackType}");
				attack.m_attackRange = Mathf.Max(attack.m_attackRange, 2.1f);
				attack.m_attackAngle = Mathf.Max(attack.m_attackAngle, 120f);
				attack.m_attackRayWidth = Mathf.Max(attack.m_attackRayWidth, 0.35f);
				StripSfx(shared.m_startEffect);
				StripSfx(shared.m_triggerEffect);
				StripSfx(shared.m_trailStartEffect);
				ItemManager.Instance.AddItem(new CustomItem(val4, false));
				Log.LogInfo((object)$"Attack '{((Object)item).name}' -> '{((Object)val4).name}': blunt {val5.m_blunt}, range {shared.m_aiAttackRange}, interval {shared.m_aiAttackInterval}");
				return cache[item] = val4;
			}
			GameObject[] ConvertAll(GameObject[] arr)
			{
				return arr?.Select(Convert).ToArray();
			}
		}

		private static void SetupDeath(GameObject prefab)
		{
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			EffectData[] array = prefab.GetComponent<Character>().m_deathEffects?.m_effectPrefabs;
			if (array == null)
			{
				return;
			}
			Log.LogInfo((object)("Base death effects: " + string.Join(", ", array.Select((EffectData e) => (!Object.op_Implicit((Object)(object)e.m_prefab)) ? "null" : ((Object)e.m_prefab).name))));
			bool flag = false;
			foreach (EffectData item in array.OrderByDescending((EffectData e) => (Object)(object)e.m_prefab != (Object)null && (Object)(object)e.m_prefab.GetComponent<Ragdoll>() != (Object)null))
			{
				if ((Object)(object)item.m_prefab == (Object)null || (Object)(object)item.m_prefab.GetComponent<ZSFX>() != (Object)null)
				{
					continue;
				}
				if (flag)
				{
					item.m_enabled = false;
					continue;
				}
				Ragdoll component = item.m_prefab.GetComponent<Ragdoll>();
				GameObject val = PrefabManager.Instance.CreateClonedPrefab("HamudHabob_corpse", item.m_prefab);
				ParticleSystem[] componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true);
				foreach (ParticleSystem obj in componentsInChildren)
				{
					EmissionModule emission = obj.emission;
					((EmissionModule)(ref emission)).enabled = false;
					MainModule main = obj.main;
					((MainModule)(ref main)).playOnAwake = false;
				}
				AttachModel(val);
				HamudVisual.HideVanillaRenderers(val, val.transform.Find("HamudModel"));
				val.AddComponent<HamudCorpse>();
				Ragdoll component2 = val.GetComponent<Ragdoll>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_dropItems = false;
					component2.m_ttl = Mathf.Max(component2.m_ttl, CorpseSeconds.Value);
				}
				else
				{
					TimedDestruction obj2 = val.GetComponent<TimedDestruction>() ?? val.AddComponent<TimedDestruction>();
					obj2.m_timeout = CorpseSeconds.Value;
					obj2.m_triggerOnAwake = true;
				}
				PrefabManager.Instance.AddPrefab(val);
				Log.LogInfo((object)$"Corpse cloned from '{((Object)item.m_prefab).name}' (ragdoll: {(Object)(object)component != (Object)null}, networked: {(Object)(object)val.GetComponent<ZNetView>() != (Object)null})");
				item.m_prefab = val;
				flag = true;
			}
		}
	}
	public static class WavLoader
	{
		public static AudioClip Load(string path)
		{
			byte[] array = File.ReadAllBytes(path);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = -1;
			int num5 = 0;
			int num6;
			for (int i = 12; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1))
			{
				string text = Encoding.ASCII.GetString(array, i, 4);
				num6 = BitConverter.ToInt32(array, i + 4);
				if (text == "fmt ")
				{
					num = BitConverter.ToInt16(array, i + 10);
					num2 = BitConverter.ToInt32(array, i + 12);
					num3 = BitConverter.ToInt16(array, i + 22);
				}
				else if (text == "data")
				{
					num4 = i + 8;
					num5 = Math.Min(num6, array.Length - num4);
					break;
				}
			}
			if (num3 != 16 || num4 < 0 || num < 1)
			{
				throw new InvalidDataException(path + ": expected 16-bit PCM wav");
			}
			int num7 = num5 / 2 / num;
			float[] array2 = new float[num7 * num];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f;
			}
			AudioClip obj = AudioClip.Create(Path.GetFileNameWithoutExtension(path), num7, num, num2, false);
			obj.SetData(array2, 0);
			return obj;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}