Decompiled source of StitchEyelessDog v1.1.0

BepInEx/plugins/StitchEyelessDog/StitchDog.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[BepInPlugin("local.stitcheyelessdog", "Stitch Eyeless Dog", "1.1.0")]
public sealed class StitchDog : BaseUnityPlugin
{
	private const string Id = "local.stitcheyelessdog";

	private static StitchDog instance;

	private static readonly int BaseMap = Shader.PropertyToID("_BaseColorMap");

	private Texture2D skin;

	private Texture2D detailsTexture;

	private Texture2D detailsMask;

	private StitchDetails details;

	private Material detailsMaterial;

	private bool reported;

	private string directory;

	private bool useDetails;

	private Texture2D fallback;

	private Texture2D bodyMask;

	private StitchDetails body0;

	private StitchDetails body1;

	private Material bodyMaterial;

	private Material toothMaterial;

	private bool correctNormals;

	private void LoadBodyAssets()
	{
		fallback = LoadPng(Path.Combine(directory, "StitchFallback.png"));
		bodyMask = LoadPng(Path.Combine(directory, "StitchMask.png"));
		body0 = StitchDetails.Load(Path.Combine(directory, "StitchBody0.mesh"));
		body1 = StitchDetails.Load(Path.Combine(directory, "StitchBody1.mesh"));
		((Object)body0.Mesh).name = "Stitch_Body_LOD0";
		((Object)body1.Mesh).name = "Stitch_Body_LOD1";
	}

	private void Awake()
	{
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Expected O, but got Unknown
		directory = Path.GetDirectoryName(typeof(StitchDog).Assembly.Location);
		try
		{
			skin = LoadPng(Path.Combine(directory, "Stitch.png"));
			correctNormals = ((BaseUnityPlugin)this).Config.Bind<bool>("Appearance", "CorrectSkinnedNormals", true, "Keep lighting normals aligned with the visible deformed mesh; does not change its geometry or animation.").Value;
			LoadBodyAssets();
			useDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("Appearance", "UseTerrierDetails", true, "Add small cosmetic folded ears and eye caps to the original dog rig.").Value;
			if (useDetails)
			{
				try
				{
					detailsTexture = LoadPng(Path.Combine(directory, "StitchDetails.png"));
					detailsMask = LoadPng(Path.Combine(directory, "StitchDetailsMask.png"));
					details = StitchDetails.Load(Path.Combine(directory, "Stitch.details"));
				}
				catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Using the fur texture without optional terrier details: " + ex.Message));
				}
			}
			instance = this;
			new Harmony("local.stitcheyelessdog").Patch((MethodBase)AccessTools.DeclaredMethod(typeof(MouthDogAI), "Start", Type.EmptyTypes, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(StitchDog), "AfterDogStart", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded Stitch.png; original AI, audio, animation controller and colliders are retained.");
		}
		catch (Exception ex2) when (ex2 is IOException || ex2 is UnauthorizedAccessException || ex2 is ArgumentException)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not load the Stitch skin. The original dog will be used. " + ex2.Message));
		}
	}

