Decompiled source of TetoAndPearto v0.3.0

BepInEx/plugins/RepoTeto/TetoAddon.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RepoTeto;

[BepInPlugin("local.repo.tetoaddon", "R.E.P.O. Teto Addon", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class TetoAddon : BaseUnityPlugin
{
	private const string ExpectedBaseHash = "C5C0DAF063A670313CA7DAD45DF7257DF916F7AA0E2B7D9AE8129E53244F68B5";

	private const string ModelName = "KasaneTeto";

	private const string CacheKey = "repo-teto/kasaneteto.prefab";

	private const int SpeedGrowth = 30;

	private const int PowerGrowth = 30;

	private AssetBundle bundle;

	private RuntimeModelAssets runtimeAssets;

	private static readonly List<Action> pendingRegistrations = new List<Action>();

	private static TetoAddon activeInstance;

	private static int registeredModelId = -1;

	private static int registeredSlotId = -1;

	public static int RegisteredModelId => registeredModelId;

	public static int RegisteredSlotId => registeredSlotId;

	public static void AfterTetoRegistered(Action registerCharacter)
	{
		if (registerCharacter == null)
		{
			throw new ArgumentNullException("registerCharacter");
		}
		if (RegisteredModelId < 0)
		{
			pendingRegistrations.Add(registerCharacter);
		}
		else
		{
			RunRegistration(registerCharacter);
		}
	}

	private static void RunRegistration(Action callback)
	{
		try
		{
			callback();
		}
		catch (Exception ex)
		{
			if ((Object)(object)activeInstance != (Object)null)
			{
				((BaseUnityPlugin)activeInstance).Logger.LogError((object)("Dependent character registration failed: " + ex));
			}
			else
			{
				Debug.LogError((object)("[TetoAddon] Dependent character registration failed: " + ex));
			}
		}
	}

	private void Awake()
	{
		activeInstance = this;
		SceneManager.sceneLoaded += RegisterAfterSceneLoad;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Teto initialization queued for the first loaded scene.");
	}

	private void RegisterAfterSceneLoad(Scene scene, LoadSceneMode mode)
	{
		SceneManager.sceneLoaded -= RegisterAfterSceneLoad;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Preparing Teto after scene load: " + ((Scene)(ref scene)).name));
		try
		{
			RegisterModel();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Teto was not registered: " + ex.ToString()));
		}
		if (Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-self-test") >= 0)
		{
			Application.Quit();
		}
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= RegisterAfterSceneLoad;
	}

	private void RegisterModel()
	{
		if (!Chainloader.PluginInfos.TryGetValue("UmamusumeSemiBots", out var value))
		{
			throw new InvalidOperationException("UmamusumeSemibots is required.");
		}
		Type type = ((object)value.Instance).GetType();
		using (SHA256 sHA = SHA256.Create())
		{
			using FileStream inputStream = File.OpenRead(type.Assembly.Location);
			string a = BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "");
			if (!string.Equals(a, "C5C0DAF063A670313CA7DAD45DF7257DF916F7AA0E2B7D9AE8129E53244F68B5", StringComparison.Ordinal))
			{
				throw new InvalidOperationException("This addon supports the inspected UmamusumeSemibots 2.1.0 DLL only.");
			}
		}
		string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		string text = Path.Combine(directoryName, "tetoassets");
		List<string> list = ReadField<List<string>>(type, "ModelNames");
		List<string> list2 = ReadField<List<string>>(type, "ModelAssetPaths");
		List<Texture2D> list3 = ReadField<List<Texture2D>>(type, "Thumbnails");
		List<Texture2D> list4 = ReadField<List<Texture2D>>(type, "Chibis");
		List<Texture2D> list5 = ReadField<List<Texture2D>>(type, "ChibisTalking");
		List<List<int>> list6 = ReadField<List<List<int>>>(type, "ModelOutfitGroups");
		Dictionary<int, int> dictionary = ReadField<Dictionary<int, int>>(type, "SlotOutfitSelection");
		Dictionary<int, int> dictionary2 = ReadField<Dictionary<int, int>>(type, "ColorToModel");
		Dictionary<string, GameObject> dictionary3 = ReadField<Dictionary<string, GameObject>>(type, "_loadedPrefabs");
		if (list.Contains("KasaneTeto"))
		{
			throw new InvalidOperationException("KasaneTeto is already registered.");
		}
		int count = list.Count;
		if (list2.Count != count || list3.Count != count || list4.Count != count || list5.Count != count)
		{
			throw new InvalidOperationException("Base model lists are not aligned; refusing registration.");
		}
		int count2 = list6.Count;
		if (dictionary.ContainsKey(count2) || dictionary2.ContainsKey(count2) || dictionary3.ContainsKey("repo-teto/kasaneteto.prefab"))
		{
			throw new InvalidOperationException("Model slot/cache collision; refusing registration.");
		}
		Type type2 = type.Assembly.GetType("UmamusumeSemiBots.UmaGrowthRateData", throwOnError: true);
		Type type3 = type.Assembly.GetType("UmamusumeSemiBots.UmaGrowthRates", throwOnError: true);
		IDictionary dictionary4 = ReadField<IDictionary>(type2, "UmaGrowthRateTable");
		if (dictionary4.Contains("KasaneTeto"))
		{
			throw new InvalidOperationException("Teto growth rates already exist; refusing registration.");
		}
		object value2 = Activator.CreateInstance(type3, 30, 0, 30, 0, 0);
		MethodInfo method = type.GetMethod("GetPrefabFlat", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (method == null || count == 0)
		{
			throw new InvalidOperationException("Reference prefab loader is unavailable.");
		}
		object? obj = method.Invoke(null, new object[1] { 0 });
		GameObject val = (GameObject)((obj is GameObject) ? obj : null);
		Animator val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<Animator>());
		if ((Object)(object)val2 == (Object)null || (Object)(object)val2.runtimeAnimatorController == (Object)null)
		{
			throw new InvalidOperationException("Reference animation controller is unavailable.");
		}
		GameObject val3;
		Texture2D val4;
		Texture2D val5;
		Texture2D val6;
		if (File.Exists(text))
		{
			bundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)bundle == (Object)null)
			{
				throw new InvalidOperationException("Could not read tetoassets.");
			}
			val3 = bundle.LoadAsset<GameObject>("KasaneTeto");
			val4 = bundle.LoadAsset<Texture2D>("KasaneTetoThumbnail");
			val5 = bundle.LoadAsset<Texture2D>("KasaneTetoChibi");
			val6 = bundle.LoadAsset<Texture2D>("KasaneTetoChibiTalk");
		}
		else
		{
			string text2 = Path.Combine(directoryName, "assets");
			if (!File.Exists(Path.Combine(text2, "teto.rpm")) || !File.Exists(Path.Combine(text2, "pearto.rpm")))
			{
				throw new FileNotFoundException("Prepared Teto and Pearto data is missing.");
			}
			runtimeAssets = RuntimeModelFactory.Create(text2, val);
			val3 = runtimeAssets.Prefab;
			val4 = runtimeAssets.Thumbnail;
			val5 = runtimeAssets.Chibi;
			val6 = runtimeAssets.ChibiTalk;
		}
		if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null)
		{
			throw new InvalidOperationException("The prefab and portrait textures are required.");
		}
		ValidatePrefab(val3);
		val3.GetComponent<Animator>().runtimeAnimatorController = val2.runtimeAnimatorController;
		((Object)val3).name = "KasaneTeto";
		Type type4 = type.Assembly.GetType("UmamusumeSemiBots.UmaModelCrouchData");
		Dictionary<string, float> dictionary5 = ReadField<Dictionary<string, float>>(type4, "CrouchOffsets");
		if (!dictionary5.TryGetValue(Path.GetFileNameWithoutExtension(list[0]), out var value3))
		{
			throw new InvalidOperationException("Reference model has no calibrated crouch camera distance.");
		}
		dictionary5["KasaneTeto"] = value3;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Teto crouch camera uses reference " + list[0] + ": " + value3));
		dictionary4.Add("KasaneTeto", value2);
		dictionary3.Add("repo-teto/kasaneteto.prefab", val3);
		list.Add("KasaneTeto");
		list2.Add("repo-teto/kasaneteto.prefab");
		list3.Add(val4);
		list4.Add(val5);
		list5.Add(val6);
		list6.Add(new List<int> { count });
		dictionary.Add(count2, 0);
		dictionary2.Add(count2, count);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Kasane Teto registered: slot=" + count2 + ", model=" + count + ". Both players need identical base mod and addon assets."));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Teto growth rates: Speed=+30%, Power=+30%; Stamina/Guts/Wit=0%. Uses the base mod's upgrade multipliers and EnableGrowthRates setting.");
		if (Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-self-test") >= 0)
		{
			ValidateGrowthMultipliers(type);
		}
		registeredModelId = count;
		registeredSlotId = count2;
		Action[] array = pendingRegistrations.ToArray();
		pendingRegistrations.Clear();
		Action[] array2 = array;
		foreach (Action callback in array2)
		{
			RunRegistration(callback);
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Character registration callback ready; pending callbacks processed=" + array.Length));
		MethodInfo method2 = type.GetMethod("LoadSavedModel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (method2 != null)
		{
			try
			{
				method2.Invoke(value.Instance, null);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not restore saved selection: " + ex.Message));
			}
		}
	}

	private static T ReadField<T>(Type type, string name) where T : class
	{
		FieldInfo field = type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		T val = ((field == null) ? null : (field.GetValue(null) as T));
		if (val == null)
		{
			throw new InvalidOperationException("Missing/incompatible base mod field: " + name);
		}
		return val;
	}

	private static void ValidateGrowthMultipliers(Type modType)
	{
		Type nestedType = modType.GetNestedType("PunManagerUpgradePatch", BindingFlags.Public | BindingFlags.NonPublic);
		MethodInfo methodInfo = ((nestedType == null) ? null : nestedType.GetMethod("GetGrowthMultiplier", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
		if (methodInfo == null)
		{
			throw new InvalidOperationException("Original growth multiplier method is unavailable.");
		}
		string[] array = new string[5] { "speed", "strength", "stamina", "health", "range" };
		foreach (string text in array)
		{
			float num = (float)methodInfo.Invoke(null, new object[2] { "KasaneTeto", text });
			float num2 = ((text == "speed" || text == "strength") ? 1.3f : 1f);
			if (!Mathf.Approximately(num, num2))
			{
				throw new InvalidOperationException("Original growth multiplier differs for " + text + ": " + num);
			}
			Debug.Log((object)("[TetoAddon] Original upgrade multiplier verified: " + text + "=" + num));
		}
	}

	private static void ValidatePrefab(GameObject prefab)
	{
		Animator component = prefab.GetComponent<Animator>();
		Transform val = prefab.transform.Find("Body");
		Transform val2 = prefab.transform.Find("Smol");
		if ((Object)(object)component == (Object)null || (Object)(object)component.avatar == (Object)null || !component.avatar.isValid || !component.avatar.isHuman)
		{
			throw new InvalidOperationException("KasaneTeto needs a valid Humanoid Animator on its root.");
		}
		if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).GetComponent<SkinnedMeshRenderer>() == (Object)null)
		{
			throw new InvalidOperationException("KasaneTeto needs a direct Body child with a SkinnedMeshRenderer.");
		}
		if ((Object)(object)prefab.transform.Find("Armature/Hips/Spine/Chest/Neck") == (Object)null)
		{
			throw new InvalidOperationException("Expected Armature/Hips/Spine/Chest/Neck hierarchy is missing.");
		}
		Animator val3 = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).GetComponent<Animator>());
		if ((Object)(object)val3 == (Object)null || (Object)(object)val3.avatar == (Object)null || !val3.avatar.isValid || !val3.avatar.isHuman)
		{
			throw new InvalidOperationException("Smol needs its own valid Humanoid Animator; a static pear alone does not provide the original chibi IK.");
		}
		if ((Object)(object)((Component)val2).GetComponentInChildren<SkinnedMeshRenderer>(true) == (Object)null)
		{
			throw new InvalidOperationException("Smol needs a SkinnedMeshRenderer.");
		}
		if ((Object)(object)val2.Find("SmolEyePosition") == (Object)null)
		{
			throw new InvalidOperationException("Smol/SmolEyePosition anchor is missing.");
		}
	}
}
internal sealed class RuntimeModelAssets
{
	public GameObject Prefab;

