Decompiled source of Disguise v1.0.0

BepInEx/plugins/Disguise.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Disguise")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Disguise")]
[assembly: AssemblyTitle("Disguise")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ShiftAtMidnightDisguise
{
	internal sealed class BodyTarget
	{
		private const string BonePrefix = "mixamorig:";

		public Transform Root;

		public List<SkinnedMeshRenderer> Parts;

		public bool IsPlayer;

		public bool Valid => (Object)(object)Root != (Object)null && Parts != null && Parts.Count > 0;

		public Animator Source => ((Object)(object)Root != (Object)null) ? ((Component)Root).GetComponent<Animator>() : null;

		public static BodyTarget OfPlayer(ThirdPersonManager body)
		{
			if ((Object)(object)body == (Object)null || (Object)(object)body.bodyAnim == (Object)null)
			{
				return null;
			}
			Transform transform = ((Component)body.bodyAnim).transform;
			List<SkinnedMeshRenderer> list = new List<SkinnedMeshRenderer>();
			foreach (SkinnedMeshRenderer item in Interop.Safe<SkinnedMeshRenderer>((Il2CppArrayBase<SkinnedMeshRenderer>)(object)body.models))
			{
				Transform parent = ((Component)item).transform.parent;
				if ((Object)(object)parent != (Object)null && ((Il2CppObjectBase)parent).Pointer == ((Il2CppObjectBase)transform).Pointer)
				{
					list.Add(item);
				}
			}
			return new BodyTarget
			{
				Root = transform,
				Parts = list,
				IsPlayer = true
			};
		}

		public static BodyTarget OfMannequin(GameObject root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			SkinnedMeshRenderer val = null;
			int num = int.MaxValue;
			foreach (SkinnedMeshRenderer item in Interop.Safe<SkinnedMeshRenderer>(root.GetComponentsInChildren<SkinnedMeshRenderer>(true)))
			{
				if (item.bones != null && !((Object)(object)item.rootBone == (Object)null) && ((Object)item.rootBone).name.StartsWith("mixamorig:", StringComparison.Ordinal))
				{
					int num2 = Depth(((Component)item).transform);
					if (num2 <= num && (num2 != num || !((Object)(object)val != (Object)null) || ((Il2CppArrayBase<Transform>)(object)item.bones).Length > ((Il2CppArrayBase<Transform>)(object)val.bones).Length))
					{
						val = item;
						num = num2;
					}
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform.parent == (Object)null)
			{
				return null;
			}
			Transform parent = ((Component)val).transform.parent;
			List<SkinnedMeshRenderer> list = new List<SkinnedMeshRenderer>();
			foreach (SkinnedMeshRenderer item2 in Interop.Safe<SkinnedMeshRenderer>(((Component)parent).GetComponentsInChildren<SkinnedMeshRenderer>(true)))
			{
				if ((Object)(object)((Component)item2).transform.parent != (Object)null && ((Il2CppObjectBase)((Component)item2).transform.parent).Pointer == ((Il2CppObjectBase)parent).Pointer)
				{
					list.Add(item2);
				}
			}
			return new BodyTarget
			{
				Root = parent,
				Parts = list
			};
		}

		private static int Depth(Transform t)
		{
			int num = 0;
			while ((Object)(object)t.parent != (Object)null)
			{
				num++;
				t = t.parent;
			}
			return num;
		}
	}
	[BepInPlugin("clementinise.shiftatmidnight.disguise", "Disguise", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class DisguisePlugin : BasePlugin
	{
		public const string Guid = "clementinise.shiftatmidnight.disguise";

		private const string NuisanceGuid = "clementinise.shiftatmidnight.nuisance";

		internal static ConfigEntry<string> Model;

		public override void Load()
		{
			ModLog.Source = ((BasePlugin)this).Log;
			Model = ((BasePlugin)this).Config.Bind<string>("Appearance", "Model", "", "Which NPC you appear as. Empty is your own body.");
			ClassInjector.RegisterTypeInIl2Cpp<DisguiseBehaviour>();
			((BasePlugin)this).AddComponent<DisguiseBehaviour>();
			ModLog.Msg("Disguise ready.");
		}
	}
	public class DisguiseBehaviour : MonoBehaviour
	{
		private SkinSync _sync;

		private LockerPreview _locker;

		private LockerPicker _picker;

		private int _lastSceneHandle;

		public DisguiseBehaviour(IntPtr handle)
			: base(handle)
		{
		}

		private void Awake()
		{
			//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)
			_sync = new SkinSync();
			_locker = new LockerPreview();
			_picker = new LockerPicker(_locker);
			Scene activeScene = SceneManager.GetActiveScene();
			_lastSceneHandle = ((Scene)(ref activeScene)).handle;
		}

		private void Update()
		{
			try
			{
				DetectSceneChange();
				_sync.LocalChoice = DisguisePlugin.Model.Value;
				_sync.Tick();
				_picker.Tick();
				_locker.Tick(_picker.Previewing ?? DisguisePlugin.Model.Value);
			}
			catch (Exception value)
			{
				ModLog.Error($"Update: {value}");
			}
		}

		private void LateUpdate()
		{
			Pose();
			try
			{
				_picker.TickBaking();
			}
			catch (Exception value)
			{
				ModLog.Error($"LateUpdate: {value}");
			}
		}

		private void Pose()
		{
			try
			{
				_sync.LateTick();
				_locker.LateTick();
			}
			catch (Exception value)
			{
				ModLog.Error($"Pose: {value}");
			}
		}

		private void OnDestroy()
		{
			try
			{
				_sync.Clear();
			}
			catch
			{
			}
			try
			{
				_locker.Clear();
			}
			catch
			{
			}
		}

		private void DetectSceneChange()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			int handle = ((Scene)(ref activeScene)).handle;
			if (handle != _lastSceneHandle)
			{
				_lastSceneHandle = handle;
				_sync.Clear();
				_locker.Clear();
				_picker.Forget();
				NpcCatalog.Invalidate();
			}
		}
	}
	internal static class Interop
	{
		public static IEnumerable<T> Safe<T>(Il2CppArrayBase<T> array) where T : Il2CppObjectBase
		{
			if (array == null)
			{
				yield break;
			}
			for (int i = 0; i < array.Length; i++)
			{
				T v = array[i];
				if (v != null)
				{
					yield return v;
				}
			}
		}

		public static IEnumerable<T> Safe<T>(List<T> list)
		{
			if (list == null)
			{
				yield break;
			}
			for (int i = 0; i < list.Count; i++)
			{
				T v = list[i];
				if (v != null)
				{
					yield return v;
				}
			}
		}
	}
	internal static class LocalModel
	{
		private const int MaxComponents = 4000;

		public static GameObject Create(GameObject prefab, Transform parent)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			GameObject val = null;
			try
			{
				val = new GameObject("DisguiseHolder");
				val.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)val);
				GameObject val2 = Object.Instantiate<GameObject>(prefab, val.transform);
				int length = val2.GetComponentsInChildren<Component>(true).Length;
				if (length > 4000)
				{
					ModLog.Warning($"'{((Object)prefab).name}' has {length} components, too large to strip " + "safely, skipping to avoid freezing the game.");
					return null;
				}
				Strip(val2);
				Activate(val2);
				val2.transform.SetParent(parent, false);
				val2.transform.localPosition = Vector3.zero;
				val2.transform.localRotation = Quaternion.identity;
				((Object)val2).name = "Disguise_" + ((Object)prefab).name;
				val2.SetActive(true);
				return val2;
			}
			catch (Exception value)
			{
				ModLog.Error($"Failed to build the model for '{((Object)prefab).name}': {value}");
				return null;
			}
			finally
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static void Activate(GameObject root)
		{
			root.SetActive(true);
			foreach (SkinnedMeshRenderer componentsInChild in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
			{
				if ((Object)(object)componentsInChild == (Object)null)
				{
					continue;
				}
				((Renderer)componentsInChild).enabled = true;
				Transform val = ((Component)componentsInChild).transform;
				while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root.transform)
				{
					if (!((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(true);
					}
					val = val.parent;
				}
			}
		}

		private static void Strip(GameObject root)
		{
			foreach (Component componentsInChild in root.GetComponentsInChildren<Component>(true))
			{
				if (!((Object)(object)componentsInChild == (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast<Transform>() != (Object)null) && !((Object)(object)((Il2CppObjectBase)componentsInChild).TryCast<SkinnedMeshRenderer>() != (Object)null))
				{
					try
					{
						Object.DestroyImmediate((Object)(object)componentsInChild, true);
					}
					catch
					{
					}
				}
			}
			foreach (Collider componentsInChild2 in root.GetComponentsInChildren<Collider>(true))
			{
				if ((Object)(object)componentsInChild2 != (Object)null)
				{
					try
					{
						Object.DestroyImmediate((Object)(object)componentsInChild2, true);
					}
					catch
					{
					}
				}
			}
		}

		public static void SetLayer(GameObject root, int layer)
		{
			foreach (Transform item in Interop.Safe<Transform>(root.GetComponentsInChildren<Transform>(true)))
			{
				((Component)item).gameObject.layer = layer;
			}
		}
	}
	internal sealed class LockerPicker
	{
		private const string ContentPath = "Scroll View/Viewport/Content";

		private const string SlotTemplate = "Scroll View/Viewport/Content/Slot";

		private const string SlotButton = "HatSlotButton";

		private const string SlotIcon = "Item Icon";

		private const string SlotLocked = "LOCKED";

		private const string LabelName = "Disguise Label";

		private const string ExitButton = "ExitButton";

		private const string EquipButton = "Equip Button";

		private const string EquippedLabel = "Equipped";

		private const string TitleLabel = "TITLE";

		private const string NameLabel = "Name";

		private const string GlyphPath = "HAT SLOT CONTROLLER BUTTON PROMPT/Make This Disable In KB&M/GlyphText";

		private const float BackButtonGap = 4f;

		private const string BackGlyph = "<";

		private const string ChangeText = "CHANGE";

		private const string WearingText = "CURRENT";

		private const string DefaultLabel = "DEFAULT";

		private const string HatBadgeSprite = "Customizables Icon";

		private const float HatBadgeGap = 6f;

		private static readonly Color BackTint = new Color(0.52f, 0.58f, 0.66f);

		private const string PreviewImage = "RawImage";

		private readonly ThumbnailBaker _thumbnails;

		private readonly Dictionary<string, Image> _icons = new Dictionary<string, Image>(StringComparer.Ordinal);

		private readonly Dictionary<string, Transform> _labels = new Dictionary<string, Transform>(StringComparer.Ordinal);

		private GameObject _builtFor;

		private GameObject _locker;

		private GameObject _chooser;

		private GameObject _models;

		private TextMeshProUGUI _modelsName;

		private string _previewing;

		private string _previewingLabel;

		private GameObject _changeButton;

		private GameObject _appliedLabel;

		private GameObject _hatsRow;

		private string _hatsRowFor;

		private GameObject _hatBadge;

		private bool _inHats;

		public string Previewing => ((Object)(object)_models != (Object)null && _models.activeSelf) ? _previewing : null;

		public LockerPicker(LockerPreview preview)
		{
			_thumbnails = new ThumbnailBaker(preview);
			_thumbnails.OnBaked = SetIcon;
		}

		public void TickBaking()
		{
			_thumbnails.Tick();
		}

		public void Tick()
		{
			try
			{
				PlayerManager localPlayerManager = NetworkContext.LocalPlayerManager;
				GameObject val = (((Object)(object)localPlayerManager != (Object)null) ? localPlayerManager.customizablesMenu : null);
				if (!((Object)(object)val == (Object)null))
				{
					if ((Object)(object)_chooser == (Object)null || (Object)(object)_builtFor == (Object)null || ((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)_builtFor).Pointer)
					{
						Build(val);
					}
					Intercept(localPlayerManager, val);
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Locker picker: {value}");
				_builtFor = null;
			}
		}

		public void Forget()
		{
			_builtFor = null;
			_locker = null;
			_chooser = null;
			_models = null;
			_modelsName = null;
			_previewing = null;
			_previewingLabel = null;
			_changeButton = null;
			_appliedLabel = null;
			_hatsRow = null;
			_hatsRowFor = null;
			_hatBadge = null;
			_inHats = false;
			_icons.Clear();
			_labels.Clear();
			_thumbnails.Forget();
		}

		private void Intercept(PlayerManager pm, GameObject menu)
		{
			if (!pm.customizablesMenuOpen)
			{
				if (_chooser.activeSelf)
				{
					_chooser.SetActive(false);
				}
				if (_models.activeSelf)
				{
					_models.SetActive(false);
				}
				_inHats = false;
				return;
			}
			if (!_inHats && !_thumbnails.Busy)
			{
				LockerPreview.NoteEquippedHat();
			}
			RefreshHatsRow();
			if (menu.activeSelf && !_inHats)
			{
				menu.SetActive(false);
				_chooser.SetActive(true);
				_thumbnails.Begin(LiveTexture(menu), NpcCatalog.Offered);
			}
			_thumbnails.Gentle = !_chooser.activeSelf;
			if (_thumbnails.Done && Previewing == null && NpcTuning.IsFitted(DisguisePlugin.Model.Value ?? string.Empty))
			{
				_thumbnails.BeginHats(LiveTexture(menu), menu.GetComponent<CustomizablesLocker>(), DisguisePlugin.Model.Value ?? string.Empty);
			}
		}

		private static RenderTexture LiveTexture(GameObject menu)
		{
			Transform val = menu.transform.Find("RawImage");
			RawImage val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<RawImage>() : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.texture == (Object)null)
			{
				return null;
			}
			return ((Il2CppObjectBase)val2.texture).TryCast<RenderTexture>();
		}

		private void SetIcon(string name, Sprite sprite)
		{
			if (_icons.TryGetValue(name, out var value) && !((Object)(object)value == (Object)null) && !((Object)(object)sprite == (Object)null))
			{
				value.sprite = sprite;
				((Component)value).gameObject.SetActive(true);
				if (_labels.TryGetValue(name, out var value2) && (Object)(object)value2 != (Object)null)
				{
					((Component)value2).gameObject.SetActive(false);
				}
			}
		}

		private void Build(GameObject menu)
		{
			Transform transform = menu.transform;
			Transform val = Require(transform, "Scroll View/Viewport/Content/Slot");
			_locker = menu;
			_chooser = BuildChooser(menu, val);
			_models = BuildModels(menu, val);
			AddBackButton(menu.transform, delegate
			{
				LockerPreview.RestoreEquippedHat();
				Show(_chooser, menu);
			});
			SetText(transform, "TITLE", "HATS");
			CustomizablesLocker component = menu.GetComponent<CustomizablesLocker>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.equipButton != (Object)null)
			{
				((UnityEvent)component.equipButton.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)new Action(LockerPreview.NoteEquippedHat)));
			}
			_builtFor = menu;
		}

		private GameObject BuildChooser(GameObject menu, Transform rowTemplate)
		{
			GameObject val = Clone(menu, "Disguise Chooser");
			Transform content = Require(val.transform, "Scroll View/Viewport/Content");
			AddRow(content, rowTemplate, "MODELS", delegate
			{
				string name = DisguisePlugin.Model.Value ?? string.Empty;
				Preview(name, LabelFor(name));
				Show(_models, _chooser);
			});
			_hatsRow = AddRow(content, rowTemplate, "HATS", delegate
			{
				if (NpcTuning.IsFitted(DisguisePlugin.Model.Value ?? string.Empty))
				{
					_inHats = true;
					Show(_locker, _chooser);
				}
			});
			SetText(val.transform, "TITLE", "CUSTOMIZE");
			SetText(val.transform, "Name", string.Empty);
			return val;
		}

		private GameObject BuildModels(GameObject menu, Transform slot)
		{
			GameObject panel = Clone(menu, "Disguise Models");
			Transform content = Require(panel.transform, "Scroll View/Viewport/Content");
			AddRow(content, slot, "DEFAULT", delegate
			{
				Preview(string.Empty, "DEFAULT");
			});
			Stopwatch stopwatch = Stopwatch.StartNew();
			List<NpcEntry> offered = NpcCatalog.Offered;
			foreach (NpcEntry item in offered)
			{
				string name = item.Name;
				string label = item.Label;
				GameObject val = AddRow(content, slot, label, delegate
				{
					Preview(name, label);
				});
				Transform val2 = val.transform.Find("Item Icon");
				if ((Object)(object)val2 != (Object)null)
				{
					_icons[name] = ((Component)val2).GetComponent<Image>();
				}
				Transform val3 = val.transform.Find("Disguise Label");
				if ((Object)(object)val3 != (Object)null)
				{
					_labels[name] = val3;
				}
				SetIcon(name, _thumbnails.Get(name));
			}
			stopwatch.Stop();
			SetText(panel.transform, "TITLE", "MODELS");
			_modelsName = Find(panel.transform, "Name");
			Transform val4 = panel.transform.Find("Equip Button");
			_changeButton = (((Object)(object)val4 != (Object)null) ? ((Component)val4).gameObject : null);
			Transform val5 = panel.transform.Find("Equipped");
			_appliedLabel = (((Object)(object)val5 != (Object)null) ? ((Component)val5).gameObject : null);
			Unanimate(val4);
			Unanimate(val5);
			Relabel(val4, "CHANGE");
			Relabel(val5, "CURRENT");
			Wire(val4, Commit);
			_hatBadge = AddHatBadge(panel.transform, val4, slot);
			AddBackButton(panel.transform, delegate
			{
				_previewing = null;
				_previewingLabel = null;
				Show(_chooser, panel);
			});
			return panel;
		}

		private GameObject Clone(GameObject menu, string name)
		{
			GameObject val = Object.Instantiate<GameObject>(menu, menu.transform.parent);
			((Object)val).name = name;
			val.SetActive(false);
			CustomizablesLocker component = val.GetComponent<CustomizablesLocker>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Transform val2 = Require(val.transform, "Scroll View/Viewport/Content");
			for (int num = val2.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)val2.GetChild(num)).gameObject);
			}
			Hide(val.transform.Find("Equip Button"));
			Hide(val.transform.Find("Equipped"));
			return val;
		}

		private GameObject AddRow(Transform content, Transform template, string label, Action onClick)
		{
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, content);
			((Object)val).name = "Disguise " + label;
			val.SetActive(true);
			Animator component = val.GetComponent<Animator>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Hide(val.transform.Find("Item Icon"));
			Hide(val.transform.Find("LOCKED"));
			Label(val, label);
			Wire(val.transform.Find("HatSlotButton"), onClick);
			return val;
		}

		private static void Label(GameObject row, string text)
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
			Transform val = row.transform.Find("HAT SLOT CONTROLLER BUTTON PROMPT/Make This Disable In KB&M/GlyphText");
			if ((Object)(object)val == (Object)null)
			{
				ModLog.Warning("[picker] no glyph to label '" + text + "' with.");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, row.transform);
			((Object)val2).name = "Disguise Label";
			val2.SetActive(true);
			ChangeTextToKeybind component = val2.GetComponent<ChangeTextToKeybind>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			TextMeshProUGUI component2 = val2.GetComponent<TextMeshProUGUI>();
			if (!((Object)(object)component2 == (Object)null))
			{
				((TMP_Text)component2).text = text;
				((TMP_Text)component2).enableAutoSizing = true;
				((TMP_Text)component2).alignment = (TextAlignmentOptions)514;
				RectTransform component3 = val2.GetComponent<RectTransform>();
				if (!((Object)(object)component3 == (Object)null))
				{
					component3.anchorMin = Vector2.zero;
					component3.anchorMax = Vector2.one;
					component3.offsetMin = Vector2.zero;
					component3.offsetMax = Vector2.zero;
					((Transform)component3).localScale = Vector3.one;
					val2.transform.SetAsLastSibling();
				}
			}
		}

		private void AddBackButton(Transform panel, Action onClick)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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)
			Transform val = panel.Find("ExitButton");
			if ((Object)(object)val == (Object)null)
			{
				ModLog.Warning("[picker] no ExitButton to clone a back button from.");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, panel);
			((Object)val2).name = "Disguise Back";
			val2.SetActive(true);
			TextMeshProUGUI componentInChildren = val2.GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				LanguageText component = ((Component)componentInChildren).GetComponent<LanguageText>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				((TMP_Text)componentInChildren).enableWordWrapping = false;
				((TMP_Text)componentInChildren).text = "<";
			}
			foreach (Image item in Interop.Safe<Image>(val2.GetComponentsInChildren<Image>(true)))
			{
				((Graphic)item).color = BackTint;
			}
			RectTransform component2 = val2.GetComponent<RectTransform>();
			RectTransform component3 = ((Component)val).GetComponent<RectTransform>();
			if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null)
			{
				Vector2 anchoredPosition = component3.anchoredPosition;
				Rect rect = component3.rect;
				component2.anchoredPosition = anchoredPosition + new Vector2(0f - (((Rect)(ref rect)).width + 4f), 0f);
			}
			Wire(val2.transform, onClick);
		}

		private static void Wire(Transform holder, Action onClick)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			if ((Object)(object)holder == (Object)null)
			{
				return;
			}
			Button val = ((Component)holder).GetComponent<Button>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)holder).GetComponentInChildren<Button>(true);
			}
			if (!((Object)(object)val == (Object)null))
			{
				Component component = ((Component)val).GetComponent(Il2CppType.Of<UIEventCallbacks>());
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				val.onClick = new ButtonClickedEvent();
				((UnityEvent)val.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)onClick));
			}
		}

		private static void Show(GameObject panel, GameObject andHide)
		{
			if ((Object)(object)andHide != (Object)null)
			{
				andHide.SetActive(false);
			}
			if ((Object)(object)panel != (Object)null)
			{
				panel.SetActive(true);
			}
		}

		private void Preview(string name, string label)
		{
			_previewing = name;
			_previewingLabel = label;
			if ((Object)(object)_modelsName != (Object)null)
			{
				((TMP_Text)_modelsName).text = label;
			}
			RefreshChangeButton();
		}

		private void Commit()
		{
			if (_previewing != null)
			{
				Choose(_previewing, _previewingLabel);
				RefreshChangeButton();
			}
		}

		private void RefreshHatsRow()
		{
			if ((Object)(object)_hatsRow == (Object)null)
			{
				return;
			}
			string text = DisguisePlugin.Model.Value ?? string.Empty;
			if (!string.Equals(_hatsRowFor, text, StringComparison.Ordinal))
			{
				_hatsRowFor = text;
				Transform val = _hatsRow.transform.Find("LOCKED");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(!NpcTuning.IsFitted(text));
				}
			}
		}

		private static string LabelFor(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "DEFAULT";
			}
			NpcEntry npcEntry = NpcCatalog.Find(name);
			return (npcEntry != null) ? npcEntry.Label : name;
		}

		private void RefreshChangeButton()
		{
			bool flag = string.Equals(_previewing ?? string.Empty, DisguisePlugin.Model.Value ?? string.Empty, StringComparison.Ordinal);
			if ((Object)(object)_changeButton != (Object)null)
			{
				_changeButton.SetActive(_previewing != null && !flag);
			}
			if ((Object)(object)_appliedLabel != (Object)null)
			{
				_appliedLabel.SetActive(_previewing != null && flag);
			}
			if ((Object)(object)_hatBadge != (Object)null)
			{
				_hatBadge.SetActive(_previewing != null && NpcTuning.IsFitted(_previewing));
			}
		}

		private void Choose(string name, string label)
		{
			DisguisePlugin.Model.Value = name;
			ModLog.Msg(string.IsNullOrEmpty(name) ? "Back to your own body." : ("Appearing as '" + label + "'."));
		}

		private static GameObject AddHatBadge(Transform panel, Transform beside, Transform slot)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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)
			Transform val = slot.Find("Item Icon");
			if ((Object)(object)val == (Object)null || (Object)(object)beside == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, panel);
			((Object)val2).name = "Disguise Hat Badge";
			val2.SetActive(false);
			Unanimate(val2.transform);
			Image component = val2.GetComponent<Image>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			component.sprite = FindSprite("Customizables Icon");
			component.overrideSprite = null;
			((Graphic)component).color = Color.white;
			if ((Object)(object)component.sprite == (Object)null)
			{
				ModLog.Warning("[picker] no sprite called 'Customizables Icon' is loaded, badge will be blank.");
			}
			RectTransform component2 = val2.GetComponent<RectTransform>();
			RectTransform component3 = ((Component)beside).GetComponent<RectTransform>();
			if ((Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null)
			{
				return val2;
			}
			Rect rect = component3.rect;
			float height = ((Rect)(ref rect)).height;
			component2.anchorMin = component3.anchorMin;
			component2.anchorMax = component3.anchorMax;
			component2.pivot = component3.pivot;
			component2.sizeDelta = new Vector2(height, height);
			((Transform)component2).localScale = Vector3.one;
			Vector2 anchoredPosition = component3.anchoredPosition;
			rect = component3.rect;
			component2.anchoredPosition = anchoredPosition + new Vector2((((Rect)(ref rect)).width + height) * 0.5f + 6f, 0f);
			return val2;
		}

		private static Sprite FindSprite(string name)
		{
			foreach (Sprite item in Interop.Safe<Sprite>(Resources.FindObjectsOfTypeAll<Sprite>()))
			{
				if ((Object)(object)item != (Object)null && string.Equals(((Object)item).name, name, StringComparison.Ordinal))
				{
					return item;
				}
			}
			return null;
		}

		private static void Unanimate(Transform holder)
		{
			if ((Object)(object)holder == (Object)null)
			{
				return;
			}
			foreach (Animator item in Interop.Safe<Animator>(((Component)holder).GetComponentsInChildren<Animator>(true)))
			{
				Object.Destroy((Object)(object)item);
			}
		}

		private static void Relabel(Transform holder, string text)
		{
			if ((Object)(object)holder == (Object)null)
			{
				return;
			}
			TextMeshProUGUI componentInChildren = ((Component)holder).GetComponentInChildren<TextMeshProUGUI>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				LanguageText component = ((Component)componentInChildren).GetComponent<LanguageText>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				((TMP_Text)componentInChildren).enableWordWrapping = false;
				((TMP_Text)componentInChildren).text = text;
			}
		}

		private static void Hide(Transform t)
		{
			if ((Object)(object)t != (Object)null)
			{
				((Component)t).gameObject.SetActive(false);
			}
		}

		private static TextMeshProUGUI Find(Transform panel, string child)
		{
			Transform val = panel.Find(child);
			return ((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null;
		}

		private static void SetText(Transform panel, string child, string text)
		{
			TextMeshProUGUI val = Find(panel, child);
			if (!((Object)(object)val == (Object)null))
			{
				LanguageText component = ((Component)val).GetComponent<LanguageText>();
				if ((Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
				((TMP_Text)val).text = text;
			}
		}

		private static Transform Require(Transform root, string path)
		{
			Transform val = root.Find(path);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("Customizables path missing: '" + path + "'");
			}
			return val;
		}
	}
	internal sealed class LockerPreview
	{
		private const string CameraHolder = "CameraHolder";

		private readonly PlayerSkin _skin = new PlayerSkin();

		private GameObject _builtFor;

		private Transform _holder;

		private Vector3 _holderRest;

		private const int Unknown = -1;

		private const int BareHeaded = -2;

		private static int _equippedHat = -1;

		public bool Suspended { get; set; }

		public string Worn => _skin.Current ?? string.Empty;

		public Transform Head
		{
			get
			{
				Transform head = _skin.Head;
				if ((Object)(object)head != (Object)null)
				{
					return head;
				}
				HatsRenderer instance = HatsRenderer.Instance;
				return ((Object)(object)instance != (Object)null) ? PlayerSkin.FindJoint(((Component)instance).transform, "mixamorig:HeadTop_End") : null;
			}
		}

		public bool Wear(NpcEntry entry)
		{
			HatsRenderer instance = HatsRenderer.Instance;
			if ((Object)(object)instance == (Object)null || entry == null)
			{
				return false;
			}
			BodyTarget bodyTarget = BodyTarget.OfMannequin(((Component)instance).gameObject);
			if (bodyTarget == null || !bodyTarget.Valid)
			{
				return false;
			}
			_builtFor = ((Component)instance).gameObject;
			return _skin.Apply(bodyTarget, entry);
		}

		public void FaceTowards(float degrees)
		{
			_skin.Turn(degrees);
		}

		public void Tick(string wanted)
		{
			if (Suspended)
			{
				return;
			}
			try
			{
				HatsRenderer instance = HatsRenderer.Instance;
				GameObject val = (((Object)(object)instance != (Object)null) ? ((Component)instance).gameObject : null);
				if ((Object)(object)val == (Object)null || ((Object)(object)_builtFor != (Object)null && ((Il2CppObjectBase)val).Pointer != ((Il2CppObjectBase)_builtFor).Pointer))
				{
					_skin.Revert();
					_builtFor = null;
				}
				if ((Object)(object)val == (Object)null || _skin.Current == (string.IsNullOrEmpty(wanted) ? null : wanted))
				{
					return;
				}
				if (string.IsNullOrEmpty(wanted))
				{
					_skin.Revert();
					return;
				}
				NpcEntry npcEntry = NpcCatalog.Find(wanted);
				if (npcEntry != null)
				{
					BodyTarget bodyTarget = BodyTarget.OfMannequin(val);
					if (bodyTarget == null || !bodyTarget.Valid)
					{
						ModLog.Warning("[locker] found the mannequin but not its body, leaving the preview alone.");
					}
					else if (_skin.Apply(bodyTarget, npcEntry))
					{
						_builtFor = val;
					}
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Locker preview: {value}");
			}
		}

		public void LateTick()
		{
			_skin.LateTick();
			AimAtHead();
		}

		private void AimAtHead()
		{
			//IL_0017: 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)
			if (FindHolder())
			{
				_holder.localPosition = _holderRest + new Vector3(0f, _skin.HeadLift, 0f);
			}
		}

		private bool FindHolder()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_holder != (Object)null)
			{
				return true;
			}
			HatsRenderer instance = HatsRenderer.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			_holder = ((Component)instance).transform.Find("CameraHolder");
			if ((Object)(object)_holder == (Object)null)
			{
				return false;
			}
			_holderRest = _holder.localPosition;
			return true;
		}

		public static void NoteEquippedHat()
		{
			HatsRenderer instance = HatsRenderer.Instance;
			if ((Object)(object)instance == (Object)null || instance.hatObjs == null)
			{
				return;
			}
			for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)instance.hatObjs).Length; i++)
			{
				GameObject val = ((Il2CppArrayBase<GameObject>)(object)instance.hatObjs)[i];
				if (!((Object)(object)val == (Object)null) && val.activeSelf)
				{
					_equippedHat = i;
					return;
				}
			}
			_equippedHat = -2;
		}

		public static void RestoreEquippedHat()
		{
			HatsRenderer instance = HatsRenderer.Instance;
			if ((Object)(object)instance == (Object)null || instance.hatObjs == null || _equippedHat == -1)
			{
				return;
			}
			try
			{
				if (_equippedHat == -2)
				{
					foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)instance.hatObjs)
					{
						if ((Object)(object)item != (Object)null)
						{
							item.SetActive(false);
						}
					}
					return;
				}
				instance.SelectHat(_equippedHat);
			}
			catch (Exception ex)
			{
				ModLog.Warning("[locker] could not put the hat back: " + ex.Message);
			}
		}

		public void Clear()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_holder != (Object)null)
				{
					_holder.localPosition = _holderRest;
				}
			}
			catch
			{
			}
			try
			{
				_skin.Revert();
			}
			catch
			{
			}
			_builtFor = null;
			_holder = null;
			_equippedHat = -1;
		}
	}
	internal static class ModLog
	{
		public static ManualLogSource Source;

		[Conditional("DEVTOOLS")]
		public static void Debug(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Msg(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		public static void Warning(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogWarning((object)message);
			}
		}

		public static void Error(string message)
		{
			ManualLogSource source = Source;
			if (source != null)
			{
				source.LogError((object)message);
			}
		}
	}
	internal static class NetworkContext
	{
		public static NetworkRunner Runner
		{
			get
			{
				FusionNetworkManager instance = FusionNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				NetworkRunner runner = instance._runner;
				if ((Object)(object)runner == (Object)null || !runner.IsRunning)
				{
					return null;
				}
				return runner;
			}
		}

		public static bool InSession => (Object)(object)Runner != (Object)null;

		public static PlayerManager LocalPlayerManager
		{
			get
			{
				ClientPlayer instance = ClientPlayer.Instance;
				return ((Object)(object)instance == (Object)null) ? null : instance.playerMan;
			}
		}

		public static ThirdPersonManager LocalBody
		{
			get
			{
				PlayerManager localPlayerManager = LocalPlayerManager;
				return ((Object)(object)localPlayerManager == (Object)null) ? null : localPlayerManager.thirdPersonMan;
			}
		}
	}
	internal sealed class NpcEntry
	{
		public string Name;

		public string Label;

		public GameObject Prefab;
	}
	internal static class NpcCatalog
	{
		private const int MinimumBones = 16;

		private const string BonePrefix = "mixamorig:";

		private static List<NpcEntry> _entries;

		private static List<NpcEntry> _offered;

		public static List<NpcEntry> Entries
		{
			get
			{
				if (_entries == null)
				{
					_entries = Build();
				}
				return _entries;
			}
		}

		public static List<NpcEntry> Offered
		{
			get
			{
				if (_offered == null)
				{
					_offered = Curate();
				}
				return _offered;
			}
		}

		public static void Invalidate()
		{
			_entries = null;
			_offered = null;
		}

		private static List<NpcEntry> Curate()
		{
			List<NpcEntry> list = new List<NpcEntry>();
			List<string> list2 = new List<string>();
			foreach (string name in NpcRoster.Names)
			{
				NpcEntry npcEntry = Find(name);
				if (npcEntry != null)
				{
					list.Add(npcEntry);
				}
				else
				{
					list2.Add(name);
				}
			}
			if (list2.Count > 0)
			{
				ModLog.Warning("[catalog] offered but not in this build: " + string.Join(", ", list2));
			}
			ModLog.Msg($"[catalog] offering {list.Count} curated NPCs, {list2.Count} not found.");
			return list;
		}

		private static List<NpcEntry> Build()
		{
			Stopwatch stopwatch = Stopwatch.StartNew();
			Dictionary<string, NpcEntry> dictionary = new Dictionary<string, NpcEntry>(StringComparer.OrdinalIgnoreCase);
			AddDayPeople(dictionary);
			int count = dictionary.Count;
			AddPrefabTable(dictionary);
			stopwatch.Stop();
			List<NpcEntry> list = new List<NpcEntry>(dictionary.Values);
			Dictionary<string, string> dictionary2 = NpcRoster.Labels(dictionary.Keys);
			foreach (NpcEntry item in list)
			{
				item.Label = (dictionary2.ContainsKey(item.Name) ? dictionary2[item.Name] : item.Name);
			}
			list.Sort((NpcEntry a, NpcEntry b) => string.Compare(a.Label, b.Label, StringComparison.OrdinalIgnoreCase));
			return list;
		}

		private static void AddDayPeople(Dictionary<string, NpcEntry> found)
		{
			TryAdd(delegate
			{
				StoreManager instance = StoreManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				foreach (GameObject item in Interop.Safe<GameObject>(instance.allBrowsingNpcs))
				{
					Add(found, item);
				}
				foreach (GameObject item2 in Interop.Safe<GameObject>(instance.allNuisanceNpcs))
				{
					Add(found, item2);
				}
			}, "StoreManager");
			TryAdd(delegate
			{
				CurrentDayManager instance = CurrentDayManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				foreach (GameObject item3 in Interop.Safe<GameObject>((Il2CppArrayBase<GameObject>)(object)instance.thieves))
				{
					Add(found, item3);
				}
				foreach (GameObject item4 in Interop.Safe<GameObject>(instance.eventNpcs))
				{
					Add(found, item4);
				}
			}, "CurrentDayManager");
			TryAdd(delegate
			{
				EventManager instance = EventManager.Instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.vanessa == (Object)null))
				{
					Add(found, ((Component)instance.vanessa).gameObject);
				}
			}, "EventManager");
		}

		private static void AddPrefabTable(Dictionary<string, NpcEntry> found)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				NetworkProjectConfig global = NetworkProjectConfig.Global;
				NetworkPrefabTable val = ((global != null) ? global.PrefabTable : null);
				List<INetworkPrefabSource> val2 = ((val != null) ? val._sources : null);
				if (val2 == null)
				{
					ModLog.Warning("[catalog] Fusion prefab table unavailable.");
					return;
				}
				for (int i = 0; i < val2.Count; i++)
				{
					try
					{
						INetworkPrefabSource val3 = val2[i];
						if (val3 != null)
						{
							NetworkObject val4 = val.Load(val.GetId(val3.AssetGuid), true);
							if ((Object)(object)val4 != (Object)null)
							{
								Add(found, ((Component)val4).gameObject);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("[catalog] prefab table pass failed: " + ex.Message);
			}
		}

		private static void Add(Dictionary<string, NpcEntry> found, GameObject go)
		{
			if (!((Object)(object)go == (Object)null) && !string.IsNullOrEmpty(((Object)go).name) && !found.ContainsKey(((Object)go).name) && Wearable(go))
			{
				found[((Object)go).name] = new NpcEntry
				{
					Name = ((Object)go).name,
					Prefab = go
				};
			}
		}

		private static bool Wearable(GameObject go)
		{
			foreach (SkinnedMeshRenderer item in Interop.Safe<SkinnedMeshRenderer>(go.GetComponentsInChildren<SkinnedMeshRenderer>(true)))
			{
				if ((Object)(object)item.sharedMesh == (Object)null || item.bones == null || ((Il2CppArrayBase<Transform>)(object)item.bones).Length < 16)
				{
					continue;
				}
				int num = 0;
				foreach (Transform item2 in Interop.Safe<Transform>((Il2CppArrayBase<Transform>)(object)item.bones))
				{
					if (((Object)item2).name.StartsWith("mixamorig:", StringComparison.Ordinal))
					{
						num++;
					}
				}
				if (num < 16)
				{
					continue;
				}
				return true;
			}
			return false;
		}

		private static void TryAdd(Action action, string source)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				ModLog.Warning("[catalog] source '" + source + "' failed: " + ex.Message);
			}
		}

		public static NpcEntry Find(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			foreach (NpcEntry entry in Entries)
			{
				if (string.Equals(entry.Name, name, StringComparison.OrdinalIgnoreCase))
				{
					return entry;
				}
			}
			return null;
		}
	}
	internal static class NpcRoster
	{
		private static readonly string[] Offered = Build("Agnes Wells Doppel 1", "Amelia Kramer", "Amiah Gutierrez 1", "Andal Khan 1", "Anita Varma", "Aria Romero 1", "Baron Dean Doppel 1", "Barry Aoki", "Bartholomew Kessler 1", "Beth Callahan", "Bonnie McCree", "Brandon Keller", "Cara Hastings", "Colin Shirley 1", "Daniel Flores", "Darla Groves 1", "Dave Buster Doppel 1", "David Kennedy", "DerrickVaughn", "Diana Volkov", "Diane Hays 1");

		private static readonly string[] Ranges = Build(Range("BrowsingPerson", 1, 8), Range("BrowsingPerson", 10, 19));

		private static readonly string[] Categories = new string[7] { "CAR", "BIG CAR", "CAR SUV", "CAR MINIVAN", "BrowsingPerson", "Nuisance Customer", "Thief" };

		public static IEnumerable<string> Names
		{
			get
			{
				string[] offered = Offered;
				for (int i = 0; i < offered.Length; i++)
				{
					yield return offered[i];
				}
				string[] ranges = Ranges;
				for (int j = 0; j < ranges.Length; j++)
				{
					yield return ranges[j];
				}
			}
		}

		public static Dictionary<string, string> Labels(IEnumerable<string> prefabs)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			foreach (string prefab in prefabs)
			{
				dictionary[prefab] = Shorten(prefab);
			}
			return dictionary;
		}

		private static string Shorten(string prefab)
		{
			string text = prefab.Trim();
			string text2 = TrimTrailingNumber(text);
			string[] categories = Categories;
			foreach (string b in categories)
			{
				if (string.Equals(text2, b, StringComparison.OrdinalIgnoreCase))
				{
					return text;
				}
			}
			text = text2;
			if (text.EndsWith(" Doppel", StringComparison.OrdinalIgnoreCase))
			{
				text = TrimTrailingNumber(text.Substring(0, text.Length - " Doppel".Length).TrimEnd());
			}
			return (text.Length == 0) ? prefab : text;
		}

		private static string TrimTrailingNumber(string name)
		{
			int num = name.Length;
			while (num > 0 && char.IsDigit(name[num - 1]))
			{
				num--;
			}
			if (num == name.Length || num == 0)
			{
				return name;
			}
			if (name[num - 1] != ' ')
			{
				return name;
			}
			return name.Substring(0, num).TrimEnd();
		}

		private static string[] Build(params string[] names)
		{
			return names;
		}

		private static string[] Build(params string[][] groups)
		{
			List<string> list = new List<string>();
			foreach (string[] collection in groups)
			{
				list.AddRange(collection);
			}
			return list.ToArray();
		}

		private static string[] Range(string prefix, int from, int to)
		{
			string[] array = new string[to - from + 1];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = prefix + " " + (from + i);
			}
			return array;
		}
	}
	internal static class NpcTuning
	{
		internal struct Offsets
		{
			public float Up;

			public float Forward;

			public float HatUp;

			public float HatForward;

			public float HatScale;
		}

		private sealed class Entry
		{
			public readonly string Match;

			public readonly Offsets Values;

			public Entry(string match, float up = 0f, float forward = 0f, float hatUp = 0f, float hatForward = 0f, float hatScale = 1f)
			{
				Match = match;
				Values = new Offsets
				{
					Up = up,
					Forward = forward,
					HatUp = hatUp,
					HatForward = hatForward,
					HatScale = hatScale
				};
			}
		}

		private static readonly Entry[] Measured = new Entry[14]
		{
			new Entry("Agnes Wells Doppel 1", 0f, 0f, 0f, 0.03f, 1.128f),
			new Entry("Amelia Kramer", 0f, 0f, 0f, 0.04f),
			new Entry("Amiah Gutierrez 1", 0f, 0f, 0f, 0.02f),
			new Entry("Andal Khan 1", 0f, 0f, 0f, 0f, 1.1f),
			new Entry("Anita Varma", 0f, 0f, 0f, 0.08f, 0.94f),
			new Entry("Aria Romero 1", 0f, 0f, 0f, 0.06f, 0.9f),
			new Entry("Baron Dean Doppel 1", 0f, 0f, 0f, 0.016f, 1.06f),
			new Entry("Barry Aoki", 0f, 0f, 0f, 0.018f, 0.9f),
			new Entry("Bartholomew Kessler 1", 0f, 0f, 0f, 0.01f, 0.92f),
			new Entry("Beth Callahan", 0f, 0f, 0f, 0.03f),
			new Entry("Bonnie McCree", 0f, 0f, 0.006f),
			new Entry("Brandon Keller"),
			new Entry("Cara Hastings", 0f, 0f, -0.01f, 0.018f),
			new Entry("Daniel Flores", 0f, 0f, 0f, 0.016f, 1.05f)
		};

		public static bool IsFitted(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return true;
			}
			Entry[] measured = Measured;
			foreach (Entry entry in measured)
			{
				if (string.Equals(entry.Match, name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public static Offsets For(string name)
		{
			Offsets result = Lookup(name);
			if (result.HatScale <= 0f)
			{
				result.HatScale = 1f;
			}
			return result;
		}

		private static Offsets Lookup(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return default(Offsets);
			}
			Entry[] measured = Measured;
			foreach (Entry entry in measured)
			{
				if (string.Equals(entry.Match, name, StringComparison.OrdinalIgnoreCase))
				{
					return entry.Values;
				}
			}
			return default(Offsets);
		}
	}
	internal sealed class PlayerSkin
	{
		private struct Hidden
		{
			public SkinnedMeshRenderer Renderer;

			public Mesh Mesh;
		}

		private struct Moved
		{
			public Transform Thing;

			public Transform Home;

			public Vector3 Rest;

			public Vector3 HomeScale;

			public Vector3 WornScale;
		}

		private struct BonePair
		{
			public Transform Source;

			public Transform Model;
		}

		private const string BonePrefix = "mixamorig:";

		private const string HipsBone = "mixamorig:Hips";

		internal const string HeadBone = "mixamorig:HeadTop_End";

		private static readonly string[] FootBones = new string[4] { "mixamorig:LeftToeBase", "mixamorig:RightToeBase", "mixamorig:LeftFoot", "mixamorig:RightFoot" };

		private const int MinimumBones = 12;

		private readonly List<Hidden> _hidden = new List<Hidden>();

		private readonly List<BonePair> _pairs = new List<BonePair>();

		private readonly List<BonePair> _feet = new List<BonePair>();

		private readonly List<Renderer> _worn = new List<Renderer>();

		private readonly List<Moved> _moved = new List<Moved>();

		private readonly List<Renderer> _blanked = new List<Renderer>();

		private BodyTarget _target;

		private GameObject _model;

		private Transform _sourceHips;

		private Transform _modelHips;

		private Transform _modelHead;

		private Transform _sourceHead;

		private Vector3 _hipOffset;

		private Vector3 _alignment;

		private NpcTuning.Offsets _tuning;

		private const float FootTolerance = 0.001f;

		public Transform Head => _modelHead;

		public float HeadLift => ((Object)(object)_modelHead != (Object)null && (Object)(object)_sourceHead != (Object)null) ? (_modelHead.position.y - _sourceHead.position.y) : 0f;

		public bool Active => (Object)(object)_model != (Object)null;

		public string Current { get; private set; }

		public NpcTuning.Offsets Tuning
		{
			get
			{
				return _tuning;
			}
			set
			{
				_tuning = value;
				Place();
				PlaceHats();
			}
		}

		private void Place()
		{
			//IL_001f: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_model == (Object)null))
			{
				_model.transform.localPosition = _alignment + new Vector3(0f, _tuning.Up, _tuning.Forward);
			}
		}

		public void Turn(float degrees)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_model != (Object)null)
			{
				_model.transform.localRotation = Quaternion.Euler(0f, degrees, 0f);
			}
		}

		private void PlaceHats()
		{
			//IL_003c: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_model == (Object)null)
			{
				return;
			}
			Vector3 val = _model.transform.TransformVector(new Vector3(0f, _tuning.HatUp, _tuning.HatForward));
			foreach (Moved item in _moved)
			{
				if (!((Object)(object)item.Thing == (Object)null) && !((Object)(object)item.Thing.parent == (Object)null))
				{
					item.Thing.localPosition = item.Rest + item.Thing.parent.InverseTransformVector(val);
					item.Thing.localScale = item.WornScale * _tuning.HatScale;
				}
			}
		}

		public bool Apply(BodyTarget target, NpcEntry npc)
		{
			if (target == null || !target.Valid || npc == null || (Object)(object)npc.Prefab == (Object)null)
			{
				return false;
			}
			Dictionary<string, Transform> dictionary = MapSkeleton(target.Root);
			Revert();
			GameObject val = LocalModel.Create(npc.Prefab, target.Root);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			LocalModel.SetLayer(val, ((Component)target.Parts[0]).gameObject.layer);
			if (!PairBones(val, dictionary, npc.Name))
			{
				Object.Destroy((Object)(object)val);
				return false;
			}
			_model = val;
			_target = target;
			_modelHead = FindJoint(val.transform, "mixamorig:HeadTop_End");
			dictionary.TryGetValue("mixamorig:HeadTop_End", out _sourceHead);
			Pose();
			Align(dictionary);
			CarryHats(npc.Name);
			Tuning = NpcTuning.For(npc.Name);
			foreach (SkinnedMeshRenderer part in target.Parts)
			{
				_hidden.Add(new Hidden
				{
					Renderer = part,
					Mesh = part.sharedMesh
				});
				part.sharedMesh = null;
			}
			foreach (Renderer item in Interop.Safe<Renderer>(val.GetComponentsInChildren<Renderer>(true)))
			{
				_worn.Add(item);
			}
			Current = npc.Name;
			ModLog.Msg($"'{((Object)target.Root).name}' wearing '{npc.Name}' ({_pairs.Count} joints driven).");
			WarnIfNothingToSee(npc.Name);
			return true;
		}

		public void Revert()
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			foreach (Hidden item in _hidden)
			{
				if (!((Object)(object)item.Renderer == (Object)null))
				{
					try
					{
						item.Renderer.sharedMesh = item.Mesh;
					}
					catch (Exception ex)
					{
						ModLog.Warning("Could not restore '" + ((Object)item.Renderer).name + "': " + ex.Message);
					}
				}
			}
			foreach (Moved item2 in _moved)
			{
				if (!((Object)(object)item2.Thing == (Object)null) && !((Object)(object)item2.Home == (Object)null))
				{
					try
					{
						item2.Thing.SetParent(item2.Home, false);
						item2.Thing.localPosition = item2.Rest;
						item2.Thing.localScale = item2.HomeScale;
					}
					catch (Exception ex2)
					{
						ModLog.Warning("Could not return '" + ((Object)item2.Thing).name + "': " + ex2.Message);
					}
				}
			}
			foreach (Renderer item3 in _blanked)
			{
				if ((Object)(object)item3 != (Object)null)
				{
					item3.enabled = true;
				}
			}
			_hidden.Clear();
			_pairs.Clear();
			_feet.Clear();
			_worn.Clear();
			_moved.Clear();
			_blanked.Clear();
			_target = null;
			_sourceHips = null;
			_modelHips = null;
			_modelHead = null;
			_sourceHead = null;
			if ((Object)(object)_model != (Object)null)
			{
				try
				{
					Object.Destroy((Object)(object)_model);
				}
				catch
				{
				}
				_model = null;
			}
			Current = null;
		}

		public void LateTick()
		{
			if (!((Object)(object)_model == (Object)null))
			{
				Pose();
				FollowBodyVisibility();
			}
		}

		private void Pose()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _pairs.Count; i++)
			{
				BonePair bonePair = _pairs[i];
				if (!((Object)(object)bonePair.Source == (Object)null) && !((Object)(object)bonePair.Model == (Object)null))
				{
					bonePair.Model.localRotation = bonePair.Source.localRotation;
				}
			}
			if ((Object)(object)_modelHips != (Object)null && (Object)(object)_sourceHips != (Object)null)
			{
				_modelHips.localPosition = _sourceHips.localPosition + _hipOffset;
			}
			FollowFeet();
		}

		private void FollowFeet()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_model == (Object)null || _target == null || !_target.IsPlayer || _feet.Count == 0)
			{
				return;
			}
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			for (int i = 0; i < _feet.Count; i++)
			{
				BonePair bonePair = _feet[i];
				if (!((Object)(object)bonePair.Source == (Object)null) && !((Object)(object)bonePair.Model == (Object)null))
				{
					if (bonePair.Source.position.y < num)
					{
						num = bonePair.Source.position.y;
					}
					if (bonePair.Model.position.y < num2)
					{
						num2 = bonePair.Model.position.y;
					}
				}
			}
			if (num != float.MaxValue && num2 != float.MaxValue)
			{
				float num3 = Mathf.Max(num, _target.Root.position.y);
				float num4 = num3 - num2;
				if (!(Mathf.Abs(num4) < 0.001f))
				{
					Transform transform = _model.transform;
					transform.position += new Vector3(0f, num4, 0f);
				}
			}
		}

		private void FollowBodyVisibility()
		{
			if (_hidden.Count == 0)
			{
				return;
			}
			bool flag = false;
			foreach (Hidden item in _hidden)
			{
				if ((Object)(object)item.Renderer == (Object)null || !((Renderer)item.Renderer).enabled || !((Component)item.Renderer).gameObject.activeInHierarchy)
				{
					continue;
				}
				flag = true;
				break;
			}
			for (int i = 0; i < _worn.Count; i++)
			{
				Renderer val = _worn[i];
				if ((Object)(object)val != (Object)null && val.enabled != flag)
				{
					val.enabled = flag;
				}
			}
		}

		private void WarnIfNothingToSee(string name)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			Bounds val = default(Bounds);
			bool flag = false;
			foreach (Renderer item in _worn)
			{
				if (!((Object)(object)item == (Object)null))
				{
					if (!flag)
					{
						val = item.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref val)).Encapsulate(item.bounds);
					}
				}
			}
			if (!flag || !(((Bounds)(ref val)).size.y >= 0.3f))
			{
				ModLog.Warning(flag ? ($"'{name}' is only {((Bounds)(ref val)).size.y:0.##}m tall, so there is probably nothing to see. " + "It is in the list because it stands on the right skeleton, not because it is a person.") : ("'" + name + "' has no renderers at all, so nothing will show."));
			}
		}

		private void CarryHats(string npc)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_model == (Object)null || _target == null)
			{
				return;
			}
			if (!NpcTuning.IsFitted(npc))
			{
				BlankHats();
				return;
			}
			Transform val = FindJoint(_target.Root, "mixamorig:HeadTop_End");
			Transform val2 = FindJoint(_model.transform, "mixamorig:HeadTop_End");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return;
			}
			for (int num = val.childCount - 1; num >= 0; num--)
			{
				Transform child = val.GetChild(num);
				if (!((Object)child).name.StartsWith("mixamorig:", StringComparison.Ordinal))
				{
					Transform home = val;
					Vector3 lossyScale = child.lossyScale;
					Vector3 localScale = child.localScale;
					child.SetParent(val2, false);
					Rescale(child, lossyScale);
					_moved.Add(new Moved
					{
						Thing = child,
						Home = home,
						HomeScale = localScale,
						WornScale = child.localScale,
						Rest = child.localPosition
					});
				}
			}
			if (_moved.Count <= 0)
			{
			}
		}

		private static void Rescale(Transform t, Vector3 wanted)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006d: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)t.parent != (Object)null) ? t.parent.lossyScale : Vector3.one);
			if (!Mathf.Approximately(val.x, 0f) && !Mathf.Approximately(val.y, 0f) && !Mathf.Approximately(val.z, 0f))
			{
				t.localScale = new Vector3(wanted.x / val.x, wanted.y / val.y, wanted.z / val.z);
			}
		}

		private void BlankHats()
		{
			Transform val = FindJoint(_target.Root, "mixamorig:HeadTop_End");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int i = 0; i < val.childCount; i++)
			{
				Transform child = val.GetChild(i);
				if (((Object)child).name.StartsWith("mixamorig:", StringComparison.Ordinal))
				{
					continue;
				}
				foreach (Renderer item in Interop.Safe<Renderer>(((Component)child).GetComponentsInChildren<Renderer>(true)))
				{
					if (item.enabled)
					{
						item.enabled = false;
						_blanked.Add(item);
					}
				}
			}
		}

		internal static Transform FindJoint(Transform root, string name)
		{
			foreach (Transform item in Interop.Safe<Transform>(((Component)root).GetComponentsInChildren<Transform>(true)))
			{
				if (((Object)item).name == name)
				{
					return item;
				}
			}
			return null;
		}

		private void Align(Dictionary<string, Transform> skeleton)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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)
			_alignment = Vector3.zero;
			if (!((Object)(object)_model == (Object)null) && !((Object)(object)_modelHips == (Object)null) && !((Object)(object)_sourceHips == (Object)null))
			{
				Vector3 val = _sourceHips.position - _modelHips.position;
				if (LowestFoot(skeleton, out var y) && LowestFoot(_model.transform, out var y2))
				{
					float num = (_target.IsPlayer ? Mathf.Max(y, _target.Root.position.y) : y);
					val.y = num - y2;
				}
				Transform transform = _model.transform;
				transform.position += val;
				_alignment = _model.transform.localPosition;
			}
		}

		private static bool LowestFoot(Dictionary<string, Transform> skeleton, out float y)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			y = 0f;
			bool flag = false;
			string[] footBones = FootBones;
			foreach (string key in footBones)
			{
				if (skeleton.TryGetValue(key, out var value) && !((Object)(object)value == (Object)null))
				{
					if (!flag || value.position.y < y)
					{
						y = value.position.y;
					}
					flag = true;
				}
			}
			return flag;
		}

		private static bool LowestFoot(Transform root, out float y)
		{
			//IL_0044: 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)
			y = 0f;
			bool flag = false;
			foreach (Transform item in Interop.Safe<Transform>(((Component)root).GetComponentsInChildren<Transform>(true)))
			{
				if (Array.IndexOf(FootBones, ((Object)item).name) >= 0)
				{
					if (!flag || item.position.y < y)
					{
						y = item.position.y;
					}
					flag = true;
				}
			}
			return flag;
		}

		private bool PairBones(GameObject model, Dictionary<string, Transform> skeleton, string name)
		{
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			foreach (Transform item in Interop.Safe<Transform>(model.GetComponentsInChildren<Transform>(true)))
			{
				if (((Object)item).name.StartsWith("mixamorig:", StringComparison.Ordinal) && skeleton.TryGetValue(((Object)item).name, out var value))
				{
					_pairs.Add(new BonePair
					{
						Source = value,
						Model = item
					});
					if (Array.IndexOf(FootBones, ((Object)item).name) >= 0)
					{
						_feet.Add(new BonePair
						{
							Source = value,
							Model = item
						});
					}
					if (((Object)item).name == "mixamorig:Hips" && (Object)(object)_modelHips == (Object)null)
					{
						_modelHips = item;
						_sourceHips = value;
						_hipOffset = item.localPosition - value.localPosition;
					}
				}
			}
			if (_pairs.Count >= 12)
			{
				return true;
			}
			ModLog.Warning($"'{name}' shares only {_pairs.Count} joints with the body, refusing rather " + "than showing a model that cannot move.");
			_pairs.Clear();
			_feet.Clear();
			_modelHips = null;
			_sourceHips = null;
			return false;
		}

		private static Dictionary<string, Transform> MapSkeleton(Transform root)
		{
			Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(StringComparer.Ordinal);
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal);
			foreach (Transform item in Interop.Safe<Transform>(((Component)root).GetComponentsInChildren<Transform>(true)))
			{
				if (((Object)item).name.StartsWith("mixamorig:", StringComparison.Ordinal))
				{
					int num = DepthBelow(item, root);
					if (!dictionary2.TryGetValue(((Object)item).name, out var value) || value > num)
					{
						dictionary[((Object)item).name] = item;
						dictionary2[((Object)item).name] = num;
					}
				}
			}
			return dictionary;
		}

		private static int DepthBelow(Transform t, Transform root)
		{
			int num = 0;
			while ((Object)(object)t != (Object)null && ((Il2CppObjectBase)t).Pointer != ((Il2CppObjectBase)root).Pointer)
			{
				num++;
				t = t.parent;
			}
			return num;
		}

		private static string FullPath(Transform t)
		{
			List<string> list = new List<string>();
			while ((Object)(object)t != (Object)null)
			{
				list.Add(((Object)t).name);
				t = t.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
	internal sealed class SkinSync
	{
		private const string Key = "disguise";

		private const string Version = "1";

		private const char Separator = '|';

		private const float PollInterval = 1f;

		private readonly Dictionary<int, PlayerSkin> _skins = new Dictionary<int, PlayerSkin>();

		private readonly Dictionary<int, string> _wanted = new Dictionary<int, string>();

		private readonly List<int> _seen = new List<int>();

		private float _nextPoll;

		private string _published;

		private int _reportedMembers = -1;

		private int _reportedPublishers = -1;

		public string LocalChoice { get; set; }

		public int Publishers { get; private set; }

		public int Members { get; private set; }

		public void Tick()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CSteamID val = Lobby();
				if (val.m_SteamID != 0)
				{
					Publish(val);
					if (!(Time.unscaledTime < _nextPoll))
					{
						_nextPoll = Time.unscaledTime + 1f;
						Poll(val);
						ApplyAll();
					}
				}
			}
			catch (Exception value)
			{
				ModLog.Error($"Sync: {value}");
			}
		}

		public void LateTick()
		{
			foreach (PlayerSkin value in _skins.Values)
			{
				value.LateTick();
			}
		}

		public void Clear()
		{
			foreach (PlayerSkin value in _skins.Values)
			{
				try
				{
					value.Revert();
				}
				catch
				{
				}
			}
			_skins.Clear();
			_wanted.Clear();
			_published = null;
		}

		private void Publish(CSteamID lobby)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			NetworkRunner runner = NetworkContext.Runner;
			if (!((Object)(object)runner == (Object)null))
			{
				int playerId;
				try
				{
					PlayerRef localPlayer = runner.LocalPlayer;
					playerId = ((PlayerRef)(ref localPlayer)).PlayerId;
				}
				catch
				{
					return;
				}
				string text = (string.IsNullOrEmpty(LocalChoice) ? string.Empty : ("1|" + playerId + "|" + LocalChoice));
				if (!(text == _published))
				{
					SteamMatchmaking.SetLobbyMemberData(lobby, "disguise", text);
					_published = text;
				}
			}
		}

		private void Poll(CSteamID lobby)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			_wanted.Clear();
			Publishers = 0;
			Members = SteamMatchmaking.GetNumLobbyMembers(lobby);
			for (int i = 0; i < Members; i++)
			{
				CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(lobby, i);
				string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(lobby, lobbyMemberByIndex, "disguise");
				if (!string.IsNullOrEmpty(lobbyMemberData))
				{
					Publishers++;
					if (Parse(lobbyMemberData, out var id, out var npc))
					{
						_wanted[id] = npc;
					}
				}
			}
			Report();
		}

		private void Report()
		{
			if (Members != _reportedMembers || Publishers != _reportedPublishers)
			{
				_reportedMembers = Members;
				_reportedPublishers = Publishers;
				ModLog.Msg((Publishers >= Members) ? $"All {Members} player(s) in the lobby can see your model." : $"{Publishers} of {Members} players can see your model. The rest do not have the mod.");
			}
		}

		private static bool Parse(string raw, out int id, out string npc)
		{
			id = -1;
			npc = null;
			string[] array = raw.Split(new char[1] { '|' }, 3);
			if (array.Length != 3 || array[0] != "1")
			{
				return false;
			}
			if (!int.TryParse(array[1], out id))
			{
				return false;
			}
			if (string.IsNullOrEmpty(array[2]))
			{
				return false;
			}
			npc = array[2];
			return true;
		}

		private void ApplyAll()
		{
			_seen.Clear();
			foreach (ThirdPersonManager item in Interop.Safe<ThirdPersonManager>(Resources.FindObjectsOfTypeAll<ThirdPersonManager>()))
			{
				int num = FusionId(item);
				if (num < 0)
				{
					continue;
				}
				_seen.Add(num);
				PlayerSkin playerSkin = SkinFor(num);
				if (!_wanted.TryGetValue(num, out var value))
				{
					if (playerSkin.Active)
					{
						playerSkin.Revert();
					}
				}
				else if (!(playerSkin.Current == value))
				{
					NpcEntry npcEntry = NpcCatalog.Find(value);
					if (npcEntry != null)
					{
						playerSkin.Apply(BodyTarget.OfPlayer(item), npcEntry);
					}
				}
			}
			PruneDeparted();
		}

		private void PruneDeparted()
		{
			List<int> list = null;
			foreach (KeyValuePair<int, PlayerSkin> skin in _skins)
			{
				if (!_seen.Contains(skin.Key))
				{
					(list ?? (list = new List<int>())).Add(skin.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (int item in list)
			{
				try
				{
					_skins[item].Revert();
				}
				catch
				{
				}
				_skins.Remove(item);
			}
		}

		private PlayerSkin SkinFor(int id)
		{
			if (!_skins.TryGetValue(id, out var value))
			{
				value = new PlayerSkin();
				_skins[id] = value;
			}
			return value;
		}

		private static int FusionId(ThirdPersonManager body)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)body == (Object)null || (Object)(object)((SimulationBehaviour)body).Object == (Object)null)
				{
					return -1;
				}
				PlayerRef inputAuthority = ((SimulationBehaviour)body).Object.InputAuthority;
				return ((PlayerRef)(ref inputAuthority)).PlayerId;
			}
			catch
			{
				return -1;
			}
		}

		private static CSteamID Lobby()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlatformManager instance = PlatformManager.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return default(CSteamID);
				}
				return new CSteamID
				{
					m_SteamID = instance._lobbyID
				};
			}
			catch
			{
				return default(CSteamID);
			}
		}
	}
	internal sealed class ThumbnailBaker
	{
		private const int RowSize = 128;

		private const int Size = 128;

		private const string SlotIcon = "Item Icon";

		private const int QuickPace = 2;

		private const int GentlePace = 12;

		private readonly Dictionary<string, Sprite> _baked = new Dictionary<string, Sprite>(StringComparer.Ordinal);

		private readonly LockerPreview _preview;

		private List<NpcEntry> _queue;

		private NpcEntry _pending;

		private RenderTexture _source;

		private int _at;

		private int _wait;

		public Action<string, Sprite> OnBaked;

		private readonly Dictionary<int, Sprite> _hatIcons = new Dictionary<int, Sprite>();

		private List<int> _hatQueue;

		private int _hatAt;

		private int _pendingHat = -1;

		private string _hatsShowing;

		private CustomizablesLocker _locker;

		private readonly List<Animator> _frozen = new List<Animator>();

		private Camera _camera;

		private Transform _spinner;

		private Quaternion _spinnerRotation;

		private CameraClearFlags _clearFlags;

		private Color _background;

		private RenderTexture _private;

		private RenderTexture _liveTarget;

		private UniversalAdditionalCameraData _post;

		private bool _postWas;

		private bool _tookCamera;

		private Texture2D _overBlack;

		private const float MinimumCoverage = 0.02f;

		public bool Gentle { get; set; }

		private int SettleFrames => Gentle ? 12 : 2;

		public bool Running => _queue != null;

		public bool Done { get; private set; }

		public bool Busy => _queue != null || _hatQueue != null;

		private RenderTexture Frame => ((Object)(object)_private != (Object)null) ? _private : _source;

		public ThumbnailBaker(LockerPreview preview)
		{
			_preview = preview;
		}

		public Sprite Get(string name)
		{
			Sprite value;
			return _baked.TryGetValue(name, out value) ? value : null;
		}

		public void BeginHats(RenderTexture source, CustomizablesLocker locker, string model)
		{
			if (Running || (Object)(object)source == (Object)null || (Object)(object)locker == (Object)null || _hatsShowing == model || !string.Equals(_preview.Worn, model, StringComparison.Ordinal))
			{
				return;
			}
			HatsRenderer instance = HatsRenderer.Instance;
			Il2CppReferenceArray<Animator> slotAnimators = locker.slotAnimators;
			if (!((Object)(object)instance == (Object)null) && instance.hatObjs != null && slotAnimators != null)
			{
				_hatQueue = new List<int>();
				for (int i = 1; i < ((Il2CppArrayBase<GameObject>)(object)instance.hatObjs).Length && i < ((Il2CppArrayBase<Animator>)(object)slotAnimators).Length; i++)
				{
					_hatQueue.Add(i);
				}
				if (_hatQueue.Count == 0)
				{
					_hatQueue = null;
					return;
				}
				_locker = locker;
				_source = source;
				_hatsShowing = model;
				_hatAt = 0;
				_wait = 0;
				_pendingHat = -1;
				_preview.Suspended = true;
				TakeCamera();
				FaceCamera(string.IsNullOrEmpty(model) ? ThumbnailFraming.Rotation : 0f);
			}
		}

		public void Begin(RenderTexture source, List<NpcEntry> entries)
		{
			if (!Running && !Done)
			{
				if ((Object)(object)source == (Object)null)
				{
					ModLog.Warning("[thumbs] no live preview texture to copy from, leaving the rows as names.");
					Done = true;
					return;
				}
				_source = source;
				_queue = entries;
				_at = 0;
				_wait = 0;
				_pending = null;
				_preview.Suspended = true;
				HideHats();
				TakeCamera();
				FaceCamera(0f);
				ModLog.Msg($"[thumbs] rendering {entries.Count} previews.");
			}
		}

		private void TakeCamera()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (_tookCamera)
			{
				return;
			}
			HatsRenderer instance = HatsRenderer.Instance;
			GameObject val = (((Object)(object)instance != (Object)null) ? ((Component)instance).gameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			_camera = FindPreviewCamera(val);
			_tookCamera = true;
			try
			{
				Freeze(val);
				if ((Object)(object)_camera == (Object)null)
				{
					return;
				}
				_clearFlags = _camera.clearFlags;
				_background = _camera.backgroundColor;
				_liveTarget = _camera.targetTexture;
				_private = new RenderTexture(_source.descriptor);
				_camera.targetTexture = _private;
				if (ThumbnailFraming.Transparent)
				{
					_camera.clearFlags = (CameraClearFlags)2;
					_camera.backgroundColor = Color.black;
					_post = ((Component)_camera).GetComponent<UniversalAdditionalCameraData>();
					if ((Object)(object)_post != (Object)null)
					{
						_postWas = _post.renderPostProcessing;
						_post.renderPostProcessing = false;
					}
				}
			}
			catch (Exception ex)
			{
				ModLog.Warning("[thumbs] could not prepare the camera: " + ex.Message);
			}
		}

		private Camera FindPreviewCamera(GameObject root)
		{
			Camera val = null;
			foreach (Camera item in Interop.Safe<Camera>(root.GetComponentsInChildren<Camera>(true)))
			{
				RenderTexture targetTexture = item.targetTexture;
				if (!((Object)(object)targetTexture == (Object)null))
				{
					if ((Object)(object)_source != (Object)null && ((Il2CppObjectBase)targetTexture).Pointer == ((Il2CppObjectBase)_source).Pointer)
					{
						return item;
					}
					if ((Object)(object)val == (Object)null)
					{
						val = item;
					}
				}
			}
			return val;
		}

		private void Freeze(GameObject root)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			foreach (Animator item in Interop.Safe<Animator>(root.GetComponentsInChildren<Animator>(true)))
			{
				if (((Behaviour)item).enabled)
				{
					_frozen.Add(item);
					((Behaviour)item).enabled = false;
				}
			}
			if (!((Object)(object)_camera == (Object)null))
			{
				_spinner = (((Object)(object)((Component)_camera).transform.parent != (Object)null) ? ((Component)_camera).transform.parent : ((Component)_camera).transform);
				_spinnerRotation = _spinner.localRotation;
				_spinner.localRotation = Quaternion.identity;
			}
		}

		private void FaceCamera(float degrees)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_spinner != (Object)null)
			{
				_spinner.localRotation = Quaternion.Euler(0f, degrees, 0f);
			}
		}

		private void ReturnCamera()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			if (!_tookCamera)
			{
				return;
			}
			_tookCamera = false;
			try
			{
				if ((Object)(object)_spinner != (Object)null)
				{
					_spinner.localRotation = _spinnerRotation;
				}
				foreach (Animator item in _frozen)
				{
					if ((Object)(object)item != (Object)null)
					{
						((Behaviour)item).enabled = true;
					}
				}
				_preview.FaceTowards(0f);
				if ((Object)(object)_post != (Object)null)
				{
					_post.renderPostProcessing = _postWas;
				}
				if ((Object)(object)_camera != (Object)null)
				{
					_camera.clearFlags = _clearFlags;
					_camera.backgroundColor = _background;
					_camera.targetTexture = _liveTarget;
				}
			}
			catch
			{
			}
			_post = null;
			_liveTarget = null;
			if ((Object)(object)_private != (Object)null)
			{
				_private.Release();
				Object.Destroy((Object)(object)_private);
				_private = null;
			}
			if ((Object)(object)_overBlack != (Object)null)
			{
				Object.Destroy((Object)(object)_overBlack);
				_overBlack = null;
			}
			_frozen.Clear();
			_spinner = null;
			_camera = null;
		}

		private void Background(Color colour)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_camera != (Object)null)
			{
				_camera.backgroundColor = colour;
			}
		}

		public void Tick()
		{
			if (_queue == null)
			{
				TickHats();
				return;
			}
			if (_wait > 0)
			{
				_wait--;
				return;
			}
			if (_pending != null)
			{
				if (!Capture(_pending))
				{
					return;
				}
				_pending = null;
			}
			if (_at >= _queue.Count)
			{
				Finish();
				return;
			}
			NpcEntry npcEntry = _queue[_at++];
			if (_preview.Wear(npcEntry))
			{
				_preview.FaceTowards(ThumbnailFraming.Rotation);
				_pending = npcEntry;
				_wait = SettleFrames;
			}
		}

		private void TickHats()
		{
			if (_hatQueue == null)
			{
				return;
			}
			if (_wait > 0)
			{
				_wait--;
				return;
			}
			if (_pendingHat >= 0)
			{
				if (!CaptureHat(_pendingHat))
				{
					return;
				}
				_pendingHat = -1;
			}
			if (_hatAt >= _hatQueue.Count)
			{
				FinishHats();
				return;
			}
			int num = _hatQueue[_hatAt++];
			try
			{
				HatsRenderer.Instance.SelectHat(num);
			}
			catch (Exception ex)
			{
				ModLog.Warning($"[thumbs] hat {num}: {ex.Message}");
				return;
			}
			_preview.FaceTowards(ThumbnailFraming.Rotation);
			_pendingHat = num;
			_wait = SettleFrames;
		}

		private bool CaptureHat(int index)
		{
			if (!Render(out var sprite))
			{
				return false;
			}
			if ((Object)(object)sprite == (Object)null)
			{
				Skipped(index, "the render came back empty");
				return true;
			}
			Il2CppReferenceArray<Animator> val = (((Object)(object)_locker != (Object)null) ? _locker.slotAnimators : null);
			if (val == null)
			{
				Skipped(index, "the locker has no slot list");
				return true;
			}
			if (index >= ((Il2CppArrayBase<Animator>)(object)val).Length)
			{
				Skipped(index, $"the slot list holds only {((Il2CppArrayBase<Animator>)(object)val).Length}");
				return true;
			}
			if ((Object)(object)((Il2CppArrayBase<Animator>)(object)val)[index] == (Object)null)
			{
				Skipped(index, "that slot is empty");
				return true;
			}
			Transform transform = ((Component)((Il2CppArrayBase<Animator>)(object)val)[index]).transform;
			Transform val2 = FindIcon(transform);
			if ((Object)(object)val2 == (Object)null)
			{
				Skipped(index, $"no '{"Item Icon"}' anywhere under '{((Object)transform).name}', which holds {Children(transform)}");
				return true;
			}
			Image component = ((Component)val2).GetComponent<Image>();
			if ((Object)(object)component == (Object)null)
			{
				Skipped(index, $"'{"Item Icon"}' under '{((Object)transform).name}' carries no Image");
				return true;
			}
			Sprite val3 = (_hatIcons.ContainsKey(index) ? _hatIcons[index] : null);
			if ((Object)(object)val3 != (Object)null)
			{
				Object.Destroy((Object)(object)val3.texture);
				Object.Destroy((Object)(object)val3);
			}
			_hatIcons[index] = sprite;
			component.overrideSprite = sprite;
			return true;
		}

		private void FinishHats()
		{
			_hatQueue = null;
			_locker = null;
			_source = null;
			ReturnCamera();
			_preview.Suspended = false;
			RestoreHat();
		}

		private static void HideHats()
		{
			HatsRenderer instance = HatsRenderer.Instance;
			if ((Object)(object)instance == (Object)null || instance.hatObjs == null)
			{
				return;
			}
			foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)instance.hatObjs)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.SetActive(false);
				}
			}
		}

		private static void RestoreHat()
		{
			LockerPreview.RestoreEquippedHat();
		}

		private static void Skipped(int index, string why)
		{
			ModLog.Msg($"[thumbs] hat {index} skipped, {why}.");
		}

		private static Transform FindIcon(Transform slot)
		{
			for (int i = 0; i < slot.childCount; i++)
			{
				Transform child = slot.GetChild(i);
				if (((Object)child).name.StartsWith("Item Icon", StringComparison.Ordinal))
				{
					return child;
				}
			}
			return null;
		}

		private static string Children(Transform slot)
		{
			List<string> list = new List<string>();
			for (int i = 0; i < slot.childCount; i++)
			{
				list.Add("'" + ((Object)slot.GetChild(i)).name + "'");
			}
			return (list.Count == 0) ? "nothing" : string.Join(", ", list);
		}

		private void Finish()
		{
			_queue = null;
			_source = null;
			Done = true;
			ReturnCamera();
			_preview.Suspended = false;
			RestoreHat();
			ModLog.Msg($"[thumbs] {_baked.Count} previews ready.");
		}

		public void Forget()
		{
			_queue = null;
			_pending = null;
			_source = null;
			_hatQueue = null;
			_pendingHat = -1;
			_hatsShowing = null;
			_locker = null;
			Done = false;
			ReturnCamera();
			_preview.Suspended = false;
			foreach (KeyValuePair<int, Sprite> hatIcon in _hatIcons)
			{
				try
				{
					Image val = FindHatIcon(hatIcon.Key);
					if ((Object)(object)val != (Object)null)
					{
						val.overrideSprite = null;
					}
					if ((Object)(object)hatIcon.Value != (Object)null)
					{
						Object.Destroy((Object)(object)hatIcon.Value.texture);
						Object.Destroy((Object)(object)hatIcon.Value);
					}
				}
				catch
				{
				}
			}
			_hatIcons.Clear();
			foreach (Sprite value in _baked.Values)
			{
				if (!((Object)(object)value == (Object)null))
				{
					try
					{
						Object.Destroy((Object)(object)value.texture);
						Object.Destroy((Object)(object)value);
					}
					catch
					{
					}
				}
			}
			_baked.Clear();
		}

		private bool Capture(NpcEntry entry)
		{
			if (!Render(out var sprite))
			{
				return false;
			}
			if ((Object)(object)sprite == (Object)null)
			{
				return true;
			}
			_baked[entry.Name] = sprite;
			if (OnBaked != null)
			{
				OnBaked(entry.Name, sprite);
			}
			return true;
		}

		private static Image FindHatIcon(int slot)
		{
			CustomizablesLocker val = Object.FindObjectOfType<CustomizablesLocker>();
			Il2CppReferenceArray<Animator> val2 = (((Object)(object)val != (Object)null) ? val.slotAnimators : null);
			if (val2 == null || slot >= ((Il2CppArrayBase<Animator>)(object)val2).Length || (Object)(object)((Il2CppArrayBase<Animator>)(object)val2)[slot] == (Object)null)
			{
				return null;
			}
			Transform val3 = FindIcon(((Component)((Il2CppArrayBase<Animator>)(object)val2)[slot]).transform);
			return ((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Image>() : null;
		}

		private bool Render(out Sprite sprite)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			sprite = null;
			if (!ThumbnailFraming.Transparent)
			{
				Texture2D val = ReadFrame();
				if ((Object)(object)val != (Object)null)
				{
					sprite = ToSprite(val);
				}
				return true;
			}
			if ((Object)(object)_overBlack == (Object)null)
			{
				_overBlack = ReadFrame();
				if ((Object)(object)_overBlack == (Object)null)
				{
					return true;
				}
				Background(Color.white);
				return false;
			}
			Texture2D val2 = ReadFrame();
			Background(Color.black);
			if ((Object)(object)val2 != (Object)null)
			{
				Solve(_overBlack, val2);
				sprite = ToSprite(_overBlack);
				Object.Destroy((Object)(object)val2);
			}
			else
			{
				Object.Destroy((Object)(object)_overBlack);
			}
			_overBlack = null;
			return true;
		}

		private static void Solve(Texture2D black, Texture2D white)
		{
			//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_003c: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0095: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			Il2CppStructArray<Color32> pixels = black.GetPixels32();
			Il2CppStructArray<Color32> pixels2 = white.GetPixels32();
			if (((Il2CppArrayBase<Color32>)(object)pixels).Length == ((Il2CppArrayBase<Color32>)(object)pixels2).Length)
			{
				for (int i = 0; i < ((Il2CppArrayBase<Color32>)(object)pixels).Length; i++)
				{
					Color32 val = ((Il2CppArrayBase<Color32>)(object)pixels)[i];
					Color32 val2 = ((Il2CppArrayBase<Color32>)(object)pixels2)[i];
					float num = (float)(val2.r - val.r + (val2.g - val.g) + (val2.b - val.b)) / 765f;
					float num2 = Mathf.Clamp01(1f - num);
					((Il2CppArrayBase<Color32>)(object)pixels)[i] = ((num2 < 0.02f) ? new Color32((byte)0, (byte)0, (byte)0, (byte)0) : new Color32(Unpremultiply(val.r, num2), Unpremultiply(val.g, num2), Unpremultiply(val.b, num2), (byte)(num2 * 255f)));
				}
				black.SetPixels32(pixels);
				black.Apply();
			}
		}

		private static byte Unpremultiply(byte channel, float alpha)
		{
			return (byte)Mathf.Clamp((float)(int)channel / alpha, 0f, 255f);
		}

		private Sprite ToSprite(Texture2D texture)
		{
			//IL_0015: 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)
			return Sprite.Create(texture, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f));
		}

		private Texture2D ReadFrame()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_005e: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture val = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				val = new RenderTexture(128, 128, 0);
				RenderTexture frame = Frame;
				Crop(((Texture)frame).width, ((Texture)frame).height, out var scale, out var offset);
				if (FindCrown(out var v))
				{
					offset.y = v - ThumbnailFraming.HeadHeight * scale.y;
				}
				Graphics.Blit((Texture)(object)frame, val, scale, offset);
				RenderTexture.active = val;
				Texture2D val2 = new Texture2D(128, 128, (TextureFormat)4, false);
				val2.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0);
				val2.Apply();
				return val2;
			}
			catch (Exception ex)
			{
				ModLog.Warning("[thumbs] a preview did not render: " + ex.Message);
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					val.Release();
					Object.Destroy((Object)(object)val);
				}
			}
		}

		private static void Crop(int width, int height, out Vector2 scale, out Vector2 offset)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			if (width <= 0 || height <= 0)
			{
				scale = Vector2.one;
				offset = Vector2.zero;
				return;
			}
			if (width > height)
			{
				float num = (float)height / (float)width;
				scale = new Vector2(num, 1f);
				offset = new Vector2((1f - num) * 0.5f, 0f);
			}
			else
			{
				float num2 = (float)width / (float)height;
				scale = new Vector2(1f, num2);
				offset = new Vector2(0f, (1f - num2) * 0.5f);
			}
			float num3 = Mathf.Max(ThumbnailFraming.Zoom, 0.05f);
			Vector2 val = scale / num3;
			offset += (scale - val) * 0.5f;
			scale = val;
		}

		private bool FindCrown(out float v)
		{
			//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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			v = 0f;
			Transf