	private static Texture2D LoadPng(string path)
	{
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Expected O, but got Unknown
		byte[] array;
		using (FileStream fileStream = File.OpenRead(path))
		{
			if (fileStream.Length < 33 || fileStream.Length > 33554432)
			{
				throw new InvalidDataException("PNG file size is invalid: " + Path.GetFileName(path));
			}
			using BinaryReader binaryReader = new BinaryReader(fileStream);
			array = binaryReader.ReadBytes((int)fileStream.Length);
		}
		byte[] array2 = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };
		for (int i = 0; i < array2.Length; i++)
		{
			if (array[i] != array2[i])
			{
				throw new InvalidDataException("Invalid PNG signature.");
			}
		}
		uint num = BigEndianUInt(array, 16);
		uint num2 = BigEndianUInt(array, 20);
		if (BigEndianUInt(array, 8) != 13 || BigEndianUInt(array, 12) != 1229472850 || num == 0 || num2 == 0 || num > 4096 || num2 > 4096)
		{
			throw new InvalidDataException("Use a PNG with dimensions up to 4096 x 4096.");
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, false);
		if (!ImageConversion.LoadImage(val, array, true))
		{
			Object.Destroy((Object)(object)val);
			throw new InvalidDataException("Unity could not decode the PNG.");
		}
		((Object)val).name = Path.GetFileNameWithoutExtension(path);
		((Texture)val).filterMode = (FilterMode)2;
		((Texture)val).wrapMode = (TextureWrapMode)1;
		return val;
	}

	private static uint BigEndianUInt(byte[] data, int offset)
	{
		return (uint)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]);
	}

	public static void ReloadForPreview()
	{
		if (Object.FindObjectsOfType<MouthDogAI>().Length != 0 || ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.connectedPlayersAmount != 0))
		{
			throw new InvalidOperationException("Preview reload requires no live dogs and no connected peers.");
		}
		StitchDog stitchDog = instance;
		Texture2D val = LoadPng(Path.Combine(stitchDog.directory, "Stitch.png"));
		Texture2D val2 = null;
		Texture2D val3 = null;
		StitchDetails stitchDetails = null;
		try
		{
			if (stitchDog.useDetails)
			{
				val2 = LoadPng(Path.Combine(stitchDog.directory, "StitchDetails.png"));
				val3 = LoadPng(Path.Combine(stitchDog.directory, "StitchDetailsMask.png"));
				stitchDetails = StitchDetails.Load(Path.Combine(stitchDog.directory, "Stitch.details"));
			}
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)val2);
			}
			if ((Object)(object)val3 != (Object)null)
			{
				Object.Destroy((Object)(object)val3);
			}
			throw;
		}
		Object.Destroy((Object)(object)stitchDog.skin);
		if ((Object)(object)stitchDog.detailsTexture != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.detailsTexture);
		}
		if ((Object)(object)stitchDog.detailsMask != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.detailsMask);
		}
		if ((Object)(object)stitchDog.detailsMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.detailsMaterial);
		}
		if (stitchDog.details != null)
		{
			stitchDog.details.Release();
		}
		if (stitchDog.body0 != null)
		{
			stitchDog.body0.Release();
		}
		if (stitchDog.body1 != null)
		{
			stitchDog.body1.Release();
		}
		if ((Object)(object)stitchDog.fallback != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.fallback);
		}
		if ((Object)(object)stitchDog.bodyMask != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.bodyMask);
		}
		if ((Object)(object)stitchDog.bodyMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)stitchDog.bodyMaterial);
		}
		stitchDog.skin = val;
		stitchDog.detailsTexture = val2;
		stitchDog.detailsMask = val3;
		stitchDog.details = stitchDetails;
		stitchDog.detailsMaterial = null;
		stitchDog.bodyMaterial = null;
		stitchDog.LoadBodyAssets();
	}

	private static void AfterDogStart(MouthDogAI __instance)
	{
		try
		{
			ApplyTo(((Component)__instance).gameObject);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)instance).Logger.LogWarning((object)("Stitch appearance could not be applied: " + ex));
		}
	}

	public static void ApplyTo(GameObject root)
	{
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fd: Expected O, but got Unknown
		//IL_043a: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Expected O, but got Unknown
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Expected O, but got Unknown
		//IL_015c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_029a: Expected O, but got Unknown
		//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
		StitchDog stitchDog = instance;
		if ((Object)(object)stitchDog == (Object)null || (Object)(object)stitchDog.skin == (Object)null || (Object)(object)root.GetComponent<StitchDogApplied>() != (Object)null)
		{
			return;
		}
		int num = 0;
		Dictionary<Renderer, Renderer> dictionary = new Dictionary<Renderer, Renderer>();
		SkinnedMeshRenderer[] componentsInChildren = root.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			Mesh sharedMesh = val.sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null || (((Object)sharedMesh).name != "ToothDogBody" && ((Object)sharedMesh).name != "ToothDogBodyLOD1"))
			{
				continue;
			}
			Material sharedMaterial = ((Renderer)val).sharedMaterial;
			if ((Object)(object)sharedMaterial == (Object)null || !sharedMaterial.HasProperty(BaseMap))
			{
				continue;
			}
			StitchDetails stitchDetails = ((((Object)sharedMesh).name == "ToothDogBody") ? stitchDog.body0 : stitchDog.body1);
			bool flag = stitchDetails?.Matches(val) ?? false;
			if (flag)
			{
				val.sharedMesh = stitchDetails.Mesh;
				if ((Object)(object)stitchDog.bodyMaterial == (Object)null)
				{
					Material val2 = new Material(sharedMaterial)
					{
						name = "Stitch_OriginalShapeFur"
					};
					val2.SetTexture(BaseMap, (Texture)(object)stitchDog.skin);
					val2.SetTexture("_MainTex", (Texture)(object)stitchDog.skin);
					val2.SetTexture("_MaskMap", (Texture)(object)stitchDog.bodyMask);
					val2.SetColor("_BaseColor", Color.white);
					val2.SetFloat("_Metallic", 0f);
					val2.SetFloat("_MetallicRemapMin", 0f);
					val2.SetFloat("_MetallicRemapMax", 0f);
					val2.SetFloat("_SmoothnessRemapMin", 0f);
					val2.SetFloat("_SmoothnessRemapMax", 1f);
					val2.EnableKeyword("_MASKMAP");
					HDMaterial.ValidateMaterial(val2);
					stitchDog.bodyMaterial = val2;
				}
				((Renderer)val).sharedMaterial = stitchDog.bodyMaterial;
				if (stitchDog.correctNormals)
				{
					((Component)val).gameObject.AddComponent<StitchNormals>().Initialize(val);
				}
			}
			MaterialPropertyBlock val3 = new MaterialPropertyBlock();
			((Renderer)val).GetPropertyBlock(val3);
			val3.SetTexture(BaseMap, (Texture)(object)(flag ? stitchDog.skin : stitchDog.fallback));
			val3.SetTexture("_MainTex", (Texture)(object)(flag ? stitchDog.skin : stitchDog.fallback));
			((Renderer)val).SetPropertyBlock(val3);
			num++;
			if (stitchDog.details != null && stitchDog.details.Matches(val))
			{
				if ((Object)(object)stitchDog.detailsMaterial == (Object)null)
				{
					Material val4 = new Material(sharedMaterial)
					{
						name = "Stitch_TerrierDetails"
					};
					val4.SetTexture(BaseMap, (Texture)(object)stitchDog.detailsTexture);
					val4.SetTexture("_MainTex", (Texture)(object)stitchDog.detailsTexture);
					val4.SetTexture("_MaskMap", (Texture)(object)stitchDog.detailsMask);
					val4.SetColor("_BaseColor", Color.white);
					val4.SetColor("_EmissiveColor", Color.black);
					val4.SetFloat("_Metallic", 0f);
					val4.SetFloat("_MetallicRemapMin", 0f);
					val4.SetFloat("_MetallicRemapMax", 0f);
					val4.SetFloat("_SmoothnessRemapMin", 0f);
					val4.SetFloat("_SmoothnessRemapMax", 1f);
					val4.EnableKeyword("_MASKMAP");
					HDMaterial.ValidateMaterial(val4);
					stitchDog.detailsMaterial = val4;
				}
				dictionary.Add((Renderer)(object)val, (Renderer)(object)stitchDog.details.Attach(val, stitchDog.detailsMaterial));
			}
		}
		if (num == 0)
		{
			return;
		}
		MeshRenderer[] componentsInChildren2 = root.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val5 in componentsInChildren2)
		{
			if (!(((Object)val5).name != "TeethTop") || !(((Object)val5).name != "TeethBottom"))
			{
				if ((Object)(object)stitchDog.toothMaterial == (Object)null)
				{
					Material val6 = new Material(((Renderer)val5).sharedMaterial)
					{
						name = "Stitch_CleanIvoryTeeth"
					};
					val6.SetTexture(BaseMap, (Texture)(object)Texture2D.whiteTexture);
					val6.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture);
					val6.SetColor("_BaseColor", new Color(0.8f, 0.76f, 0.64f, 1f));
					val6.SetFloat("_Smoothness", 0.24f);
					val6.SetFloat("_Metallic", 0f);
					HDMaterial.ValidateMaterial(val6);
					stitchDog.toothMaterial = val6;
				}
				((Renderer)val5).sharedMaterial = stitchDog.toothMaterial;
			}
		}
		LODGroup[] componentsInChildren3 = root.GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val7 in componentsInChildren3)
		{
			LOD[] lODs = val7.GetLODs();
			for (int j = 0; j < lODs.Length; j++)
			{
				List<Renderer> list = new List<Renderer>(lODs[j].renderers);
				Renderer[] renderers = lODs[j].renderers;
				foreach (Renderer val8 in renderers)
				{
					if ((Object)(object)val8 != (Object)null && dictionary.TryGetValue(val8, out var value))
					{
						list.Add(value);
					}
				}
				lODs[j].renderers = list.ToArray();
			}
			val7.SetLODs(lODs);
		}
		root.AddComponent<StitchDogApplied>();
		if (!stitchDog.reported)
		{
			stitchDog.reported = true;
			((BaseUnityPlugin)stitchDog).Logger.LogInfo((object)$"Applied Stitch to {num} stock LOD(s), with {dictionary.Count} matching cosmetic detail renderer(s).");
		}
	}
}
public sealed class StitchDogApplied : MonoBehaviour
{
}
internal sealed class StitchDetails
{
	private string[] names;