	public Texture2D Thumbnail;

	public Texture2D Chibi;

	public Texture2D ChibiTalk;

	public GameObject Storage;
}
internal static class RuntimeModelFactory
{
	private static readonly Dictionary<Texture2D, Texture2D> alphaMasks = new Dictionary<Texture2D, Texture2D>();

	private static int Count(BinaryReader reader, int max)
	{
		int num = reader.ReadInt32();
		if (num < 0 || num > max)
		{
			throw new InvalidDataException("Invalid prepared asset count.");
		}
		return num;
	}

	private static string Text(BinaryReader reader)
	{
		int num = Count(reader, 4096);
		byte[] array = reader.ReadBytes(num);
		if (array.Length != num)
		{
			throw new EndOfStreamException();
		}
		return Encoding.UTF8.GetString(array);
	}

	private static Vector3 Vec(BinaryReader reader)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
	}

	private static Texture2D Texture(string path)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
		if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path), false))
		{
			throw new InvalidDataException("Cannot decode " + Path.GetFileName(path));
		}
		((Object)val).name = Path.GetFileNameWithoutExtension(path);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		return val;
	}

	private static Material Surface(Shader shader, Texture2D texture, Color color, string name)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0227: Unknown result type (might be due to invalid IL or missing references)
		Material val = new Material(shader);
		((Object)val).name = name;
		val.mainTexture = (Texture)(object)texture;
		if (val.HasProperty("_Color"))
		{
			val.SetColor("_Color", color);
		}
		if (val.HasProperty("_Glossiness"))
		{
			val.SetFloat("_Glossiness", 0.12f);
		}
		if (val.HasProperty("_Metallic"))
		{
			val.SetFloat("_Metallic", 0f);
		}
		if (val.HasProperty("_Cull"))
		{
			val.SetInt("_Cull", 0);
		}
		if (val.HasProperty("_ShadowTex"))
		{
			val.SetTexture("_ShadowTex", (Texture)(object)texture);
		}
		if (val.HasProperty("_MinBrightness"))
		{
			val.SetFloat("_MinBrightness", 0.25f);
		}
		if (val.HasProperty("_AmbientStrength"))
		{
			val.SetFloat("_AmbientStrength", 0.35f);
		}
		if (val.HasProperty("_ShadowStrength"))
		{
			val.SetFloat("_ShadowStrength", 0.35f);
		}
		if (val.HasProperty("_BrightnessClamp"))
		{
			val.SetFloat("_BrightnessClamp", 1f);
		}
		if (val.HasProperty("_RimStrength"))
		{
			val.SetFloat("_RimStrength", 0f);
		}
		if (val.HasProperty("_SpecularStrength"))
		{
			val.SetFloat("_SpecularStrength", 0f);
		}
		if (val.HasProperty("_MatcapStrength"))
		{
			val.SetFloat("_MatcapStrength", 0f);
		}
		if (val.HasProperty("_RflStrength"))
		{
			val.SetFloat("_RflStrength", 0f);
		}
		if (val.HasProperty("_OutlineWidth"))
		{
			val.SetFloat("_OutlineWidth", (((Object)shader).name == "Custom/Chibi Shader") ? 0.003f : 0.5f);
		}
		if (val.HasProperty("_MaskTex") && (Object)(object)texture != (Object)null)
		{
			val.SetTexture("_MaskTex", (Texture)(object)AlphaMask(texture));
		}
		if (((Object)shader).name == "Standard")
		{
			val.SetFloat("_Glossiness", 0f);
			val.SetFloat("_SpecularHighlights", 0f);
			val.SetFloat("_GlossyReflections", 0f);
			val.SetColor("_EmissionColor", Color.black);
			val.DisableKeyword("_EMISSION");
		}
		if (val.HasProperty("_Cutoff"))
		{
			val.SetFloat("_Cutoff", 0.25f);
			if (val.HasProperty("_Mode"))
			{
				val.SetFloat("_Mode", 1f);
				val.EnableKeyword("_ALPHATEST_ON");
			}
			val.renderQueue = 2450;
		}
		return val;
	}

	private static Material ReferenceSurface(Material template, Texture2D texture, Color color, string name)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		Material val = new Material(template);
		((Object)val).name = "Teto_" + name;
		val.mainTexture = (Texture)(object)texture;
		if (val.HasProperty("_Color"))
		{
			val.SetColor("_Color", color);
		}
		if (val.HasProperty("_ShadowTex"))
		{
			val.SetTexture("_ShadowTex", (Texture)(object)texture);
		}
		if (val.HasProperty("_MaskTex") && (Object)(object)texture != (Object)null)
		{
			val.SetTexture("_MaskTex", (Texture)(object)AlphaMask(texture));
		}
		if (val.HasProperty("_EmissionColor"))
		{
			val.SetColor("_EmissionColor", Color.black);
		}
		if (val.HasProperty("_EmissionStrength"))
		{
			val.SetFloat("_EmissionStrength", 0f);
		}
		val.DisableKeyword("_EMISSION");
		string[] array = new string[4] { "_MatcapStrength", "_SpecularStrength", "_RflStrength", "_RimStrength" };
		foreach (string text in array)
		{
			if (val.HasProperty(text))
			{
				val.SetFloat(text, 0f);
			}
		}
		if (val.HasProperty("_Cutoff"))
		{
			val.SetFloat("_Cutoff", 0.25f);
		}
		val.renderQueue = 2450;
		return val;
	}

	private static Texture2D AlphaMask(Texture2D source)
	{
		//IL_003a: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Expected O, but got Unknown
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		if (alphaMasks.TryGetValue(source, out var value))
		{
			return value;
		}
		Color32[] pixels = source.GetPixels32();
		for (int i = 0; i < pixels.Length; i++)
		{
			ref Color32 reference = ref pixels[i];
			reference = new Color32(byte.MaxValue, (byte)0, pixels[i].a, byte.MaxValue);
		}
		value = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, true);
		((Object)value).name = ((Object)source).name + "_AlphaMask";
		((Texture)value).wrapMode = ((Texture)source).wrapMode;
		value.SetPixels32(pixels);
		value.Apply();
		alphaMasks.Add(source, value);
		return value;
	}

	public static RuntimeModelAssets Create(string directory, GameObject reference)
	{
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//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_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_017b: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0284: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: 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)
		Transform val = reference.transform.Find("Body");
		SkinnedMeshRenderer val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<SkinnedMeshRenderer>());
		Shader val3 = (((Object)(object)val2 != (Object)null && ((Renderer)val2).sharedMaterials.Length > 0) ? ((Renderer)val2).sharedMaterials[0].shader : Shader.Find("Standard"));
		if ((Object)(object)val3 == (Object)null)
		{
			val3 = Shader.Find("Unlit/Texture");
		}
		if ((Object)(object)val3 == (Object)null)
		{
			throw new InvalidOperationException("No supported texture shader in the game.");
		}
		Debug.Log((object)("[TetoAddon] Surface shader: " + ((Object)val3).name));
		RuntimeModelAssets runtimeModelAssets = new RuntimeModelAssets();
		runtimeModelAssets.Storage = new GameObject("TetoAddon_Templates");
		Object.DontDestroyOnLoad((Object)(object)runtimeModelAssets.Storage);
		try
		{
			GameObject val4 = CreateTeto(directory, val3, reference);
			val4.transform.SetParent(runtimeModelAssets.Storage.transform, false);
			Animator component = val4.GetComponent<Animator>();
			component.runtimeAnimatorController = reference.GetComponent<Animator>().runtimeAnimatorController;
			CreatePear(directory, val3, reference, val4);
			((Component)val4.transform.Find("Smol")).gameObject.SetActive(false);
			((Behaviour)component).enabled = false;
			runtimeModelAssets.Thumbnail = Portrait(val4, val4.transform.Find("Armature/Hips/Spine/Chest/Neck/Head").position + Vector3.up * 0.12f, 0.38f);
			File.WriteAllBytes(Path.Combine(directory, "preview-upperbody.png"), ImageConversion.EncodeToPNG(Portrait(val4, new Vector3(0f, 1.3f, -0.05f), 0.48f)));
			if (Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-self-test") >= 0)
			{
				GameObject val5 = Object.Instantiate<GameObject>(reference);
				val5.transform.position = Vector3.zero;
				((Behaviour)val5.GetComponent<Animator>()).enabled = false;
				((Component)val5.transform.Find("Smol")).gameObject.SetActive(false);
				File.WriteAllBytes(Path.Combine(directory, "test-reference-lighting.png"), ImageConversion.EncodeToPNG(Portrait(val5, new Vector3(0f, 1.3f, -0.05f), 0.48f)));
				Object.Destroy((Object)(object)val5);
			}
			Transform val6 = val4.transform.Find("Smol");
			((Component)val4.transform.Find("Body")).gameObject.SetActive(false);
			((Component)val6).gameObject.SetActive(true);
			SkinnedMeshRenderer componentInChildren = ((Component)val6).GetComponentInChildren<SkinnedMeshRenderer>(true);
			Bounds val7 = SkinnedWorldBounds(componentInChildren);
			float size = Mathf.Max(Mathf.Max(((Bounds)(ref val7)).size.y, ((Bounds)(ref val7)).size.x) * 0.58f, 0.2f);
			Texture2D val8 = Portrait(val4, ((Bounds)(ref val7)).center, size);
			File.WriteAllBytes(Path.Combine(directory, "preview-teto.png"), ImageConversion.EncodeToPNG(runtimeModelAssets.Thumbnail));
			File.WriteAllBytes(Path.Combine(directory, "preview-pearto.png"), ImageConversion.EncodeToPNG(val8));
			((Component)val6).gameObject.SetActive(false);
			((Behaviour)((Component)val6).GetComponent<Animator>()).enabled = true;
			((Component)val4.transform.Find("Body")).gameObject.SetActive(true);
			CreateUiPortraits(directory, val4, runtimeModelAssets);
			((Behaviour)component).enabled = true;
			runtimeModelAssets.Storage.SetActive(false);
			runtimeModelAssets.Prefab = val4;
			ValidateReferenceAnimation(val4, reference, runtimeModelAssets.Storage);
			if (Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-self-test") >= 0)
			{
				ValidateBodyPoses(val4, reference, runtimeModelAssets.Storage, directory);
			}
			Debug.Log((object)("[TetoAddon] Prepared model created; main Avatar valid=" + component.avatar.isValid + ", human=" + component.avatar.isHuman));
			return runtimeModelAssets;
		}
		catch
		{
			Object.Destroy((Object)(object)runtimeModelAssets.Storage);
			throw;
		}
	}

	private static GameObject CreateTeto(string directory, Shader shader, GameObject reference)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: 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_0280: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0352: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_0373: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: 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_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_040b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0410: Unknown result type (might be due to invalid IL or missing references)
		//IL_0447: Unknown result type (might be due to invalid IL or missing references)
		//IL_044c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04da: Unknown result type (might be due to invalid IL or missing references)
		//IL_04df: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0830: Unknown result type (might be due to invalid IL or missing references)
		//IL_0778: Unknown result type (might be due to invalid IL or missing references)
		//IL_077f: Unknown result type (might be due to invalid IL or missing references)
		//IL_078d: 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_0797: Unknown result type (might be due to invalid IL or missing references)
		//IL_0887: Unknown result type (might be due to invalid IL or missing references)
		//IL_088e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0893: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a3c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a43: Expected O, but got Unknown
		//IL_08ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0904: Unknown result type (might be due to invalid IL or missing references)
		//IL_090b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0982: Unknown result type (might be due to invalid IL or missing references)
		//IL_0984: Unknown result type (might be due to invalid IL or missing references)
		//IL_0993: Unknown result type (might be due to invalid IL or missing references)
		//IL_09a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_09b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_09c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_09d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_09d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_09e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_09f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_09fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a0d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a19: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a1e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a23: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a28: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a97: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aa2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aa7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0aac: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0605: Unknown result type (might be due to invalid IL or missing references)
		//IL_060a: Unknown result type (might be due to invalid IL or missing references)
		//IL_061f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0626: Unknown result type (might be due to invalid IL or missing references)
		//IL_062b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0630: Unknown result type (might be due to invalid IL or missing references)
		//IL_0645: Unknown result type (might be due to invalid IL or missing references)
		//IL_0be9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d70: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d77: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d7c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e3a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e46: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e52: Unknown result type (might be due to invalid IL or missing references)
		using BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(directory, "teto.rpm")));
		if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "TETO0001")
		{
			throw new InvalidDataException("Unknown Teto model format.");
		}
		GameObject val = Object.Instantiate<GameObject>(reference);
		((Object)val).name = "KasaneTeto";
		val.transform.position = Vector3.zero;
		val.transform.rotation = Quaternion.identity;
		Animator component = val.GetComponent<Animator>();
		((Behaviour)component).enabled = false;
		if ((Object)(object)component.avatar == (Object)null || !component.avatar.isHuman || !component.avatar.isValid)
		{
			throw new InvalidDataException("Reference Avatar is not valid.");
		}
		MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val2 in componentsInChildren)
		{
			if (((object)val2).GetType().FullName == "JigglePhysicsPlugin.JiggleRigBuilder")
			{
				((Behaviour)val2).enabled = false;
			}
		}
		Transform val3 = val.transform.Find("Armature");
		if ((Object)(object)val3 == (Object)null)
		{
			throw new InvalidDataException("Reference armature is missing.");
		}
		int num = Count(binaryReader, 1024);
		Transform[] array = (Transform[])(object)new Transform[num];
		int[] array2 = new int[num];
		Vector3[] array3 = (Vector3[])(object)new Vector3[num];
		string[] array4 = new string[num];
		for (int j = 0; j < num; j++)
		{
			array4[j] = Text(binaryReader);
			array2[j] = binaryReader.ReadInt32();
			ref Vector3 reference2 = ref array3[j];
			reference2 = Vec(binaryReader);
			if (array2[j] >= num || array2[j] == j)
			{
				throw new InvalidDataException("Invalid bone hierarchy.");
			}
		}
		int num2 = Count(binaryReader, 100);
		Dictionary<HumanBodyBones, int> dictionary = new Dictionary<HumanBodyBones, int>();
		for (int k = 0; k < num2; k++)
		{
			HumanBodyBones val4 = (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), Text(binaryReader));
			int num3 = binaryReader.ReadInt32();
			if (num3 < 0 || num3 >= num)
			{
				throw new InvalidDataException("Invalid human mapping.");
			}
			dictionary.Add(val4, num3);
			array[num3] = component.GetBoneTransform(val4);
			if ((Object)(object)array[num3] == (Object)null)
			{
				throw new InvalidDataException("Reference bone missing: " + val4);
			}
		}
		float num4 = array3[dictionary[(HumanBodyBones)13]].x - array3[dictionary[(HumanBodyBones)14]].x;
		float num5 = val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)13]].position).x - val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)14]].position).x;
		bool flag = Mathf.Sign(num4) != Mathf.Sign(num5);
		if (flag)
		{
			for (int l = 0; l < array3.Length; l++)
			{
				array3[l].x = 0f - array3[l].x;
			}
		}
		Debug.Log((object)("[TetoAddon] Source left/right axis corrected=" + flag));
		float num6 = (array3[dictionary[(HumanBodyBones)21]].y + array3[dictionary[(HumanBodyBones)22]].y) * 0.5f;
		float num7 = (val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)21]].position).y + val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)22]].position).y) * 0.5f;
		float num8 = num7 / num6;
		if (num8 < 0.3f || num8 > 3f || float.IsNaN(num8))
		{
			throw new InvalidDataException("Invalid reference scale.");
		}
		bool[] array5 = new bool[num];
		foreach (int value3 in dictionary.Values)
		{
			array5[value3] = true;
		}
		float num9 = val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)9]].position).y - array3[dictionary[(HumanBodyBones)9]].y * num8;
		float num10 = val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)9]].position).z - array3[dictionary[(HumanBodyBones)9]].z * num8;
		Vector3[] array6 = (Vector3[])(object)new Vector3[num];
		for (int m = 0; m < num; m++)
		{
			int num11 = m;
			int num12 = 0;
			while (num11 >= 0 && !array5[num11] && ++num12 <= num)
			{
				num11 = array2[num11];
			}
			if (num12 > num)
			{
				throw new InvalidDataException("Cyclic source hierarchy.");
			}
			ref Vector3 reference3 = ref array6[m];
			reference3 = ((num11 >= 0) ? (val.transform.InverseTransformPoint(array[num11].position) - array3[num11] * num8) : Vector3.zero);
			if (num11 == dictionary[(HumanBodyBones)7] || num11 == dictionary[(HumanBodyBones)8])
			{
				array6[m].y = num9;
			}
			if (num11 == dictionary[(HumanBodyBones)0] || num11 == dictionary[(HumanBodyBones)7] || num11 == dictionary[(HumanBodyBones)8])
			{
				array6[m].z = num10;
			}
			if (num11 == dictionary[(HumanBodyBones)19] || num11 == dictionary[(HumanBodyBones)20])
			{
				int num13 = dictionary[(HumanBodyBones)((num11 == dictionary[(HumanBodyBones)19]) ? 5 : 6)];
				ref Vector3 reference4 = ref array6[m];
				reference4 = val.transform.InverseTransformPoint(array[num13].position) - array3[num13] * num8;
			}
			if (num11 == dictionary[(HumanBodyBones)21] || num11 == dictionary[(HumanBodyBones)22])
			{
				ref Vector3 reference5 = ref array6[m];
				reference5 = val.transform.InverseTransformPoint(array[dictionary[(HumanBodyBones)10]].position) - array3[dictionary[(HumanBodyBones)10]] * num8;
			}
			if (!array5[m])
			{
				array[m] = new GameObject(array4[m]).transform;
			}
		}
		Debug.Log((object)("[TetoAddon] Torso rest spacing preserved relative to neck: yShift=" + num9 + "; source neck/chest spacing=" + (array3[dictionary[(HumanBodyBones)9]].y - array3[dictionary[(HumanBodyBones)8]].y) * num8));
		Debug.Log((object)("[TetoAddon] Pelvis/torso depth aligned together: zShift=" + num10 + "; toe vertices retain ankle offset."));
		for (int n = 0; n < num; n++)
		{
			if (!array5[n])
			{
				array[n].SetParent((array2[n] < 0) ? val3 : array[array2[n]], false);
			}
		}
		Dictionary<Transform, int> dictionary2 = new Dictionary<Transform, int>();
		for (int num14 = 0; num14 < num; num14++)
		{
			if (!array5[num14])
			{
				dictionary2.Add(array[num14], num14);
			}
		}
		Transform[] componentsInChildren2 = val.GetComponentsInChildren<Transform>(true);
		foreach (Transform val5 in componentsInChildren2)
		{
			if (dictionary2.TryGetValue(val5, out var value))
			{
				val5.position = val.transform.TransformPoint(array3[value] * num8 + array6[value]);
			}
		}
		Debug.Log((object)("[TetoAddon] Original reference Avatar reused=" + ((Object)(object)component.avatar == (Object)(object)reference.GetComponent<Animator>().avatar) + "; skeleton=" + ((Object)reference).name + "; humanScale=" + component.humanScale + "; eyeHeight=" + num7));
		Debug.Log((object)("[TetoAddon] Reference animation visibility preserved: " + component.cullingMode));
		int num15 = Count(binaryReader, 100000);
		Vector3[] array7 = (Vector3[])(object)new Vector3[num15];
		Vector3[] array8 = (Vector3[])(object)new Vector3[num15];
		Vector2[] array9 = (Vector2[])(object)new Vector2[num15];
		BoneWeight[] array10 = (BoneWeight[])(object)new BoneWeight[num15];
		for (int num16 = 0; num16 < num15; num16++)
		{
			ref Vector3 reference6 = ref array7[num16];
			reference6 = Vec(binaryReader) * num8;
			ref Vector3 reference7 = ref array8[num16];
			reference7 = Vec(binaryReader);
			if (flag)
			{
				array7[num16].x = 0f - array7[num16].x;
				array8[num16].x = 0f - array8[num16].x;
			}
			ref Vector2 reference8 = ref array9[num16];
			reference8 = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			BoneWeight val6 = default(BoneWeight);
			((BoneWeight)(ref val6)).boneIndex0 = binaryReader.ReadInt32();
			((BoneWeight)(ref val6)).boneIndex1 = binaryReader.ReadInt32();
			((BoneWeight)(ref val6)).boneIndex2 = binaryReader.ReadInt32();
			((BoneWeight)(ref val6)).boneIndex3 = binaryReader.ReadInt32();
			((BoneWeight)(ref val6)).weight0 = binaryReader.ReadSingle();
			((BoneWeight)(ref val6)).weight1 = binaryReader.ReadSingle();
			((BoneWeight)(ref val6)).weight2 = binaryReader.ReadSingle();
			((BoneWeight)(ref val6)).weight3 = binaryReader.ReadSingle();
			array10[num16] = val6;
			ref Vector3 reference9 = ref array7[num16];
			reference9 += array6[((BoneWeight)(ref val6)).boneIndex0] * ((BoneWeight)(ref val6)).weight0 + array6[((BoneWeight)(ref val6)).boneIndex1] * ((BoneWeight)(ref val6)).weight1 + array6[((BoneWeight)(ref val6)).boneIndex2] * ((BoneWeight)(ref val6)).weight2 + array6[((BoneWeight)(ref val6)).boneIndex3] * ((BoneWeight)(ref val6)).weight3;
		}
		Mesh val7 = new Mesh();
		((Object)val7).name = "TdaVkTeto";
		val7.indexFormat = (IndexFormat)1;
		val7.vertices = array7;
		val7.normals = array8;
		val7.uv = array9;
		val7.boneWeights = array10;
		Matrix4x4[] array11 = (Matrix4x4[])(object)new Matrix4x4[num];
		for (int num17 = 0; num17 < num; num17++)
		{
			ref Matrix4x4 reference10 = ref array11[num17];
			reference10 = array[num17].worldToLocalMatrix * val.transform.localToWorldMatrix;
		}
		val7.bindposes = array11;
		int num18 = (val7.subMeshCount = Count(binaryReader, 128));
		Material[] array12 = (Material[])(object)new Material[num18];
		Dictionary<string, Texture2D> dictionary3 = new Dictionary<string, Texture2D>();
		Color color = default(Color);
		for (int num20 = 0; num20 < num18; num20++)
		{
			string text = Text(binaryReader);
			string text2 = Text(binaryReader);
			((Color)(ref color))..ctor(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			bool flag2 = binaryReader.ReadByte() != 0;
			Texture2D value2 = null;
			if (text2.Length > 0)
			{
				if (Path.GetFileName(text2) != text2)
				{
					throw new InvalidDataException("Invalid texture filename.");
				}
				if (!dictionary3.TryGetValue(text2, out value2))
				{
					value2 = Texture(Path.Combine(directory, text2));
					dictionary3.Add(text2, value2);
				}
			}
			Material[] sharedMaterials = ((Renderer)((Component)reference.transform.Find("Body")).GetComponent<SkinnedMeshRenderer>()).sharedMaterials;
			int num21 = ((text.StartsWith("neck", StringComparison.OrdinalIgnoreCase) || text.StartsWith("face", StringComparison.OrdinalIgnoreCase)) ? 2 : ((text.IndexOf("hair", StringComparison.OrdinalIgnoreCase) >= 0) ? 4 : 0));
			array12[num20] = ReferenceSurface(sharedMaterials[Mathf.Min(num21, sharedMaterials.Length - 1)], value2, color, text);
			int num22 = Count(binaryReader, 1000000);
			if (num22 % 3 != 0)
			{
				throw new InvalidDataException("Invalid triangles.");
			}
			bool flag3 = flag2 && !array12[num20].HasProperty("_OutlineWidth");
			int[] array13 = new int[flag3 ? (num22 * 2) : num22];
			for (int num23 = 0; num23 < num22; num23++)
			{
				array13[num23] = binaryReader.ReadInt32();
				if (array13[num23] < 0 || array13[num23] >= num15)
				{
					throw new InvalidDataException("Invalid vertex index.");
				}
			}
			if (flag)
			{
				for (int num24 = 0; num24 < num22; num24 += 3)
				{
					int num25 = array13[num24 + 1];
					array13[num24 + 1] = array13[num24 + 2];
					array13[num24 + 2] = num25;
				}
			}
			if (flag3)
			{
				for (int num26 = 0; num26 < num22; num26 += 3)
				{
					array13[num22 + num26] = array13[num26];
					array13[num22 + num26 + 1] = array13[num26 + 2];
					array13[num22 + num26 + 2] = array13[num26 + 1];
				}
			}
			val7.SetTriangles(array13, num20);
		}
		int num27 = Count(binaryReader, 256);
		Vector3[] array14 = (Vector3[])(object)new Vector3[num15];
		for (int num28 = 0; num28 < num27; num28++)
		{
			string text3 = Text(binaryReader);
			int num29 = Count(binaryReader, num15);
			Vector3[] array15 = (Vector3[])(object)new Vector3[num15];
			for (int num30 = 0; num30 < num29; num30++)
			{
				int num31 = binaryReader.ReadInt32();
				if (num31 < 0 || num31 >= num15)
				{
					throw new InvalidDataException("Invalid shape vertex.");
				}
				ref Vector3 reference11 = ref array15[num31];
				reference11 = Vec(binaryReader) * num8;
				if (flag)
				{
					array15[num31].x = 0f - array15[num31].x;
				}
			}
			val7.AddBlendShapeFrame(text3, 100f, array15, array14, array14);
		}
		if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
		{
			throw new InvalidDataException("Trailing model data.");
		}
		val7.RecalculateBounds();
		Transform val8 = val.transform.Find("Body");
		SkinnedMeshRenderer val9 = (((Object)(object)val8 == (Object)null) ? null : ((Component)val8).GetComponent<SkinnedMeshRenderer>());
		if ((Object)(object)val9 == (Object)null)
		{
			throw new InvalidDataException("Reference Body renderer is missing.");
		}
		val8.localPosition = Vector3.zero;
		val8.localRotation = Quaternion.identity;
		val8.localScale = Vector3.one;
		val9.sharedMesh = val7;
		((Renderer)val9).sharedMaterials = array12;
		val9.bones = array;
		val9.rootBone = array[4];
		val9.quality = (SkinQuality)4;
		SetMeshBounds(val9, val7);
		TetoHairMotion tetoHairMotion = val.AddComponent<TetoHairMotion>();
		tetoHairMotion.Head = array[9];
		tetoHairMotion.Roots = (Transform[])(object)new Transform[7]
		{
			array[154],
			array[160],
			array[19],
			array[21],
			array[23],
			array[15],
			array[17]
		};
		Debug.Log((object)("[TetoAddon] Teto geometry: vertices=" + num15 + ", materials=" + num18 + ", shapes=" + num27));
		return val;
	}

	private static void ValidateReferenceAnimation(GameObject root, GameObject reference, GameObject storage)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: 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_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0261: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: 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_0361: Unknown result type (might be due to invalid IL or missing references)
		//IL_046c: 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_047e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0483: Unknown result type (might be due to invalid IL or missing references)
		//IL_049c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c9: 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_0446: Unknown result type (might be due to invalid IL or missing references)
		//IL_044b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(root, storage.transform);
		GameObject val2 = Object.Instantiate<GameObject>(reference, storage.transform);
		try
		{
			val.SetActive(true);
			val2.SetActive(true);
			storage.SetActive(true);
			Transform transform = val.transform;
			Vector3 localPosition = (val2.transform.localPosition = Vector3.zero);
			transform.localPosition = localPosition;
			Transform transform2 = val.transform;
			Quaternion localRotation = (val2.transform.localRotation = Quaternion.identity);
			transform2.localRotation = localRotation;
			Animator component = val.GetComponent<Animator>();
			Animator component2 = val2.GetComponent<Animator>();
			((Component)val.transform.Find("Body")).gameObject.SetActive(false);
			((Component)val2.transform.Find("Body")).gameObject.SetActive(false);
			((Component)val.transform.Find("Smol")).gameObject.SetActive(false);
			((Component)val2.transform.Find("Smol")).gameObject.SetActive(false);
			bool enabled = (((Behaviour)component2).enabled = true);
			((Behaviour)component).enabled = enabled;
			component.Rebind();
			component2.Rebind();
			component.Update(0f);
			component2.Update(0f);
			float num = (val.transform.InverseTransformPoint(component.GetBoneTransform((HumanBodyBones)21).position).y + val.transform.InverseTransformPoint(component.GetBoneTransform((HumanBodyBones)22).position).y) * 0.5f;
			float num2 = (val2.transform.InverseTransformPoint(component2.GetBoneTransform((HumanBodyBones)21).position).y + val2.transform.InverseTransformPoint(component2.GetBoneTransform((HumanBodyBones)22).position).y) * 0.5f;
			Debug.Log((object)("[TetoAddon] Hidden-renderer camera sample: modelEye=" + num + ", referenceEye=" + num2 + ", error=" + Mathf.Abs(num - num2)));
			if (Mathf.Abs(num - num2) > 0.001f || num < 1f)
			{
				throw new InvalidDataException("Standing camera sample differs from the reference.");
			}
			((Component)val.transform.Find("Body")).gameObject.SetActive(true);
			((Component)val2.transform.Find("Body")).gameObject.SetActive(true);
			AnimatorCullingMode cullingMode = (AnimatorCullingMode)0;
			component2.cullingMode = (AnimatorCullingMode)0;
			component.cullingMode = cullingMode;
			bool enabled2 = (((Behaviour)component2).enabled = true);
			((Behaviour)component).enabled = enabled2;
			component.Rebind();
			component2.Rebind();
			component.Update(0f);
			component2.Update(0f);
			object[] array = new object[12]
			{
				"[TetoAddon] Idle controllers identical=",
				(Object)(object)component.runtimeAnimatorController == (Object)(object)component2.runtimeAnimatorController,
				", avatars identical=",
				(Object)(object)component.avatar == (Object)(object)component2.avatar,
				", states=",
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			AnimatorStateInfo currentAnimatorStateInfo = component.GetCurrentAnimatorStateInfo(0);
			array[5] = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash;
			array[6] = "/";
			AnimatorStateInfo currentAnimatorStateInfo2 = component2.GetCurrentAnimatorStateInfo(0);
			array[7] = ((AnimatorStateInfo)(ref currentAnimatorStateInfo2)).fullPathHash;
			array[8] = ", root scales=";
			array[9] = val.transform.localScale;
			array[10] = "/";
			array[11] = val2.transform.localScale;
			Debug.Log((object)string.Concat(array));
			float num3 = 0f;
			float num4 = 0f;
			int num5 = 0;
			for (int i = 0; i < 55; i++)
			{
				Transform boneTransform = component.GetBoneTransform((HumanBodyBones)i);
				Transform boneTransform2 = component2.GetBoneTransform((HumanBodyBones)i);
				if (!((Object)(object)boneTransform == (Object)null) && !((Object)(object)boneTransform2 == (Object)null))
				{
					if (i < 23)
					{
						Debug.Log((object)string.Concat("[TetoAddon] Idle bone ", (object)(HumanBodyBones)i, ": model=", ((Object)boneTransform).name, "@", val.transform.InverseTransformPoint(boneTransform.position), ", reference=", ((Object)boneTransform2).name, "@", val2.transform.InverseTransformPoint(boneTransform2.position)));
					}
					num3 = Mathf.Max(num3, Vector3.Distance(val.transform.InverseTransformPoint(boneTransform.position), val2.transform.InverseTransformPoint(boneTransform2.position)));
					num4 = Mathf.Max(num4, Quaternion.Angle(Quaternion.Inverse(val.transform.rotation) * boneTransform.rotation, Quaternion.Inverse(val2.transform.rotation) * boneTransform2.rotation));
					num5++;
				}
			}
			Debug.Log((object)("[TetoAddon] Reference idle animation comparison: bones=" + num5 + ", maxPositionError=" + num3 + ", maxAngleError=" + num4));
			if (num5 < 20 || num3 > 0.001f || num4 > 0.1f)
			{
				throw new InvalidDataException("Original-rig idle comparison failed.");
			}
		}
		finally
		{
			Object.Destroy((Object)(object)val);
			Object.Destroy((Object)(object)val2);
			storage.SetActive(false);
		}
	}

	private static void ValidateBodyPoses(GameObject root, GameObject reference, GameObject storage, string directory)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: 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_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Expected O, but got Unknown
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Expected O, but got Unknown
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: 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)
		//IL_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: 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_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_0274: 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_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_035e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_0373: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0401: Unknown result type (might be due to invalid IL or missing references)
		storage.SetActive(true);
		try
		{
			GameObject[] array = (GameObject[])(object)new GameObject[2] { root, reference };
			foreach (GameObject val in array)
			{
				GameObject val2 = Object.Instantiate<GameObject>(val, storage.transform);
				try
				{
					val2.SetActive(true);
					val2.transform.localPosition = Vector3.zero;
					val2.transform.localRotation = Quaternion.identity;
					((Component)val2.transform.Find("Smol")).gameObject.SetActive(false);
					Animator component = val2.GetComponent<Animator>();
					component.cullingMode = (AnimatorCullingMode)0;
					SkinnedMeshRenderer component2 = ((Component)val2.transform.Find("Body")).GetComponent<SkinnedMeshRenderer>();
					string[] array2 = new string[4] { "Bind", "Stand", "SpecialIdle", "Crouch" };
					foreach (string text in array2)
					{
						((Behaviour)component).enabled = true;
						component.Rebind();
						if (text != "Bind")
						{
							int num = Animator.StringToHash("Base Layer." + text);
							if (!component.HasState(0, num))
							{
								throw new InvalidDataException("Body state missing: " + text);
							}
							component.Play(num, 0, 0f);
							component.Update(0f);
						}
						((Behaviour)component).enabled = false;
						Bounds val3 = SkinnedWorldBounds(component2);
						string text2 = (((Object)(object)val == (Object)(object)root) ? "teto" : "reference");
						string text3 = "test-body-" + text2 + "-" + text;
						File.WriteAllBytes(Path.Combine(directory, text3 + "-side.png"), ImageConversion.EncodeToPNG(Portrait(val2, ((Bounds)(ref val3)).center, ((Bounds)(ref val3)).size.y * 0.56f, transparent: false, mirrored: false, side: true)));
						if (text == "Bind" || text == "Stand")
						{
							Mesh val4 = new Mesh();
							component2.BakeMesh(val4);
							Vector3 val5 = Vector3.zero;
							int num2 = 0;
							Vector3[] vertices = val4.vertices;
							foreach (Vector3 val6 in vertices)
							{
								Vector3 val7 = ((Component)component2).transform.TransformPoint(val6);
								if (val7.y < ((Bounds)(ref val3)).min.y + 0.2f)
								{
									val5 += val7;
									num2++;
								}
							}
							Object.Destroy((Object)(object)val4);
							if (num2 == 0)
							{
								throw new InvalidDataException("Feet sample is empty.");
							}
							val5 /= (float)num2;
							Debug.Log((object)string.Concat("[TetoAddon] Feet framing: ", text2, " ", text, ", centre=", val5, ", samples=", num2));
							File.WriteAllBytes(Path.Combine(directory, text3 + "-feet.png"), ImageConversion.EncodeToPNG(Portrait(val2, val5, 0.19f, transparent: false, mirrored: false, side: true, 0.8f)));
						}
						Mesh val8 = new Mesh();
						component2.BakeMesh(val8);
						try
						{
							Vector3[] vertices2 = val8.vertices;
							using BinaryWriter binaryWriter = new BinaryWriter(File.Create(Path.Combine(directory, text3 + ".vertices")));
							binaryWriter.Write(vertices2.Length);
							Vector3[] array3 = vertices2;
							foreach (Vector3 val9 in array3)
							{
								Vector3 val10 = val2.transform.InverseTransformPoint(((Component)component2).transform.TransformPoint(val9));
								binaryWriter.Write(val10.x);
								binaryWriter.Write(val10.y);
								binaryWriter.Write(val10.z);
							}
						}
						finally
						{
							Object.Destroy((Object)(object)val8);
						}
						Debug.Log((object)("[TetoAddon] Body surface sampled: " + text2 + " " + text + ", bounds=" + val3));
					}
				}
				finally
				{
					Object.Destroy((Object)(object)val2);
				}
			}
		}
		finally
		{
			storage.SetActive(false);
		}
	}

	private static void CreatePear(string directory, Shader shader, GameObject reference, GameObject root)
	{
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Expected O, but got Unknown
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: 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_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: 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_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Expected O, but got Unknown
		//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0340: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0368: Unknown result type (might be due to invalid IL or missing references)
		//IL_036d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_0376: Unknown result type (might be due to invalid IL or missing references)
		//IL_0392: Unknown result type (might be due to invalid IL or missing references)
		//IL_0397: 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_03c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_046a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0476: Unknown result type (might be due to invalid IL or missing references)
		//IL_047b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0480: Unknown result type (might be due to invalid IL or missing references)
		//IL_0509: Unknown result type (might be due to invalid IL or missing references)
		//IL_058d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0592: Unknown result type (might be due to invalid IL or missing references)
		Transform val = reference.transform.Find("Smol");
		if ((Object)(object)val == (Object)null)
		{
			throw new InvalidDataException("Base model has no Smol form.");
		}
		Transform val2 = root.transform.Find("Smol");
		GameObject val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : Object.Instantiate<GameObject>(((Component)val).gameObject, root.transform));
		((Object)val3).name = "Smol";
		val3.SetActive(true);
		Animator component = val3.GetComponent<Animator>();
		if ((Object)(object)component == (Object)null || (Object)(object)component.avatar == (Object)null || !component.avatar.isHuman)
		{
			throw new InvalidDataException("Base small rig is unavailable.");
		}
		SkinnedMeshRenderer componentInChildren = val3.GetComponentInChildren<SkinnedMeshRenderer>(true);
		if ((Object)(object)componentInChildren == (Object)null)
		{
			throw new InvalidDataException("Base small mesh is unavailable.");
		}
		Transform[] bones = componentInChildren.bones;
		Transform boneTransform = component.GetBoneTransform((HumanBodyBones)0);
		Transform boneTransform2 = component.GetBoneTransform((HumanBodyBones)10);
		int num = Array.IndexOf(bones, boneTransform);
		int num2 = Array.IndexOf(bones, boneTransform2);
		if (num < 0 || num2 < 0)
		{
			throw new InvalidDataException("Base small weighted bones do not match its Avatar.");
		}
		Mesh val4 = new Mesh();
		componentInChildren.BakeMesh(val4);
		Matrix4x4 val5 = val3.transform.worldToLocalMatrix * ((Component)componentInChildren).transform.localToWorldMatrix;
		Vector3[] vertices = val4.vertices;
		if (vertices.Length == 0)
		{
			throw new InvalidDataException("Small reference pose is empty.");
		}
		Bounds val6 = default(Bounds);
		((Bounds)(ref val6))..ctor(((Matrix4x4)(ref val5)).MultiplyPoint3x4(vertices[0]), Vector3.zero);
		for (int i = 1; i < vertices.Length; i++)
		{
			((Bounds)(ref val6)).Encapsulate(((Matrix4x4)(ref val5)).MultiplyPoint3x4(vertices[i]));
		}
		Object.Destroy((Object)(object)val4);
		Matrix4x4 val7 = ((Component)componentInChildren).transform.worldToLocalMatrix * val3.transform.localToWorldMatrix;
		float num3 = Mathf.Max(((Bounds)(ref val6)).size.y * 0.92f, 0.5f);
		Debug.Log((object)string.Concat("[TetoAddon] Small renderer frame=", ((Component)componentInChildren).transform.localEulerAngles, "; root-space bounds=", val6, "; pear height=", num3));
		Mesh val8 = new Mesh();
		((Object)val8).name = "Pearto";
		using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(directory, "pearto.rpm"))))
		{
			if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "PEAR0001")
			{
				throw new InvalidDataException("Unknown pear format.");
			}
			int num4 = Count(binaryReader, 10000);
			Vector3[] array = (Vector3[])(object)new Vector3[num4];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num4];
			Vector2[] array3 = (Vector2[])(object)new Vector2[num4];
			BoneWeight[] array4 = (BoneWeight[])(object)new BoneWeight[num4];
			Vector3 val10 = default(Vector3);
			for (int j = 0; j < num4; j++)
			{
				Vector3 val9 = Vec(binaryReader);
				((Vector3)(ref val10))..ctor(0f - val9.z, val9.y, val9.x);
				ref Vector3 reference2 = ref array[j];
				reference2 = ((Matrix4x4)(ref val7)).MultiplyPoint3x4(val10 * num3 + new Vector3(((Bounds)(ref val6)).center.x, ((Bounds)(ref val6)).min.y, ((Bounds)(ref val6)).center.z));
				val9 = Vec(binaryReader);
				ref Vector3 reference3 = ref array2[j];
				Vector3 val11 = ((Matrix4x4)(ref val7)).MultiplyVector(new Vector3(0f - val9.z, val9.y, val9.x));
				reference3 = ((Vector3)(ref val11)).normalized;
				ref Vector2 reference4 = ref array3[j];
				reference4 = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
				ref BoneWeight reference5 = ref array4[j];
				BoneWeight val12 = default(BoneWeight);
				((BoneWeight)(ref val12)).boneIndex0 = num;
				((BoneWeight)(ref val12)).weight0 = 1f;
				reference5 = val12;
			}
			int num5 = Count(binaryReader, 100000);
			int[] array5 = new int[num5];
			for (int k = 0; k < num5; k++)
			{
				array5[k] = binaryReader.ReadInt32();
				if (array5[k] < 0 || array5[k] >= num4)
				{
					throw new InvalidDataException("Invalid pear indices.");
				}
			}
			val8.vertices = array;
			val8.normals = array2;
			val8.uv = array3;
			val8.boneWeights = array4;
			Matrix4x4[] array6 = (Matrix4x4[])(object)new Matrix4x4[bones.Length];
			for (int l = 0; l < bones.Length; l++)
			{
				ref Matrix4x4 reference6 = ref array6[l];
				reference6 = bones[l].worldToLocalMatrix * ((Component)componentInChildren).transform.localToWorldMatrix;
			}
			val8.bindposes = array6;
			Material[] sharedMaterials = ((Renderer)componentInChildren).sharedMaterials;
			val8.subMeshCount = sharedMaterials.Length;
			val8.SetTriangles(array5, 0);
			for (int m = 1; m < sharedMaterials.Length; m++)
			{
				val8.SetTriangles(new int[0], m);
			}
			Shader shader2 = sharedMaterials[0].shader;
			sharedMaterials[0] = Surface(((Object)(object)shader2 != (Object)null) ? shader2 : shader, Texture(Path.Combine(directory, "pearto.png")), Color.white, "Pearto");
			((Renderer)componentInChildren).sharedMaterials = sharedMaterials;
			val8.RecalculateBounds();
			componentInChildren.sharedMesh = val8;
			SetMeshBounds(componentInChildren, val8);
			Debug.Log((object)("[TetoAddon] Pearto geometry: triangles=" + num5 / 3 + "; existing small Avatar and ragdoll bones retained."));
		}
		((Behaviour)component).enabled = false;
		if (Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-self-test") >= 0)
		{
			ValidatePear(val3, root.GetComponent<Animator>().runtimeAnimatorController, ((Matrix4x4)(ref val7)).MultiplyVector(Vector3.up), directory);
		}
	}

	private static void SetMeshBounds(SkinnedMeshRenderer renderer, Mesh mesh)
	{
		//IL_001e: 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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		Transform val = (((Object)(object)renderer.rootBone != (Object)null) ? renderer.rootBone : ((Component)renderer).transform);
		Matrix4x4 val2 = val.worldToLocalMatrix * ((Component)renderer).transform.localToWorldMatrix;
		Bounds localBounds = ((Renderer)renderer).localBounds;
		Vector3[] vertices = mesh.vertices;
		foreach (Vector3 val3 in vertices)
		{
			((Bounds)(ref localBounds)).Encapsulate(((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3));
		}
		((Bounds)(ref localBounds)).Expand(0.3f);
		((Renderer)renderer).localBounds = localBounds;
		Debug.Log((object)("[TetoAddon] Mesh visibility bounds preserve reference and use root frame: " + ((Object)val).name + ", bounds=" + localBounds));
	}

	private static Bounds SkinnedWorldBounds(SkinnedMeshRenderer renderer)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		Mesh val = new Mesh();
		renderer.BakeMesh(val);
		try
		{
			Vector3[] vertices = val.vertices;
			if (vertices.Length == 0)
			{
				throw new InvalidDataException("Skinned pose is empty.");
			}
			Bounds result = default(Bounds);
			((Bounds)(ref result))..ctor(((Component)renderer).transform.TransformPoint(vertices[0]), Vector3.zero);
			for (int i = 1; i < vertices.Length; i++)
			{
				((Bounds)(ref result)).Encapsulate(((Component)renderer).transform.TransformPoint(vertices[i]));
			}
			return result;
		}
		finally
		{
			Object.Destroy((Object)(object)val);
		}
	}

	private static void ValidatePear(GameObject small, RuntimeAnimatorController controller, Vector3 meshUp, string directory)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: 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_0176: 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_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_0250: Unknown result type (might be due to invalid IL or missing references)
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(small);
		try
		{
			val.SetActive(true);
			val.transform.position = Vector3.zero;
			val.transform.rotation = Quaternion.identity;
			Animator component = val.GetComponent<Animator>();
			SkinnedMeshRenderer componentInChildren = val.GetComponentInChildren<SkinnedMeshRenderer>(true);
			component.runtimeAnimatorController = controller;
			Debug.Log((object)("[TetoAddon] Pear validation controller=" + (((Object)(object)controller == (Object)null) ? "null" : ((Object)controller).name)));
			component.cullingMode = (AnimatorCullingMode)0;
			((Behaviour)component).enabled = true;
			string[] array = new string[5] { "Bind", "Stand", "SpecialIdle", "Stand to Crouch", "Crouch" };
			foreach (string text in array)
			{
				component.Rebind();
				if (text != "Bind")
				{
					int num = Animator.StringToHash("Base Layer." + text);
					if (!component.HasState(0, num))
					{
						Debug.Log((object)("[TetoAddon] Pear state unavailable: " + text));
						continue;
					}
					component.Play(num, 0, 0f);
					component.Update(0f);
				}
				else
				{
					((Behaviour)component).enabled = false;
				}
				((Behaviour)component).enabled = false;
				Bounds val2 = SkinnedWorldBounds(componentInChildren);
				int boneIndex = ((BoneWeight)(ref componentInChildren.sharedMesh.boneWeights[0])).boneIndex0;
				Matrix4x4 localToWorldMatrix = componentInChildren.bones[boneIndex].localToWorldMatrix;
				Vector3 val3 = ((Matrix4x4)(ref localToWorldMatrix)).MultiplyVector(((Matrix4x4)(ref componentInChildren.sharedMesh.bindposes[boneIndex])).MultiplyVector(meshUp));
				Vector3 normalized = ((Vector3)(ref val3)).normalized;
				float num2 = Vector3.Dot(normalized, val.transform.up);
				Debug.Log((object)string.Concat("[TetoAddon] Pear pose ", text, ": world bounds=", val2, ", uprightDot=", num2, ", hips=", component.GetBoneTransform((HumanBodyBones)0).eulerAngles));
				if ((text == "Stand" || text == "SpecialIdle") && num2 < 0.9f)
				{
					throw new InvalidDataException("Pear is not upright in " + text);
				}
				float num3 = Mathf.Max(((Bounds)(ref val2)).size.y, Mathf.Max(((Bounds)(ref val2)).size.x, ((Bounds)(ref val2)).size.z)) * 0.58f;
				File.WriteAllBytes(Path.Combine(directory, "test-pear-" + text + ".png"), ImageConversion.EncodeToPNG(Portrait(val, ((Bounds)(ref val2)).center, Mathf.Max(num3, 0.2f))));
				((Behaviour)component).enabled = true;
			}
		}
		finally
		{
			Object.Destroy((Object)(object)val);
		}
	}

	private static void CreateUiPortraits(string directory, GameObject root, RuntimeModelAssets result)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(root);
		try
		{
			val.SetActive(true);
			val.transform.position = Vector3.zero;
			val.transform.rotation = Quaternion.identity;
			((Component)val.transform.Find("Body")).gameObject.SetActive(true);
			((Component)val.transform.Find("Smol")).gameObject.SetActive(false);
			Animator component = val.GetComponent<Animator>();
			component.cullingMode = (AnimatorCullingMode)0;
			((Behaviour)component).enabled = true;
			component.Rebind();
			int num = Animator.StringToHash("Base Layer.SpecialIdle");
			if (component.HasState(0, num))
			{
				component.Play(num, 0, 0f);
				component.Update(0f);
			}
			((Behaviour)component).enabled = false;
			result.Thumbnail = Texture(Path.Combine(directory, "teto-thumbnail.png"));
			((Component)val.transform.Find("Body")).gameObject.SetActive(false);
			GameObject gameObject = ((Component)val.transform.Find("Smol")).gameObject;
			gameObject.SetActive(true);
			Animator component2 = gameObject.GetComponent<Animator>();
			component2.runtimeAnimatorController = component.runtimeAnimatorController;
			component2.cullingMode = (AnimatorCullingMode)0;
			((Behaviour)component2).enabled = true;
			component2.Rebind();
			if (component2.HasState(0, num))
			{
				component2.Play(num, 0, 0f);
				component2.Update(0f);
			}
			((Behaviour)component2).enabled = false;
			result.Chibi = LoadOrRenderSkinPortrait(directory, "teto-lobby.png", val, gameObject.GetComponentInChildren<SkinnedMeshRenderer>(true), 0.58f);
			string path = Path.Combine(directory, "teto-lobby-talk.png");
			if (File.Exists(path) && Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-rebuild-icons") < 0)
			{
				result.ChibiTalk = Texture(path);
			}
			else
			{
				result.ChibiTalk = MirrorPortrait(result.Chibi);
				File.WriteAllBytes(path, ImageConversion.EncodeToPNG(result.ChibiTalk));
			}
			Debug.Log((object)("[TetoAddon] UI PNGs loaded/generated: provided Teto selection illustration (" + ((Texture)result.Thumbnail).width + "x" + ((Texture)result.Thumbnail).height + ") + Pearto lobby + exact mirrored speaking Pearto."));
		}
		finally
		{
			Object.Destroy((Object)(object)val);
		}
	}

	private static Texture2D MirrorPortrait(Texture2D source)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false);
		Color32[] pixels = source.GetPixels32();
		Color32[] array = (Color32[])(object)new Color32[pixels.Length];
		for (int i = 0; i < ((Texture)source).height; i++)
		{
			for (int j = 0; j < ((Texture)source).width; j++)
			{
				ref Color32 reference = ref array[i * ((Texture)source).width + j];
				reference = pixels[i * ((Texture)source).width + ((Texture)source).width - 1 - j];
			}
		}
		val.SetPixels32(array);
		val.Apply();
		return val;
	}

	private static Texture2D LoadOrRenderSkinPortrait(string directory, string filename, GameObject root, SkinnedMeshRenderer skin, float padding)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		string path = Path.Combine(directory, filename);
		if (File.Exists(path) && Array.IndexOf(Environment.GetCommandLineArgs(), "--teto-rebuild-icons") < 0)
		{
			return Texture(path);
		}
		Mesh val = new Mesh();
		skin.BakeMesh(val);
		val.RecalculateBounds();
		GameObject val2 = new GameObject("TetoPortraitSnapshot");
		val2.transform.SetParent(((Component)skin).transform, false);
		val2.AddComponent<MeshFilter>().sharedMesh = val;
		((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)skin).sharedMaterials;
		bool enabled = ((Renderer)skin).enabled;
		try
		{
			((Renderer)skin).enabled = false;
			Vector3[] vertices = val.vertices;
			Bounds val3 = default(Bounds);
			((Bounds)(ref val3))..ctor(((Component)skin).transform.TransformPoint(vertices[0]), Vector3.zero);
			Vector3[] array = vertices;
			foreach (Vector3 val4 in array)
			{
				((Bounds)(ref val3)).Encapsulate(((Component)skin).transform.TransformPoint(val4));
			}
			float num = Mathf.Max(((Bounds)(ref val3)).size.y, ((Bounds)(ref val3)).size.x) * padding;
			Texture2D val5 = Portrait(root, ((Bounds)(ref val3)).center, num, transparent: true);
			File.WriteAllBytes(path, ImageConversion.EncodeToPNG(val5));
			Debug.Log((object)string.Concat("[TetoAddon] Baked portrait framing: ", filename, ", bounds=", val3, ", size=", num));
			return val5;
		}
		finally
		{
			((Renderer)skin).enabled = enabled;
			val2.SetActive(false);
			Object.Destroy((Object)(object)val2);
			Object.Destroy((Object)(object)val);
		}
	}

	private static Texture2D Portrait(GameObject root, Vector3 centre, float size, bool transparent = false, bool mirrored = false, bool side = false, float elevation = 0f)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Expected O, but got Unknown
		//IL_0091: 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_00ce: 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_00e2: 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_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Expected O, but got Unknown
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: 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_01a5: Expected O, but got Unknown
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Expected O, but got Unknown
		//IL_01ec: 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_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_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)
		Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true);
		int[] array = new int[componentsInChildren.Length];
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			array[i] = ((Component)componentsInChildren[i]).gameObject.layer;
			((Component)componentsInChildren[i]).gameObject.layer = 31;
		}
		GameObject val = new GameObject("TetoPortraitCamera");
		Camera val2 = val.AddComponent<Camera>();
		((Behaviour)val2).enabled = false;
		val2.orthographic = true;
		val2.orthographicSize = size;
		val2.clearFlags = (CameraClearFlags)2;
		val2.backgroundColor = (Color)(transparent ? Color.clear : new Color(0.06f, 0.09f, 0.13f, 1f));
		val2.cullingMask = int.MinValue;
		val2.nearClipPlane = 0.01f;
		val2.farClipPlane = 10f;
		val2.useOcclusionCulling = false;
		((Component)val2).transform.position = centre + (side ? new Vector3(-3f, 0f, 0f) : new Vector3(0f, 0f, 3f)) + Vector3.up * elevation;
		((Component)val2).transform.LookAt(centre);
		GameObject val3 = new GameObject("TetoPortraitLight");
		Light val4 = val3.AddComponent<Light>();
		val4.type = (LightType)1;
		val4.intensity = 0.8f;
		val4.color = Color.white;
		val4.cullingMask = int.MinValue;
		((Component)val4).transform.rotation = Quaternion.Euler(25f, side ? 250f : 170f, 0f);
		RenderTexture val5 = (val2.targetTexture = new RenderTexture(256, 256, 24, (RenderTextureFormat)0));
		RenderTexture active = RenderTexture.active;
		try
		{
			val2.Render();
			RenderTexture.active = val5;
			Texture2D val7 = new Texture2D(256, 256, (TextureFormat)4, false);
			val7.ReadPixels(new Rect(0f, 0f, 256f, 256f), 0, 0);
			val7.Apply();
			if (mirrored)
			{
				Color32[] pixels = val7.GetPixels32();
				for (int j = 0; j < ((Texture)val7).height; j++)
				{
					for (int k = 0; k < ((Texture)val7).width / 2; k++)
					{
						int num = j * ((Texture)val7).width + k;
						int num2 = j * ((Texture)val7).width + ((Texture)val7).width - 1 - k;
						Color32 val8 = pixels[num];
						ref Color32 reference = ref pixels[num];
						reference = pixels[num2];
						pixels[num2] = val8;
					}
				}
				val7.SetPixels32(pixels);
				val7.Apply();
			}
			return val7;
		}
		finally
		{
			RenderTexture.active = active;
			val2.targetTexture = null;
			val5.Release();
			Object.Destroy((Object)(object)val5);
			Object.Destroy((Object)(object)val);
			Object.Destroy((Object)(object)val3);
			for (int l = 0; l < componentsInChildren.Length; l++)
			{
				((Component)componentsInChildren[l]).gameObject.layer = array[l];
			}
		}
	}
}
public sealed class TetoHairMotion : MonoBehaviour
{
	public Transform Head;

