Decompiled source of Sam Model v1.0.1

BepInEx/plugins/SamModel.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using ModelReplacement;
using ModelReplacement.AvatarBodyUpdater;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.SceneManagement;

[assembly: AssemblyTitle("SamModel")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("1.0.1.0")]
namespace SamModel;

[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("reagan.sammodel", "Sam Model", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "reagan.sammodel";

	public const string Name = "Sam Model";

	public const string Version = "1.0.1";

	internal static ManualLogSource Log;

	internal static ConfigEntry<string> SuitNames;

	internal static ConfigEntry<string> FitTo;

	internal static ConfigEntry<float> ScaleMultiplier;

	internal static ConfigEntry<float> HipsOffset;

	internal static ConfigEntry<float> MaxSmoothness;

	internal static ConfigEntry<bool> CompressTextures;

	internal static ConfigEntry<bool> GenerateViewModel;

	private static bool started;

	private static int attempts;

	private void Awake()
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		SuitNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SuitNames", "Sam", "Comma separated suit names that turn the wearer into Sam.");
		FitTo = ((BaseUnityPlugin)this).Config.Bind<string>("Model", "FitTo", "Arms", new ConfigDescription("What the automatic size is matched to. Arms: the hands land on the player's hands (about as tall as a vanilla player). Legs: the legs are as long as the player's (smaller, hands fall short).", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Arms", "Legs" }), new object[0]));
		ScaleMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "ScaleMultiplier", 1f, "Extra scale on top of the automatic size.");
		HipsOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "HipsOffset", 0f, "Raises (positive) or lowers the model, in game units; a player is about 2.6 units tall. The soles are put on the floor automatically, use this only to fine-tune.");
		MaxSmoothness = ((BaseUnityPlugin)this).Config.Bind<float>("Model", "MaxSmoothness", 0.75f, "Upper limit of surface smoothness. Lower it if the gear looks too shiny.");
		CompressTextures = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance", "CompressTextures", true, "Compress textures on load. Uses about a quarter of the video memory; loading takes a little longer.");
		GenerateViewModel = ((BaseUnityPlugin)this).Config.Bind<bool>("Model", "GenerateViewModel", false, "Let ModelReplacementAPI build first person arms from the model instead of showing the vanilla arms.");
		SamAssets.Directory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		EnsureSuitTexture(SamAssets.Directory);
		SceneManager.sceneLoaded += OnSceneLoaded;
	}

	private static void EnsureSuitTexture(string directory)
	{
		try
		{
			string[] files = Directory.GetFiles(directory, "Sam.png", SearchOption.AllDirectories);
			string[] array = files;
			foreach (string path in array)
			{
				string fileName = Path.GetFileName(Path.GetDirectoryName(path));
				if (string.Equals(fileName, "moresuits", StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			if (files.Length == 0)
			{
				Log.LogWarning((object)"Sam.png (the suit texture for More Suits) is missing; the suit will not appear on the rack.");
				return;
			}
			string text = Path.Combine(directory, "moresuits");
			Directory.CreateDirectory(text);
			File.Copy(files[0], Path.Combine(text, "Sam.png"), overwrite: true);
			File.Delete(files[0]);
			Log.LogInfo((object)("Moved Sam.png into " + text + "."));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not place Sam.png into a moresuits folder: " + ex.Message));
		}
	}

	private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		if (started)
		{
			return;
		}
		if ((Object)(object)Shader.Find("HDRP/Lit") == (Object)null && ++attempts < 4)
		{
			Log.LogInfo((object)("Render pipeline not ready in scene '" + ((Scene)(ref scene)).name + "', building the model on the next scene."));
			return;
		}
		started = true;
		SceneManager.sceneLoaded -= OnSceneLoaded;
		try
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			SamAssets.Build();
			string[] array = SuitNames.Value.Split(',');
			foreach (string text in array)
			{
				string text2 = text.Trim();
				if (text2.Length > 0)
				{
					ModelReplacementAPI.RegisterSuitModelReplacement(text2, typeof(SamReplacement));
					Log.LogInfo((object)("Suit '" + text2 + "' now wears the Sam model."));
				}
			}
			Log.LogInfo((object)("Sam model ready in " + (Time.realtimeSinceStartup - realtimeSinceStartup).ToString("0.0") + " s."));
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Sam model could not be built, the suit will look like a normal suit.\n" + ex));
		}
	}
}
public class SamReplacement : BodyReplacementBase
{
	private static bool apiScaleUnusable;

	private bool scaleReported;

	protected override GameObject LoadAssetsAndReturnModel()
	{
		return SamAssets.GetTemplate(((BodyReplacementBase)this).controller);
	}

	protected override void AddModelScripts()
	{
		EnforceScale(base.replacementModel);
	}

	public override void LateUpdate()
	{
		((BodyReplacementBase)this).LateUpdate();
		if (apiScaleUnusable && (Object)(object)base.replacementDeadBody != (Object)null)
		{
			EnforceScale(base.replacementDeadBody);
		}
	}

	private void EnforceScale(GameObject model)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)model == (Object)null)
		{
			return;
		}
		float scale = SamAssets.GetScale(((BodyReplacementBase)this).controller);
		Vector3 localScale = model.transform.localScale;
		bool flag = !float.IsNaN(localScale.x) && !float.IsInfinity(localScale.x) && localScale.x > 0f;
		if (!flag)
		{
			apiScaleUnusable = true;
		}
		if (!flag || Mathf.Abs(localScale.x - scale) > 0.01f * scale || Mathf.Abs(localScale.y - scale) > 0.01f * scale || Mathf.Abs(localScale.z - scale) > 0.01f * scale)
		{
			if (!scaleReported)
			{
				scaleReported = true;
				Plugin.Log.LogInfo((object)("API scale was " + localScale.x.ToString("0.000") + ", using " + scale.ToString("0.000") + "."));
			}
			model.transform.localScale = new Vector3(scale, scale, scale);
		}
	}
}
internal static class SamAssets
{
	private class BoneInfo
	{
		public string Name;