	private Mesh mesh;

	internal Mesh Mesh => mesh;

	internal void Release()
	{
		Object.Destroy((Object)(object)mesh);
	}

	private static float Finite(BinaryReader reader)
	{
		float num = reader.ReadSingle();
		if (float.IsNaN(num) || float.IsInfinity(num))
		{
			throw new InvalidDataException("Non-finite detail coordinate.");
		}
		return num;
	}

	internal static StitchDetails Load(string path)
	{
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: 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_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01db: Unknown result type (might be due to invalid IL or missing references)
		//IL_040d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0412: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Expected O, but got Unknown
		using FileStream fileStream = File.OpenRead(path);
		using BinaryReader binaryReader = new BinaryReader(fileStream);
		if (fileStream.Length > 16777216 || Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "STITCH01")
		{
			throw new InvalidDataException("Invalid Stitch detail header.");
		}
		int num = binaryReader.ReadInt32();
		int num2 = binaryReader.ReadInt32();
		int num3 = binaryReader.ReadInt32();
		if (num != 22 || num2 < 1 || num2 > 60000 || num3 < 3 || num3 > 300000 || num3 % 3 != 0)
		{
			throw new InvalidDataException("Invalid Stitch detail counts.");
		}
		StitchDetails stitchDetails = new StitchDetails
		{
			names = new string[num]
		};
		for (int i = 0; i < num; i++)
		{
			int num4 = binaryReader.ReadInt32();
			if (num4 < 1 || num4 > 96)
			{
				throw new InvalidDataException("Invalid bone name.");
			}
			byte[] array = binaryReader.ReadBytes(num4);
			if (array.Length != num4)
			{
				throw new EndOfStreamException();
			}
			stitchDetails.names[i] = Encoding.UTF8.GetString(array);
		}
		Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[num];
		for (int j = 0; j < num; j++)
		{
			for (int k = 0; k < 4; k++)
			{
				for (int l = 0; l < 4; l++)
				{
					((Matrix4x4)(ref array2[j]))[k, l] = Finite(binaryReader);
				}
			}
		}
		Vector3[] array3 = (Vector3[])(object)new Vector3[num2];
		Vector3[] array4 = (Vector3[])(object)new Vector3[num2];
		Vector2[] array5 = (Vector2[])(object)new Vector2[num2];
		for (int m = 0; m < num2; m++)
		{
			array3[m] = new Vector3(Finite(binaryReader), Finite(binaryReader), Finite(binaryReader));
		}
		for (int n = 0; n < num2; n++)
		{
			array4[n] = new Vector3(Finite(binaryReader), Finite(binaryReader), Finite(binaryReader));
		}
		for (int num5 = 0; num5 < num2; num5++)
		{
			array5[num5] = new Vector2(Finite(binaryReader), Finite(binaryReader));
		}
		BoneWeight[] array6 = (BoneWeight[])(object)new BoneWeight[num2];
		for (int num6 = 0; num6 < num2; num6++)
		{
			((BoneWeight)(ref array6[num6])).weight0 = Finite(binaryReader);
			((BoneWeight)(ref array6[num6])).weight1 = Finite(binaryReader);
			((BoneWeight)(ref array6[num6])).weight2 = Finite(binaryReader);
			((BoneWeight)(ref array6[num6])).weight3 = Finite(binaryReader);
			float num7 = ((BoneWeight)(ref array6[num6])).weight0 + ((BoneWeight)(ref array6[num6])).weight1 + ((BoneWeight)(ref array6[num6])).weight2 + ((BoneWeight)(ref array6[num6])).weight3;
			if (((BoneWeight)(ref array6[num6])).weight0 < 0f || ((BoneWeight)(ref array6[num6])).weight1 < 0f || ((BoneWeight)(ref array6[num6])).weight2 < 0f || ((BoneWeight)(ref array6[num6])).weight3 < 0f || Mathf.Abs(num7 - 1f) > 0.002f)
			{
				throw new InvalidDataException("Invalid skin weights.");
			}
		}
		for (int num8 = 0; num8 < num2; num8++)
		{
			int num9 = binaryReader.ReadInt32();
			int num10 = binaryReader.ReadInt32();
			int num11 = binaryReader.ReadInt32();
			int num12 = binaryReader.ReadInt32();
			if (num9 < 0 || num9 >= num || num10 < 0 || num10 >= num || num11 < 0 || num11 >= num || num12 < 0 || num12 >= num)
			{
				throw new InvalidDataException("Invalid bone index.");
			}
			((BoneWeight)(ref array6[num8])).boneIndex0 = num9;
			((BoneWeight)(ref array6[num8])).boneIndex1 = num10;
			((BoneWeight)(ref array6[num8])).boneIndex2 = num11;
			((BoneWeight)(ref array6[num8])).boneIndex3 = num12;
		}
		int[] array7 = new int[num3];
		for (int num13 = 0; num13 < num3; num13++)
		{
			array7[num13] = binaryReader.ReadInt32();
			if (array7[num13] < 0 || array7[num13] >= num2)
			{
				throw new InvalidDataException("Invalid triangle index.");
			}
		}
		if (fileStream.Position != fileStream.Length)
		{
			throw new InvalidDataException("Unexpected detail bytes.");
		}
		stitchDetails.mesh = new Mesh
		{
			name = "Stitch_TerrierDetails"
		};
		stitchDetails.mesh.vertices = array3;
		stitchDetails.mesh.normals = array4;
		stitchDetails.mesh.uv = array5;
		stitchDetails.mesh.bindposes = array2;
		stitchDetails.mesh.boneWeights = array6;
		stitchDetails.mesh.triangles = array7;
		stitchDetails.mesh.RecalculateBounds();
		stitchDetails.mesh.RecalculateTangents();
		return stitchDetails;
	}

