Decompiled source of PoseKit v0.1.1

Posekit.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using FistVR;
using JerryGloves;
using Microsoft.CodeAnalysis;
using Sodalite;
using Sodalite.Api;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace GT3PoseKit
{
	[Serializable]
	public class Xf
	{
		public float[] p = new float[3];

		public float[] r = new float[4] { 0f, 0f, 0f, 1f };

		public Vector3 Pos
		{
			get
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				if (p == null || p.Length < 3)
				{
					return Vector3.zero;
				}
				return new Vector3(p[0], p[1], p[2]);
			}
		}

		public Quaternion Rot
		{
			get
			{
				//IL_0013: 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_0046: 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_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: 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_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: 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)
				if (r == null || r.Length < 4)
				{
					return Quaternion.identity;
				}
				Quaternion val = default(Quaternion);
				((Quaternion)(ref val))..ctor(r[0], r[1], r[2], r[3]);
				float num = Mathf.Sqrt(val.x * val.x + val.y * val.y + val.z * val.z + val.w * val.w);
				if (!(num < 1E-06f))
				{
					return new Quaternion(val.x / num, val.y / num, val.z / num, val.w / num);
				}
				return Quaternion.identity;
			}
		}

		public static Xf From(Vector3 pos, Quaternion rot)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			Xf xf = new Xf();
			xf.p = new float[3] { pos.x, pos.y, pos.z };
			xf.r = new float[4] { rot.x, rot.y, rot.z, rot.w };
			return xf;
		}
	}
	[Serializable]
	public class PoseData
	{
		public string slot;

		public Xf[] joints;
	}
	[Serializable]
	public class MatchData
	{
		public string[] itemIds = new string[0];

		public string[] objectNames = new string[0];
	}
	[Serializable]
	public class PoseSet
	{
		public string format;

		public int version;

		public string name;

		public MatchData match;

		public bool hasTrigger;

		public bool useGrabPos;

		public Xf grabPos;

		public int jointCount;

		public PoseData[] poses;

		public bool noAutoCopy;

		public PartPoses[] parts;

		public MagazinePoses magazine;
	}
	[Serializable]
	public class PartPoses
	{
		public string name;

		public string path;

		public string type;

		public PoseData[] poses;
	}
	[Serializable]
	public class MagazinePoses
	{
		public string[] itemIds = new string[0];

		public string[] magazineTypes = new string[0];

		public PoseData[] poses;
	}
	[Serializable]
	public class RigJoint
	{
		public string name;

		public int parent;

		public Xf local;
	}
	[Serializable]
	public class RigHand
	{
		public string side;

		public string rootName;

		public RigJoint[] joints;
	}
	[Serializable]
	public class RigDump
	{
		public string format = "gt3rig";

		public int version = 1;

		public RigHand left;

		public RigHand right;
	}
	[Serializable]
	public class GloveHand
	{
		public string side;

		public int jointCount;

		public Xf[] bakeJoints;

		public float[] v;

		public float[] uv;

		public int[] t;

		public int[] bi;

		public float[] bw;

		public string weights;

		public string texture;

		public float[] color;

		public string meshName;
	}
	[Serializable]
	public class GloveDump
	{
		public string format = "gt3glove";

		public int version = 1;

		public GloveHand left;

		public GloveHand right;
	}
	[Serializable]
	public class GeoPrim
	{
		public string kind;

		public string name;

		public Xf xf;

		public float[] scale;

		public float[] center;

		public float[] size;

		public float radius;

		public float height;

		public int dir;

		public bool trigger;
	}
	[Serializable]
	public class GeoMesh
	{
		public string name;

		public float[] v;

		public int[] t;
	}
	[Serializable]
	public class Marker
	{
		public string name;

		public Xf xf;
	}
	[Serializable]
	public class PartInfo
	{
		public string name;

		public string path;

		public string type;

		public Xf xf;
	}
	[Serializable]
	public class GunGeo
	{
		public GeoPrim[] prims;

		public GeoMesh[] meshes;

		public Marker[] markers;

		public PartInfo[] parts;
	}
	[Serializable]
	public class ModelData
	{
		public string format = "gt3model";

		public int version = 1;

		public string itemId;

		public string name;

		public string category;

		public int readableMeshes;

		public int boxedMeshes;

		public string magazineType;

		public bool isMagazine;

		public string[] compatibleMags;

		public GunGeo geo;
	}
	[Serializable]
	public class ItemInfo
	{
		public string id;

		public string name;

		public string cat;

		public bool mod;
	}
	[Serializable]
	public class LocalSet
	{
		public string key;

		public string file;

		public string[] itemIds;

		public string modified;
	}
	[Serializable]
	public class LocalSetList
	{
		public string format = "gt3sets";

		public LocalSet[] sets;
	}
	[Serializable]
	public class ItemList
	{
		public string format = "gt3items";

		public ItemInfo[] items;
	}
	[Serializable]
	public class BridgeStatus
	{
		public string format = "gt3bridge";

		public string version;

		public int items;

		public bool gloves;

		public string poseFolder;
	}
	[Serializable]
	public class CaptureData
	{
		public string format = "gt3capture";

		public int version = 1;

		public string itemId;

		public string objectName;

		public string side;

		public bool onForegrip;

		public bool fromPhysics;

		public string partPath;

		public string partType;

		public Xf partXf;

		public string magazineType;

		public bool isMagazine;

		public Xf handRoot;

		public Xf[] joints;

		public RigHand rig;

		public GunGeo geo;
	}
	public static class GloveExport
	{
		public static GloveHand Build(HandsPoseSystem sys, bool left, int maxTexture, out string error)
		{
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Expected O, but got Unknown
			//IL_06cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_06df: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0639: Unknown result type (might be due to invalid IL or missing references)
			//IL_0643: Unknown result type (might be due to invalid IL or missing references)
			//IL_064d: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0531: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			if ((Object)(object)sys == (Object)null)
			{
				error = "Spawn the GlovesTan3 gloves first";
				return null;
			}
			List<KeyValuePair<GameObject[], Dictionary<Transform, int>>> list = new List<KeyValuePair<GameObject[], Dictionary<Transform, int>>>();
			GameObject[][] array = new GameObject[2][] { sys.Fingers, sys.realfingers };
			foreach (GameObject[] array2 in array)
			{
				if (array2 == null || array2.Length == 0)
				{
					continue;
				}
				Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
				for (int j = 0; j < array2.Length; j++)
				{
					if ((Object)(object)array2[j] != (Object)null)
					{
						dictionary[array2[j].transform] = j;
					}
				}
				list.Add(new KeyValuePair<GameObject[], Dictionary<Transform, int>>(array2, dictionary));
			}
			if (list.Count == 0)
			{
				error = "GlovesTan3 hand has no joints";
				return null;
			}
			List<GameObject> list2 = new List<GameObject>();
			if ((Object)(object)sys.HandPhys != (Object)null && sys.HandPhys.activeInHierarchy)
			{
				list2.Add(sys.HandPhys);
			}
			if ((Object)(object)sys.HandAnim != (Object)null)
			{
				list2.Add(sys.HandAnim);
			}
			if ((Object)(object)sys.HandPhys != (Object)null && !list2.Contains(sys.HandPhys))
			{
				list2.Add(sys.HandPhys);
			}
			list2.Add(((Component)sys).gameObject);
			SkinnedMeshRenderer[] array3 = null;
			foreach (GameObject item in list2)
			{
				SkinnedMeshRenderer[] componentsInChildren = item.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				if (componentsInChildren.Length != 0)
				{
					array3 = componentsInChildren;
					break;
				}
			}
			if (array3 == null)
			{
				error = "No skinned glove mesh found on the GlovesTan3 hand";
				return null;
			}
			GameObject[] key = list[0].Key;
			Dictionary<Transform, int> value = list[0].Value;
			int num = -1;
			SkinnedMeshRenderer[] array4;
			foreach (KeyValuePair<GameObject[], Dictionary<Transform, int>> item2 in list)
			{
				int num2 = 0;
				array4 = array3;
				for (int i = 0; i < array4.Length; i++)
				{
					Transform[] array5 = (Transform[])(((object)array4[i].bones) ?? ((object)new Transform[0]));
					foreach (Transform val in array5)
					{
						if ((Object)(object)val != (Object)null && item2.Value.ContainsKey(val))
						{
							num2++;
						}
					}
				}
				if (num2 > num)
				{
					num = num2;
					key = item2.Key;
					value = item2.Value;
				}
			}
			Transform root = CommonRoot(key);
			if ((Object)(object)root == (Object)null)
			{
				error = "Could not find the hand root";
				return null;
			}
			Quaternion invRot = Quaternion.Inverse(root.rotation);
			Func<Vector3, Vector3> func = (Vector3 w) => invRot * (w - root.position);
			List<float> list3 = new List<float>();
			List<float> list4 = new List<float>();
			List<int> list5 = new List<int>();
			List<int> list6 = new List<int>();
			List<float> list7 = new List<float>();
			bool flag = true;
			string text = "";
			string text2 = "";
			float[] color = new float[4] { 1f, 1f, 1f, 1f };
			array4 = array3;
			foreach (SkinnedMeshRenderer val2 in array4)
			{
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2.sharedMesh == (Object)null)
				{
					continue;
				}
				Mesh val3 = new Mesh();
				try
				{
					val2.BakeMesh(val3);
				}
				catch
				{
					continue;
				}
				Vector3[] vertices = val3.vertices;
				int[] triangles = val3.triangles;
				if (vertices == null || vertices.Length == 0 || triangles == null || triangles.Length == 0)
				{
					continue;
				}
				int num3 = list3.Count / 3;
				Transform transform = ((Component)val2).transform;
				Vector3[] array6 = vertices;
				foreach (Vector3 val4 in array6)
				{
					Vector3 val5 = func(transform.position + transform.rotation * val4);
					list3.Add(val5.x);
					list3.Add(val5.y);
					list3.Add(val5.z);
				}
				Vector2[] uv = val3.uv;
				if (uv != null && uv.Length == vertices.Length)
				{
					Vector2[] array7 = uv;
					foreach (Vector2 val6 in array7)
					{
						list4.Add(val6.x);
						list4.Add(val6.y);
					}
				}
				else
				{
					for (int num4 = 0; num4 < vertices.Length; num4++)
					{
						list4.Add(0f);
						list4.Add(0f);
					}
				}
				int[] array8 = triangles;
				foreach (int num5 in array8)
				{
					list5.Add(num5 + num3);
				}
				BoneWeight[] array9 = null;
				Mesh sharedMesh = val2.sharedMesh;
				if (sharedMesh.isReadable)
				{
					try
					{
						array9 = sharedMesh.boneWeights;
					}
					catch
					{
						array9 = null;
					}
				}
				Transform[] array10 = (Transform[])(((object)val2.bones) ?? ((object)new Transform[0]));
				if (array9 != null && array9.Length == vertices.Length && array10.Length != 0)
				{
					int[] array11 = new int[array10.Length];
					for (int num6 = 0; num6 < array10.Length; num6++)
					{
						array11[num6] = JointFor(array10[num6], value, root);
					}
					BoneWeight[] array12 = array9;
					for (int k = 0; k < array12.Length; k++)
					{
						BoneWeight val7 = array12[k];
						AddWeight(list6, list7, Map(array11, ((BoneWeight)(ref val7)).boneIndex0), ((BoneWeight)(ref val7)).weight0);
						AddWeight(list6, list7, Map(array11, ((BoneWeight)(ref val7)).boneIndex1), ((BoneWeight)(ref val7)).weight1);
						AddWeight(list6, list7, Map(array11, ((BoneWeight)(ref val7)).boneIndex2), ((BoneWeight)(ref val7)).weight2);
						AddWeight(list6, list7, Map(array11, ((BoneWeight)(ref val7)).boneIndex3), ((BoneWeight)(ref val7)).weight3);
					}
				}
				else
				{
					flag = false;
					NearestWeights(vertices, transform, key, root, func, list6, list7);
				}
				if (text2 == "")
				{
					text2 = ((Object)sharedMesh).name;
				}
				if (text == "")
				{
					Material sharedMaterial = ((Renderer)val2).sharedMaterial;
					if ((Object)(object)sharedMaterial != (Object)null)
					{
						if (sharedMaterial.HasProperty("_Color"))
						{
							Color color2 = sharedMaterial.color;
							color = new float[4] { color2.r, color2.g, color2.b, color2.a };
						}
						text = ReadTexture(sharedMaterial.mainTexture, maxTexture);
					}
				}
				Object.Destroy((Object)(object)val3);
			}
			if (list3.Count == 0)
			{
				error = "The glove mesh could not be read";
				return null;
			}
			Xf[] array13 = new Xf[key.Length];
			for (int num7 = 0; num7 < key.Length; num7++)
			{
				if ((Object)(object)key[num7] == (Object)null)
				{
					array13[num7] = new Xf();
					continue;
				}
				Transform transform2 = key[num7].transform;
				array13[num7] = Xf.From(func(transform2.position), invRot * transform2.rotation);
			}
			return new GloveHand
			{
				side = (left ? "L" : "R"),
				jointCount = key.Length,
				bakeJoints = array13,
				v = list3.ToArray(),
				uv = list4.ToArray(),
				t = list5.ToArray(),
				bi = list6.ToArray(),
				bw = list7.ToArray(),
				weights = (flag ? "skin" : "nearest"),
				texture = text,
				color = color,
				meshName = text2
			};
		}

		private static int Map(int[] map, int boneIndex)
		{
			if (boneIndex < 0 || boneIndex >= map.Length)
			{
				return -1;
			}
			return map[boneIndex];
		}

		private static void AddWeight(List<int> bi, List<float> bw, int joint, float weight)
		{
			bi.Add(joint);
			bw.Add(weight);
		}

		private static int JointFor(Transform bone, Dictionary<Transform, int> index, Transform root)
		{
			Transform val = bone;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				if (index.TryGetValue(val, out var value))
				{
					return value;
				}
				val = val.parent;
			}
			return -1;
		}

		private static void NearestWeights(Vector3[] bv, Transform smrT, GameObject[] joints, Transform root, Func<Vector3, Vector3> toRoot, List<int> bi, List<float> bw)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: 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_01fc: Unknown result type (might be due to invalid IL or missing references)
			int num = joints.Length;
			Vector3[] array = (Vector3[])(object)new Vector3[num];
			int[] array2 = new int[num];
			bool[] array3 = new bool[num];
			Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
			for (int i = 0; i < num; i++)
			{
				if ((Object)(object)joints[i] != (Object)null)
				{
					dictionary[joints[i].transform] = i;
					array[i] = joints[i].transform.position;
				}
			}
			for (int j = 0; j < num; j++)
			{
				array2[j] = -1;
				if ((Object)(object)joints[j] == (Object)null)
				{
					continue;
				}
				Transform parent = joints[j].transform.parent;
				while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)root)
				{
					if (dictionary.TryGetValue(parent, out var value))
					{
						array2[j] = value;
						break;
					}
					parent = parent.parent;
				}
				if (array2[j] >= 0)
				{
					array3[array2[j]] = true;
				}
			}
			Vector3[] array4 = (Vector3[])(object)new Vector3[num];
			Vector3[] array5 = (Vector3[])(object)new Vector3[num];
			for (int k = 0; k < num; k++)
			{
				array4[k] = array[k];
				int num2 = -1;
				for (int l = 0; l < num; l++)
				{
					if (array2[l] == k)
					{
						num2 = l;
						break;
					}
				}
				if (num2 >= 0)
				{
					array5[k] = array[num2];
				}
				else if (array2[k] >= 0)
				{
					array5[k] = array[k] + (array[k] - array[array2[k]]) * 0.7f;
				}
				else
				{
					array5[k] = array[k];
				}
			}
			foreach (Vector3 val in bv)
			{
				Vector3 p = smrT.position + smrT.rotation * val;
				int num3 = -1;
				int num4 = -1;
				float num5 = float.MaxValue;
				float num6 = float.MaxValue;
				for (int n = 0; n < num; n++)
				{
					if (!((Object)(object)joints[n] == (Object)null))
					{
						float num7 = SegDist(p, array4[n], array5[n]);
						if (num7 < num5)
						{
							num6 = num5;
							num4 = num3;
							num5 = num7;
							num3 = n;
						}
						else if (num7 < num6)
						{
							num6 = num7;
							num4 = n;
						}
					}
				}
				float num8 = 1f / Mathf.Pow(Mathf.Max(num5, 0.0001f), 4f);
				float num9 = ((num4 >= 0) ? (1f / Mathf.Pow(Mathf.Max(num6, 0.0001f), 4f)) : 0f);
				float num10 = num8 + num9;
				bi.Add(num3);
				bw.Add(num8 / num10);
				bi.Add((num4 >= 0) ? num4 : num3);
				bw.Add(num9 / num10);
				bi.Add(num3);
				bw.Add(0f);
				bi.Add(num3);
				bw.Add(0f);
			}
		}

		private static float SegDist(Vector3 p, Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0042: 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)
			Vector3 val = b - a;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			float num = ((sqrMagnitude < 1E-10f) ? 0f : Mathf.Clamp01(Vector3.Dot(p - a, val) / sqrMagnitude));
			Vector3 val2 = p - (a + val * num);
			return ((Vector3)(ref val2)).magnitude;
		}

		private static string ReadTexture(Texture tex, int maxSize)
		{
			//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_008a: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			if ((Object)(object)tex == (Object)null)
			{
				return "";
			}
			try
			{
				int width = tex.width;
				int height = tex.height;
				float num = Mathf.Min(1f, (float)maxSize / (float)Mathf.Max(width, height));
				width = Mathf.Max(1, Mathf.RoundToInt((float)width * num));
				height = Mathf.Max(1, Mathf.RoundToInt((float)height * num));
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0);
				RenderTexture active = RenderTexture.active;
				Graphics.Blit(tex, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height, (TextureFormat)5, false);
				val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				byte[] array = val.EncodeToPNG();
				Object.Destroy((Object)val);
				return (array != null) ? Convert.ToBase64String(array) : "";
			}
			catch
			{
				return "";
			}
		}

		private static Transform CommonRoot(GameObject[] joints)
		{
			List<Transform> list = null;
			GameObject[] array = joints;
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				List<Transform> list2 = new List<Transform>();
				Transform val2 = val.transform;
				while ((Object)(object)val2 != (Object)null)
				{
					list2.Insert(0, val2);
					val2 = val2.parent;
				}
				if (list == null)
				{
					list = list2;
					continue;
				}
				int j;
				for (j = 0; j < list.Count && j < list2.Count && (Object)(object)list[j] == (Object)(object)list2[j]; j++)
				{
				}
				list.RemoveRange(j, list.Count - j);
			}
			if (list == null || list.Count == 0)
			{
				return null;
			}
			Transform val3 = list[list.Count - 1];
			array = joints;
			foreach (GameObject val4 in array)
			{
				if ((Object)(object)val4 != (Object)null && (Object)(object)val4.transform == (Object)(object)val3)
				{
					return val3.parent ?? val3;
				}
			}
			return val3;
		}
	}
	public class ModelServer
	{
		public delegate void Handler(string method, string path, Dictionary<string, string> query, string body, out int status, out string json);

		private const long MaxBody = 33554432L;

		private readonly HttpListener _listener = new HttpListener();

		private readonly Queue<HttpListenerContext> _pending = new Queue<HttpListenerContext>();

		private readonly Handler _handler;

		private Thread _thread;

		private volatile bool _running;

		public byte[] PageHtml;

		public int Port { get; private set; }

		public ModelServer(int port, Handler handler)
		{
			Port = port;
			_handler = handler;
			_listener.Prefixes.Add("http://127.0.0.1:" + port + "/");
			_listener.Prefixes.Add("http://localhost:" + port + "/");
		}

		public void Start()
		{
			_listener.Start();
			_running = true;
			_thread = new Thread(Loop)
			{
				IsBackground = true,
				Name = "GT3PoseKit bridge"
			};
			_thread.Start();
		}

		public void Stop()
		{
			_running = false;
			try
			{
				_listener.Stop();
				_listener.Close();
			}
			catch
			{
			}
		}

		private void Loop()
		{
			while (_running)
			{
				try
				{
					HttpListenerContext context = _listener.GetContext();
					lock (_pending)
					{
						_pending.Enqueue(context);
					}
				}
				catch
				{
					if (!_running)
					{
						break;
					}
				}
			}
		}

		public void Pump(int max)
		{
			for (int i = 0; i < max; i++)
			{
				HttpListenerContext ctx;
				lock (_pending)
				{
					if (_pending.Count == 0)
					{
						break;
					}
					ctx = _pending.Dequeue();
				}
				Respond(ctx);
			}
		}

		private void Respond(HttpListenerContext ctx)
		{
			int status = 200;
			try
			{
				HttpListenerResponse response = ctx.Response;
				response.AddHeader("Access-Control-Allow-Origin", "*");
				response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
				response.AddHeader("Access-Control-Allow-Headers", "Content-Type, X-PoseKit");
				response.AddHeader("Access-Control-Allow-Private-Network", "true");
				response.AddHeader("Cache-Control", "no-store");
				string httpMethod = ctx.Request.HttpMethod;
				string text = ctx.Request.Url.AbsolutePath.TrimEnd(new char[1] { '/' }).ToLowerInvariant();
				if (httpMethod == "GET" && PageHtml != null)
				{
					switch (text)
					{
					case "":
					case "/editor":
					case "/index.html":
						response.StatusCode = 200;
						response.ContentType = "text/html; charset=utf-8";
						response.ContentLength64 = PageHtml.Length;
						response.OutputStream.Write(PageHtml, 0, PageHtml.Length);
						response.OutputStream.Close();
						return;
					}
				}
				string json;
				if (httpMethod == "OPTIONS")
				{
					json = "";
					status = 204;
				}
				else if (httpMethod != "GET" && httpMethod != "POST")
				{
					json = Err("only GET and POST are supported");
					status = 405;
				}
				else if (httpMethod == "POST" && ctx.Request.Headers["X-PoseKit"] == null)
				{
					json = Err("missing X-PoseKit header");
					status = 403;
				}
				else if (httpMethod == "POST" && ctx.Request.ContentLength64 > 33554432)
				{
					json = Err("request too large");
					status = 413;
				}
				else
				{
					Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
					NameValueCollection queryString = ctx.Request.QueryString;
					string[] allKeys = queryString.AllKeys;
					foreach (string text2 in allKeys)
					{
						if (text2 != null)
						{
							dictionary[text2] = queryString[text2];
						}
					}
					string body = null;
					if (httpMethod == "POST")
					{
						using StreamReader streamReader = new StreamReader(ctx.Request.InputStream, Encoding.UTF8);
						body = streamReader.ReadToEnd();
					}
					try
					{
						_handler(httpMethod, ctx.Request.Url.AbsolutePath.TrimEnd(new char[1] { '/' }).ToLowerInvariant(), dictionary, body, out status, out json);
					}
					catch (Exception ex)
					{
						status = 500;
						json = Err(ex.Message);
					}
				}
				byte[] bytes = Encoding.UTF8.GetBytes(json ?? "");
				response.StatusCode = status;
				response.ContentType = "application/json; charset=utf-8";
				response.ContentLength64 = bytes.Length;
				if (bytes.Length != 0)
				{
					response.OutputStream.Write(bytes, 0, bytes.Length);
				}
				response.OutputStream.Close();
			}
			catch
			{
				try
				{
					ctx.Response.Abort();
				}
				catch
				{
				}
			}
		}

		public static string Err(string msg)
		{
			return "{\"error\":\"" + (msg ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", " ") + "\"}";
		}
	}
	[BepInPlugin("gt3posekit.loader", "GlovesTan3 PoseKit", "1.0.0")]
	[BepInProcess("h3vr.exe")]
	public class PoseKitPlugin : BaseUnityPlugin
	{
		private class Injected
		{
			public HandPoseItem hpi;

			public Transform parent;

			public PoseSet set;

			public string target;
		}

		public const string Guid = "gt3posekit.loader";

		public const string Version = "1.0.0";

		private const string InjectedName = "GT3PoseKit_HandPoseItem";

		private static readonly string[] Slots = new string[8] { "IdleL", "IdleR", "ForeL", "ForeR", "FireStartL", "FireStartR", "FireEndL", "FireEndR" };

		private string _dir;

		private readonly Dictionary<string, PoseSet> _byItemId = new Dictionary<string, PoseSet>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, PoseSet> _byName = new Dictionary<string, PoseSet>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, PoseSet> _magById = new Dictionary<string, PoseSet>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, PoseSet> _magByType = new Dictionary<string, PoseSet>(StringComparer.OrdinalIgnoreCase);

		private readonly HashSet<int> _checked = new HashSet<int>();

		private ConfigEntry<KeyCode> _keyCaptureL;

		private ConfigEntry<KeyCode> _keyCaptureR;

		private ConfigEntry<KeyCode> _keyReload;

		private ConfigEntry<KeyCode> _keyDumpRig;

		private ConfigEntry<KeyCode> _keyExportModel;

		private ConfigEntry<KeyCode> _keyOpenEditor;

		private ConfigEntry<bool> _exportMeshes;

		private ConfigEntry<bool> _bridgeEnabled;

		private ConfigEntry<bool> _allowLive;

		private ConfigEntry<bool> _autoCopy;

		private ConfigEntry<bool> _openOnStart;

		private ConfigEntry<float> _autoCopyThreshold;

		private ConfigEntry<int> _maxMeshVerts;

		private ConfigEntry<int> _bridgePort;

		private ConfigEntry<int> _gloveTexSize;

		private ModelServer _server;

		private readonly List<Injected> _injected = new List<Injected>();

		private static readonly FieldInfo LockedHpiField = typeof(HandsPoseSystem).GetField("lockedHpi", BindingFlags.Instance | BindingFlags.NonPublic);

		private readonly Dictionary<string, PoseSet> _similarCache = new Dictionary<string, PoseSet>(StringComparer.OrdinalIgnoreCase);

		private void Awake()
		{
			_dir = Path.Combine(Paths.ConfigPath, "GlovesTan3Poses");
			Directory.CreateDirectory(_dir);
			Directory.CreateDirectory(Path.Combine(_dir, "captures"));
			Directory.CreateDirectory(Path.Combine(_dir, "models"));
			_keyCaptureL = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "CaptureLeft", (KeyCode)286, "Capture the left hand's pose on the object it holds.");
			_keyCaptureR = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "CaptureRight", (KeyCode)287, "Capture the right hand's pose on the object it holds.");
			_keyReload = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "ReloadPoses", (KeyCode)288, "Reload every pose file and re-apply to spawned objects.");
			_keyDumpRig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "DumpRig", (KeyCode)289, "Write the GlovesTan3 hand skeleton to rig.json.");
			_exportMeshes = ((BaseUnityPlugin)this).Config.Bind<bool>("Capture", "ExportMeshes", true, "Include readable gun meshes in captures (the editor shows them as reference).");
			_maxMeshVerts = ((BaseUnityPlugin)this).Config.Bind<int>("Capture", "MaxMeshVertices", 120000, "Upper limit on total exported mesh vertices per capture or model.");
			_gloveTexSize = ((BaseUnityPlugin)this).Config.Bind<int>("Capture", "GloveTextureSize", 1024, "Largest side of the glove texture sent to the editor (pixels).");
			_keyExportModel = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "ExportHeldModel", (KeyCode)290, "Write the model of the object in either hand to the models folder.");
			_keyOpenEditor = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "OpenEditor", (KeyCode)291, "Open the PoseKit editor in your default browser.");
			_bridgeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Editor bridge", "Enabled", true, "Serve item models, the hand rig and captures to the PoseKit editor over localhost.");
			_openOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("Editor bridge", "OpenEditorOnStart", false, "Open the editor in your default browser automatically when the game starts.");
			_bridgePort = ((BaseUnityPlugin)this).Config.Bind<int>("Editor bridge", "Port", 48261, "Localhost port for the editor bridge (must match the port in the editor).");
			_allowLive = ((BaseUnityPlugin)this).Config.Bind<bool>("Editor bridge", "AllowLiveImport", true, "Let the editor push pose sets into the running game (and save them into the pose folder when asked).");
			_autoCopy = ((BaseUnityPlugin)this).Config.Bind<bool>("Auto copy", "InGameFallback", false, "Off by default: use the editor's \"Auto copy to similar guns\" button instead. When on, a gun without poses silently reuses the poses of the most similarly named gun that has them (e.g. G18 uses G17's).");
			_autoCopyThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Auto copy", "MinimumSimilarity", 0.8f, "How alike the names must be, 0 to 1. 0.9 = only number variants like G17/G18; 0.85 also allows suffixes like G17L.");
			LoadPoseSets();
			try
			{
				RegisterWristMenu();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Sodalite wrist menu unavailable, hotkeys only: " + ex.Message));
			}
			if (_bridgeEnabled.Value)
			{
				try
				{
					_server = new ModelServer(_bridgePort.Value, HandleRequest);
					_server.PageHtml = LoadEditorPage();
					_server.Start();
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Editor bridge listening on http://127.0.0.1:" + _bridgePort.Value + "/" + ((_server.PageHtml != null) ? "  (open that address in a browser for the editor)" : "")));
					if (_openOnStart.Value)
					{
						OpenEditor();
					}
				}
				catch (Exception ex2)
				{
					_server = null;
					((BaseUnityPlugin)this).Logger.LogError((object)("Editor bridge could not start on port " + _bridgePort.Value + ": " + ex2.Message));
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Pose folder: " + _dir));
		}

		private byte[] LoadEditorPage()
		{
			try
			{
				string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "index.html");
				if (File.Exists(path))
				{
					return File.ReadAllBytes(path);
				}
				using Stream stream = typeof(PoseKitPlugin).Assembly.GetManifestResourceStream("GT3PoseKit.editor.html");
				if (stream == null)
				{
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				return array;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Editor page unavailable: " + ex.Message));
				return null;
			}
		}

		private void OnDestroy()
		{
			if (_server != null)
			{
				_server.Stop();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void RegisterWristMenu()
		{
			AddButton("PoseKit: Capture L", delegate
			{
				Capture(left: true);
			});
			AddButton("PoseKit: Capture R", delegate
			{
				Capture(left: false);
			});
			AddButton("PoseKit: Reload poses", delegate
			{
				Reload();
			});
			AddButton("PoseKit: Dump rig", delegate
			{
				DumpRig();
			});
			AddButton("PoseKit: Export held model", delegate
			{
				ExportHeldModel();
			});
			AddButton("PoseKit: Open editor", delegate
			{
				OpenEditor();
			});
		}

		private void OpenEditor()
		{
			if (_server == null || _server.PageHtml == null)
			{
				Notify("The editor bridge isn't running (check [Editor bridge] Enabled in gt3posekit.loader.cfg)");
				return;
			}
			string text = "http://127.0.0.1:" + _server.Port + "/";
			try
			{
				Application.OpenURL(text);
				Notify("Opened the PoseKit editor in your browser: " + text);
			}
			catch (Exception ex)
			{
				Notify("Could not open a browser (" + ex.Message + "). Open " + text + " yourself.");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void AddButton(string text, Action<FVRViveHand> onClick)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			WristMenuButton item = new WristMenuButton(text, (ButtonClickEvent)delegate(object sender, ButtonClickEventArgs args)
			{
				onClick(args.Hand);
			});
			WristMenuAPI.Buttons.Add(item);
		}

		private void Update()
		{
			//IL_0006: 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_0038: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(_keyCaptureL.Value))
			{
				Capture(left: true);
			}
			if (Input.GetKeyDown(_keyCaptureR.Value))
			{
				Capture(left: false);
			}
			if (Input.GetKeyDown(_keyReload.Value))
			{
				Reload();
			}
			if (Input.GetKeyDown(_keyDumpRig.Value))
			{
				DumpRig();
			}
			if (Input.GetKeyDown(_keyExportModel.Value))
			{
				ExportHeldModel();
			}
			if (Input.GetKeyDown(_keyOpenEditor.Value))
			{
				OpenEditor();
			}
			if (_server != null)
			{
				_server.Pump(2);
			}
			if (_byItemId.Count == 0 && _byName.Count == 0 && _magById.Count == 0 && _magByType.Count == 0)
			{
				return;
			}
			FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
			if ((Object)(object)currentMovementManager == (Object)null || currentMovementManager.Hands == null)
			{
				return;
			}
			FVRViveHand[] hands = currentMovementManager.Hands;
			foreach (FVRViveHand val in hands)
			{
				if (!((Object)(object)val == (Object)null))
				{
					FVRPhysicalObject val2 = RootObject(val.CurrentInteractable);
					if ((Object)(object)val2 != (Object)null)
					{
						TryInject(val2);
					}
				}
			}
		}

		private static bool HasPoses(PoseData[] poses)
		{
			if (poses == null)
			{
				return false;
			}
			foreach (PoseData poseData in poses)
			{
				if (poseData != null && poseData.joints != null && poseData.joints.Length != 0)
				{
					return true;
				}
			}
			return false;
		}

		private void LoadPoseSets()
		{
			_byItemId.Clear();
			_byName.Clear();
			_magById.Clear();
			_magByType.Clear();
			int num = 0;
			string[] files = Directory.GetFiles(_dir, "*.json");
			foreach (string text in files)
			{
				if (Path.GetFileName(text).Equals("rig.json", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				try
				{
					PoseSet poseSet = JsonUtility.FromJson<PoseSet>(File.ReadAllText(text));
					if (poseSet != null && !(poseSet.format != "gt3poses"))
					{
						if (poseSet.match == null)
						{
							((BaseUnityPlugin)this).Logger.LogWarning((object)(text + ": no match block, skipped"));
							continue;
						}
						Register(poseSet);
						num++;
					}
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Failed to read " + text + ": " + ex.Message));
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded " + num + " pose set(s)."));
		}

		private void Register(PoseSet set)
		{
			string[] array;
			if (set.match != null)
			{
				array = set.match.itemIds ?? new string[0];
				foreach (string text in array)
				{
					if (!string.IsNullOrEmpty(text))
					{
						_byItemId[text.Trim()] = set;
					}
				}
				array = set.match.objectNames ?? new string[0];
				foreach (string text2 in array)
				{
					if (!string.IsNullOrEmpty(text2))
					{
						_byName[text2.Trim()] = set;
					}
				}
			}
			MagazinePoses magazine = set.magazine;
			if (magazine == null || !HasPoses(magazine.poses))
			{
				return;
			}
			array = magazine.itemIds ?? new string[0];
			foreach (string text3 in array)
			{
				if (!string.IsNullOrEmpty(text3))
				{
					_magById[text3.Trim()] = set;
				}
			}
			array = magazine.magazineTypes ?? new string[0];
			foreach (string text4 in array)
			{
				if (!string.IsNullOrEmpty(text4))
				{
					_magByType[text4.Trim()] = set;
				}
			}
		}

		private static string SetKey(PoseSet s)
		{
			if (s == null)
			{
				return "";
			}
			if (!string.IsNullOrEmpty(s.name))
			{
				return s.name.Trim();
			}
			if (s.match != null && s.match.itemIds != null && s.match.itemIds.Length != 0)
			{
				return s.match.itemIds[0];
			}
			if (s.magazine != null && s.magazine.magazineTypes != null && s.magazine.magazineTypes.Length != 0)
			{
				return "mag:" + s.magazine.magazineTypes[0];
			}
			return "";
		}

		private static void Unregister(Dictionary<string, PoseSet> dict, string key)
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, PoseSet> item in dict)
			{
				if (SetKey(item.Value) == key)
				{
					list.Add(item.Key);
				}
			}
			foreach (string item2 in list)
			{
				dict.Remove(item2);
			}
		}

		private static PoseData[] PosesFor(PoseSet set, string target)
		{
			if (target == "gun")
			{
				return set.poses;
			}
			if (target == "mag")
			{
				if (set.magazine == null)
				{
					return null;
				}
				return set.magazine.poses;
			}
			if (target.StartsWith("part:"))
			{
				string text = target.Substring(5);
				PartPoses[] array = set.parts ?? new PartPoses[0];
				foreach (PartPoses partPoses in array)
				{
					if (partPoses != null && partPoses.path == text)
					{
						return partPoses.poses;
					}
				}
			}
			return null;
		}

		private static HandPose GetSlot(HandPoseItem h, string slot)
		{
			return (HandPose)(slot switch
			{
				"IdleL" => h.IdleL, 
				"IdleR" => h.IdleR, 
				"ForeL" => h.ForeL, 
				"ForeR" => h.ForeR, 
				"FireStartL" => h.FireStartL, 
				"FireStartR" => h.FireStartR, 
				"FireEndL" => h.FireEndL, 
				_ => h.FireEndR, 
			});
		}

		private static bool UpdateInPlace(HandPoseItem h, PoseData[] data, bool hasTrigger)
		{
			//IL_011d: 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)
			Dictionary<string, PoseData> dictionary = new Dictionary<string, PoseData>();
			PoseData[] array = data ?? new PoseData[0];
			foreach (PoseData poseData in array)
			{
				if (poseData != null && !string.IsNullOrEmpty(poseData.slot) && poseData.joints != null && poseData.joints.Length != 0)
				{
					dictionary[poseData.slot] = poseData;
				}
			}
			string[] slots = Slots;
			foreach (string text in slots)
			{
				HandPose slot = GetSlot(h, text);
				PoseData value;
				bool flag = dictionary.TryGetValue(text, out value);
				if ((Object)(object)slot != (Object)null != flag)
				{
					return false;
				}
				if ((Object)(object)slot != (Object)null && (slot.Fingers == null || slot.Fingers.Length != value.joints.Length))
				{
					return false;
				}
			}
			slots = Slots;
			foreach (string text2 in slots)
			{
				HandPose slot2 = GetSlot(h, text2);
				if ((Object)(object)slot2 == (Object)null)
				{
					continue;
				}
				PoseData poseData2 = dictionary[text2];
				for (int j = 0; j < slot2.Fingers.Length; j++)
				{
					if (!((Object)(object)slot2.Fingers[j] == (Object)null))
					{
						slot2.Fingers[j].transform.localPosition = poseData2.joints[j].Pos;
						slot2.Fingers[j].transform.localRotation = poseData2.joints[j].Rot;
					}
				}
			}
			h.hasTrigger = hasTrigger && (((Object)(object)h.FireStartL != (Object)null && (Object)(object)h.FireEndL != (Object)null) || ((Object)(object)h.FireStartR != (Object)null && (Object)(object)h.FireEndR != (Object)null));
			return true;
		}

		private static void Relock(HandPoseItem oldHpi, HandPoseItem newHpi)
		{
			if ((object)LockedHpiField == null)
			{
				return;
			}
			HandsPoseSystem[] array = Object.FindObjectsOfType<HandsPoseSystem>();
			foreach (HandsPoseSystem val in array)
			{
				if ((Object)(object)val != (Object)null && LockedHpiField.GetValue(val) == oldHpi)
				{
					LockedHpiField.SetValue(val, newHpi);
				}
			}
		}

		private string ApplyLive(PoseSet set, bool save)
		{
			string text = SetKey(set);
			if (text == "")
			{
				throw new Exception("pose set needs a name or an item ID");
			}
			Unregister(_byItemId, text);
			Unregister(_byName, text);
			Unregister(_magById, text);
			Unregister(_magByType, text);
			Register(set);
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Injected[] array = _injected.ToArray();
			foreach (Injected injected in array)
			{
				if ((Object)(object)injected.hpi == (Object)null || (Object)(object)injected.parent == (Object)null)
				{
					_injected.Remove(injected);
				}
				else
				{
					if (SetKey(injected.set) != text && !SharesKeys(injected.set, set))
					{
						continue;
					}
					PoseData[] array2 = PosesFor(set, injected.target);
					bool hasTrigger = injected.target == "gun" && set.hasTrigger;
					if (!HasPoses(array2))
					{
						Object.Destroy((Object)(object)((Component)injected.hpi).gameObject);
						_injected.Remove(injected);
						num3++;
						continue;
					}
					((Component)injected.hpi).transform.SetSiblingIndex(0);
					if (UpdateInPlace(injected.hpi, array2, hasTrigger))
					{
						num++;
					}
					else
					{
						HandPoseItem hpi = injected.hpi;
						injected.hpi = InjectHpi(injected.parent, array2, hasTrigger, (injected.target == "gun" && set.useGrabPos) ? set.grabPos : null);
						Relock(hpi, injected.hpi);
						Object.DestroyImmediate((Object)(object)((Component)hpi).gameObject);
						num2++;
					}
					injected.set = set;
				}
			}
			_checked.Clear();
			_similarCache.Clear();
			string text2 = "";
			if (save)
			{
				text2 = Path.Combine(_dir, SafeFileName(text) + ".json");
				File.WriteAllText(text2, JsonUtility.ToJson((object)set, true));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Live update '" + text + "': " + num + " updated, " + num2 + " rebuilt, " + num3 + " removed" + (save ? (", saved to " + text2) : "")));
			return "{\"ok\":true,\"key\":\"" + Esc(text) + "\",\"updated\":" + num + ",\"rebuilt\":" + num2 + ",\"removed\":" + num3 + ",\"saved\":\"" + Esc(text2) + "\"}";
		}

		private static bool SharesKeys(PoseSet a, PoseSet b)
		{
			Func<string[], string[], bool> func = delegate(string[] x, string[] y)
			{
				if (x == null || y == null)
				{
					return false;
				}
				foreach (string text in x)
				{
					foreach (string text2 in y)
					{
						if (!string.IsNullOrEmpty(text) && string.Equals(text.Trim(), (text2 ?? "").Trim(), StringComparison.OrdinalIgnoreCase))
						{
							return true;
						}
					}
				}
				return false;
			};
			if (a == null || b == null)
			{
				return false;
			}
			if (a.match != null && b.match != null && (func(a.match.itemIds, b.match.itemIds) || func(a.match.objectNames, b.match.objectNames)))
			{
				return true;
			}
			if (a.magazine != null && b.magazine != null)
			{
				if (!func(a.magazine.itemIds, b.magazine.itemIds))
				{
					return func(a.magazine.magazineTypes, b.magazine.magazineTypes);
				}
				return true;
			}
			return false;
		}

		private static string Esc(string s)
		{
			return (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"");
		}

		private void Reload()
		{
			HandPoseItem[] array = Object.FindObjectsOfType<HandPoseItem>();
			foreach (HandPoseItem val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name == "GT3PoseKit_HandPoseItem")
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
			}
			_injected.Clear();
			_checked.Clear();
			_similarCache.Clear();
			LoadPoseSets();
			Notify("Poses reloaded (" + (_byItemId.Count + _byName.Count) + " gun keys, " + (_magById.Count + _magByType.Count) + " magazine keys)");
		}

		private PoseSet FindSet(FVRPhysicalObject phys)
		{
			string text = (((Object)(object)phys.ObjectWrapper != (Object)null) ? phys.ObjectWrapper.ItemID : null);
			if (!string.IsNullOrEmpty(text) && _byItemId.TryGetValue(text, out var value))
			{
				return value;
			}
			if (_byName.TryGetValue(((Object)((Component)phys).gameObject).name, out value))
			{
				return value;
			}
			return AutoCopy(phys, text);
		}

		private static string DisplayNameOf(string itemId)
		{
			if (IM.OD == null || !IM.OD.TryGetValue(itemId, out var value) || !((Object)(object)value != (Object)null))
			{
				return null;
			}
			return value.DisplayName;
		}

		private PoseSet AutoCopy(FVRPhysicalObject phys, string id)
		{
			if (!_autoCopy.Value || string.IsNullOrEmpty(id) || phys is FVRFireArmMagazine || !(phys is FVRFireArm))
			{
				return null;
			}
			if (_similarCache.TryGetValue(id, out var value))
			{
				return value;
			}
			string text = (((Object)(object)phys.ObjectWrapper != (Object)null) ? phys.ObjectWrapper.DisplayName : null);
			PoseSet poseSet = null;
			string text2 = null;
			float num = _autoCopyThreshold.Value;
			foreach (KeyValuePair<string, PoseSet> item in _byItemId)
			{
				if (item.Value != null && !item.Value.noAutoCopy && (HasPoses(item.Value.poses) || (item.Value.parts != null && item.Value.parts.Length != 0)))
				{
					float num2 = Similarity.Score(id, item.Key);
					string text3 = DisplayNameOf(item.Key);
					if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text3))
					{
						num2 = Math.Max(num2, Similarity.Score(text, text3));
					}
					if (num2 >= num)
					{
						num = num2;
						poseSet = item.Value;
						text2 = item.Key;
					}
				}
			}
			_similarCache[id] = poseSet;
			if (poseSet != null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Auto copy: " + id + " uses the poses of " + text2 + " ('" + poseSet.name + "', similarity " + num.ToString("0.00") + ")"));
			}
			return poseSet;
		}

		private PoseSet FindMagazineSet(FVRFireArmMagazine mag)
		{
			string text = (((Object)(object)((FVRPhysicalObject)mag).ObjectWrapper != (Object)null) ? ((FVRPhysicalObject)mag).ObjectWrapper.ItemID : null);
			if (!string.IsNullOrEmpty(text) && _magById.TryGetValue(text, out var value))
			{
				return value;
			}
			if (_magByType.TryGetValue(((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref mag.MagazineType)/*cast due to .constrained prefix*/).ToString(), out value))
			{
				return value;
			}
			return null;
		}

		private static Transform HpiParent(FVRInteractiveObject io)
		{
			if (!((Object)(object)io.GameObject != (Object)null))
			{
				return ((Component)io).transform;
			}
			return io.GameObject.transform;
		}

		private static bool HasDirectHpi(Transform t)
		{
			for (int i = 0; i < t.childCount; i++)
			{
				if ((Object)(object)((Component)t.GetChild(i)).GetComponent<HandPoseItem>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		private static string RelPath(Transform root, Transform t)
		{
			List<string> list = new List<string>();
			while ((Object)(object)t != (Object)null && (Object)(object)t != (Object)(object)root)
			{
				list.Insert(0, ((Object)t).name);
				t = t.parent;
			}
			return string.Join("/", list.ToArray());
		}

		private static bool IsPart(FVRInteractiveObject io, Transform root)
		{
			if ((Object)(object)io != (Object)null && (Object)(object)((Component)io).transform != (Object)(object)root && !(io is FVRPhysicalObject) && !(io is FVRAlternateGrip))
			{
				return (Object)(object)((Component)io).GetComponentInParent<HandPoseItem>() == (Object)null;
			}
			return false;
		}

		private static FVRInteractiveObject FindPart(Transform root, PartPoses part)
		{
			FVRInteractiveObject[] componentsInChildren = ((Component)root).GetComponentsInChildren<FVRInteractiveObject>(true);
			FVRInteractiveObject[] array = componentsInChildren;
			foreach (FVRInteractiveObject val in array)
			{
				if (IsPart(val, root) && RelPath(root, ((Component)val).transform) == part.path)
				{
					return val;
				}
			}
			if (!string.IsNullOrEmpty(part.type))
			{
				array = componentsInChildren;
				foreach (FVRInteractiveObject val2 in array)
				{
					if (IsPart(val2, root) && ((object)val2).GetType().Name == part.type)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private void TryInject(FVRPhysicalObject phys)
		{
			int instanceID = ((Object)phys).GetInstanceID();
			if (_checked.Contains(instanceID))
			{
				return;
			}
			_checked.Add(instanceID);
			PoseSet poseSet = FindSet(phys);
			if (poseSet != null)
			{
				try
				{
					InjectGun(phys, poseSet);
					return;
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Could not apply '" + poseSet.name + "': " + ex));
					return;
				}
			}
			FVRFireArmMagazine val = (FVRFireArmMagazine)(object)((phys is FVRFireArmMagazine) ? phys : null);
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			poseSet = FindMagazineSet(val);
			if (poseSet == null)
			{
				return;
			}
			Transform val2 = HpiParent((FVRInteractiveObject)(object)val);
			if (HasDirectHpi(val2))
			{
				return;
			}
			try
			{
				Track(InjectHpi(val2, poseSet.magazine.poses, hasTrigger: false, null), val2, poseSet, "mag");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied magazine poses from '" + poseSet.name + "' to " + ((Object)((Component)val).gameObject).name));
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not apply magazine poses from '" + poseSet.name + "': " + ex2));
			}
		}

		private void InjectGun(FVRPhysicalObject phys, PoseSet set)
		{
			Transform transform = ((Component)phys).transform;
			Transform val = HpiParent((FVRInteractiveObject)(object)phys);
			if (HasPoses(set.poses) && !HasDirectHpi(val))
			{
				Track(InjectHpi(val, set.poses, set.hasTrigger, set.useGrabPos ? set.grabPos : null), val, set, "gun");
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied pose set '" + set.name + "' to " + ((Object)((Component)phys).gameObject).name));
			}
			PartPoses[] array = set.parts ?? new PartPoses[0];
			foreach (PartPoses partPoses in array)
			{
				if (partPoses == null || !HasPoses(partPoses.poses))
				{
					continue;
				}
				FVRInteractiveObject val2 = FindPart(transform, partPoses);
				if ((Object)(object)val2 == (Object)null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("'" + set.name + "': part '" + partPoses.path + "' not found on " + ((Object)((Component)phys).gameObject).name));
				}
				else
				{
					Transform val3 = HpiParent(val2);
					if (!HasDirectHpi(val3))
					{
						Track(InjectHpi(val3, partPoses.poses, hasTrigger: false, null), val3, set, "part:" + partPoses.path);
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied '" + (partPoses.name ?? partPoses.path) + "' poses to " + ((Object)((Component)phys).gameObject).name));
					}
				}
			}
		}

		private void Track(HandPoseItem hpi, Transform parent, PoseSet set, string target)
		{
			_injected.Add(new Injected
			{
				hpi = hpi,
				parent = parent,
				set = set,
				target = target
			});
		}

		private HandPoseItem InjectHpi(Transform parent, PoseData[] data, bool hasTrigger, Xf grabPos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0031: 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_004c: 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)
			//IL_0058: 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_006e: 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_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Expected O, but got Unknown
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("GT3PoseKit_HandPoseItem");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			val.transform.SetSiblingIndex(0);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			Vector3 lossyScale = parent.lossyScale;
			val.transform.localScale = new Vector3(SafeInv(lossyScale.x), SafeInv(lossyScale.y), SafeInv(lossyScale.z));
			Dictionary<string, PoseData> dictionary = new Dictionary<string, PoseData>();
			PoseData[] array = data ?? new PoseData[0];
			foreach (PoseData poseData in array)
			{
				if (poseData != null && !string.IsNullOrEmpty(poseData.slot) && poseData.joints != null && poseData.joints.Length != 0)
				{
					dictionary[poseData.slot] = poseData;
				}
			}
			HandPoseItem val2 = val.AddComponent<HandPoseItem>();
			val2.IdleL = Build(val.transform, "IdleL", dictionary);
			val2.IdleR = Build(val.transform, "IdleR", dictionary);
			val2.ForeL = Build(val.transform, "ForeL", dictionary);
			val2.ForeR = Build(val.transform, "ForeR", dictionary);
			val2.FireStartL = Build(val.transform, "FireStartL", dictionary);
			val2.FireStartR = Build(val.transform, "FireStartR", dictionary);
			val2.FireEndL = Build(val.transform, "FireEndL", dictionary);
			val2.FireEndR = Build(val.transform, "FireEndR", dictionary);
			val2.CurPoseL = (((Object)(object)val2.IdleL != (Object)null) ? Build(val.transform, "CurPoseL", dictionary["IdleL"]) : null);
			val2.CurPoseR = (((Object)(object)val2.IdleR != (Object)null) ? Build(val.transform, "CurPoseR", dictionary["IdleR"]) : null);
			val2.hasTrigger = hasTrigger && (((Object)(object)val2.FireStartL != (Object)null && (Object)(object)val2.FireEndL != (Object)null) || ((Object)(object)val2.FireStartR != (Object)null && (Object)(object)val2.FireEndR != (Object)null));
			if (grabPos != null)
			{
				GameObject val3 = new GameObject("GrabPos");
				val3.transform.SetParent(val.transform, false);
				val3.transform.localPosition = grabPos.Pos;
				val3.transform.localRotation = grabPos.Rot;
				val2.grabpos = val3;
			}
			val.SetActive(true);
			return val2;
		}

		private static HandPose Build(Transform parent, string slot, Dictionary<string, PoseData> poses)
		{
			if (!poses.TryGetValue(slot, out var value))
			{
				return null;
			}
			return Build(parent, slot, value);
		}

		private static HandPose Build(Transform parent, string name, PoseData pd)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			HandPose val2 = val.AddComponent<HandPose>();
			GameObject[] array = (GameObject[])(object)new GameObject[pd.joints.Length];
			for (int i = 0; i < array.Length; i++)
			{
				GameObject val3 = new GameObject("j" + i);
				val3.transform.SetParent(val.transform, false);
				val3.transform.localPosition = pd.joints[i].Pos;
				val3.transform.localRotation = pd.joints[i].Rot;
				array[i] = val3;
			}
			val2.Fingers = array;
			return val2;
		}

		private static float SafeInv(float v)
		{
			if (!(Mathf.Abs(v) < 1E-06f))
			{
				return 1f / v;
			}
			return 1f;
		}

		private static FVRPhysicalObject RootObject(FVRInteractiveObject io)
		{
			if ((Object)(object)io == (Object)null)
			{
				return null;
			}
			FVRAlternateGrip val = (FVRAlternateGrip)(object)((io is FVRAlternateGrip) ? io : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.PrimaryObject != (Object)null)
			{
				return val.PrimaryObject;
			}
			FVRPhysicalObject val2 = (FVRPhysicalObject)(object)((io is FVRPhysicalObject) ? io : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			return ((Component)io).GetComponentInParent<FVRPhysicalObject>();
		}

		private static HandsPoseSystem FindSystem(bool left)
		{
			HandsPoseSystem[] array = Object.FindObjectsOfType<HandsPoseSystem>();
			foreach (HandsPoseSystem val in array)
			{
				if ((Object)(object)val != (Object)null && val.isLeft == left)
				{
					return val;
				}
			}
			return null;
		}

		private static FVRViveHand FindHand(bool left)
		{
			FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
			if ((Object)(object)currentMovementManager == (Object)null || currentMovementManager.Hands == null)
			{
				return null;
			}
			FVRViveHand[] hands = currentMovementManager.Hands;
			foreach (FVRViveHand val in hands)
			{
				if ((Object)(object)val != (Object)null && val.IsThisTheRightHand != left)
				{
					return val;
				}
			}
			return null;
		}

		private static Xf ToGunSpace(Transform gun, Transform t)
		{
			//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_000b: 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_000e: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Quaternion val = Quaternion.Inverse(gun.rotation);
			return Xf.From(val * (t.position - gun.position), val * t.rotation);
		}

		private static Transform CommonRoot(GameObject[] joints)
		{
			List<Transform> list = null;
			GameObject[] array = joints;
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				List<Transform> list2 = new List<Transform>();
				Transform val2 = val.transform;
				while ((Object)(object)val2 != (Object)null)
				{
					list2.Insert(0, val2);
					val2 = val2.parent;
				}
				if (list == null)
				{
					list = list2;
					continue;
				}
				int j;
				for (j = 0; j < list.Count && j < list2.Count && (Object)(object)list[j] == (Object)(object)list2[j]; j++)
				{
				}
				list.RemoveRange(j, list.Count - j);
			}
			if (list == null || list.Count == 0)
			{
				return null;
			}
			Transform val3 = list[list.Count - 1];
			array = joints;
			foreach (GameObject val4 in array)
			{
				if ((Object)(object)val4 != (Object)null && (Object)(object)val4.transform == (Object)(object)val3)
				{
					return val3.parent ?? val3;
				}
			}
			return val3;
		}

		private static RigHand BuildRig(bool left, GameObject[] src)
		{
			//IL_011b: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			Transform val = CommonRoot(src);
			Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
			for (int i = 0; i < src.Length; i++)
			{
				if ((Object)(object)src[i] != (Object)null)
				{
					dictionary[src[i].transform] = i;
				}
			}
			RigJoint[] array = new RigJoint[src.Length];
			for (int j = 0; j < src.Length; j++)
			{
				RigJoint obj = new RigJoint
				{
					name = (((Object)(object)src[j] != (Object)null) ? ((Object)src[j]).name : ("missing" + j)),
					parent = -1,
					local = new Xf()
				};
				RigJoint rigJoint = (array[j] = obj);
				if ((Object)(object)src[j] == (Object)null)
				{
					continue;
				}
				Transform transform = src[j].transform;
				Transform val2 = val;
				Transform parent = transform.parent;
				while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)val)
				{
					if (dictionary.TryGetValue(parent, out var value))
					{
						rigJoint.parent = value;
						val2 = parent;
						break;
					}
					parent = parent.parent;
				}
				if ((Object)(object)val2 == (Object)null)
				{
					rigJoint.local = Xf.From(transform.position, transform.rotation);
					continue;
				}
				Quaternion val3 = Quaternion.Inverse(val2.rotation);
				rigJoint.local = Xf.From(val3 * (transform.position - val2.position), val3 * transform.rotation);
			}
			return new RigHand
			{
				side = (left ? "L" : "R"),
				rootName = (((Object)(object)val != (Object)null) ? ((Object)val).name : ""),
				joints = array
			};
		}

		private static GameObject[] PoseSource(HandsPoseSystem sys, out bool fromPhysics)
		{
			fromPhysics = (Object)(object)sys.HandPhys != (Object)null && sys.HandPhys.activeInHierarchy && sys.realfingers != null && sys.Fingers != null && sys.realfingers.Length == sys.Fingers.Length;
			if (!fromPhysics)
			{
				return sys.Fingers;
			}
			return sys.realfingers;
		}

		private RigDump BuildRigDump(out string error)
		{
			error = null;
			HandsPoseSystem val = FindSystem(left: true);
			HandsPoseSystem val2 = FindSystem(left: false);
			if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null)
			{
				error = "Spawn the GlovesTan3 gloves first";
				return null;
			}
			bool fromPhysics;
			return new RigDump
			{
				left = (((Object)(object)val != (Object)null) ? BuildRig(left: true, PoseSource(val, out fromPhysics)) : null),
				right = (((Object)(object)val2 != (Object)null) ? BuildRig(left: false, PoseSource(val2, out fromPhysics)) : null)
			};
		}

		private void DumpRig()
		{
			string error;
			RigDump rigDump = BuildRigDump(out error);
			if (rigDump == null)
			{
				Notify(error);
				return;
			}
			string text = Path.Combine(_dir, "rig.json");
			File.WriteAllText(text, JsonUtility.ToJson((object)rigDump, true));
			Notify("Rig written: " + text);
			GloveDump gloveDump = BuildGloveDump(out error);
			if (gloveDump != null)
			{
				string text2 = Path.Combine(_dir, "glove.json");
				File.WriteAllText(text2, JsonUtility.ToJson((object)gloveDump));
				Notify("Glove model written: " + text2);
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Glove model not exported: " + error));
			}
		}

		private GloveDump BuildGloveDump(out string error)
		{
			error = null;
			HandsPoseSystem val = FindSystem(left: true);
			HandsPoseSystem val2 = FindSystem(left: false);
			if ((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null)
			{
				error = "Spawn the GlovesTan3 gloves first";
				return null;
			}
			string error2 = null;
			string error3 = null;
			GloveDump gloveDump = new GloveDump
			{
				left = (((Object)(object)val != (Object)null) ? GloveExport.Build(val, left: true, _gloveTexSize.Value, out error2) : null),
				right = (((Object)(object)val2 != (Object)null) ? GloveExport.Build(val2, left: false, _gloveTexSize.Value, out error3) : null)
			};
			if (gloveDump.left == null && gloveDump.right == null)
			{
				error = error3 ?? error2 ?? "No glove mesh found";
				return null;
			}
			return gloveDump;
		}

		private CaptureData BuildCapture(bool left, out string error)
		{
			error = null;
			HandsPoseSystem val = FindSystem(left);
			if ((Object)(object)val == (Object)null)
			{
				error = "Spawn the GlovesTan3 gloves first";
				return null;
			}
			FVRViveHand val2 = FindHand(left);
			FVRInteractiveObject val3 = (((Object)(object)val2 != (Object)null) ? val2.CurrentInteractable : null);
			FVRPhysicalObject val4 = RootObject(val3);
			if ((Object)(object)val4 == (Object)null)
			{
				error = "Hold an object with the " + (left ? "left" : "right") + " hand to capture";
				return null;
			}
			bool fromPhysics;
			GameObject[] array = PoseSource(val, out fromPhysics);
			Transform transform = ((Component)val4).transform;
			Transform val5 = CommonRoot(array);
			int readable;
			int boxed;
			CaptureData captureData = new CaptureData
			{
				itemId = (((Object)(object)val4.ObjectWrapper != (Object)null) ? val4.ObjectWrapper.ItemID : ""),
				objectName = ((Object)((Component)val4).gameObject).name,
				side = (left ? "L" : "R"),
				onForegrip = (val3 is FVRAlternateGrip),
				fromPhysics = fromPhysics,
				handRoot = (((Object)(object)val5 != (Object)null) ? ToGunSpace(transform, val5) : new Xf()),
				joints = new Xf[array.Length],
				rig = BuildRig(left, array),
				geo = BuildGeo(transform, out readable, out boxed)
			};
			for (int i = 0; i < array.Length; i++)
			{
				captureData.joints[i] = (((Object)(object)array[i] != (Object)null) ? ToGunSpace(transform, array[i].transform) : new Xf());
			}
			if (IsPart(val3, transform))
			{
				captureData.partPath = RelPath(transform, ((Component)val3).transform);
				captureData.partType = ((object)val3).GetType().Name;
				captureData.partXf = ToGunSpace(transform, HpiParent(val3));
			}
			FVRFireArmMagazine val6 = (FVRFireArmMagazine)(object)((val4 is FVRFireArmMagazine) ? val4 : null);
			if ((Object)(object)val6 != (Object)null)
			{
				captureData.isMagazine = true;
				captureData.magazineType = ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref val6.MagazineType)/*cast due to .constrained prefix*/).ToString();
			}
			return captureData;
		}

		private void Capture(bool left)
		{
			string error;
			CaptureData captureData = BuildCapture(left, out error);
			if (captureData == null)
			{
				Notify(error);
				return;
			}
			string text = SafeFileName(string.IsNullOrEmpty(captureData.itemId) ? captureData.objectName : captureData.itemId);
			string text2 = Path.Combine(Path.Combine(_dir, "captures"), text + "_" + captureData.side + (captureData.onForegrip ? "_fore" : "") + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".json");
			File.WriteAllText(text2, JsonUtility.ToJson((object)captureData));
			Notify("Captured " + captureData.side + " on " + text);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Capture written: " + text2));
		}

		private static string SafeFileName(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				s = "object";
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				s = s.Replace(oldChar, '_');
			}
			return s;
		}

		private ModelData BuildModel(string itemId, string name, string category, Transform root)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			int readable;
			int boxed;
			GunGeo geo = BuildGeo(root, out readable, out boxed);
			ModelData modelData = new ModelData
			{
				itemId = itemId,
				name = name,
				category = category,
				readableMeshes = readable,
				boxedMeshes = boxed,
				geo = geo
			};
			FVRFireArmMagazine component = ((Component)root).GetComponent<FVRFireArmMagazine>();
			FVRFireArm component2 = ((Component)root).GetComponent<FVRFireArm>();
			if ((Object)(object)component != (Object)null)
			{
				modelData.isMagazine = true;
				modelData.magazineType = ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref component.MagazineType)/*cast due to .constrained prefix*/).ToString();
			}
			else if ((Object)(object)component2 != (Object)null)
			{
				modelData.magazineType = ((object)Unsafe.As<FireArmMagazineType, FireArmMagazineType>(ref component2.MagazineType)/*cast due to .constrained prefix*/).ToString();
				List<string> list = new List<string>();
				if (IM.CompatMags != null && IM.CompatMags.TryGetValue(component2.MagazineType, out var value) && value != null)
				{
					foreach (FVRObject item in value)
					{
						if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(item.ItemID))
						{
							list.Add(item.ItemID);
						}
					}
				}
				modelData.compatibleMags = list.ToArray();
			}
			return modelData;
		}

		private void ExportHeldModel()
		{
			FVRMovementManager currentMovementManager = GM.CurrentMovementManager;
			FVRPhysicalObject val = null;
			if ((Object)(object)currentMovementManager != (Object)null && currentMovementManager.Hands != null)
			{
				FVRViveHand[] hands = currentMovementManager.Hands;
				foreach (FVRViveHand val2 in hands)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val == (Object)null)
					{
						val = RootObject(val2.CurrentInteractable);
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Notify("Hold an object to export its model");
				return;
			}
			FVRObject objectWrapper = val.ObjectWrapper;
			string text = (((Object)(object)objectWrapper != (Object)null) ? objectWrapper.ItemID : ((Object)((Component)val).gameObject).name);
			ModelData modelData = BuildModel(text, ((Object)(object)objectWrapper != (Object)null) ? objectWrapper.DisplayName : ((Object)((Component)val).gameObject).name, ((Object)(object)objectWrapper != (Object)null) ? ((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref objectWrapper.Category)/*cast due to .constrained prefix*/).ToString() : "", ((Component)val).transform);
			string text2 = Path.Combine(Path.Combine(_dir, "models"), SafeFileName(text) + ".json");
			File.WriteAllText(text2, JsonUtility.ToJson((object)modelData));
			Notify("Model written: " + text2 + " (" + modelData.readableMeshes + " meshes, " + modelData.boxedMeshes + " boxed)");
		}

		private void HandleRequest(string method, string path, Dictionary<string, string> q, string body, out int status, out string json)
		{
			status = 200;
			string value;
			if (method == "POST")
			{
				if (path != "/poses")
				{
					status = 404;
					json = ModelServer.Err("Unknown endpoint " + path);
					return;
				}
				if (!_allowLive.Value)
				{
					status = 403;
					json = ModelServer.Err("Live import is turned off in gt3posekit.loader.cfg");
					return;
				}
				PoseSet poseSet;
				try
				{
					poseSet = JsonUtility.FromJson<PoseSet>(body ?? "");
				}
				catch (Exception ex)
				{
					status = 400;
					json = ModelServer.Err("Not valid JSON: " + ex.Message);
					return;
				}
				if (poseSet == null || poseSet.format != "gt3poses")
				{
					status = 400;
					json = ModelServer.Err("Expected a gt3poses pose set");
					return;
				}
				bool save = q.TryGetValue("save", out value) && (value == "1" || value == "true");
				try
				{
					json = ApplyLive(poseSet, save);
					return;
				}
				catch (Exception ex2)
				{
					status = 400;
					json = ModelServer.Err(ex2.Message);
					return;
				}
			}
			string error;
			switch (path)
			{
			case "/status":
				json = JsonUtility.ToJson((object)new BridgeStatus
				{
					version = "1.0.0",
					items = ((IM.OD != null) ? IM.OD.Count : 0),
					gloves = ((Object)(object)FindSystem(left: true) != (Object)null || (Object)(object)FindSystem(left: false) != (Object)null),
					poseFolder = _dir
				});
				break;
			case "/posesets":
			{
				List<LocalSet> list2 = new List<LocalSet>();
				string[] files = Directory.GetFiles(_dir, "*.json");
				foreach (string path2 in files)
				{
					string fileName = Path.GetFileName(path2);
					if (fileName.Equals("rig.json", StringComparison.OrdinalIgnoreCase) || fileName.Equals("glove.json", StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					try
					{
						PoseSet poseSet2 = JsonUtility.FromJson<PoseSet>(File.ReadAllText(path2));
						if (poseSet2 != null && !(poseSet2.format != "gt3poses"))
						{
							list2.Add(new LocalSet
							{
								key = SetKey(poseSet2),
								file = fileName,
								itemIds = ((poseSet2.match != null && poseSet2.match.itemIds != null) ? poseSet2.match.itemIds : new string[0]),
								modified = File.GetLastWriteTime(path2).ToString("yyyy-MM-ddTHH:mm:ss")
							});
						}
					}
					catch
					{
					}
				}
				json = JsonUtility.ToJson((object)new LocalSetList
				{
					sets = list2.ToArray()
				});
				break;
			}
			case "/items":
			{
				List<ItemInfo> list = new List<ItemInfo>();
				if (IM.OD != null)
				{
					foreach (KeyValuePair<string, FVRObject> item in IM.OD)
					{
						FVRObject value2 = item.Value;
						if (!((Object)(object)value2 == (Object)null))
						{
							list.Add(new ItemInfo
							{
								id = item.Key,
								name = value2.DisplayName,
								cat = ((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref value2.Category)/*cast due to .constrained prefix*/).ToString(),
								mod = value2.IsModContent
							});
						}
					}
				}
				list.Sort((ItemInfo a, ItemInfo b) => string.Compare(a.name ?? a.id, b.name ?? b.id, StringComparison.OrdinalIgnoreCase));
				json = JsonUtility.ToJson((object)new ItemList
				{
					items = list.ToArray()
				});
				break;
			}
			case "/model":
			{
				if (!q.TryGetValue("id", out value) || IM.OD == null || !IM.OD.TryGetValue(value, out var value3) || (Object)(object)value3 == (Object)null)
				{
					status = 404;
					json = ModelServer.Err("No item with ID '" + value + "'");
					break;
				}
				GameObject gameObject;
				try
				{
					gameObject = ((AnvilAsset)value3).GetGameObject();
				}
				catch (Exception ex3)
				{
					status = 500;
					json = ModelServer.Err("Could not load " + value + ": " + ex3.Message);
					break;
				}
				if ((Object)(object)gameObject == (Object)null)
				{
					status = 404;
					json = ModelServer.Err(value + " has no prefab");
				}
				else
				{
					json = JsonUtility.ToJson((object)BuildModel(value3.ItemID, value3.DisplayName, ((object)Unsafe.As<ObjectCategory, ObjectCategory>(ref value3.Category)/*cast due to .constrained prefix*/).ToString(), gameObject.transform));
				}
				break;
			}
			case "/rig":
			{
				RigDump rigDump = BuildRigDump(out error);
				if (rigDump == null)
				{
					status = 409;
					json = ModelServer.Err(error);
				}
				else
				{
					json = JsonUtility.ToJson((object)rigDump);
				}
				break;
			}
			case "/glove":
			{
				GloveDump gloveDump = BuildGloveDump(out error);
				if (gloveDump == null)
				{
					status = 409;
					json = ModelServer.Err(error);
				}
				else
				{
					json = JsonUtility.ToJson((object)gloveDump);
				}
				break;
			}
			case "/capture":
			{
				bool left = q.TryGetValue("side", out value) && value.ToUpperInvariant().StartsWith("L");
				CaptureData captureData = BuildCapture(left, out error);
				if (captureData == null)
				{
					status = 409;
					json = ModelServer.Err(error);
				}
				else
				{
					json = JsonUtility.ToJson((object)captureData);
				}
				break;
			}
			default:
				status = 404;
				json = ModelServer.Err("Unknown endpoint " + path);
				break;
			}
		}

		private static bool ActiveUnder(Transform t, Transform root)
		{
			while ((Object)(object)t != (Object)null)
			{
				if (!((Component)t).gameObject.activeSelf)
				{
					return false;
				}
				if ((Object)(object)t == (Object)(object)root)
				{
					return true;
				}
				t = t.parent;
			}
			return true;
		}

		private GunGeo BuildGeo(Transform gun, out int readable, out int boxed)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0513: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Unknown result type (might be due to invalid IL or missing references)
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: 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)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_049e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			readable = 0;
			boxed = 0;
			List<GeoPrim> list = new List<GeoPrim>();
			List<GeoMesh> list2 = new List<GeoMesh>();
			List<Marker> markers = new List<Marker>();
			Quaternion val = Quaternion.Inverse(gun.rotation);
			Vector3 gs = gun.lossyScale;
			Func<Transform, bool> func = (Transform t) => (Object)(object)((Component)t).GetComponentInParent<HandPoseItem>() != (Object)null;
			Func<Transform, float[]> func2 = delegate(Transform t)
			{
				//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_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				Vector3 lossyScale = t.lossyScale;
				return new float[3]
				{
					lossyScale.x * SafeInv(gs.x),
					lossyScale.y * SafeInv(gs.y),
					lossyScale.z * SafeInv(gs.z)
				};
			};
			Func<Vector3, float[]> func3 = (Vector3 v) => new float[3] { v.x, v.y, v.z };
			Collider[] componentsInChildren = ((Component)gun).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || func(((Component)val2).transform))
				{
					continue;
				}
				GeoPrim geoPrim = new GeoPrim
				{
					name = ((Object)val2).name,
					xf = ToGunSpace(gun, ((Component)val2).transform),
					scale = func2(((Component)val2).transform),
					trigger = val2.isTrigger
				};
				BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
				SphereCollider val4 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
				CapsuleCollider val5 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null);
				MeshCollider val6 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
				if ((Object)(object)val3 != (Object)null)
				{
					geoPrim.kind = "box";
					geoPrim.center = func3(val3.center);
					geoPrim.size = func3(val3.size);
				}
				else if ((Object)(object)val4 != (Object)null)
				{
					geoPrim.kind = "sphere";
					geoPrim.center = func3(val4.center);
					geoPrim.radius = val4.radius;
				}
				else if ((Object)(object)val5 != (Object)null)
				{
					geoPrim.kind = "capsule";
					geoPrim.center = func3(val5.center);
					geoPrim.radius = val5.radius;
					geoPrim.height = val5.height;
					geoPrim.dir = val5.direction;
				}
				else
				{
					if (!((Object)(object)val6 != (Object)null) || !((Object)(object)val6.sharedMesh != (Object)null))
					{
						continue;
					}
					Bounds bounds = val6.sharedMesh.bounds;
					geoPrim.kind = "bounds";
					geoPrim.center = func3(((Bounds)(ref bounds)).center);
					geoPrim.size = func3(((Bounds)(ref bounds)).size);
				}
				list.Add(geoPrim);
			}
			if (_exportMeshes.Value)
			{
				int num2 = _maxMeshVerts.Value;
				List<KeyValuePair<Transform, Mesh>> list3 = new List<KeyValuePair<Transform, Mesh>>();
				MeshFilter[] componentsInChildren2 = ((Component)gun).GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val7 in componentsInChildren2)
				{
					if (!((Object)(object)val7 == (Object)null) && !((Object)(object)val7.sharedMesh == (Object)null) && !func(((Component)val7).transform) && ActiveUnder(((Component)val7).transform, gun))
					{
						MeshRenderer component = ((Component)val7).GetComponent<MeshRenderer>();
						if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled)
						{
							list3.Add(new KeyValuePair<Transform, Mesh>(((Component)val7).transform, val7.sharedMesh));
						}
					}
				}
				SkinnedMeshRenderer[] componentsInChildren3 = ((Component)gun).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val8 in componentsInChildren3)
				{
					if (!((Object)(object)val8 == (Object)null) && !((Object)(object)val8.sharedMesh == (Object)null) && ((Renderer)val8).enabled && !func(((Component)val8).transform) && ActiveUnder(((Component)val8).transform, gun))
					{
						list3.Add(new KeyValuePair<Transform, Mesh>(((Component)val8).transform, val8.sharedMesh));
					}
				}
				foreach (KeyValuePair<Transform, Mesh> item in list3)
				{
					Transform key = item.Key;
					Mesh value = item.Value;
					Vector3[] array = null;
					int[] array2 = null;
					if (value.isReadable && value.vertexCount <= num2)
					{
						try
						{
							array = value.vertices;
							array2 = value.triangles;
						}
						catch
						{
							array = null;
						}
					}
					if (array != null && array.Length != 0 && array2 != null && array2.Length != 0)
					{
						num2 -= array.Length;
						float[] array3 = new float[array.Length * 3];
						for (int num3 = 0; num3 < array.Length; num3++)
						{
							Vector3 val9 = val * (key.TransformPoint(array[num3]) - gun.position);
							array3[num3 * 3] = val9.x;
							array3[num3 * 3 + 1] = val9.y;
							array3[num3 * 3 + 2] = val9.z;
						}
						list2.Add(new GeoMesh
						{
							name = ((Object)key).name,
							v = array3,
							t = array2
						});
						readable++;
					}
					else
					{
						Bounds bounds2 = value.bounds;
						list.Add(new GeoPrim
						{
							kind = "meshbox",
							name = ((Object)key).name,
							xf = ToGunSpace(gun, key),
							scale = func2(key),
							center = func3(((Bounds)(ref bounds2)).center),
							size = func3(((Bounds)(ref bounds2)).size)
						});
						boxed++;
					}
				}
			}
			HashSet<Transform> seen = new HashSet<Transform>();
			Action<string, Transform> action = delegate(string n, Transform t)
			{
				if (!((Object)(object)t == (Object)null) && !seen.Contains(t) && markers.Count < 64)
				{
					seen.Add(t);
					markers.Add(new Marker
					{
						name = n,
						xf = ToGunSpace(gun, t)
					});
				}
			};
			FVRInteractiveObject[] componentsInChildren4 = ((Component)gun).GetComponentsInChildren<FVRInteractiveObject>(true);
			foreach (FVRInteractiveObject val10 in componentsInChildren4)
			{
				if ((Object)(object)val10 != (Object)null && (Object)(object)val10.PoseOverride != (Object)null)
				{
					action("PoseOverride: " + ((Object)val10).name, val10.PoseOverride);
				}
			}
			string[] array4 = new string[11]
			{
				"trigger", "safety", "magrelease", "mag_release", "selector", "foregrip", "grip", "hammer", "slide", "bolt",
				"handle"
			};
			Transform[] componentsInChildren5 = ((Component)gun).GetComponentsInChildren<Transform>(true);
			foreach (Transform val11 in componentsInChildren5)
			{
				if (func(val11))
				{
					continue;
				}
				string text = ((Object)val11).name.ToLowerInvariant();
				string[] array5 = array4;
				foreach (string value2 in array5)
				{
					if (text.Contains(value2))
					{
						action(((Object)val11).name, val11);
						break;
					}
				}
			}
			List<PartInfo> list4 = new List<PartInfo>();
			componentsInChildren4 = ((Component)gun).GetComponentsInChildren<FVRInteractiveObject>(true);
			foreach (FVRInteractiveObject val12 in componentsInChildren4)
			{
				if (IsPart(val12, gun))
				{
					list4.Add(new PartInfo
					{
						name = ((Object)val12).name,
						path = RelPath(gun, ((Component)val12).transform),
						type = ((object)val12).GetType().Name,
						xf = ToGunSpace(gun, HpiParent(val12))
					});
				}
			}
			return new GunGeo
			{
				prims = list.ToArray(),
				meshes = list2.ToArray(),
				markers = markers.ToArray(),
				parts = list4.ToArray()
			};
		}

		private void Notify(string msg)
		{
			((BaseUnityPlugin)this).Logger.LogMessage((object)msg);
		}
	}
	public static class Similarity
	{
		public const float DefaultThreshold = 0.8f;

		public static float Score(string a, string b)
		{
			string text = Normalize(a);
			string text2 = Normalize(b);
			if (text.Length == 0 || text2.Length == 0)
			{
				return 0f;
			}
			if (text == text2)
			{
				return 1f;
			}
			List<string> list = Tokens(text);
			List<string> list2 = Tokens(text2);
			if (list.Count == 0 || list2.Count == 0)
			{
				return 0f;
			}
			if (FirstAlpha(list) != FirstAlpha(list2))
			{
				return 0f;
			}
			if (list.Count == list2.Count)
			{
				bool flag = true;
				bool flag2 = false;
				for (int i = 0; i < list.Count; i++)
				{
					if (!(list[i] == list2[i]))
					{
						flag2 = true;
						int result;
						bool num = int.TryParse(list[i], out result);
						int result2;
						bool flag3 = int.TryParse(list2[i], out result2);
						if (!(num && flag3) || Math.Abs(result - result2) > 2)
						{
							flag = false;
							break;
						}
					}
				}
				if (flag2 && flag)
				{
					return 0.9f;
				}
			}
			List<string> list3 = ((list.Count < list2.Count) ? list : list2);
			List<string> list4 = ((list.Count < list2.Count) ? list2 : list);
			if (list3.Count != list4.Count && list3.Count >= 2)
			{
				bool flag4 = true;
				for (int j = 0; j < list3.Count; j++)
				{
					if (list3[j] != list4[j])
					{
						flag4 = false;
						break;
					}
				}
				if (flag4)
				{
					return 0.85f;
				}
			}
			int num2 = Levenshtein(text, text2);
			return 1f - (float)num2 / (float)Math.Max(text.Length, text2.Length);
		}

		public static string Normalize(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			string text = s.ToLowerInvariant();
			foreach (char c in text)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static List<string> Tokens(string s)
		{
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			int num = -1;
			foreach (char c in s)
			{
				bool num2 = char.IsDigit(c);
				if ((num2 ? 1 : 0) != num && stringBuilder.Length > 0)
				{
					list.Add(stringBuilder.ToString());
					stringBuilder.Length = 0;
				}
				num = (num2 ? 1 : 0);
				stringBuilder.Append(c);
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (char.IsDigit(list[j][0]))
				{
					string text = list[j].TrimStart(new char[1] { '0' });
					list[j] = ((text.Length == 0) ? "0" : text);
				}
			}
			return list;
		}

		private static string FirstAlpha(List<string> t)
		{
			foreach (string item in t)
			{
				if (!char.IsDigit(item[0]))
				{
					return item;
				}
			}
			return "";
		}

		private static int Levenshtein(string a, string b)
		{
			int[] array = new int[b.Length + 1];
			int[] array2 = new int[b.Length + 1];
			for (int i = 0; i <= b.Length; i++)
			{
				array[i] = i;
			}
			for (int j = 1; j <= a.Length; j++)
			{
				array2[0] = j;
				for (int k = 1; k <= b.Length; k++)
				{
					array2[k] = Math.Min(Math.Min(array2[k - 1] + 1, array[k] + 1), array[k - 1] + ((a[j - 1] != b[k - 1]) ? 1 : 0));
				}
				int[] array3 = array;
				array = array2;
				array2 = array3;
			}
			return array[b.Length];
		}
	}
}