		public string Driver;

		public int Parent;

		public int Human;

		public Vector3 Position;

		public Quaternion Rotation;
	}

	private const string ModelFile = "sam_model.bin";

	private const float GameHipsPerLeg = 1.1868f;

	private const float GameShoulderPerLeg = 1.8379f;

	internal static string Directory;

	private static GameObject template;

	private static SkinnedMeshRenderer body;

	private static OffsetBuilder offsets;

	private static Bounds meshBounds;

	private static Quaternion hipsRest = Quaternion.identity;

	private static float modelLeg;

	private static float modelArm;

	private static float modelHipsHeight;

	private static float modelShoulderHeight;

	private static float gameLeg = -1f;

	private static float gameArm = -1f;

	private static float gameHipsScale = 1f;

	internal static GameObject GetTemplate(PlayerControllerB player)
	{
		//IL_0011: 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_0026: Unknown result type (might be due to invalid IL or missing references)
		float scale = GetScale(player);
		template.transform.localScale = Vector3.one;
		offsets.rootPositionOffset = GetHipsOffset(scale);
		offsets.GenerateViewModel = Plugin.GenerateViewModel.Value;
		return template;
	}

	internal static float GetScale(PlayerControllerB player)
	{
		Measure(player);
		float num = ((gameLeg > 0f) ? (gameLeg / modelLeg) : 1.23f);
		float num2 = num;
		if (gameLeg > 0f && gameArm > 0f && !string.Equals(Plugin.FitTo.Value, "Legs", StringComparison.OrdinalIgnoreCase))
		{
			float num3 = gameArm / modelArm;
			float num4 = 1.8379f * gameLeg / modelShoulderHeight;
			num2 = 0.5f * (num3 + num4);
		}
		return num2 * Mathf.Clamp(Plugin.ScaleMultiplier.Value, 0.2f, 5f);
	}