	internal bool Matches(SkinnedMeshRenderer renderer)
	{
		if (renderer.bones.Length != names.Length)
		{
			return false;
		}
		for (int i = 0; i < names.Length; i++)
		{
			if ((Object)(object)renderer.bones[i] == (Object)null || ((Object)renderer.bones[i]).name != names[i])
			{
				return false;
			}
		}
		return true;
	}

	internal SkinnedMeshRenderer Attach(SkinnedMeshRenderer source, Material material)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: 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_0098: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("Stitch_TerrierDetails");
		val.layer = ((Component)source).gameObject.layer;
		val.transform.SetParent(((Component)source).transform, false);
		SkinnedMeshRenderer obj = val.AddComponent<SkinnedMeshRenderer>();
		obj.sharedMesh = mesh;
		((Renderer)obj).sharedMaterial = material;
		obj.bones = source.bones;
		obj.rootBone = source.rootBone;
		obj.quality = (SkinQuality)4;
		((Renderer)obj).shadowCastingMode = ((Renderer)source).shadowCastingMode;
		((Renderer)obj).receiveShadows = ((Renderer)source).receiveShadows;
		Bounds localBounds = ((Renderer)source).localBounds;
		((Bounds)(ref localBounds)).Encapsulate(mesh.bounds);
		((Renderer)obj).localBounds = localBounds;
		val.AddComponent<StitchDetailVisibility>().Source = source;
		return obj;
	}
}
public sealed class StitchDetailVisibility : MonoBehaviour
{
	public SkinnedMeshRenderer Source;