	public Transform[] Roots;

	private Quaternion[] rest;

	private Vector3 previous;

	private Vector3 angle;

	private Vector3 velocity;

	private void OnEnable()
	{
		//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_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: 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)
		//IL_0036: 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_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)Head == (Object)null) && Roots != null)
		{
			previous = Head.position;
			angle = (velocity = Vector3.zero);
			rest = (Quaternion[])(object)new Quaternion[Roots.Length];
			for (int i = 0; i < Roots.Length; i++)
			{
				ref Quaternion reference = ref rest[i];
				reference = Roots[i].localRotation;
			}
		}
	}

	private void LateUpdate()
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Head == (Object)null || Roots == null)
		{
			return;
		}
		if (rest == null || rest.Length != Roots.Length)
		{
			OnEnable();
			return;
		}
		float num = Mathf.Clamp(Time.deltaTime, 0.001f, 0.05f);
		Vector3 val = Head.InverseTransformDirection((Head.position - previous) / num);
		previous = Head.position;
		if (((Vector3)(ref val)).sqrMagnitude > 400f)
		{
			angle = (velocity = Vector3.zero);
			return;
		}
		Vector3 val2 = default(Vector3);
		((Vector3)(ref val2))..ctor(Mathf.Clamp((0f - val.z) * 4f, -12f, 12f), 0f, Mathf.Clamp(val.x * 4f, -12f, 12f));
		angle = Vector3.SmoothDamp(angle, val2, ref velocity, 0.12f, 250f, num);
		for (int i = 0; i < Roots.Length; i++)
		{
			if ((Object)(object)Roots[i] != (Object)null)
			{
				Roots[i].localRotation = rest[i] * Quaternion.Euler(angle);
			}
		}
	}
}