	private static Vector3 GetHipsOffset(float scale)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		float num = Plugin.HipsOffset.Value;
		if (gameLeg > 0f)
		{
			num += scale * modelHipsHeight - 1.1868f * gameLeg;
		}
		return Quaternion.Inverse(hipsRest) * Vector3.up * (num / gameHipsScale);
	}

	private static void Measure(PlayerControllerB player)
	{
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Unknown result type (might be due to invalid IL or missing references)
		if (gameLeg > 0f || (Object)(object)player == (Object)null || (Object)(object)player.thisPlayerModel == (Object)null)
		{
			return;
		}
		Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>();
		Transform[] bones = player.thisPlayerModel.bones;
		foreach (Transform val in bones)
		{
			if ((Object)(object)val != (Object)null)
			{
				dictionary[((Object)val).name] = val;
			}
		}
		if (!dictionary.TryGetValue("thigh.L", out var value) || !dictionary.TryGetValue("shin.L", out var value2) || !dictionary.TryGetValue("foot.L", out var value3) || !dictionary.TryGetValue("arm.L_upper", out var value4) || !dictionary.TryGetValue("arm.L_lower", out var value5) || !dictionary.TryGetValue("hand.L", out var value6) || !dictionary.TryGetValue("spine", out var value7))
		{
			Plugin.Log.LogWarning((object)"The player rig has unexpected bone names; using the default size.");
			return;
		}
		gameLeg = Vector3.Distance(value.position, value2.position) + Vector3.Distance(value2.position, value3.position);
		gameArm = Vector3.Distance(value4.position, value5.position) + Vector3.Distance(value5.position, value6.position);
		gameHipsScale = Mathf.Max(value7.lossyScale.y, 0.0001f);
		float scale = GetScale(null);
		ManualLogSource log = Plugin.Log;
		string[] array = new string[15]
		{
			"Player leg ",
			gameLeg.ToString("0.000"),
			", arm ",
			gameArm.ToString("0.000"),
			"; model leg ",
			modelLeg.ToString("0.000"),
			", arm ",
			modelArm.ToString("0.000"),
			"; fit '",
			Plugin.FitTo.Value,
			"' gives scale ",
			scale.ToString("0.000"),
			", hips offset ",
			null,
			null
		};
		Vector3 hipsOffset = GetHipsOffset(scale);
		array[13] = ((Vector3)(ref hipsOffset)).ToString("0.000");
		array[14] = ".";
		log.LogInfo((object)string.Concat(array));
	}

	internal static void Build()
	{
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: 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_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: 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_020c: 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_0299: Unknown result type (might be due to invalid IL or missing references)
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Expected O, but got Unknown
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_0342: 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_0375: Expected O, but got Unknown
		//IL_040c: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0433: Unknown result type (might be due to invalid IL or missing references)
		//IL_0444: Unknown result type (might be due to invalid IL or missing references)
		//IL_0460: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Unknown result type (might be due to invalid IL or missing references)
		//IL_0487: Unknown result type (might be due to invalid IL or missing references)
		//IL_0498: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ca: Expected O, but got Unknown
		//IL_04de: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e5: Expected O, but got Unknown
		//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0538: Unknown result type (might be due to invalid IL or missing references)
		//IL_0544: Unknown result type (might be due to invalid IL or missing references)
		//IL_0549: Unknown result type (might be due to invalid IL or missing references)
		//IL_054e: 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_062a: Unknown result type (might be due to invalid IL or missing references)
		//IL_063b: Unknown result type (might be due to invalid IL or missing references)
		//IL_064a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0666: Unknown result type (might be due to invalid IL or missing references)
		//IL_0675: Unknown result type (might be due to invalid IL or missing references)
		//IL_0750: Unknown result type (might be due to invalid IL or missing references)
		//IL_077c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0792: Unknown result type (might be due to invalid IL or missing references)
		//IL_080b: Unknown result type (might be due to invalid IL or missing references)
		//IL_088b: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_07f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_08eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_08f2: Expected O, but got Unknown
		//IL_09d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_09dd: Unknown result type (might be due to invalid IL or missing references)
		string text = Find("sam_model.bin");
		if (text == null)
		{
			throw new FileNotFoundException("sam_model.bin not found under " + Directory);
		}
		BoneInfo[] array;
		Vector3[] array7;
		Vector3[] array8;
		Vector2[] array9;
		BoneWeight[] array10;
		string[] array11;
		int[][] array12;
		using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(text)))
		{
			if (new string(binaryReader.ReadChars(4)) != "HGLC" || binaryReader.ReadUInt32() != 1)
			{
				throw new InvalidDataException("unexpected model file header");
			}
			int num = (int)binaryReader.ReadUInt32();
			int num2 = (int)binaryReader.ReadUInt32();
			int num3 = (int)binaryReader.ReadUInt32();
			array = new BoneInfo[num];
			for (int i = 0; i < num; i++)
			{
				BoneInfo boneInfo = new BoneInfo();
				boneInfo.Name = ReadString(binaryReader);
				boneInfo.Driver = ReadString(binaryReader);
				boneInfo.Parent = binaryReader.ReadInt32();
				boneInfo.Human = binaryReader.ReadInt32();
				boneInfo.Position = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
				boneInfo.Rotation = new Quaternion(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
				array[i] = boneInfo;
			}
			float[] array2 = ReadFloats(binaryReader, num2 * 3);
			float[] array3 = ReadFloats(binaryReader, num2 * 3);
			float[] array4 = ReadFloats(binaryReader, num2 * 2);
			byte[] array5 = binaryReader.ReadBytes(num2 * 4);
			float[] array6 = ReadFloats(binaryReader, num2 * 4);
			array7 = (Vector3[])(object)new Vector3[num2];
			array8 = (Vector3[])(object)new Vector3[num2];
			array9 = (Vector2[])(object)new Vector2[num2];
			array10 = (BoneWeight[])(object)new BoneWeight[num2];
			for (int j = 0; j < num2; j++)
			{
				ref Vector3 reference = ref array7[j];
				reference = new Vector3(array2[j * 3], array2[j * 3 + 1], array2[j * 3 + 2]);
				ref Vector3 reference2 = ref array8[j];
				reference2 = new Vector3(array3[j * 3], array3[j * 3 + 1], array3[j * 3 + 2]);
				ref Vector2 reference3 = ref array9[j];
				reference3 = new Vector2(array4[j * 2], array4[j * 2 + 1]);
				BoneWeight val = default(BoneWeight);
				((BoneWeight)(ref val)).boneIndex0 = array5[j * 4];
				((BoneWeight)(ref val)).weight0 = array6[j * 4];
				((BoneWeight)(ref val)).boneIndex1 = array5[j * 4 + 1];
				((BoneWeight)(ref val)).weight1 = array6[j * 4 + 1];
				((BoneWeight)(ref val)).boneIndex2 = array5[j * 4 + 2];
				((BoneWeight)(ref val)).weight2 = array6[j * 4 + 2];
				((BoneWeight)(ref val)).boneIndex3 = array5[j * 4 + 3];
				((BoneWeight)(ref val)).weight3 = array6[j * 4 + 3];
				array10[j] = val;
			}
			array11 = new string[num3];
			array12 = new int[num3][];
			for (int k = 0; k < num3; k++)
			{
				array11[k] = ReadString(binaryReader);
				int num4 = (int)binaryReader.ReadUInt32();
				byte[] array13 = binaryReader.ReadBytes(num4 * 4);
				array12[k] = new int[num4];
				Buffer.BlockCopy(array13, 0, array12[k], 0, array13.Length);
			}
		}
		GameObject val2 = new GameObject("SamModel");
		val2.transform.position = Vector3.zero;
		val2.transform.rotation = Quaternion.identity;
		Transform[] array14 = (Transform[])(object)new Transform[array.Length];
		Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>();
		for (int l = 0; l < array.Length; l++)
		{
			GameObject val3 = new GameObject(array[l].Name);
			val3.transform.SetParent((array[l].Parent < 0) ? val2.transform : array14[array[l].Parent], false);
			val3.transform.position = array[l].Position;
			val3.transform.rotation = array[l].Rotation;
			array14[l] = val3.transform;
			dictionary[array[l].Name] = val3.transform;
		}
		modelLeg = Vector3.Distance(dictionary["LeftUpperLeg"].position, dictionary["LeftLowerLeg"].position) + Vector3.Distance(dictionary["LeftLowerLeg"].position, dictionary["LeftFoot"].position);
		modelArm = Vector3.Distance(dictionary["LeftUpperArm"].position, dictionary["LeftLowerArm"].position) + Vector3.Distance(dictionary["LeftLowerArm"].position, dictionary["LeftHand"].position);
		hipsRest = dictionary["Hips"].rotation;
		GameObject val4 = new GameObject("Body");
		val4.transform.SetParent(val2.transform, false);
		Mesh val5 = new Mesh();
		((Object)val5).name = "Sam";
		val5.indexFormat = (IndexFormat)1;
		val5.vertices = array7;
		val5.normals = array8;
		val5.uv = array9;
		val5.boneWeights = array10;
		Matrix4x4[] array15 = (Matrix4x4[])(object)new Matrix4x4[array.Length];
		for (int m = 0; m < array.Length; m++)
		{
			ref Matrix4x4 reference4 = ref array15[m];
			reference4 = array14[m].worldToLocalMatrix * val4.transform.localToWorldMatrix;
		}
		val5.bindposes = array15;
		List<string> list = new List<string>();
		List<int[]> list2 = new List<int[]>();
		for (int n = 0; n < array11.Length; n++)
		{
			int num5 = array11[n].IndexOf('#');
			if (num5 < 0 || PartEnabled(array11[n].Substring(num5 + 1)))
			{
				list.Add((num5 >= 0) ? array11[n].Substring(0, num5) : array11[n]);
				list2.Add(array12[n]);
			}
		}
		val5.subMeshCount = list2.Count;
		for (int num6 = 0; num6 < list2.Count; num6++)
		{
			val5.SetTriangles(list2[num6], num6, false);
		}
		val5.RecalculateBounds();
		val5.RecalculateTangents();
		meshBounds = val5.bounds;
		modelHipsHeight = dictionary["Hips"].position.y - ((Bounds)(ref meshBounds)).min.y;
		modelShoulderHeight = dictionary["LeftUpperArm"].position.y - ((Bounds)(ref meshBounds)).min.y;
		Material[] array16 = (Material[])(object)new Material[list.Count];
		Shader val6 = Shader.Find("HDRP/Lit");
		if ((Object)(object)val6 == (Object)null)
		{
			throw new InvalidOperationException("shader HDRP/Lit is not available");
		}
		Dictionary<string, Material> dictionary2 = new Dictionary<string, Material>();
		for (int num7 = 0; num7 < list.Count; num7++)
		{
			if (!dictionary2.TryGetValue(list[num7], out var value))
			{
				value = BuildMaterial(val6, list[num7]);
				dictionary2[list[num7]] = value;
			}
			array16[num7] = value;
		}
		body = val4.AddComponent<SkinnedMeshRenderer>();
		body.sharedMesh = val5;
		body.bones = array14;
		body.rootBone = null;
		((Renderer)body).sharedMaterials = array16;
		((Renderer)body).localBounds = meshBounds;
		body.quality = (SkinQuality)4;
		List<HumanBone> list3 = new List<HumanBone>();
		List<SkeletonBone> list4 = new List<SkeletonBone>();
		list4.Add(ToSkeletonBone(val2.transform));
		for (int num8 = 0; num8 < array.Length; num8++)
		{
			list4.Add(ToSkeletonBone(array14[num8]));
			if (array[num8].Human >= 0 && array[num8].Human < HumanTrait.BoneCount)
			{
				HumanBone item = default(HumanBone);
				((HumanBone)(ref item)).boneName = array[num8].Name;
				((HumanBone)(ref item)).humanName = HumanTrait.BoneName[array[num8].Human];
				((HumanLimit)(ref item.limit)).useDefaultValues = true;
				list3.Add(item);
			}
		}
		HumanDescription val7 = new HumanDescription
		{
			human = list3.ToArray(),
			skeleton = list4.ToArray()
		};
		((HumanDescription)(ref val7)).upperArmTwist = 0.5f;
		((HumanDescription)(ref val7)).lowerArmTwist = 0.5f;
		((HumanDescription)(ref val7)).upperLegTwist = 0.5f;
		((HumanDescription)(ref val7)).lowerLegTwist = 0.5f;
		((HumanDescription)(ref val7)).armStretch = 0.05f;
		((HumanDescription)(ref val7)).legStretch = 0.05f;
		((HumanDescription)(ref val7)).feetSpacing = 0f;
		((HumanDescription)(ref val7)).hasTranslationDoF = false;
		Avatar val8 = AvatarBuilder.BuildHumanAvatar(val2, val7);
		((Object)val8).name = "SamAvatar";
		if (!val8.isValid || !val8.isHuman)
		{
			Object.Destroy((Object)(object)val2);
			throw new InvalidOperationException("the humanoid avatar is not valid (see the Unity log above for the bone it rejects)");
		}
		Animator val9 = val2.AddComponent<Animator>();
		val9.avatar = val8;
		val9.applyRootMotion = false;
		val9.cullingMode = (AnimatorCullingMode)0;
		GameObject val10 = new GameObject("ItemHolder");
		val10.transform.SetParent(dictionary["RightHand"], false);
		offsets = val2.AddComponent<OffsetBuilder>();
		offsets.itemHolder = val10;
		int num9 = 0;
		BoneInfo[] array17 = array;
		foreach (BoneInfo boneInfo2 in array17)
		{
			if (boneInfo2.Driver.Length > 0 && (Object)(object)val9.GetBoneTransform((HumanBodyBones)boneInfo2.Human) == (Object)(object)dictionary[boneInfo2.Name])
			{
				num9++;
			}
		}
		ManualLogSource log = Plugin.Log;
		object[] array18 = new object[9] { "Built Sam: ", array7.Length, " vertices, ", array.Length, " bones, ", num9, " of them driven by the player rig, bounds ", null, null };
		Vector3 size = ((Bounds)(ref meshBounds)).size;
		array18[7] = ((Vector3)(ref size)).ToString("0.00");
		array18[8] = ".";
		log.LogInfo((object)string.Concat(array18));
		Object.DontDestroyOnLoad((Object)(object)val2);
		val2.SetActive(false);
		template = val2;
	}

	private static SkeletonBone ToSkeletonBone(Transform t)
	{
		//IL_0002: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		return new SkeletonBone
		{
			name = ((Object)t).name,
			position = t.localPosition,
			rotation = t.localRotation,
			scale = t.localScale
		};
	}

	private static bool PartEnabled(string part)
	{
		return true;
	}

	private static Material BuildMaterial(Shader lit, string set)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Invalid comparison between Unknown and I4
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Invalid comparison between Unknown and I4
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_019e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		Material val = new Material(lit);
		((Object)val).name = "Sam_" + set;
		val.SetColor("_BaseColor", Color.white);
		Texture2D val2 = LoadImage("sam_" + set + "_bc", linear: false);
		bool flag = false;
		if ((Object)(object)val2 != (Object)null)
		{
			flag = (int)val2.format == 4 || (int)val2.format == 5;
			Finish(val2, alreadyApplied: true);
			val.SetTexture("_BaseColorMap", (Texture)(object)val2);
		}
		Texture2D val3 = LoadImage("sam_" + set + "_n", linear: true);
		if ((Object)(object)val3 != (Object)null)
		{
			Color32[] pixels = val3.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				ref Color32 reference = ref pixels[i];
				reference = new Color32(byte.MaxValue, pixels[i].g, byte.MaxValue, pixels[i].r);
			}
			Texture2D val4 = FromPixels(val3, pixels, "sam_" + set + "_n");
			val.SetTexture("_NormalMap", (Texture)(object)val4);
			val.SetFloat("_NormalScale", 1f);
			val.EnableKeyword("_NORMALMAP");
			val.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
		}
		Texture2D val5 = LoadImage("sam_" + set + "_agm", linear: true);
		if ((Object)(object)val5 != (Object)null)
		{
			Color32[] pixels2 = val5.GetPixels32();
			for (int j = 0; j < pixels2.Length; j++)
			{
				ref Color32 reference2 = ref pixels2[j];
				reference2 = new Color32(pixels2[j].b, pixels2[j].r, (byte)0, pixels2[j].g);
			}
			Texture2D val6 = FromPixels(val5, pixels2, "sam_" + set + "_mask");
			val.SetTexture("_MaskMap", (Texture)(object)val6);
			val.EnableKeyword("_MASKMAP");
			val.SetFloat("_Metallic", 1f);
			val.SetFloat("_MetallicRemapMin", 0f);
			val.SetFloat("_MetallicRemapMax", 1f);
			val.SetFloat("_AORemapMin", 0f);
			val.SetFloat("_AORemapMax", 1f);
			val.SetFloat("_SmoothnessRemapMin", 0f);
			val.SetFloat("_SmoothnessRemapMax", Mathf.Clamp01(Plugin.MaxSmoothness.Value));
		}
		else
		{
			val.SetFloat("_Metallic", 0f);
			val.SetFloat("_Smoothness", 0.3f);
		}
		if (flag)
		{
			val.SetFloat("_AlphaCutoffEnable", 1f);
			val.SetFloat("_AlphaCutoff", 0.33f);
			val.SetFloat("_DoubleSidedEnable", 1f);
			val.SetFloat("_CullMode", 0f);
			val.SetFloat("_CullModeForward", 0f);
			val.EnableKeyword("_ALPHATEST_ON");
			val.EnableKeyword("_DOUBLESIDED_ON");
			val.renderQueue = 2450;
		}
		try
		{
			Validate(val);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("HDRP material validation is unavailable (" + ex.GetType().Name + "); keywords set by hand."));
		}
		return val;
	}

	private static void Validate(Material m)
	{
		HDMaterial.ValidateMaterial(m);
	}

	private static string FindImage(string name)
	{
		string text = Find(name + ".png");
		if (text == null)
		{
			return Find(name + ".jpg");
		}
		return text;
	}

	private static Texture2D LoadImage(string name, bool linear)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		string text = FindImage(name);
		if (text == null)
		{
			Plugin.Log.LogWarning((object)("Texture " + name + " is missing."));
			return null;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear);
		if (!ImageConversion.LoadImage(val, File.ReadAllBytes(text), false))
		{
			Plugin.Log.LogWarning((object)("Texture " + text + " could not be decoded."));
			Object.Destroy((Object)(object)val);
			return null;
		}
		((Object)val).name = name;
		return val;
	}

	private static Texture2D FromPixels(Texture2D source, Color32[] pixels, string name)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		Texture2D val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, true, true);
		((Object)val).name = name;
		val.SetPixels32(pixels);
		val.Apply(true, false);
		Object.Destroy((Object)(object)source);
		Finish(val, alreadyApplied: false);
		return val;
	}

	private static void Finish(Texture2D tex, bool alreadyApplied)
	{
		((Texture)tex).wrapMode = (TextureWrapMode)1;
		((Texture)tex).filterMode = (FilterMode)2;
		((Texture)tex).anisoLevel = 4;
		if (Plugin.CompressTextures.Value && ((Texture)tex).width % 4 == 0 && ((Texture)tex).height % 4 == 0)
		{
			tex.Compress(true);
		}
		tex.Apply(false, true);
	}

	private static string Find(string fileName)
	{
		string text = Path.Combine(Directory, fileName);
		if (File.Exists(text))
		{
			return text;
		}
		string text2 = Path.Combine(Path.Combine(Directory, "sam"), fileName);
		if (File.Exists(text2))
		{
			return text2;
		}
		string[] files = System.IO.Directory.GetFiles(Directory, fileName, SearchOption.AllDirectories);
		if (files.Length <= 0)
		{
			return null;
		}
		return files[0];
	}

	private static string ReadString(BinaryReader r)
	{
		int count = r.ReadUInt16();
		return Encoding.UTF8.GetString(r.ReadBytes(count));
	}

	private static float[] ReadFloats(BinaryReader r, int count)
	{
		byte[] array = r.ReadBytes(count * 4);
		if (array.Length != count * 4)
		{
			throw new EndOfStreamException("model file is truncated");
		}
		float[] array2 = new float[count];
		Buffer.BlockCopy(array, 0, array2, 0, array.Length);
		return array2;
	}
}