	private SkinnedMeshRenderer own;

	private void Awake()
	{
		own = ((Component)this).GetComponent<SkinnedMeshRenderer>();
	}

	private void LateUpdate()
	{
		if ((Object)(object)Source == (Object)null)
		{
			((Renderer)own).enabled = false;
			return;
		}
		((Renderer)own).enabled = ((Renderer)Source).enabled;
		((Renderer)own).forceRenderingOff = ((Renderer)Source).forceRenderingOff;
		((Component)this).gameObject.layer = ((Component)Source).gameObject.layer;
	}
}
public sealed class StitchNormals : MonoBehaviour
{
	private struct VertexKey : IEquatable<VertexKey>
	{
		internal Vector3 Position;

		internal BoneWeight Weight;

		public bool Equals(VertexKey other)
		{
			//IL_0007: 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)
			if (((Vector3)(ref Position)).Equals(other.Position))
			{
				return ((BoneWeight)(ref Weight)).Equals(other.Weight);
			}
			return false;
		}

		public override bool Equals(object value)
		{
			if (value is VertexKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((object)Unsafe.As<Vector3, Vector3>(ref Position)/*cast due to .constrained prefix*/).GetHashCode() * 397) ^ ((object)Unsafe.As<BoneWeight, BoneWeight>(ref Weight)/*cast due to .constrained prefix*/).GetHashCode();
		}
	}

	private SkinnedMeshRenderer target;

	private Mesh ownMesh;

	private Vector3[] rest;

	private BoneWeight[] weights;

	private Matrix4x4[] binds;

	private Matrix4x4[] matrices;

	private Vector3[] world;

	private Vector3[] inverse0;

	private Vector3[] inverse1;

	private Vector3[] inverse2;

	private float[] inverseDet;

	private int[] groups;

	private int[] triangles;

	private int[][] neighbours;

	private Vector3[] face;

	private Vector3[] unit;

	private List<Vector3> corrected;

	private float updateAt;

	private Transform[] bones;

	public double LastBuildMilliseconds { get; private set; }

	internal void Initialize(SkinnedMeshRenderer renderer)
	{
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		target = renderer;
		ownMesh = Object.Instantiate<Mesh>(renderer.sharedMesh);
		((Object)ownMesh).name = ((Object)renderer.sharedMesh).name;
		ownMesh.MarkDynamic();
		renderer.sharedMesh = ownMesh;
		Vector3[] vertices = ownMesh.vertices;
		BoneWeight[] boneWeights = ownMesh.boneWeights;
		triangles = ownMesh.triangles;
		binds = ownMesh.bindposes;
		bones = renderer.bones;
		matrices = (Matrix4x4[])(object)new Matrix4x4[binds.Length];
		groups = new int[vertices.Length];
		Dictionary<VertexKey, int> dictionary = new Dictionary<VertexKey, int>();
		List<Vector3> list = new List<Vector3>();
		List<BoneWeight> list2 = new List<BoneWeight>();
		for (int i = 0; i < vertices.Length; i++)
		{
			VertexKey key = new VertexKey
			{
				Position = vertices[i],
				Weight = boneWeights[i]
			};
			if (!dictionary.TryGetValue(key, out var value))
			{
				value = list.Count;
				dictionary.Add(key, value);
				list.Add(vertices[i]);
				list2.Add(boneWeights[i]);
			}
			groups[i] = value;
		}
		rest = list.ToArray();
		weights = list2.ToArray();
		world = (Vector3[])(object)new Vector3[rest.Length];
		inverse0 = (Vector3[])(object)new Vector3[rest.Length];
		inverse1 = (Vector3[])(object)new Vector3[rest.Length];
		inverse2 = (Vector3[])(object)new Vector3[rest.Length];
		inverseDet = new float[rest.Length];
		face = (Vector3[])(object)new Vector3[triangles.Length / 3];
		unit = (Vector3[])(object)new Vector3[face.Length];
		List<int>[] array = new List<int>[rest.Length];
		for (int j = 0; j < array.Length; j++)
		{
			array[j] = new List<int>();
		}
		for (int k = 0; k < face.Length; k++)
		{
			for (int l = 0; l < 3; l++)
			{
				List<int> list3 = array[groups[triangles[k * 3 + l]]];
				if (!list3.Contains(k))
				{
					list3.Add(k);
				}
			}
		}
		neighbours = new int[array.Length][];
		for (int m = 0; m < array.Length; m++)
		{
			neighbours[m] = array[m].ToArray();
		}
		corrected = new List<Vector3>(ownMesh.normals);
		Rebuild();
	}

	private static Vector3 Column(Matrix4x4 matrix, int column)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		Vector4 column2 = ((Matrix4x4)(ref matrix)).GetColumn(column);
		return new Vector3(column2.x, column2.y, column2.z);
	}

	private void LateUpdate()
	{
		if (!((Object)(object)target == (Object)null) && !((Object)(object)ownMesh == (Object)null) && ((Renderer)target).enabled && ((Renderer)target).isVisible && !(Time.unscaledTime < updateAt))
		{
			updateAt = Time.unscaledTime + 1f / 30f;
			Rebuild();
		}
	}

	public void ForceRebuild()
	{
		if ((Object)(object)target != (Object)null && (Object)(object)ownMesh != (Object)null)
		{
			Rebuild();
		}
	}

	private void Rebuild()
	{
		//IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: 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_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_015e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: 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_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_0220: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Unknown result type (might be due to invalid IL or missing references)
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: 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)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_0292: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0322: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_035f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0364: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0370: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Unknown result type (might be due to invalid IL or missing references)
		//IL_0377: Unknown result type (might be due to invalid IL or missing references)
		//IL_0379: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_039f: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ee: 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_041c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0459: Unknown result type (might be due to invalid IL or missing references)
		//IL_045e: Unknown result type (might be due to invalid IL or missing references)
		//IL_046d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0472: Unknown result type (might be due to invalid IL or missing references)
		//IL_0481: Unknown result type (might be due to invalid IL or missing references)
		//IL_0486: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_049b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_042d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0437: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
		long timestamp = Stopwatch.GetTimestamp();
		for (int i = 0; i < matrices.Length; i++)
		{
			if ((Object)(object)bones[i] == (Object)null)
			{
				return;
			}
			matrices[i] = bones[i].localToWorldMatrix * binds[i];
		}
		for (int j = 0; j < rest.Length; j++)
		{
			BoneWeight val = weights[j];
			Matrix4x4 matrix = matrices[((BoneWeight)(ref val)).boneIndex0];
			Matrix4x4 matrix2 = matrices[((BoneWeight)(ref val)).boneIndex1];
			Matrix4x4 matrix3 = matrices[((BoneWeight)(ref val)).boneIndex2];
			Matrix4x4 matrix4 = matrices[((BoneWeight)(ref val)).boneIndex3];
			world[j] = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(rest[j]) * ((BoneWeight)(ref val)).weight0 + ((Matrix4x4)(ref matrix2)).MultiplyPoint3x4(rest[j]) * ((BoneWeight)(ref val)).weight1 + ((Matrix4x4)(ref matrix3)).MultiplyPoint3x4(rest[j]) * ((BoneWeight)(ref val)).weight2 + ((Matrix4x4)(ref matrix4)).MultiplyPoint3x4(rest[j]) * ((BoneWeight)(ref val)).weight3;
			Vector3 val2 = Column(matrix, 0) * ((BoneWeight)(ref val)).weight0 + Column(matrix2, 0) * ((BoneWeight)(ref val)).weight1 + Column(matrix3, 0) * ((BoneWeight)(ref val)).weight2 + Column(matrix4, 0) * ((BoneWeight)(ref val)).weight3;
			Vector3 val3 = Column(matrix, 1) * ((BoneWeight)(ref val)).weight0 + Column(matrix2, 1) * ((BoneWeight)(ref val)).weight1 + Column(matrix3, 1) * ((BoneWeight)(ref val)).weight2 + Column(matrix4, 1) * ((BoneWeight)(ref val)).weight3;
			Vector3 val4 = Column(matrix, 2) * ((BoneWeight)(ref val)).weight0 + Column(matrix2, 2) * ((BoneWeight)(ref val)).weight1 + Column(matrix3, 2) * ((BoneWeight)(ref val)).weight2 + Column(matrix4, 2) * ((BoneWeight)(ref val)).weight3;
			inverse0[j] = Vector3.Cross(val3, val4);
			inverse1[j] = Vector3.Cross(val4, val2);
			inverse2[j] = Vector3.Cross(val2, val3);
			float num = Vector3.Dot(val2, inverse0[j]);
			inverseDet[j] = ((Mathf.Abs(num) > 1E-10f) ? (1f / num) : 0f);
		}
		for (int k = 0; k < face.Length; k++)
		{
			Vector3 val5 = world[groups[triangles[k * 3]]];
			Vector3 val6 = world[groups[triangles[k * 3 + 1]]];
			Vector3 val7 = world[groups[triangles[k * 3 + 2]]];
			face[k] = Vector3.Cross(val6 - val5, val7 - val5);
			unit[k] = ((Vector3)(ref face[k])).normalized;
		}
		for (int l = 0; l < face.Length; l++)
		{
			for (int m = 0; m < 3; m++)
			{
				int num2 = triangles[l * 3 + m];
				int num3 = groups[num2];
				Vector3 val8 = Vector3.zero;
				int[] array = neighbours[num3];
				foreach (int num4 in array)
				{
					if (Vector3.Dot(unit[l], unit[num4]) > 0.35f)
					{
						val8 += face[num4];
					}
				}
				Vector3 val9 = new Vector3(Vector3.Dot(inverse0[num3], val8), Vector3.Dot(inverse1[num3], val8), Vector3.Dot(inverse2[num3], val8)) * inverseDet[num3];
				if (((Vector3)(ref val9)).sqrMagnitude > 1E-12f)
				{
					corrected[num2] = ((Vector3)(ref val9)).normalized;
				}
			}
		}
		ownMesh.SetNormals(corrected);
		LastBuildMilliseconds = (double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency;
	}

	private void OnDestroy()
	{
		if ((Object)(object)ownMesh != (Object)null)
		{
			Object.Destroy((Object)(object)ownMesh);
		}
	}
}