Decompiled source of CreaturePreview v1.0.0

BepInEx/plugins/Untamo.CreaturePreview.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.GUI;
using Jotunn.Managers;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Untamo.CreaturePreview;

[BepInPlugin("Untamo.CreaturePreview", "Untamo.CreaturePreview", "1.0.0")]
[BepInDependency("com.jotunn.jotunn", "2.29.2")]
[DefaultExecutionOrder(10000)]
public sealed class CustomCharacterEditPlugin : BaseUnityPlugin
{
	private enum EditTarget
	{
		Character,
		Wolf,
		Lox
	}

	private sealed class AppearanceSelectionState
	{
		public int Gender;

		public string Hair = "HairNone";

		public string Beard = "BeardNone";
	}

	private sealed class ArmorSelectionState
	{
		public string Head = "Reset";

		public string Chest = "Reset";

		public string Legs = "Reset";

		public string Cape = "Reset";

		public string Accessory = "Reset";
	}

	private class BodyCapture
	{
		public Texture2D copy;

		public Color32[] originalPixels;

		public HashSet<int> eyeIndices;

		public HashSet<int> bodyIndices;

		public int width;

		public int height;

		public float eyeCenterX;

		public float eyeCenterY;

		public float eyeBaseCenterX;

		public float eyeBaseCenterY;

		public float eyeSize;

		public float irisRadius;

		public float pupilRadius;

		public Color lastBodyColor;

		public bool hasLastBodyColor;
	}

	private enum ColorTarget
	{
		Body,
		Hair,
		HairFade,
		Beard,
		BeardFade,
		Eye,
		Iris,
		OriginalBody,
		OriginalHair,
		OriginalHairFade,
		OriginalBeard,
		OriginalBeardFade,
		OriginalEye,
		OriginalIris
	}

	private enum LightMode
	{
		Day,
		Dusk,
		Night,
		Morning
	}

	private sealed class FreeFlyCanvasGroupState
	{
		public float Alpha;

		public bool Interactable;

		public bool BlocksRaycasts;
	}

	private sealed class ArmorSetDefinition
	{
		public readonly string Name;

		public readonly string Head;

		public readonly string Chest;

		public readonly string Legs;

		public readonly string Cape;

		public ArmorSetDefinition(string name, string head = "", string chest = "", string legs = "", string cape = "")
		{
			Name = name;
			Head = head;
			Chest = chest;
			Legs = legs;
			Cape = cape;
		}
	}

	private sealed class AnimationSelectionState
	{
		public string Idle = "";

		public string Run = "";

		public string Active = "";
	}

	private sealed class ReferenceObjectComparer : IEqualityComparer<object>
	{
		public static readonly ReferenceObjectComparer Instance = new ReferenceObjectComparer();

		public new bool Equals(object x, object y)
		{
			return x == y;
		}

		public int GetHashCode(object obj)
		{
			return RuntimeHelpers.GetHashCode(obj);
		}
	}

	private struct SavedSkinColorState
	{
		public Player Player;

		public Vector3 RuntimeColor;

		public bool Changed;
	}

	[HarmonyPatch(typeof(Character), "Awake")]
	private static class ApplyCreatureBodyColorPatch
	{
		private static void Postfix(Character __instance)
		{
			CustomCharacterEditPlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)__instance == (Object)null) && !(((Object)((Component)__instance).gameObject).name ?? "").StartsWith("CCE_", StringComparison.Ordinal))
			{
				((MonoBehaviour)instance).StartCoroutine(instance.ApplyInWorldCreatureColorWhenReady(__instance));
			}
		}
	}

	[HarmonyPatch(typeof(PlayerProfile), "SavePlayerData")]
	private static class PreserveBodyColorWhenSavingPatch
	{
		private static void Prefix(PlayerProfile __instance, Player __0, out SavedSkinColorState __state)
		{
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			__state = default(SavedSkinColorState);
			if (CreaturePreviewOnly)
			{
				return;
			}
			CustomCharacterEditPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || __instance == null || (Object)(object)__0 == (Object)null)
			{
				return;
			}
			string name;
			try
			{
				name = __instance.GetName();
			}
			catch
			{
				return;
			}
			string value = instance.GetBodyForProfile(name, null);
			if (instance.pendingNewCharacterAppearance && !string.IsNullOrEmpty(name))
			{
				value = instance.bodyHex;
				instance.SetBodyForProfile(name, instance.bodyHex);
				instance.SetBeardForProfile(name, instance.linkHairAndBeard ? instance.hairHex : instance.beardHex);
				instance.SetEyeForProfile(name, instance.eyeHex, instance.eyeRainbowLoop);
				instance.SetHairFadeForProfile(name);
				instance.SetSizeForProfile(name, instance.bodyScale);
				instance.appearanceSelectionMap[name] = CloneAppearanceSelection(instance.pendingAppearance);
				instance.SaveAppearanceSelectionMap();
				instance.ApplyAppearanceSelection(__0, instance.pendingAppearance);
				instance.pendingNewCharacterAppearance = false;
			}
			if (string.IsNullOrEmpty(value) || !instance.TryParseHex(value, out var color))
			{
				return;
			}
			Vector3 runtimeColor = Vector3.one;
			if (skinColorField != null)
			{
				try
				{
					runtimeColor = (Vector3)skinColorField.GetValue(__0);
				}
				catch
				{
					runtimeColor = Vector3.one;
				}
			}
			__state.Player = __0;
			__state.RuntimeColor = runtimeColor;
			__state.Changed = true;
			__0.SetSkinColor(ToVec3(color));
		}

		private static void Postfix(SavedSkinColorState __state)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (__state.Changed && (Object)(object)__state.Player != (Object)null)
			{
				__state.Player.SetSkinColor(__state.RuntimeColor);
			}
		}
	}

	[HarmonyPatch]
	private static class BlockNativeCharacterMenuKeysWhileEditingNamePatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(FejdStartup).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo method in methods)
			{
				string name = method.Name.ToLowerInvariant();
				bool characterNavigation = name.Contains("character") && (name.Contains("left") || name.Contains("right"));
				bool startAction = name == "onstart" || name.Contains("startgame") || (name.Contains("character") && name.Contains("start"));
				bool newCharacterAction = name == "onnew" || name.Contains("newcharacter");
				if (characterNavigation || startAction || newCharacterAction)
				{
					yield return method;
				}
			}
		}

		private static bool Prefix()
		{
			CustomCharacterEditPlugin instance = Instance;
			if (CreaturePreviewOnly)
			{
				return true;
			}
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			return !instance.IsNameInputFocused() && Time.unscaledTime > instance.blockNativeNameMenuKeysUntil;
		}
	}

	[HarmonyPatch(typeof(Input), "GetKeyDown", new Type[] { typeof(KeyCode) })]
	private static class BlockNativeNKeyAtInputSourcePatch
	{
		private static bool Prefix(KeyCode __0, ref bool __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if (CreaturePreviewOnly)
			{
				return true;
			}
			if ((int)__0 != 110)
			{
				return true;
			}
			CustomCharacterEditPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.IsNameInputFocused())
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(Input), "GetKeyDown", new Type[] { typeof(string) })]
	private static class BlockNativeNStringKeyAtInputSourcePatch
	{
		private static bool Prefix(string __0, ref bool __result)
		{
			if (CreaturePreviewOnly)
			{
				return true;
			}
			if (!string.Equals(__0, "n", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			CustomCharacterEditPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.IsNameInputFocused())
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch]
	private static class BlockNativeNThroughZInputPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(ZInput).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo method in methods)
			{
				if (!(method.ReturnType != typeof(bool)))
				{
					string name = method.Name.ToLowerInvariant();
					if (name == "getkeydown" || name == "getbuttondown")
					{
						yield return method;
					}
				}
			}
		}

		private static bool Prefix(MethodBase __originalMethod, object[] __args, ref bool __result)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			if (CreaturePreviewOnly)
			{
				return true;
			}
			CustomCharacterEditPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null || !instance.IsNameInputFocused())
			{
				return true;
			}
			string text = ((__originalMethod != null) ? __originalMethod.Name.ToLowerInvariant() : "");
			int num = 0;
			while (__args != null && num < __args.Length)
			{
				object obj = __args[num];
				if (obj is KeyCode val && (int)val == 110)
				{
					__result = false;
					return false;
				}
				string text2 = obj as string;
				if (!string.IsNullOrEmpty(text2) && ((text == "getkeydown" && string.Equals(text2, "n", StringComparison.OrdinalIgnoreCase)) || (text == "getbuttondown" && text2.IndexOf("new", StringComparison.OrdinalIgnoreCase) >= 0)))
				{
					__result = false;
					return false;
				}
				num++;
			}
			return true;
		}
	}

	private static readonly bool CreaturePreviewOnly;

	private static CustomCharacterEditPlugin Instance;

	private GameObject panelRoot;

	private GameObject creaturePanelRoot;

	private GameObject creatureListRoot;

	private Transform creatureListContent;

	private Text creatureListPageText;

	private int creatureListPage;

	private EditTarget editTarget;

	private GameObject creaturePreview;

	private string creaturePreviewKind = "";

	private string selectedCreaturePrefab = "Wolf";

	private int creatureLevel = 1;

	private Text creatureLevelText;

	private GameObject creatureNameLabelRoot;

	private Text creatureNameText;

	private GameObject henSkinMinusButton;

	private GameObject henSkinPlusButton;

	private GameObject henSkinValueRoot;

	private Text henSkinText;

	private int henSkinIndex;

	private int creatureSkinVariantCount;

	private GameObject creatureCloseButton;

	private GameObject creatureChooseButton;

	private readonly HashSet<string> creatureLevelWarningLogged = new HashSet<string>();

	private readonly Dictionary<Renderer, bool> hiddenPreviewRenderers = new Dictionary<Renderer, bool>();

	private readonly Dictionary<Light, bool> hiddenPreviewLights = new Dictionary<Light, bool>();

	private ConfigEntry<string> wolfColorCfg;

	private ConfigEntry<string> loxColorCfg;

	private ConfigEntry<float> wolfScaleCfg;

	private ConfigEntry<float> loxScaleCfg;

	private ConfigEntry<string> lastCreaturePrefabCfg;

	private ConfigEntry<int> lastCreatureLevelCfg;

	private ConfigEntry<int> henSkinCfg;

	private const float BogWitchPreviewExtraDown = 0.5f;

	private const float SerpentPreviewExtraUp = 0f;

	private const float VolturePreviewExtraUp = 1.9f;

	private const float GjallPreviewExtraUp = 1f;

	private const float FallenValkyriePreviewExtraUp = 1f;

	private static readonly string[] CharacterPrefabNames;

	private GameObject emoteMenuRoot;

	private GameObject animationMenuRoot;

	private GameObject animationMenuContentRoot;

	private GameObject itemMenuRoot;

	private GameObject itemMenuContentRoot;

	private GameObject armorMenuRoot;

	private GameObject armorMenuContentRoot;

	private GameObject appearanceMenuRoot;

	private GameObject miscMenuRoot;

	private GameObject infoMenuRoot;

	private GameObject activeColorPicker;

	private Button emoteMenuButton;

	private Button animationMenuButton;

	private Button itemMenuButton;

	private Button armorMenuButton;

	private Button miscMenuButton;

	private Button infoMenuButton;

	private Text emoteSpeedText;

	private Text animationSpeedText;

	private Text animationPageText;

	private Text itemMenuTitleText;

	private Text armorMenuTitleText;

	private ConfigEntry<string> editorPanelPositionCfg;

	private ConfigEntry<string> itemMenuPositionCfg;

	private ConfigEntry<string> sharedContentMenuPositionCfg;

	private ConfigEntry<string> miscMenuPositionCfg;

	private ConfigEntry<string> infoMenuPositionCfg;

	private ConfigEntry<string> appearanceMenuPositionCfg;

	private ConfigEntry<string> colorPickerPositionCfg;

	private ConfigEntry<string> lastHandItemCfg;

	private ConfigEntry<string> lastArmorHeadCfg;

	private ConfigEntry<string> lastArmorChestCfg;

	private ConfigEntry<string> lastArmorLegsCfg;

	private ConfigEntry<string> lastArmorCapeCfg;

	private ConfigEntry<string> lastArmorAccessoryCfg;

	private ConfigEntry<string> handItemMapCfg;

	private ConfigEntry<string> armorSelectionMapCfg;

	private ConfigEntry<string> animationSelectionMapCfg;

	private ConfigEntry<string> appearanceSelectionMapCfg;

	private ConfigEntry<string> devProfilesCfg;

	private ConfigEntry<float> editorEmoteSpeedCfg;

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

	private readonly Dictionary<string, ArmorSelectionState> armorSelectionMap = new Dictionary<string, ArmorSelectionState>();

	private readonly Dictionary<string, AnimationSelectionState> animationSelectionMap = new Dictionary<string, AnimationSelectionState>();

	private readonly Dictionary<string, AppearanceSelectionState> appearanceSelectionMap = new Dictionary<string, AppearanceSelectionState>();

	private readonly HashSet<string> devProfiles = new HashSet<string>(StringComparer.Ordinal);

	private Button devModeButton;

	private Player devModeAppliedPlayer;

	private string devModeAppliedProfile = "";

	private bool devModeAppliedValue;

	private Vector2 lastEditorPanelPosition;

	private Vector2 lastSharedContentMenuPosition;

	private Vector2 lastMiscMenuPosition;

	private Vector2 lastInfoMenuPosition;

	private Vector2 lastAppearanceMenuPosition;

	private Vector2 lastColorPickerPosition;

	private float editorPanelPositionSaveAt = -1f;

	private float sharedContentMenuPositionSaveAt = -1f;

	private float miscMenuPositionSaveAt = -1f;

	private float infoMenuPositionSaveAt = -1f;

	private float appearanceMenuPositionSaveAt = -1f;

	private float colorPickerPositionSaveAt = -1f;

	private string originalEditorRightVisual = "";

	private string originalEditorLeftVisual = "";

	private Player editorEquipmentPlayer;

	private Player savedHandItemAppliedPlayer;

	private Player savedArmorAppliedPlayer;

	private Player savedAnimationAppliedPlayer;

	private string savedAnimationProfileName = "";

	private bool loadingSavedAnimation;

	private bool suppressAnimationToast;

	private FieldInfo newCharacterPanelField;

	private bool newCharacterPanelFieldResolved;

	private bool wasNewCharacterMenuOpen;

	private bool pendingNewCharacterAppearance;

	private bool ownCharacterEditorOpen;

	private GameObject characterSelectEditButton;

	private GameObject characterSelectCreatureButton;

	private bool characterSelectCreatureButtonStyled;

	private bool creaturePreviewScreenOpen;

	private bool characterSelectEditButtonStyled;

	private GameObject characterSelectEditPanel;

	private GameObject characterSelectCreaturePanel;

	private GameObject characterCloneButton;

	private GameObject characterEditorSaveButton;

	private GameObject characterEditorActionPanel;

	private GameObject newCharacterSavePanel;

	private GameObject characterCloneNamePrompt;

	private InputField characterCloneNameInput;

	private FieldInfo characterSelectScreenField;

	private bool characterSelectScreenFieldResolved;

	private string savedEquipmentProfileName = "";

	private bool editorEquipmentCaptured;

	private string originalArmorHead = "";

	private string originalArmorChest = "";

	private string originalArmorLegs = "";

	private string originalArmorCape = "";

	private string originalArmorAccessory = "";

	private Player armorEquipmentPlayer;

	private bool armorEquipmentCaptured;

	private Text appearanceHairStyleText;

	private Text appearanceBeardStyleText;

	private InputField playerNameInput;

	private GameObject nativeNameOverlayObject;

	private InputField nativeNameOverlayInput;

	private Text hiddenNativeNameLabel;

	private bool syncingNameInputs;

	private bool refreshingPlayerNameInput;

	private float blockNativeNameMenuKeysUntil;

	private string lastRenamedOldName = "";

	private string lastRenamedNewName = "";

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

	private List<string> hairStyleNames = new List<string>();

	private List<string> beardStyleNames = new List<string>();

	private AppearanceSelectionState pendingAppearance = new AppearanceSelectionState();

	private Player appearanceAppliedPlayer;

	private string appearanceAppliedProfile = "";

	private Image bodySwatch;

	private Image hairSwatch;

	private Button linkBeardButton;

	private Text scaleValueText;

	private bool uiDirty;

	private Image[] panelImages;

	private bool holdScaleMinus;

	private bool holdScalePlus;

	private float holdScaleNextTime;

	private const float HoldScaleDelay = 0.35f;

	private const float HoldScaleRate = 0.05f;

	private string bodyHex = "#C68642";

	private string hairHex = "#3B2417";

	private string hairFadeHex = "#8A5A3B";

	private string originalHairFadeHex = "#8A5A3B";

	private int hairFadeAngle = 90;

	private string beardFadeHex = "#8A5A3B";

	private string originalBeardFadeHex = "#8A5A3B";

	private int beardFadeAngle = 90;

	private bool eyeRainbowLoop;

	private int eyeRainbowMode;

	private Button eyeRainbowDropdownButton;

	private GameObject eyeRainbowDropdownList;

	private static readonly string[] EyeLoopNames;

	private string beardHex = "#3B2417";

	private string originalBeardHex = "#3B2417";

	private string eyeHex = "#4A6B8C";

	private string originalEyeHex = "#4A6B8C";

	private string irisHex = "#4A90E2";

	private string originalIrisHex = "#4A90E2";

	private bool useIrisAndPupil = true;

	private Button irisPupilToggleButton;

	private float irisSize = 0.45f;

	private float pupilSize = 0.15f;

	private float irisPositionX = 0.1f;

	private float irisPositionY;

	private Slider irisSizeSlider;

	private Slider pupilSizeSlider;

	private Slider irisPositionXSlider;

	private Slider irisPositionYSlider;

	private Text irisSizeValueText;

	private Text pupilSizeValueText;

	private Text irisPositionXValueText;

	private Text irisPositionYValueText;

	private string originalBodyHex;

	private string originalHairHex;

	private string status = "Select a character and press Edit Character.";

	private bool customEditorEnabled = true;

	private bool linkHairAndBeard = true;

	private Player lastPlayer;

	private string lastPreviewBodyProfile = "";

	private readonly Dictionary<string, Color> previewBodyColorByProfile = new Dictionary<string, Color>();

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

	private Image beardSwatch;

	private Image originalBeardSwatch;

	private Image hairFadeSwatch;

	private Image originalHairFadeSwatch;

	private Image beardFadeSwatch;

	private Image originalBeardFadeSwatch;

	private Slider hairFadeAngleSlider;

	private Text hairFadeAngleValueText;

	private Slider beardFadeAngleSlider;

	private Text beardFadeAngleValueText;

	private Image eyeSwatch;

	private Image originalEyeSwatch;

	private Image irisSwatch;

	private Image originalIrisSwatch;

	private Image originalBodySwatch;

	private Image originalHairSwatch;

	private float bodyScale = 1f;

	private const float MinScale = 0.8f;

	private const float MaxScale = 1.2f;

	private const float ScaleStep = 0.01f;

	private ConfigEntry<float> bodyScaleCfg;

	private ConfigEntry<string> scaleProfileCfg;

	private ConfigEntry<string> sizeMapCfg;

	private Dictionary<string, float> sizeMap = new Dictionary<string, float>();

	private ConfigEntry<bool> linkHairAndBeardCfg;

	private ConfigEntry<string> beardMapCfg;

	private Dictionary<string, string> beardMap = new Dictionary<string, string>();

	private ConfigEntry<string> eyeMapCfg;

	private Dictionary<string, string> eyeMap = new Dictionary<string, string>();

	private readonly Dictionary<int, BodyCapture> _captures = new Dictionary<int, BodyCapture>();

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

	private SkinnedMeshRenderer _currentBodyRenderer;

	private Material _currentBodyMaterial;

	private BodyCapture _currentCapture;

	private ColorTarget selectedColor = ColorTarget.Body;

	private static readonly FieldInfo skinColorField;

	private static readonly FieldInfo visEquipmentField;

	private static readonly FieldInfo currentRightVisualField;

	private static readonly FieldInfo currentLeftVisualField;

	private static readonly FieldInfo terminalCheatField;

	private static readonly FieldInfo playerGodModeField;

	private static readonly FieldInfo playerNoCostField;

	private static readonly MethodInfo getRightItemMethod;

	private static readonly MethodInfo getLeftItemMethod;

	private static readonly MethodInfo getHelmetItemMethod;

	private static readonly MethodInfo getChestItemMethod;

	private static readonly MethodInfo getLegItemMethod;

	private static readonly MethodInfo getShoulderItemMethod;

	private static readonly MethodInfo getUtilityItemMethod;

	private static readonly FieldInfo helmetItemField;

	private static readonly FieldInfo chestItemField;

	private static readonly FieldInfo legItemField;

	private static readonly FieldInfo shoulderItemField;

	private static readonly FieldInfo utilityItemField;

	private static MaterialPropertyBlock _beardMPB;

	private static MaterialPropertyBlock _hairFadeMPB;

	private float undoRepeatTimer;

	private float redoRepeatTimer;

	private const float RepeatDelay = 0.5f;

	private const float RepeatRate = 0.12f;

	private string colorClipboard = "";

	private readonly Stack<(string body, string hair, string beard, string eye, float size)> undoHistory = new Stack<(string, string, string, string, float)>();

	private readonly Stack<(string body, string hair, string beard, string eye, float size)> redoHistory = new Stack<(string, string, string, string, float)>();

	private const int MaxUndoHistory = 360;

	private ConfigEntry<KeyboardShortcut> toggleHotkey;

	private ConfigEntry<KeyboardShortcut> copyHotkey;

	private ConfigEntry<KeyboardShortcut> pasteHotkey;

	private ConfigEntry<KeyboardShortcut> saveHotkey;

	private ConfigEntry<KeyboardShortcut> undoHotkey;

	private ConfigEntry<KeyboardShortcut> redoHotkey;

	private ConfigEntry<string> bodyColorCfg;

	private ConfigEntry<string> hairColorCfg;

	private ConfigEntry<string> hairFadeMapCfg;

	private ConfigEntry<string> bodyMapCfg;

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

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

	private readonly Dictionary<int, Texture2D> hairFadeOriginalTextures = new Dictionary<int, Texture2D>();

	private readonly Dictionary<int, Texture2D> hairFadeGeneratedTextures = new Dictionary<int, Texture2D>();

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

	private const string MultiplayerAppearanceZdoKey = "Untamo.CustomCharacterEdit.Appearance.v1";

	private string lastPublishedAppearance = "";

	private float nextMultiplayerAppearanceUpdate;

	private const float MultiplayerAppearanceInterval = 1f;

	private static Type localizationType;

	private static FieldInfo localizationInstanceField;

	private static PropertyInfo localizationInstanceProperty;

	private static MethodInfo localizationLocalizeMethod;

	private static MethodInfo localizationGetSelectedLanguageMethod;

	private static readonly Dictionary<string, string> CloneActionTranslations;

	private GameObject toastGo;

	private Text toastText;

	private CanvasGroup toastCanvasGroup;

	private float toastEndTime;

	private const float ToastFadeDuration = 0.4f;

	private LightMode currentLightMode = LightMode.Day;

	private ConfigEntry<string> lightModeCfg;

	private Light _sceneLight;

	private Color _origLightColor;

	private float _origLightIntensity;

	private Color _origAmbient;

	private AmbientMode _origAmbientMode;

	private bool _lightSaved;

	private Button lightBtn;

	private Coroutine _reapplyRoutine;

	private Camera _editorCamera;

	private Player _zoomPlayer;

	private Vector3 _editorCameraOriginalPosition;

	private Quaternion _editorCameraOriginalRotation;

	private float _editorCameraOriginalDistance;

	private float _editorZoomDistance;

	private int _editorZoomLevel;

	private ConfigEntry<int> editorZoomLevelCfg;

	private ConfigEntry<bool> editorHeadFocusCfg;

	private ConfigEntry<float> freeFlySpeedCfg;

	private bool _headFocusMode = true;

	private bool _editorZoomActive;

	private bool _cameraSpinActive;

	private bool _freeFlyCameraActive;

	private bool _inGameCameraActive;

	private bool _creatureHeadCameraActive;

	private Vector3 _inGamePlayerStartPosition;

	private Quaternion _inGamePlayerStartRotation;

	private float _inGameCameraYaw;

	private float _inGameCameraPitch = 18f;

	private float _inGameCameraDistance = 4f;

	private string _inGameLocomotionCommand = "";

	private readonly List<Collider> _inGameGeneratedModelColliders = new List<Collider>();

	private static readonly HashSet<string> InGameCollisionModelNames;

	private bool _inGameCharacterSelectHidden;

	private bool _inGameDanceActive;

	private GameObject _inGameEmoteWheelRoot;

	private readonly List<Text> _inGameEmoteWheelLabels = new List<Text>();

	private int _inGameEmoteWheelSelection = -1;

	private object _inGameEmoteRadial;

	private bool _inGameEmoteRadialOpen;

	private GameObject _inGameNativeRadialClone;

	private GameObject _cachedNativeRadialTemplate;

	private object _cachedNativeRadialData;

	private bool _nativeRadialMissingLogged;

	private readonly List<AssetBundle> _nativeWheelAssetBundles = new List<AssetBundle>();

	private bool _nativeWheelBundleLoadAttempted;

	private bool _freeFlyUiHidden;

	private bool _freeFlyPanelWasVisible;

	private bool _freeFlyColorPickerWasVisible;

	private bool _freeFlyOriginalCursorVisible;

	private CursorLockMode _freeFlyOriginalCursorLockMode;

	private readonly Dictionary<CanvasGroup, FreeFlyCanvasGroupState> _freeFlyOriginalPanelStates = new Dictionary<CanvasGroup, FreeFlyCanvasGroupState>();

	private readonly Dictionary<CanvasGroup, FreeFlyCanvasGroupState> creaturePreviewNativePanelStates = new Dictionary<CanvasGroup, FreeFlyCanvasGroupState>();

	private Vector3 _freeFlyPosition;

	private float _freeFlyYaw;

	private float _freeFlyPitch;

	private float _freeFlyMoveSpeed = 5f;

	private float _cameraFocusHeightOverride = -1f;

	private int _cameraPresetIndex;

	private static readonly string[] CameraPresetCycle;

	private static readonly string[] CreatureCameraPresetCycle;

	private float _cameraSpinAngle;

	private float _cameraSpinDirection = 1f;

	private const int EditorZoomLevels = 7;

	private const float EditorZoomMinDistance = 1.1f;

	private const float EditorBodyZoomMinDistance = 2.4f;

	private const float CreatureHeadZoomMinDistance = 2.4f;

	private const float CreatureHeadZoomMaxDistance = 30f;

	private const float EditorSpinSpeed = 30f;

	private const float FreeFlyMinSpeed = 5f;

	private const float FreeFlyMaxSpeed = 25f;

	private const float FreeFlySpeedStep = 0.5f;

	private const float InGameRunSpeed = 5f;

	private const float InGameCrouchTurnSpeed = 90f;

	private const float InGameCameraMinDistance = 2.2f;

	private const float InGameCameraMaxDistance = 10f;

	private const float InGameCameraZoomStep = 0.4f;

	private const float InGameCollisionRadius = 0.25f;

	private const float InGameCollisionHeight = 1.75f;

	private const float InGameCollisionSkin = 0.015f;

	private const float InGameMaxStepUp = 0.5f;

	private const float InGameMaxDrop = 1.3f;

	private const float InGameMinGroundNormalY = 0.55f;

	private Animator _previewEmoteAnimator;

	private AnimationClip _previewEmoteClip;

	private AnimationClip _previewEmoteLoopClip;

	private float _previewEmoteLoopEndPadding;

	private bool _previewEmoteReverse;

	private float _previewEmotePlaybackMultiplier = 1f;

	private string _previewEmotePendingCommand;

	private bool _previewEmoteExitingSit;

	private float _previewEmoteTime;

	private bool _previewEmoteLoop;

	private AudioSource _haldorDanceMusicSource;

	private Coroutine _haldorDanceMusicFadeInRoutine;

	private Coroutine _haldorDanceMusicFadeRoutine;

	private Coroutine _menuMusicFadeInRoutine;

	private readonly List<AudioSource> _pausedMenuMusicSources = new List<AudioSource>();

	private readonly Dictionary<AudioSource, float> _pausedMenuMusicVolumes = new Dictionary<AudioSource, float>();

	private const float HaldorDanceMusicFadeInSeconds = 2f;

	private const float HaldorDanceMusicFadeSeconds = 2f;

	private const float MenuMusicFadeInSeconds = 2f;

	private float _editorEmoteSpeed = 1f;

	private int _animationMenuPage;

	private string _animationMenuCategory = "Idle";

	private const int AnimationCommandsPerPage = 20;

	private static readonly string[] AnimationMenuCategories;

	private const float EditorEmoteSpeedStep = 0.25f;

	private const float EditorEmoteSpeedMin = 0.25f;

	private const float EditorEmoteSpeedMax = 2f;

	private bool _handItemAnimationActive;

	private static readonly HashSet<string> EditorEmotes;

	private static readonly HashSet<string> LoopingEditorEmotes;

	private static readonly string[] EditorEmoteMenuCommands;

	private static readonly Dictionary<string, string[]> HandItemCategories;

	private static readonly Dictionary<string, string[]> HandToolCategories;

	private static readonly Dictionary<string, string[]> HandMagicCategories;

	private static readonly ArmorSetDefinition[] EditorArmorSets;

	private static readonly string[] EditorArmorHeads;

	private static readonly string[] EditorArmorChests;

	private static readonly string[] EditorArmorLegs;

	private static readonly string[] EditorArmorCapes;

	private static readonly string[] EditorArmorAccessories;

	private static readonly Dictionary<string, string[]> ExtendedEditorEmoteClipNames;

	private static readonly string[] EditorAnimationMenuCommands;

	private static readonly HashSet<string> LoopingEditorAnimations;

	private static readonly Dictionary<string, string> EditorAnimationClipNames;

	private static readonly string[] AdditionalEditorAnimationClipNames;

	private static string GetEyeLoopName(int mode)
	{
		return (mode >= 0 && mode < EyeLoopNames.Length) ? EyeLoopNames[mode] : EyeLoopNames[0];
	}

	private string GetIrisPupilToggleText()
	{
		return "Iris & Pupil: " + (useIrisAndPupil ? "On" : "Off");
	}

	static CustomCharacterEditPlugin()
	{
		CreaturePreviewOnly = true;
		CharacterPrefabNames = new string[160]
		{
			"Abomination", "AshCrow", "Asksvin", "Asksvin_hatchling", "Bat", "Bjorn", "Blob", "BlobElite", "BlobFrost", "BlobLava",
			"BlobTar", "Boar", "Boar_piggy", "BogWitch", "BogWitchKvastur", "Bonemass", "BonemawSerpent", "Charred_Archer", "Charred_Archer_Fader", "Charred_Mage",
			"Charred_Melee", "Charred_Melee_Dyrnwyn", "Charred_Melee_Fader", "Charred_Twitcher", "Charred_Twitcher_Summoned", "Chicken", "Crow", "Deathsquito", "Deer", "Dragon",
			"Draugr", "Draugr_Elite", "Draugr_Ranged", "Dverger", "DvergerAshlands", "DvergerMageFire", "DvergerMageIce", "DvergerMageSupport", "DvergerTest", "Eikthyr",
			"Fader", "FallenValkyrie", "Fenring", "Fenring_Cultist", "Fenring_Cultist_Hildir", "gd_king", "Ghost", "Gjall", "Goblin", "Goblin_Gem",
			"GoblinArcher", "GoblinBrute", "GoblinBrute_Hildir", "GoblinBruteBros", "GoblinKing", "GoblinShaman", "GoblinShaman_Hildir", "Greydwarf", "Greydwarf_Elite", "Greydwarf_Shaman",
			"Greyling", "Haldor", "Hare", "Hatchling", "Hen", "Hildir", "Hive", "Hugin", "Leech", "Leech_cave",
			"Lox", "Lox_Calf", "Mistile", "Morgen", "Morgen_NonSleeping", "Munin", "Neck", "odin", "piece_TrainingDummy", "Seagal",
			"Seeker", "SeekerBrood", "SeekerBrute", "SeekerQueen", "Serpent", "Skeleton", "Skeleton_Friendly", "Skeleton_Hildir", "Skeleton_NoArcher", "Skeleton_Poison",
			"staff_greenroots_tentaroot", "StoneGolem", "Surtling", "TentaRoot", "Tick", "TrainingDummy", "Troll", "Troll_Summoned", "Ulv", "Unbjorn",
			"Volture", "Wolf", "Wolf_cub", "Wraith", "Aspect_Bonemass", "Aspect_Eikthyr", "Aspect_Elder", "Aspect_Fader", "Aspect_Moder", "Aspect_SeekerQueen",
			"Aspect_TentaRoot", "Aspect_Yagluth", "Barka", "Bat_Swamp", "Bjorn_spiritcaller", "BlobAspect", "BlobMork", "BlobMorkMini", "Boar_spiritcaller", "Deer_White",
			"DvergerDeepNorth", "DvergerMage", "Elaking", "ElakingLantern", "ElakingMole", "FallenWarrior", "FrostWisp", "FrozenKing", "FrozenKing_p2", "FrozenKing_p3",
			"Frysling", "Ghost_old", "Ghost_Void", "GoblinDeepNorth", "Greydwarf_Frozen", "Greydwarf_Shaman_Frozen", "JotunWarrior", "JotunWarriorDualWield", "JotunWitch", "Moose",
			"Moose_calf", "Moose_spiritcaller", "Seal", "Seal_Pup", "ShadowPerson", "Skeleton_aspect", "Skeleton_DeepNorth", "Skeleton_Meadows", "Skeleton_Meadows_noarcher", "Skeleton_Mountains",
			"Skeleton_Mountains_noarcher", "Skeleton_Swamps", "Skeleton_Swamps_noarcher", "Tendril", "Tendril_back", "TentaRoot_wild", "TheHive", "TrollFrost", "Wolf_spiritcaller", "Writhan"
		};
		EyeLoopNames = new string[9] { "Eye Loop Off", "Full Rainbow", "Pastel Rainbow", "Fire", "Hair to Fade Color", "White Fade", "Blue Fade", "White to Blue", "Flash White/Yellow" };
		skinColorField = typeof(Player).GetField("m_skinColor", BindingFlags.Instance | BindingFlags.NonPublic);
		visEquipmentField = typeof(Humanoid).GetField("m_visEquipment", BindingFlags.Instance | BindingFlags.NonPublic);
		currentRightVisualField = typeof(VisEquipment).GetField("m_currentRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		currentLeftVisualField = typeof(VisEquipment).GetField("m_currentLeftItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		terminalCheatField = typeof(Terminal).GetField("m_cheat", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		playerGodModeField = typeof(Player).GetField("m_godMode", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		playerNoCostField = typeof(Player).GetField("m_noPlacementCost", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getRightItemMethod = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getLeftItemMethod = typeof(Humanoid).GetMethod("GetLeftItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getHelmetItemMethod = typeof(Humanoid).GetMethod("GetHelmetItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getChestItemMethod = typeof(Humanoid).GetMethod("GetChestItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getLegItemMethod = typeof(Humanoid).GetMethod("GetLegItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getShoulderItemMethod = typeof(Humanoid).GetMethod("GetShoulderItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		getUtilityItemMethod = typeof(Humanoid).GetMethod("GetUtilityItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		helmetItemField = typeof(Humanoid).GetField("m_helmetItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		chestItemField = typeof(Humanoid).GetField("m_chestItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		legItemField = typeof(Humanoid).GetField("m_legItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		shoulderItemField = typeof(Humanoid).GetField("m_shoulderItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		utilityItemField = typeof(Humanoid).GetField("m_utilityItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		CloneActionTranslations = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "English", "Clone" },
			{ "Swedish", "Klona" },
			{ "French", "Cloner" },
			{ "Italian", "Clona" },
			{ "German", "Klonen" },
			{ "Spanish", "Clonar" },
			{ "Russian", "Клонировать" },
			{ "Romanian", "Clonează" },
			{ "Bulgarian", "Клонирай" },
			{ "Macedonian", "Клонирај" },
			{ "Finnish", "Kloonaa" },
			{ "Danish", "Klon" },
			{ "Norwegian", "Klon" },
			{ "Icelandic", "Klóna" },
			{ "Turkish", "Klonla" },
			{ "Lithuanian", "Klonuoti" },
			{ "Czech", "Klonovat" },
			{ "Hungarian", "Klónozás" },
			{ "Slovak", "Klonovať" },
			{ "Polish", "Klonuj" },
			{ "Dutch", "Klonen" },
			{ "Portuguese_European", "Clonar" },
			{ "Portuguese_Brazilian", "Clonar" },
			{ "Chinese", "克隆" },
			{ "Chinese_Trad", "複製" },
			{ "Japanese", "クローン" },
			{ "Korean", "복제" },
			{ "Hindi", "क\u094dल\u094bन कर\u0947\u0902" },
			{ "Thai", "โคลน" },
			{ "Abenaki", "Clone" },
			{ "Croatian", "Kloniraj" },
			{ "Georgian", "კლონირება" },
			{ "Greek", "Κλωνοποίηση" },
			{ "Serbian", "Клонирај" },
			{ "Ukrainian", "Клонувати" },
			{ "Latvian", "Klonēt" }
		};
		InGameCollisionModelNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Rock_4", "Rock_3", "FirTree", "Pinetree_01", "FirTree_small", "stubbe", "Bush01", "Bush01_heath" };
		CameraPresetCycle = new string[6] { "Face", "Full Body", "Back", "Free Fly", "In-game", "Default" };
		CreatureCameraPresetCycle = new string[1] { "Free Fly" };
		AnimationMenuCategories = new string[2] { "Idle", "Run" };
		EditorEmotes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"blowkiss", "bow", "challenge", "cheer", "comehere", "cower", "cry", "dance", "despair", "flex",
			"headbang", "kneel", "laugh", "lie_down", "lie_down_2", "lisa_dance", "loveyou", "nonono", "point", "roar",
			"shrug", "sit", "thumbsup", "toast", "wave"
		};
		LoopingEditorEmotes = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "dance", "headbang", "kneel", "lie_down", "lie_down_2", "lisa_dance", "sit" };
		EditorEmoteMenuCommands = new string[25]
		{
			"blowkiss", "bow", "challenge", "cheer", "comehere", "cower", "cry", "dance", "despair", "flex",
			"headbang", "kneel", "laugh", "lie_down", "lie_down_2", "lisa_dance", "loveyou", "nonono", "point", "roar",
			"shrug", "sit", "thumbsup", "toast", "wave"
		};
		HandItemCategories = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"Axes",
				new string[11]
				{
					"AxeStone", "AxeFlint", "AxeEarly", "AxeBronze", "AxeIron", "AxeBlackMetal", "AxeJotunBane", "AxeBerzerkr", "AxeBerzerkrBlood", "AxeBerzerkrLightning",
					"AxeBerzerkrNature"
				}
			},
			{
				"Battleaxes",
				new string[4] { "Battleaxe", "BattleaxeCrystal", "BattleaxeBlackmetal", "BattleaxeSkullSplittur" }
			},
			{
				"Clubs",
				new string[8] { "Torch", "Club", "MaceBronze", "MaceIron", "MaceSilver", "MaceNeedle", "MaceEldner", "Sparkler" }
			},
			{
				"Sledgehammers",
				new string[3] { "SledgeStagbreaker", "SledgeIron", "SledgeDemolisher" }
			},
			{
				"Swords",
				new string[11]
				{
					"SwordBronze", "SwordIron", "SwordIronFire", "SwordSilver", "SwordBlackmetal", "SwordMistwalker", "SwordNiedhogg", "SwordNiedhoggBlood", "SwordNiedhoggLightning", "SwordNiedhoggNature",
					"SwordDyrnwyn"
				}
			},
			{
				"Two-handed Swords",
				new string[5] { "THSwordKrom", "THSwordSlayer", "THSwordSlayerBlood", "THSwordSlayerLightning", "THSwordSlayerNature" }
			},
			{
				"Spears",
				new string[6] { "SpearFlint", "SpearBronze", "SpearElderbark", "SpearWolfFang", "SpearCarapace", "SpearSplitner" }
			},
			{
				"Polearms",
				new string[4] { "AtgeirBronze", "AtgeirIron", "AtgeirBlackmetal", "AtgeirHimminAfl" }
			},
			{
				"Knives",
				new string[7] { "KnifeFlint", "KnifeCopper", "KnifeButcher", "KnifeChitin", "KnifeSilver", "KnifeBlackMetal", "KnifeSkollAndHati" }
			},
			{
				"Fists",
				new string[3] { "FistBjornClaw", "FistFenrirClaw", "FistBjornUndeadClaw" }
			},
			{
				"Bows",
				new string[9] { "Bow", "BowFineWood", "BowHuntsman", "BowDraugrFang", "BowSpineSnap", "BowAshlands", "BowAshlandsBlood", "BowAshlandsRoot", "BowAshlandsStorm" }
			},
			{
				"Crossbows",
				new string[5] { "CrossbowArbalest", "CrossbowRipper", "CrossbowRipperBlood", "CrossbowRipperLightning", "CrossbowRipperNature" }
			},
			{
				"Blob bombs",
				new string[5] { "BombBlob_Poison", "BombBlob_PoisonElite", "BombBlob_Frost", "BombBlob_Tar", "BombBlob_Lava" }
			},
			{
				"Bombs",
				new string[3] { "BombOoze", "BombBile", "BombSmoke" }
			},
			{
				"Wooden weapons",
				new string[9] { "SwordWood", "AxeWood", "KnifeWood", "MaceWood", "SpearWood", "SledgeWood", "BattleaxeWood", "AtgeirWood", "THSwordWood" }
			}
		};
		HandToolCategories = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"Adventuring",
				new string[3] { "Tankard", "Tankard_dvergr", "Lantern" }
			},
			{
				"Building",
				new string[3] { "Hammer", "Hoe", "Feaster" }
			},
			{
				"Farming",
				new string[3] { "Cultivator", "KnifeButcher", "Scythe" }
			},
			{
				"Fishing",
				new string[1] { "FishingRod" }
			}
		};
		HandMagicCategories = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"Elemental magic",
				new string[5] { "StaffFireball", "StaffIceShards", "StaffLightning", "StaffGreenRoots", "StaffClusterbomb" }
			},
			{
				"Blood magic",
				new string[3] { "StaffShield", "StaffSkeleton", "StaffRedTroll" }
			}
		};
		EditorArmorSets = new ArmorSetDefinition[16]
		{
			new ArmorSetDefinition("Rag Armor", "", "ArmorRagsChest", "ArmorRagsLegs"),
			new ArmorSetDefinition("Leather Armor", "HelmetLeather", "ArmorLeatherChest", "ArmorLeatherLegs", "CapeDeerHide"),
			new ArmorSetDefinition("Troll Set", "HelmetTrollLeather", "ArmorTrollLeatherChest", "ArmorTrollLeatherLegs", "CapeTrollHide"),
			new ArmorSetDefinition("Bear Set", "HelmetBerserkerHood", "ArmorBerserkerChest", "ArmorBerserkerLegs"),
			new ArmorSetDefinition("Bronze Armor", "HelmetBronze", "ArmorBronzeChest", "ArmorBronzeLegs"),
			new ArmorSetDefinition("Root Set", "HelmetRoot", "ArmorRootChest", "ArmorRootLegs"),
			new ArmorSetDefinition("Iron Armor", "HelmetIron", "ArmorIronChest", "ArmorIronLegs"),
			new ArmorSetDefinition("Fenris Set", "HelmetFenring", "ArmorFenringChest", "ArmorFenringLegs"),
			new ArmorSetDefinition("Wolf Armor", "HelmetDrake", "ArmorWolfChest", "ArmorWolfLegs", "CapeWolf"),
			new ArmorSetDefinition("Vilebone Set", "HelmetBerserkerUndead", "ArmorBerserkerUndeadChest", "ArmorBerserkerUndeadLegs", "CapeLox"),
			new ArmorSetDefinition("Padded Armor", "HelmetPadded", "ArmorPaddedCuirass", "ArmorPaddedGreaves", "CapeLinen"),
			new ArmorSetDefinition("Eitr-weave Set", "HelmetMage", "ArmorMageChest", "ArmorMageLegs", "CapeFeather"),
			new ArmorSetDefinition("Carapace Armor", "HelmetCarapace", "ArmorCarapaceChest", "ArmorCarapaceLegs"),
			new ArmorSetDefinition("Ask Set", "HelmetAshlandsMediumHood", "ArmorAshlandsMediumChest", "ArmorAshlandsMediumlegs", "CapeAsksvin"),
			new ArmorSetDefinition("Embla Set", "HelmetMage_Ashlands", "ArmorMageChest_Ashlands", "ArmorMageLegs_Ashlands"),
			new ArmorSetDefinition("Flametal Armor", "HelmetFlametal", "ArmorFlametalChest", "ArmorFlametalLegs", "CapeAsh")
		};
		EditorArmorHeads = new string[34]
		{
			"HelmetLeather", "HelmetTrollLeather", "HelmetBerserkerHood", "HelmetBronze", "HelmetRoot", "HelmetIron", "HelmetFenring", "HelmetDrake", "HelmetBerserkerUndead", "HelmetPadded",
			"HelmetMage", "HelmetCarapace", "HelmetAshlandsMediumHood", "HelmetMage_Ashlands", "HelmetFlametal", "HelmetMidsummerCrown", "HelmetYule", "HelmetCelebration", "HelmetDverger", "HelmetFishingHat",
			"HelmetOdin", "HelmetHat1", "HelmetHat2", "HelmetHat3", "HelmetHat4", "HelmetHat5", "HelmetHat6", "HelmetHat7", "HelmetHat8", "HelmetHat9",
			"HelmetHat10", "HelmetStrawHat", "HelmetSweatBand", "HelmetPointyHat"
		};
		EditorArmorChests = new string[38]
		{
			"ArmorRagsChest", "ArmorLeatherChest", "ArmorTrollLeatherChest", "ArmorBerserkerChest", "ArmorBronzeChest", "ArmorRootChest", "ArmorIronChest", "ArmorFenringChest", "ArmorWolfChest", "ArmorBerserkerUndeadChest",
			"ArmorPaddedCuirass", "ArmorMageChest", "ArmorCarapaceChest", "ArmorAshlandsMediumChest", "ArmorMageChest_Ashlands", "ArmorFlametalChest", "ArmorDress1", "ArmorDress2", "ArmorDress3", "ArmorDress4",
			"ArmorDress5", "ArmorDress6", "ArmorDress7", "ArmorDress8", "ArmorDress9", "ArmorDress10", "ArmorHarvester1", "ArmorHarvester2", "ArmorTunic1", "ArmorTunic2",
			"ArmorTunic3", "ArmorTunic4", "ArmorTunic5", "ArmorTunic6", "ArmorTunic7", "ArmorTunic8", "ArmorTunic9", "ArmorTunic10"
		};
		EditorArmorLegs = new string[16]
		{
			"ArmorRagsLegs", "ArmorLeatherLegs", "ArmorTrollLeatherLegs", "ArmorBerserkerLegs", "ArmorBronzeLegs", "ArmorRootLegs", "ArmorIronLegs", "ArmorFenringLegs", "ArmorWolfLegs", "ArmorBerserkerUndeadLegs",
			"ArmorPaddedGreaves", "ArmorMageLegs", "ArmorCarapaceLegs", "ArmorAshlandsMediumlegs", "ArmorMageLegs_Ashlands", "ArmorFlametalLegs"
		};
		EditorArmorCapes = new string[9] { "CapeDeerHide", "CapeTrollHide", "CapeWolf", "CapeLox", "CapeLinen", "CapeFeather", "CapeAsksvin", "CapeAsh", "CapeOdin" };
		EditorArmorAccessories = new string[1] { "BeltStrength" };
		ExtendedEditorEmoteClipNames = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"blowkiss",
				new string[1] { "blowkiss" }
			},
			{
				"bow",
				new string[1] { "bow" }
			},
			{
				"challenge",
				new string[1] { "challengeaccepted" }
			},
			{
				"cheer",
				new string[1] { "cheer" }
			},
			{
				"comehere",
				new string[1] { "getoverhere" }
			},
			{
				"cower",
				new string[1] { "cower" }
			},
			{
				"cry",
				new string[1] { "cry" }
			},
			{
				"dance",
				new string[1] { "dance" }
			},
			{
				"despair",
				new string[1] { "despair" }
			},
			{
				"flex",
				new string[1] { "flex" }
			},
			{
				"headbang",
				new string[1] { "headbang" }
			},
			{
				"kneel",
				new string[2] { "Kneel Start", "Kneel Loop" }
			},
			{
				"laugh",
				new string[1] { "laugh 2" }
			},
			{
				"lie_down",
				new string[2] { "Standing Up", "lie down" }
			},
			{
				"lie_down_2",
				new string[2] { "Standing Up", "lie down 2" }
			},
			{
				"lisa_dance",
				new string[1] { "lisa dance" }
			},
			{
				"loveyou",
				new string[1] { "love you" }
			},
			{
				"nonono",
				new string[1] { "no no no" }
			},
			{
				"point",
				new string[1] { "point" }
			},
			{
				"roar",
				new string[1] { "roar" }
			},
			{
				"shrug",
				new string[1] { "shrug" }
			},
			{
				"sit",
				new string[2] { "Standing Up", "sitting idle" }
			},
			{
				"thumbsup",
				new string[1] { "thumbsup" }
			},
			{
				"toast",
				new string[1] { "toast" }
			},
			{
				"wave",
				new string[1] { "wave" }
			}
		};
		EditorAnimationMenuCommands = new string[72]
		{
			"atgeir_idle", "atgeir_jog", "atgeir_jump", "atgeir_run", "atgeir_strafe_left", "atgeir_strafe_right", "atgeir_walk", "attack1", "attack2", "attack3",
			"axe_secondary", "axe_swing", "block_idle", "bow_recoil", "bow_walk_forward", "bow_walk_left", "crouch_idle", "dive", "eat", "encumbered_idle",
			"encumbered_walk", "equip", "equip_mid", "fight_idle", "fishing_idle", "flying", "greatsword_strafe_left", "greatsword_strafe_right", "greatsword_walk_back", "greatsword_walk_forward",
			"hammer_swing", "hard_landing", "hoe_swing", "idle", "interact", "interact_forward", "jog_backward", "jog_forward", "jog_strafe_left", "jog_strafe_right",
			"jump", "jump_loop", "kickstep", "pickaxe_crouch", "pickaxe_idle", "pickaxe_jog", "pickaxe_jump", "pickaxe_run", "pickaxe_sneak", "pickaxe_strafe_left",
			"pickaxe_strafe_right", "pickaxe_swing", "pickaxe_walk", "pre_landing", "punch", "punch2", "run", "run_item_right", "sleep", "sneak_walk",
			"spear_throw", "standing_up", "swim", "sword_attack", "sword_jog", "standing_torch_idle_right", "torch_jog", "torch_run", "torch_walk_left", "torch_walk_right",
			"walk", "workbench"
		};
		LoopingEditorAnimations = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"atgeir_idle", "atgeir_jog", "atgeir_run", "atgeir_strafe_left", "atgeir_strafe_right", "atgeir_walk", "block_idle", "bow_walk_forward", "bow_walk_left", "crouch_idle",
			"encumbered_idle", "encumbered_walk", "equip", "fight_idle", "fishing_idle", "flying", "greatsword_strafe_left", "greatsword_strafe_right", "greatsword_walk_back", "greatsword_walk_forward",
			"idle", "jog_backward", "jog_forward", "jog_strafe_left", "jog_strafe_right", "pickaxe_crouch", "pickaxe_idle", "pickaxe_jog", "pickaxe_run", "pickaxe_sneak",
			"pickaxe_strafe_left", "pickaxe_strafe_right", "pickaxe_walk", "pre_landing", "run", "run_item_right", "sleep", "sneak_walk", "swim", "sword_jog",
			"standing_torch_idle_right", "torch_jog", "torch_run", "torch_walk_left", "torch_walk_right", "walk", "workbench", "jump_loop"
		};
		EditorAnimationClipNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "pickaxe_idle", "2-hand-pickaxe-Idle" },
			{ "atgeir_idle", "2Hand-Spear-Idle" },
			{ "atgeir_jog", "Atgeir Jog" },
			{ "atgeir_jump", "Atgeir Jump" },
			{ "atgeir_run", "Atgeir Run" },
			{ "atgeir_strafe_left", "Atgeir Strafe L" },
			{ "atgeir_strafe_right", "Atgeir Strafe R" },
			{ "atgeir_walk", "Atgeir Walk" },
			{ "attack1", "Attack1" },
			{ "attack2", "Attack2" },
			{ "attack3", "Attack3" },
			{ "axe_secondary", "Axe Secondary Attack" },
			{ "axe_swing", "axe_swing" },
			{ "block_idle", "Block idle" },
			{ "bow_recoil", "Bow Aim Recoil" },
			{ "bow_walk_forward", "Bow Aim Walk Forward" },
			{ "bow_walk_left", "Bow Aim Walk Left" },
			{ "crouch_idle", "Crouch Idle" },
			{ "dive", "Dive" },
			{ "eat", "Eat" },
			{ "encumbered_idle", "Encumbered idle" },
			{ "encumbered_walk", "Encumbered walk" },
			{ "equip", "EquipLoop" },
			{ "equip_mid", "EquipMid" },
			{ "fight_idle", "fight idle" },
			{ "flying", "flying" },
			{ "greatsword_walk_back", "Great sword walk back" },
			{ "greatsword_walk_forward", "Great sword walk f" },
			{ "hammer_swing", "hammer_Swing" },
			{ "hard_landing", "Hard Landing" },
			{ "idle", "IdleTweaked" },
			{ "interact", "Interact" },
			{ "interact_forward", "Interact_forward" },
			{ "fishing_idle", "Idle_Fishing" },
			{ "jog_backward", "Jog backward" },
			{ "jog_forward", "Jog Forward" },
			{ "jog_strafe_left", "Jog Strafe Left" },
			{ "jog_strafe_right", "Jog Strafe Left mirrored" },
			{ "sword_jog", "Jog_With Sword_right" },
			{ "jump", "JumpTweaked" },
			{ "jump_loop", "Jump Loop" },
			{ "kickstep", "Kickstep" },
			{ "pickaxe_crouch", "Pickaxe Crouch Idle" },
			{ "pickaxe_jog", "PickAxe Jog" },
			{ "pickaxe_jump", "Pickaxe Jump" },
			{ "pickaxe_run", "PickAxe Run" },
			{ "pickaxe_sneak", "Pickaxe Sneak Walk" },
			{ "pickaxe_strafe_left", "Pickaxe Strafe L" },
			{ "pickaxe_strafe_right", "Pickaxe Strafe R" },
			{ "run_item_right", "Run Item Right" },
			{ "pre_landing", "Pre landing" },
			{ "punch", "Punchstep 1" },
			{ "punch2", "Punchstep 2" },
			{ "sneak_walk", "Sneak walk" },
			{ "run", "Standard Run New" },
			{ "sleep", "Laying Sleeping" },
			{ "standing_up", "Standing Up" },
			{ "swim", "Swimming" },
			{ "greatsword_strafe_left", "strafe left" },
			{ "greatsword_strafe_right", "strafe right" },
			{ "hoe_swing", "swing_hoe" },
			{ "pickaxe_swing", "swing_pickaxe" },
			{ "sword_attack", "Sword-Attack-R4" },
			{ "spear_throw", "throw_spear" },
			{ "standing_torch_idle_right", "Standing Torch Idle right" },
			{ "torch_jog", "Jog With Torch right" },
			{ "torch_run", "Run Torch Right" },
			{ "torch_walk_left", "Walking With Torch_Left" },
			{ "torch_walk_right", "Walking With Torch_Right" },
			{ "pickaxe_walk", "Walk with PickAxe" },
			{ "walk", "Walking" },
			{ "workbench", "Workbench" }
		};
		AdditionalEditorAnimationClipNames = new string[118]
		{
			"DualAxes Idle", "Idle_Battleaxe", "Battleaxe Walk", "Battleaxe Strafe L", "Battleaxe Strafe R", "Battleaxe Jog", "Battleaxe Run", "Battleaxe Strafe Block R", "Battleaxe Jump Loop", "Battleaxe Crouch Idle",
			"Battleaxe Sneak Walk", "Standing Torch Idle left", "Sword And Shield Idle", "Sword And Shield Walk", "Sword And Shield Strafe left", "Jog With Torch Left", "MaceAltAttack", "Sword And Shield Strafe run left", "Sword And Shield Strafe right", "Sword And Shield Strafe run right",
			"Sword And Shield Walk Back", "Run Torch Left", "Greatsword Idle", "Greatsword Walk", "Greatsword Strafe L", "Greatsword Crouch Idle", "Greatsword Sneak Walk", "Greatsword Strafe R", "Greatsword Jog", "Greatsword Run",
			"Greatsword Jump", "Greatsword Jump Loop", "Greatsword Secondary Attack", "Javelin Stab", "Atgeir Crouch Idle", "Atgeir Sneak Walk", "Atgeir Jump Loop", "Atgeir Walk Block", "Atgeir Strafe Block R", "Atgeir360Attack",
			"knife_slash0", "knife_slash1", "knife_slash2", "Knife Idle", "Knife Idle Block", "Knife Walk Block", "Knife Strafe Block L", "Knife Attack Combo (1)", "Knife Attack Combo (2)", "Knife Attack Combo (3)",
			"Knife Attack Leap", "Knife Strafe Block R", "Knife JumpAttack", "Bow Aim Walk Right", "Bow Aim Walk Back", "Idle Crossbow", "CrossbowWalk", "Crossbow Strafe L", "Reload Crossbow", "Reload done",
			"Crossbow Idle Block", "Crossbow Walk Block", "Crossbow Strafe Block L", "Crossbow Strafe R", "CrossbowJog", "Fire Crossbow", "Crossbow Crouch Idle", "Crossbow Sneak Walk", "Crossbow Jump", "Crossbow Jump Loop",
			"CrossbowRun", "Idle Staff 3", "Staff Walk", "Staff Jog", "Staff Run", "Staff Jump", "Block Idle Staff", "Staff Walk Block", "Staff Strafe Block L", "Idle magic item",
			"Magic Item Walk", "Magic Item Strafe L", "Magic Item Strafe R", "Magic Item Jog", "Magic Item Run", "Magic Item Sneak", "Magic Item Crouch", "Magic Item Jump", "BombThrow", "Staff Strafe Block R",
			"Staff Walk Back Block", "Idle Feaster", "Feaster Walk", "Feaster Strafe L", "Feaster Jog", "Feaster Strafe R", "Feaster Run", "Feaster Jump Loop", "Idle Scythe", "Scythe Strafe R",
			"Scythe Jog", "Scythe Walk", "Scythe Strafe L", "Scythe Run", "Scythe Jump Loop", "Scything", "Scythe Jump", "Load", "Throw", "ReelIn",
			"BattleAxeAltAttack", "Battleaxe Walk Block", "BattleAxe1", "Battleaxe Jump", "Battleaxe Strafe Block L", "Battleaxe Walk Back Block", "player_stagger", "BattleAxe2"
		};
		Array.Sort(CharacterPrefabNames, (IComparer<string>?)StringComparer.OrdinalIgnoreCase);
		for (int i = 0; i < AdditionalEditorAnimationClipNames.Length; i++)
		{
			string text = AdditionalEditorAnimationClipNames[i];
			bool flag = false;
			foreach (string value in EditorAnimationClipNames.Values)
			{
				if (string.Equals(value, text, StringComparison.OrdinalIgnoreCase))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				string text2 = MakeAnimationCommandName(text);
				string text3 = text2;
				int num = 2;
				while (EditorAnimationClipNames.ContainsKey(text3))
				{
					text3 = text2 + "_" + num++;
				}
				EditorAnimationClipNames.Add(text3, text);
				if (IsLoopingCapturedAnimation(text))
				{
					LoopingEditorAnimations.Add(text3);
				}
			}
		}
		List<string> list = new List<string>();
		foreach (KeyValuePair<string, string> editorAnimationClipName in EditorAnimationClipNames)
		{
			if (IsDirectionalAnimationName(editorAnimationClipName.Value))
			{
				list.Add(editorAnimationClipName.Key);
			}
		}
		for (int j = 0; j < list.Count; j++)
		{
			EditorAnimationClipNames.Remove(list[j]);
			LoopingEditorAnimations.Remove(list[j]);
		}
		List<string> list2 = new List<string>();
		foreach (KeyValuePair<string, string> editorAnimationClipName2 in EditorAnimationClipNames)
		{
			string animationCategory = GetAnimationCategory(editorAnimationClipName2.Value);
			if (!string.Equals(animationCategory, "Idle", StringComparison.OrdinalIgnoreCase) && !string.Equals(animationCategory, "Run", StringComparison.OrdinalIgnoreCase))
			{
				list2.Add(editorAnimationClipName2.Key);
			}
		}
		for (int k = 0; k < list2.Count; k++)
		{
			EditorAnimationClipNames.Remove(list2[k]);
			LoopingEditorAnimations.Remove(list2[k]);
		}
	}

	private static string MakeAnimationCommandName(string clipName)
	{
		StringBuilder stringBuilder = new StringBuilder();
		bool flag = false;
		for (int i = 0; i < clipName.Length; i++)
		{
			char c = char.ToLowerInvariant(clipName[i]);
			if (char.IsLetterOrDigit(c))
			{
				stringBuilder.Append(c);
				flag = false;
			}
			else if (!flag && stringBuilder.Length > 0)
			{
				stringBuilder.Append('_');
				flag = true;
			}
		}
		while (stringBuilder.Length > 0 && stringBuilder[stringBuilder.Length - 1] == '_')
		{
			stringBuilder.Length--;
		}
		return (stringBuilder.Length > 0) ? stringBuilder.ToString() : "animation";
	}

	private static bool IsLoopingCapturedAnimation(string clipName)
	{
		string text = clipName.ToLowerInvariant();
		return text.Contains("idle") || text.Contains("walk") || text.Contains("jog") || text.Contains("run") || text.Contains("strafe") || text.Contains("sneak") || text.Contains("jump loop") || text == "reelin";
	}

	private static bool IsDirectionalAnimationName(string clipName)
	{
		string text = (clipName ?? "").ToLowerInvariant();
		switch (text)
		{
		default:
			if (!(text == "standing torch idle right"))
			{
				return text.Contains("strafe") || text.Contains("left") || text.Contains("right");
			}
			goto case "run torch left";
		case "run torch left":
		case "run torch right":
		case "standing torch idle left":
			return false;
		}
	}

	private void SaveUndo()
	{
		undoHistory.Push((bodyHex, hairHex, beardHex, eyeHex, bodyScale));
		redoHistory.Clear();
		while (undoHistory.Count > 360)
		{
			(string, string, string, string, float)[] array = undoHistory.ToArray();
			undoHistory.Clear();
			for (int num = array.Length - 2; num >= 0; num--)
			{
				undoHistory.Push(array[num]);
			}
		}
	}

	private void Undo()
	{
		if (undoHistory.Count == 0)
		{
			ShowToast("Nothing to undo.");
			return;
		}
		redoHistory.Push((bodyHex, hairHex, beardHex, eyeHex, bodyScale));
		(string, string, string, string, float) tuple = undoHistory.Pop();
		bodyHex = tuple.Item1;
		hairHex = tuple.Item2;
		beardHex = tuple.Item3;
		eyeHex = tuple.Item4;
		bodyScale = tuple.Item5;
		status = $"Undo ({undoHistory.Count} left)";
		uiDirty = true;
	}

	private void Redo()
	{
		if (redoHistory.Count == 0)
		{
			ShowToast("Nothing to redo.");
			return;
		}
		undoHistory.Push((bodyHex, hairHex, beardHex, eyeHex, bodyScale));
		(string, string, string, string, float) tuple = redoHistory.Pop();
		bodyHex = tuple.Item1;
		hairHex = tuple.Item2;
		beardHex = tuple.Item3;
		eyeHex = tuple.Item4;
		bodyScale = tuple.Item5;
		status = $"Redo ({redoHistory.Count} left)";
		uiDirty = true;
	}

	private void CopyColor(string hex)
	{
		colorClipboard = hex;
		ShowToast("Copied " + hex);
	}

	private void PasteBody()
	{
		if (TryParseHex(colorClipboard, out var _))
		{
			SaveUndo();
			bodyHex = colorClipboard;
			ShowToast("Pasted " + bodyHex);
			uiDirty = true;
		}
	}

	private void PasteHair()
	{
		if (TryParseHex(colorClipboard, out var _))
		{
			SaveUndo();
			hairHex = colorClipboard;
			ShowToast("Pasted " + hairHex);
			uiDirty = true;
		}
	}

	private void PasteBeard()
	{
		if (!linkHairAndBeard && TryParseHex(colorClipboard, out var _))
		{
			SaveUndo();
			beardHex = colorClipboard;
			ShowToast("Pasted " + beardHex);
			uiDirty = true;
		}
	}

	private void PasteEye()
	{
		if (TryParseHex(colorClipboard, out var _))
		{
			SaveUndo();
			eyeHex = colorClipboard;
			ShowToast("Pasted " + eyeHex);
			uiDirty = true;
		}
	}

	private void PasteIris()
	{
		if (TryParseHex(colorClipboard, out var _))
		{
			irisHex = colorClipboard;
			ShowToast("Pasted " + irisHex);
			uiDirty = true;
		}
	}

	private void AdjustScale(float delta)
	{
		bodyScale = Mathf.Clamp(bodyScale + delta, 0.8f, 1.2f);
		uiDirty = true;
	}

	private void ApplyScale(Player p)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)p == (Object)null))
		{
			((Component)p).transform.localScale = new Vector3(bodyScale, bodyScale, bodyScale);
		}
	}

	private string GetProfileName()
	{
		try
		{
			PlayerProfile val = FindProfile();
			return (val == null) ? "" : val.GetName();
		}
		catch
		{
			return "";
		}
	}

	private void TryAutoApplyScale()
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			bodyScale = GetSizeForProfile(GetProfileName());
			ApplyScale(localPlayer);
		}
	}

	private void Awake()
	{
		//IL_0022: 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)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a94: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		toggleHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleHotkey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Toggle the custom HEX editor on/off.");
		copyHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Copy", new KeyboardShortcut((KeyCode)99, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Copy selected color.");
		pasteHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Paste", new KeyboardShortcut((KeyCode)118, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Paste copied color.");
		saveHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Save", new KeyboardShortcut((KeyCode)115, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Save.");
		undoHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Undo", new KeyboardShortcut((KeyCode)122, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Undo.");
		redoHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Redo", new KeyboardShortcut((KeyCode)121, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Redo.");
		editorEmoteSpeedCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Emotes", "AnimationSpeed", 1f, "Remembered editor emote animation speed from 0.25 to 2.0 in 0.25 steps.");
		_editorEmoteSpeed = GetNearestEditorEmoteSpeed(editorEmoteSpeedCfg.Value);
		editorEmoteSpeedCfg.Value = _editorEmoteSpeed;
		editorZoomLevelCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Camera", "ZoomLevel", 0, $"Remembered character editor zoom level (0-{7}).");
		editorZoomLevelCfg.Value = Mathf.Clamp(editorZoomLevelCfg.Value, 0, 7);
		editorHeadFocusCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "HeadFocus", true, "Remember camera focus: true for head, false for full body.");
		freeFlySpeedCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "FreeFlySpeed", 5f, "Remembered Free Fly camera movement speed.");
		_freeFlyMoveSpeed = Mathf.Clamp(freeFlySpeedCfg.Value, 5f, 25f);
		if (!Mathf.Approximately(freeFlySpeedCfg.Value, _freeFlyMoveSpeed))
		{
			freeFlySpeedCfg.Value = _freeFlyMoveSpeed;
		}
		editorPanelPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "EditorPanelPosition", "750,0", "Saved editor panel position.");
		itemMenuPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ItemMenuPosition", "-380,0", "Saved item menu position relative to the editor panel.");
		sharedContentMenuPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "SharedContentMenuPosition", itemMenuPositionCfg.Value, "Shared position for Emotes, Animations, Hand-items, and Armor Sets.");
		miscMenuPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "MiscMenuPosition", "-380,0", "Saved miscellaneous menu position relative to the editor panel.");
		infoMenuPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "InfoMenuPosition", "-380,0", "Saved shortcut information menu position relative to the editor panel.");
		appearanceMenuPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "AppearanceMenuPosition", "-380,0", "Saved appearance menu position relative to the editor panel.");
		lastHandItemCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Hand-items", "LastEquipped", "Reset", "Remembered editor preview hand-item, None, or Reset.");
		lastArmorHeadCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "LastHead", "Reset", "Remembered editor preview head armor, None, or Reset.");
		lastArmorChestCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "LastChest", "Reset", "Remembered editor preview chest armor, None, or Reset.");
		lastArmorLegsCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "LastLegs", "Reset", "Remembered editor preview leg armor, None, or Reset.");
		lastArmorCapeCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "LastCape", "Reset", "Remembered editor preview cape, None, or Reset.");
		lastArmorAccessoryCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "LastAccessory", "Reset", "Remembered editor preview accessory, None, or Reset.");
		handItemMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Hand-items", "CharacterMap", "", "Per-character remembered editor hand-items.");
		armorSelectionMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Armor", "CharacterMap", "", "Per-character remembered editor armor slots.");
		animationSelectionMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Animations", "CharacterMap", "", "Per-character remembered Idle and Run editor animations.");
		appearanceSelectionMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Appearance", "CharacterMap", "", "Per-character gender, hair style, and beard style.");
		devProfilesCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Dev", "EnabledCharacters", "", "Character names that automatically enable devcommands, nocost, and god in-world.");
		LoadEquipmentSelectionMaps();
		LoadAnimationSelectionMap();
		LoadAppearanceSelectionMap();
		LoadDevProfiles();
		if (itemMenuPositionCfg.Value == "380,0")
		{
			itemMenuPositionCfg.Value = "-380,0";
		}
		colorPickerPositionCfg = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ColorPickerPosition", "0,0", "Saved color picker position.");
		lightModeCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Lighting", "LastMode", "Day", "Remembered character editor lighting mode.");
		if (Enum.TryParse<LightMode>(lightModeCfg.Value, ignoreCase: true, out var result))
		{
			currentLightMode = result;
		}
		else
		{
			lightModeCfg.Value = currentLightMode.ToString();
		}
		_headFocusMode = editorHeadFocusCfg.Value;
		_cameraPresetIndex = ((editorZoomLevelCfg.Value == 0) ? (CameraPresetCycle.Length - 1) : ((!_headFocusMode) ? 1 : 0));
		eyeMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "EyeMap", "", "Per-character eye color map.");
		LoadEyeMap();
		try
		{
			sizeMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Size", "SizeMap", "", "Per-character size map.");
			LoadSizeMap();
			if (sizeMap.Count == 0 && scaleProfileCfg != null && !string.IsNullOrEmpty(scaleProfileCfg.Value))
			{
				sizeMap[scaleProfileCfg.Value] = Mathf.Clamp(bodyScaleCfg.Value, 0.8f, 1.2f);
				SaveSizeMap();
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("SizeMap init failed: " + ex));
		}
		bodyColorCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "Body", "#C68642", "Last body color.");
		bodyMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "BodyMap", "", "Per-character body color map.");
		LoadBodyMap();
		hairColorCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "Hair", "#3B2417", "Last hair color.");
		hairFadeMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "HairFadeMap", "", "Per-character hair fade color and angle.");
		LoadHairFadeMap();
		bodyScaleCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Size", "Scale", 1f, "Scale.");
		scaleProfileCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Size", "Profile", "", "Character.");
		bodyHex = bodyColorCfg.Value;
		hairHex = hairColorCfg.Value;
		bodyScale = Mathf.Clamp(bodyScaleCfg.Value, 0.8f, 1.2f);
		linkHairAndBeardCfg = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LinkHairAndBeard", true, "Link hair and beard.");
		linkHairAndBeard = linkHairAndBeardCfg.Value;
		beardMapCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Colors", "BeardMap", "", "Per-character beard color map.");
		LoadBeardMap();
		wolfColorCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Creatures", "WolfColor", "#FFFFFF", "Wolf preview body color.");
		wolfScaleCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Creatures", "WolfScale", 1f, "Wolf preview size.");
		loxColorCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Creatures", "LoxColor", "#FFFFFF", "Lox preview body color.");
		loxScaleCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Creatures", "LoxScale", 1f, "Lox preview size.");
		lastCreaturePrefabCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Creatures", "LastSelectedPrefab", "Wolf", "Creature shown when Creature Preview is opened.");
		lastCreatureLevelCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Creatures", "LastSelectedLevel", 1, "Creature level shown when Creature Preview is opened (1-3).");
		creatureLevel = Mathf.Clamp(lastCreatureLevelCfg.Value, 1, 3);
		if (lastCreatureLevelCfg.Value != creatureLevel)
		{
			lastCreatureLevelCfg.Value = creatureLevel;
		}
		henSkinCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Creatures", "SkinVariant", 1, "Remembered Creature Preview visual variant.");
		henSkinIndex = Mathf.Clamp(henSkinCfg.Value, 1, 12) - 1;
		if (henSkinCfg.Value != henSkinIndex + 1)
		{
			henSkinCfg.Value = henSkinIndex + 1;
		}
		string value = lastCreaturePrefabCfg.Value;
		bool flag = false;
		for (int i = 0; i < CharacterPrefabNames.Length; i++)
		{
			if (string.Equals(CharacterPrefabNames[i], value, StringComparison.OrdinalIgnoreCase))
			{
				selectedCreaturePrefab = CharacterPrefabNames[i];
				flag = true;
				break;
			}
		}
		if (!flag)
		{
			selectedCreaturePrefab = "Wolf";
			lastCreaturePrefabCfg.Value = selectedCreaturePrefab;
		}
		SceneManager.activeSceneChanged += OnActiveSceneChanged;
		new Harmony("Untamo.CreaturePreview.Patches").PatchAll();
	}

	private void OnDestroy()
	{
		if (ownCharacterEditorOpen)
		{
			CloseOwnCharacterEditor();
		}
		RestoreNativeCharacterSelectAfterCreatureUI();
		RestorePreviewCharacterRenderers();
		DestroyCreaturePreview();
		if ((Object)(object)creaturePanelRoot != (Object)null)
		{
			Object.Destroy((Object)(object)creaturePanelRoot);
		}
		if ((Object)(object)creatureNameLabelRoot != (Object)null)
		{
			Object.Destroy((Object)(object)creatureNameLabelRoot);
		}
		if ((Object)(object)creatureListRoot != (Object)null)
		{
			Object.Destroy((Object)(object)creatureListRoot);
		}
		if ((Object)(object)characterSelectEditButton != (Object)null)
		{
			Object.Destroy((Object)(object)characterSelectEditButton);
		}
		if ((Object)(object)characterSelectCreatureButton != (Object)null)
		{
			Object.Destroy((Object)(object)characterSelectCreatureButton);
		}
		if ((Object)(object)characterSelectCreaturePanel != (Object)null)
		{
			Object.Destroy((Object)(object)characterSelectCreaturePanel);
		}
		if ((Object)(object)characterSelectEditPanel != (Object)null)
		{
			Object.Destroy((Object)(object)characterSelectEditPanel);
		}
		if ((Object)(object)characterCloneButton != (Object)null)
		{
			Object.Destroy((Object)(object)characterCloneButton);
		}
		if ((Object)(object)characterEditorSaveButton != (Object)null)
		{
			Object.Destroy((Object)(object)characterEditorSaveButton);
		}
		if ((Object)(object)characterEditorActionPanel != (Object)null)
		{
			Object.Destroy((Object)(object)characterEditorActionPanel);
		}
		if ((Object)(object)newCharacterSavePanel != (Object)null)
		{
			Object.Destroy((Object)(object)newCharacterSavePanel);
		}
		if ((Object)(object)characterCloneNamePrompt != (Object)null)
		{
			Object.Destroy((Object)(object)characterCloneNamePrompt);
		}
		if ((Object)(object)hiddenNativeNameLabel != (Object)null)
		{
			((Behaviour)hiddenNativeNameLabel).enabled = true;
		}
		if ((Object)(object)nativeNameOverlayObject != (Object)null)
		{
			Object.Destroy((Object)(object)nativeNameOverlayObject);
		}
		SavePanelPositionsNow();
		StopHaldorDanceMusicImmediately();
		RestoreEditorCamera();
		StopReapplyRoutine();
		RestoreOriginalLighting();
		SceneManager.activeSceneChanged -= OnActiveSceneChanged;
		Harmony.UnpatchID("Untamo.CreaturePreview.Patches");
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void OnActiveSceneChanged(Scene oldScene, Scene newScene)
	{
		devModeAppliedPlayer = null;
		devModeAppliedProfile = "";
		if (creaturePreviewScreenOpen)
		{
			CloseCreaturePreviewScreen();
		}
		DestroyCreaturePreview();
		editTarget = EditTarget.Character;
		if (ownCharacterEditorOpen)
		{
			CloseOwnCharacterEditor();
		}
		StopHaldorDanceMusicImmediately();
		RestoreEditorCamera();
		_lightSaved = false;
		_sceneLight = null;
		StopReapplyRoutine();
		if (currentLightMode != LightMode.Day)
		{
			_reapplyRoutine = ((MonoBehaviour)this).StartCoroutine(ReapplyLightModeWhenReady());
		}
	}

	private IEnumerator ReapplyLightModeWhenReady()
	{
		for (int i = 0; i < 180; i++)
		{
			if (currentLightMode == LightMode.Day)
			{
				_reapplyRoutine = null;
				yield break;
			}
			if ((Object)(object)FindActiveSceneDirectionalLight() != (Object)null)
			{
				break;
			}
			yield return null;
		}
		if (currentLightMode == LightMode.Day)
		{
			_reapplyRoutine = null;
			yield break;
		}
		ApplyLightMode(currentLightMode);
		if ((Object)(object)lightBtn != (Object)null)
		{
			Text t = ((Component)lightBtn).GetComponentInChildren<Text>();
			if ((Object)(object)t != (Object)null)
			{
				t.text = "LightMode: " + GetLightModeLabel(currentLightMode);
			}
		}
		_reapplyRoutine = null;
	}

	private void Update()
	{
		//IL_06d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_06dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_09c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_09ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b19: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b1e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c6f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c74: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c78: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c85: Unknown result type (might be due to invalid IL or missing references)
		//IL_0c8a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ca3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ca8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d17: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d1c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d20: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d2d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d32: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d4b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d50: Unknown result type (might be due to invalid IL or missing references)
		//IL_0dbf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0dc4: Unknown result type (might be due to invalid IL or missing references)
		if (CreaturePreviewOnly)
		{
			UpdateCreaturePreviewPlugin();
			return;
		}
		UpdateToast();
		CacheNativeEmoteRadial();
		TrackPanelPositions();
		Player val = FindTargetPlayer();
		UpdateMultiplayerAppearance();
		ApplySavedDevModeInWorld();
		bool flag = IsNewCharacterMenuOpen();
		bool flag2 = IsCharacterSelectScreenOpen();
		EnsureNativeNameOverlay(flag2 && !flag && !creaturePreviewScreenOpen);
		if (flag2)
		{
			string profileName = GetProfileName();
			if (!string.IsNullOrEmpty(profileName))
			{
				RefreshNativeCharacterNamePanel(lastRenamedOldName, profileName);
			}
		}
		if (ownCharacterEditorOpen && (!flag2 || (Object)(object)Player.m_localPlayer != (Object)null))
		{
			CloseOwnCharacterEditor();
		}
		if (creaturePreviewScreenOpen && (!flag2 || (Object)(object)Player.m_localPlayer != (Object)null))
		{
			CloseCreaturePreviewScreen();
		}
		bool visible = flag2 && !flag && !ownCharacterEditorOpen && !creaturePreviewScreenOpen && ((Object)(object)creatureListRoot == (Object)null || !creatureListRoot.activeSelf);
		EnsureCharacterSelectEditButton(visible);
		EnsureCharacterSelectCreatureButton(visible);
		EnsureCharacterSelectEditPanel(visible);
		EnsureCharacterSelectCreaturePanel(visible);
		if (((Object)(object)creaturePanelRoot != (Object)null && creaturePanelRoot.activeSelf) || ((Object)(object)creatureListRoot != (Object)null && creatureListRoot.activeSelf))
		{
			HideNativeCharacterSelectForCreatureUI();
		}
		bool flag3 = ownCharacterEditorOpen && (_freeFlyCameraActive || _inGameCameraActive) && Input.GetKey((KeyCode)306);
		bool flag4 = ownCharacterEditorOpen && flag2 && !flag && !flag3;
		EnsureCharacterCloneButton(flag4);
		EnsureCharacterEditorSaveButton(flag4 || flag);
		EnsureCharacterEditorActionPanel(flag4);
		EnsureNewCharacterSavePanel(flag);
		bool flag5 = ownCharacterEditorOpen || flag || creaturePreviewScreenOpen;
		if (flag && !wasNewCharacterMenuOpen)
		{
			pendingNewCharacterAppearance = false;
			pendingAppearance = ReadAppearanceSelection(val);
			savedAnimationAppliedPlayer = null;
			savedAnimationProfileName = "";
			_previewEmoteAnimator = null;
			_previewEmoteClip = null;
			_previewEmoteLoopClip = null;
			_previewEmoteTime = 0f;
			_previewEmoteLoop = false;
			if (customEditorEnabled && (Object)(object)val != (Object)null)
			{
				LoadColorsFromCharacter();
			}
			RefreshPlayerNameInput();
		}
		if (!flag && wasNewCharacterMenuOpen)
		{
			pendingNewCharacterAppearance = false;
		}
		wasNewCharacterMenuOpen = flag;
		if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)lastPlayer)
		{
			lastPlayer = val;
			appearanceAppliedPlayer = null;
			appearanceAppliedProfile = "";
			RefreshPlayerNameInput();
			if (flag5 && customEditorEnabled)
			{
				LoadColorsFromCharacter();
			}
			else if (!flag5)
			{
				TryAutoApplyScale();
			}
		}
		if (!flag5)
		{
			StopHaldorDanceMusic();
			RestoreEditorCamera();
			editorEquipmentPlayer = null;
			savedHandItemAppliedPlayer = null;
			savedArmorAppliedPlayer = null;
			savedEquipmentProfileName = "";
			editorEquipmentCaptured = false;
			originalEditorRightVisual = "";
			originalEditorLeftVisual = "";
			armorEquipmentPlayer = null;
			armorEquipmentCaptured = false;
			originalArmorHead = (originalArmorChest = (originalArmorLegs = (originalArmorCape = (originalArmorAccessory = ""))));
			holdScaleMinus = false;
			holdScalePlus = false;
			if ((Object)(object)panelRoot != (Object)null)
			{
				panelRoot.SetActive(false);
			}
			if ((Object)(object)emoteMenuRoot != (Object)null)
			{
				emoteMenuRoot.SetActive(false);
			}
			if ((Object)(object)animationMenuRoot != (Object)null)
			{
				animationMenuRoot.SetActive(false);
			}
			if ((Object)(object)itemMenuRoot != (Object)null)
			{
				itemMenuRoot.SetActive(false);
			}
			if ((Object)(object)armorMenuRoot != (Object)null)
			{
				armorMenuRoot.SetActive(false);
			}
			if ((Object)(object)appearanceMenuRoot != (Object)null)
			{
				appearanceMenuRoot.SetActive(false);
			}
			if ((Object)(object)miscMenuRoot != (Object)null)
			{
				miscMenuRoot.SetActive(false);
			}
			if ((Object)(object)infoMenuRoot != (Object)null)
			{
				infoMenuRoot.SetActive(false);
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null && (Object)(object)val != (Object)null)
			{
				string profileName2 = GetProfileName();
				if (!string.Equals(savedAnimationProfileName, profileName2, StringComparison.Ordinal))
				{
					savedAnimationProfileName = profileName2;
					savedAnimationAppliedPlayer = null;
				}
				if ((Object)(object)val != (Object)(object)savedAnimationAppliedPlayer)
				{
					savedAnimationAppliedPlayer = val;
					((MonoBehaviour)this).StartCoroutine(ApplySavedAnimationWhenReady(val, profileName2, idleOnly: true));
				}
			}
			else
			{
				savedAnimationAppliedPlayer = null;
				savedAnimationProfileName = "";
				_previewEmoteAnimator = null;
				_previewEmoteClip = null;
				_previewEmoteTime = 0f;
				_previewEmoteLoop = false;
			}
			ApplyScaleToPreview();
			ApplyBeardInWorld();
			UpdateEyeRainbowLoop();
			return;
		}
		string text = (ownCharacterEditorOpen ? GetProfileName() : "");
		if (!string.Equals(savedEquipmentProfileName, text, StringComparison.Ordinal))
		{
			savedEquipmentProfileName = text;
			RefreshPlayerNameInput();
			if (customEditorEnabled)
			{
				LoadColorsFromCharacter();
			}
			savedHandItemAppliedPlayer = null;
			savedArmorAppliedPlayer = null;
			savedAnimationAppliedPlayer = null;
			savedAnimationProfileName = text;
			editorEquipmentPlayer = null;
			editorEquipmentCaptured = false;
			armorEquipmentPlayer = null;
			armorEquipmentCaptured = false;
		}
		if (ownCharacterEditorOpen && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)savedHandItemAppliedPlayer)
		{
			savedHandItemAppliedPlayer = val;
			((MonoBehaviour)this).StartCoroutine(ApplySavedHandItemWhenReady(val));
		}
		if (ownCharacterEditorOpen && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)savedArmorAppliedPlayer)
		{
			savedArmorAppliedPlayer = val;
			((MonoBehaviour)this).StartCoroutine(ApplySavedArmorWhenReady(val));
		}
		if (ownCharacterEditorOpen && (Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)savedAnimationAppliedPlayer)
		{
			savedAnimationAppliedPlayer = val;
			((MonoBehaviour)this).StartCoroutine(ApplySavedAnimationWhenReady(val, text, idleOnly: false));
		}
		KeyboardShortcut value = toggleHotkey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			if (creaturePreviewScreenOpen)
			{
				CloseCreaturePreviewScreen();
				return;
			}
			if ((Object)(object)panelRoot == (Object)null)
			{
				BuildUI();
			}
			if ((Object)(object)panelRoot == (Object)null)
			{
				status = "GUI not ready.";
				return;
			}
			bool flag6 = customEditorEnabled && panelRoot.activeSelf;
			if (ownCharacterEditorOpen && flag6)
			{
				CloseOwnCharacterEditor();
				status = "Editor closed.";
				uiDirty = true;
				return;
			}
			customEditorEnabled = !flag6;
			if (!customEditorEnabled)
			{
				holdScaleMinus = false;
				holdScalePlus = false;
				StopHaldorDanceMusic();
				RestoreEditorCamera();
				if ((Object)(object)emoteMenuRoot != (Object)null)
				{
					emoteMenuRoot.SetActive(false);
				}
				if ((Object)(object)animationMenuRoot != (Object)null)
				{
					animationMenuRoot.SetActive(false);
				}
				if ((Object)(object)itemMenuRoot != (Object)null)
				{
					itemMenuRoot.SetActive(false);
				}
				if ((Object)(object)armorMenuRoot != (Object)null)
				{
					armorMenuRoot.SetActive(false);
				}
				if ((Object)(object)appearanceMenuRoot != (Object)null)
				{
					appearanceMenuRoot.SetActive(false);
				}
				if ((Object)(object)miscMenuRoot != (Object)null)
				{
					miscMenuRoot.SetActive(false);
				}
				if ((Object)(object)infoMenuRoot != (Object)null)
				{
					infoMenuRoot.SetActive(false);
				}
			}
			panelRoot.SetActive(customEditorEnabled);
			GUIManager.BlockInput(customEditorEnabled);
			if (customEditorEnabled && flag)
			{
				pendingAppearance = ReadAppearanceSelection(val);
				LoadColorsFromCharacter();
			}
			status = (customEditorEnabled ? "Editor enabled." : "Editor disabled.");
			uiDirty = true;
		}
		if (customEditorEnabled && editTarget == EditTarget.Character)
		{
			SyncColorsToPlayer();
		}
		UpdateCreaturePreview();
		UpdateEyeRainbowLoop();
		if (customEditorEnabled && _inGameCameraActive && ((Object)(object)panelRoot == (Object)null || !panelRoot.activeSelf) && !IsNameInputFocused())
		{
			HandleEditorZoomInput();
			return;
		}
		if (!customEditorEnabled || !IsAnyEditorPanelVisible())
		{
			return;
		}
		if (flag)
		{
			pendingNewCharacterAppearance = true;
		}
		if (!IsNameInputFocused())
		{
			HandleEditorZoomInput();
			value = copyHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				switch (selectedColor)
				{
				case ColorTarget.Body:
					CopyColor(bodyHex);
					break;
				case ColorTarget.Hair:
					CopyColor(hairHex);
					break;
				case ColorTarget.HairFade:
					CopyColor(hairFadeHex);
					break;
				case ColorTarget.OriginalBody:
					CopyColor(originalBodyHex);
					break;
				case ColorTarget.OriginalHair:
					CopyColor(originalHairHex);
					break;
				case ColorTarget.OriginalHairFade:
					CopyColor(originalHairFadeHex);
					break;
				case ColorTarget.Beard:
					CopyColor(beardHex);
					break;
				case ColorTarget.BeardFade:
					CopyColor(beardFadeHex);
					break;
				case ColorTarget.OriginalBeard:
					CopyColor(originalBeardHex);
					break;
				case ColorTarget.OriginalBeardFade:
					CopyColor(originalBeardFadeHex);
					break;
				case ColorTarget.Eye:
					CopyColor(eyeHex);
					break;
				case ColorTarget.Iris:
					CopyColor(irisHex);
					break;
				case ColorTarget.OriginalEye:
					CopyColor(originalEyeHex);
					break;
				case ColorTarget.OriginalIris:
					CopyColor(originalIrisHex);
					break;
				}
			}
			value = pasteHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				Color color;
				switch (selectedColor)
				{
				case ColorTarget.Body:
					PasteBody();
					break;
				case ColorTarget.Hair:
					PasteHair();
					break;
				case ColorTarget.HairFade:
					if (TryParseHex(colorClipboard, out color))
					{
						hairFadeHex = colorClipboard;
						uiDirty = true;
					}
					break;
				case ColorTarget.Beard:
					PasteBeard();
					break;
				case ColorTarget.BeardFade:
					if (TryParseHex(colorClipboard, out color))
					{
						beardFadeHex = colorClipboard;
						uiDirty = true;
					}
					break;
				case ColorTarget.Eye:
					PasteEye();
					break;
				case ColorTarget.Iris:
					PasteIris();
					break;
				}
			}
			if (holdScaleMinus && Time.unscaledTime >= holdScaleNextTime)
			{
				AdjustScale(-0.01f);
				holdScaleNextTime = Time.unscaledTime + 0.05f;
			}
			if (holdScalePlus && Time.unscaledTime >= holdScaleNextTime)
			{
				AdjustScale(0.01f);
				holdScaleNextTime = Time.unscaledTime + 0.05f;
			}
			value = undoHotkey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
			{
				value = undoHotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsPressed())
				{
					value = undoHotkey.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						Undo();
						undoRepeatTimer = Time.time + 0.5f;
					}
					else if (Time.time >= undoRepeatTimer)
					{
						Undo();
						undoRepeatTimer = Time.time + 0.12f;
					}
					goto IL_0d11;
				}
			}
			undoRepeatTimer = 0f;
			goto IL_0d11;
		}
		if (Input.GetKey((KeyCode)306) && Input.GetKeyDown((KeyCode)115))
		{
			if ((Object)(object)playerNameInput != (Object)null && playerNameInput.isFocused)
			{
				playerNameInput.DeactivateInputField();
			}
			if ((Object)(object)nativeNameOverlayInput != (Object)null && nativeNameOverlayInput.isFocused)
			{
				nativeNameOverlayInput.DeactivateInputField();
			}
			SaveColors();
		}
		return;
		IL_0d11:
		value = redoHotkey.Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey != 0)
		{
			value = redoHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsPressed())
			{
				value = redoHotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					Redo();
					redoRepeatTimer = Time.time + 0.5f;
				}
				else if (Time.time >= redoRepeatTimer)
				{
					Redo();
					redoRepeatTimer = Time.time + 0.12f;
				}
				goto IL_0db9;
			}
		}
		redoRepeatTimer = 0f;
		goto IL_0db9;
		IL_0db9:
		value = saveHotkey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			SaveColors();
		}
	}

	private void LateUpdate()
	{
		if (!IsCharacterCustomizationOpen())
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				UpdatePreviewEmote();
			}
			return;
		}
		if (_headFocusMode)
		{
			UpdatePreviewEmote();
		}
		if (_editorZoomActive)
		{
			if (_inGameCameraActive)
			{
				UpdateInGameCamera();
			}
			else if (_freeFlyCameraActive)
			{
				UpdateFreeFlyCamera();
			}
			else
			{
				if (_cameraSpinActive)
				{
					_cameraSpinAngle = Mathf.Repeat(_cameraSpinAngle + _cameraSpinDirection * 30f * Time.unscaledDeltaTime, 360f);
				}
				ApplyEditorZoom();
			}
		}
		if (!_headFocusMode)
		{
			UpdatePreviewEmote();
		}
	}

	private void UpdatePreviewEmote()
	{
		//IL_024e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_previewEmoteAnimator == (Object)null || (Object)(object)_previewEmoteClip == (Object)null)
		{
			return;
		}
		_previewEmoteTime += Time.unscaledDeltaTime * _editorEmoteSpeed * _previewEmotePlaybackMultiplier;
		if (_previewEmoteLoop)
		{
			float num = Mathf.Clamp(_previewEmoteLoopEndPadding, 0f, Mathf.Max(0f, _previewEmoteClip.length - 0.05f));
			float num2 = Mathf.Max(0.05f, _previewEmoteClip.length - num);
			_previewEmoteTime = Mathf.Repeat(_previewEmoteTime, num2);
		}
		else if (_previewEmoteTime >= _previewEmoteClip.length)
		{
			if (!((Object)(object)_previewEmoteLoopClip != (Object)null))
			{
				if (_previewEmoteExitingSit && !string.IsNullOrEmpty(_previewEmotePendingCommand))
				{
					string previewEmotePendingCommand = _previewEmotePendingCommand;
					_previewEmotePendingCommand = null;
					_previewEmoteExitingSit = false;
					_previewEmoteAnimator = null;
					_previewEmoteClip = null;
					ExecuteEditorEmoteCommand(previewEmotePendingCommand);
				}
				else
				{
					_previewEmoteAnimator = null;
					_previewEmoteClip = null;
					StopHaldorDanceMusic();
				}
				return;
			}
			_previewEmoteClip = _previewEmoteLoopClip;
			_previewEmoteLoopClip = null;
			string text = ((Object)_previewEmoteClip).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
				.Replace(" ", "");
			bool flag = text == "liedown" || text.EndsWith("liedown") || text == "liedown2" || text.EndsWith("liedown2");
			_previewEmoteLoopEndPadding = (flag ? 0f : Mathf.Min(1f, Mathf.Max(0f, _previewEmoteClip.length - 0.05f)));
			_previewEmoteTime = 0f;
			_previewEmoteLoop = true;
			_previewEmoteReverse = false;
			_previewEmotePlaybackMultiplier = 1f;
		}
		Transform transform = ((Component)_previewEmoteAnimator).transform;
		Vector3 position = transform.position;
		Quaternion rotation = transform.rotation;
		float num3 = (_previewEmoteReverse ? Mathf.Max(0f, _previewEmoteClip.length - _previewEmoteTime) : _previewEmoteTime);
		_previewEmoteClip.SampleAnimation(((Component)_previewEmoteAnimator).gameObject, num3);
		transform.position = position;
		transform.rotation = rotation;
	}

	private void ExecuteEditorEmoteCommand(string command)
	{
		string text = (command ?? "").Trim().ToLowerInvariant();
		if (text == "/stop")
		{
			_previewEmoteAnimator = null;
			_previewEmoteClip = null;
			_previewEmoteLoopClip = null;
			_previewEmoteLoopEndPadding = 0f;
			_previewEmoteReverse = false;
			_previewEmotePlaybackMultiplier = 1f;
			_previewEmotePendingCommand = null;
			_previewEmoteExitingSit = false;
			_previewEmoteTime = 0f;
			_previewEmoteLoop = false;
			_handItemAnimationActive = false;
			StopHaldorDanceMusic();
			ShowEditorAnimationToast("Emote stopped", 2f);
			return;
		}
		string text2 = (text.StartsWith("/") ? text.Substring(1) : text);
		bool flag = EditorEmotes.Contains(text2);
		bool flag2 = EditorAnimationClipNames.ContainsKey(text2);
		if (!flag && !flag2)
		{
			ShowEditorAnimationToast("Unknown emote or animation. Use /stop to return to idle", 4f);
			return;
		}
		Player val = FindTargetPlayer();
		if ((Object)(object)val == (Object)null)
		{
			ShowEditorAnimationToast("No preview character found", 3f);
			return;
		}
		try
		{
			Animator componentInChildren = ((Component)val).GetComponentInChildren<Animator>();
			if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.runtimeAnimatorController == (Object)null)
			{
				ShowEditorAnimationToast("Preview animator was not found", 4f);
				return;
			}
			string text3 = (((Object)(object)_previewEmoteClip != (Object)null) ? ((Object)_previewEmoteClip).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
				.Replace(" ", "") : "");
			if (_previewEmoteLoop && (text3 == "sittingidle" || text3.EndsWith("sittingidle")) && !string.Equals(text2, "sit", StringComparison.OrdinalIgnoreCase))
			{
				AnimationClip val2 = null;
				List<AnimationClip> list = new List<AnimationClip>(componentInChildren.runtimeAnimatorController.animationClips);
				list.AddRange(Resources.FindObjectsOfTypeAll<AnimationClip>());
				for (int i = 0; i < list.Count; i++)
				{
					AnimationClip val3 = list[i];
					if (!((Object)(object)val3 == (Object)null))
					{
						string text4 = ((Object)val3).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
							.Replace(" ", "");
						if (text4 == "standingupfromsit" || text4.EndsWith("standingupfromsit"))
						{
							val2 = val3;
							break;
						}
					}
				}
				if ((Object)(object)val2 != (Object)null)
				{
					_previewEmoteAnimator = componentInChildren;
					_previewEmoteClip = val2;
					_previewEmoteLoopClip = null;
					_previewEmoteLoopEndPadding = 0f;
					_previewEmoteReverse = false;
					_previewEmotePlaybackMultiplier = 1.6f;
					_previewEmotePendingCommand = text;
					_previewEmoteExitingSit = true;
					_previewEmoteTime = 0f;
					_previewEmoteLoop = false;
					return;
				}
			}
			string text5 = (flag2 ? EditorAnimationClipNames[text2].ToLowerInvariant() : ("emote_" + text2));
			AnimationClip val4 = null;
			int num = -1;
			AnimationClip[] animationClips = componentInChildren.runtimeAnimatorController.animationClips;
			foreach (AnimationClip val5 in animationClips)
			{
				if (!((Object)(object)val5 == (Object)null))
				{
					string text6 = ((Object)val5).name.ToLowerInvariant();
					int num2 = -1;
					if (text6 == text5)
					{
						num2 = 100;
					}
					else if (text6.EndsWith(text5))
					{
						num2 = 80;
					}
					else if (text6.Contains(text5))
					{
						num2 = 60;
					}
					else if (text6.Contains(text2))
					{
						num2 = 30;
					}
					if (num2 > num)
					{
						val4 = val5;
						num = num2;
					}
				}
			}
			AnimationClip val6 = null;
			AnimationClip val7 = null;
			AnimationClip val8 = null;
			AnimationClip val9 = null;
			AnimationClip val10 = null;
			AnimationClip val11 = null;
			string[] value2;
			if (flag2 && EditorAnimationClipNames.TryGetValue(text2, out var value))
			{
				value2 = ((!string.Equals(text2, "sneak_walk", StringComparison.OrdinalIgnoreCase)) ? new string[1] { value } : new string[5] { value, "PlayerCharacter_01_3@Sneak Walk", "PlayerCharacter_01@Sneak Walk", "PlayerCharacter_01 (1)@Sneak Walk", "PlayerCharacter_01 (2)@Sneak Walk" });
			}
			else
			{
				ExtendedEditorEmoteClipNames.TryGetValue(text2, out value2);
			}
			if (value2 != null)
			{
				AnimationClip val12 = null;
				List<AnimationClip> list2 = new List<AnimationClip>(componentInChildren.runtimeAnimatorController.animationClips);
				list2.AddRange(Resources.FindObjectsOfTypeAll<AnimationClip>());
				if (string.Equals(text2, "kneel", StringComparison.OrdinalIgnoreCase))
				{
					for (int k = 0; k < list2.Count; k++)
					{
						AnimationClip val13 = list2[k];
						if (!((Object)(object)val13 == (Object)null))
						{
							string text7 = ((Object)val13).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
								.Replace(" ", "");
							if (text7 == "kneelstart" || text7.EndsWith("kneelstart"))
							{
								val6 = val13;
							}
							if (text7 == "kneelloop" || text7.EndsWith("kneelloop"))
							{
								val7 = val13;
							}
							if ((Object)(object)val6 != (Object)null && (Object)(object)val7 != (Object)null)
							{
								break;
							}
						}
					}
					if ((Object)(object)val6 != (Object)null)
					{
						val12 = val6;
					}
				}
				else if (string.Equals(text2, "sit", StringComparison.OrdinalIgnoreCase))
				{
					for (int l = 0; l < list2.Count; l++)
					{
						AnimationClip val14 = list2[l];
						if (!((Object)(object)val14 == (Object)null))
						{
							string text8 = ((Object)val14).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
								.Replace(" ", "");
							if (text8 == "standingup" || text8.EndsWith("standingup"))
							{
								val8 = val14;
							}
							if (text8 == "sittingidle" || text8.EndsWith("sittingidle"))
							{
								val9 = val14;
							}
							if ((Object)(object)val8 != (Object)null && (Object)(object)val9 != (Object)null)
							{
								break;
							}
						}
					}
					if ((Object)(object)val8 != (Object)null)
					{
						val12 = val8;
					}
				}
				else if (string.Equals(text2, "lie_down", StringComparison.OrdinalIgnoreCase) || string.Equals(text2, "lie_down_2", StringComparison.OrdinalIgnoreCase))
				{
					bool flag3 = string.Equals(text2, "lie_down_2", StringComparison.OrdinalIgnoreCase);
					for (int m = 0; m < list2.Count; m++)
					{
						AnimationClip val15 = list2[m];
						if ((Object)(object)val15 == (Object)null)
						{
							continue;
						}
						string text9 = ((Object)val15).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
							.Replace(" ", "");
						if (text9 == "standingup" || text9.EndsWith("standingup"))
						{
							val10 = val15;
						}
						if (flag3)
						{
							if (text9 == "liedown2" || text9.EndsWith("liedown2"))
							{
								val11 = val15;
							}
						}
						else if (text9 == "liedown" || text9.EndsWith("liedown"))
						{
							val11 = val15;
						}
						if ((Object)(object)val10 != (Object)null && (Object)(object)val11 != (Object)null)
						{
							break;
						}
					}
					if ((Object)(object)val10 != (Object)null)
					{
						val12 = val10;
					}
				}
				for (int n = 0; n < value2.Length; n++)
				{
					if (!((Object)(object)val12 == (Object)null))
					{
						break;
					}
					string text10 = value2[n].ToLowerInvariant().Replace("_", "").Replace("-", "")
						.Replace(" ", "");
					foreach (AnimationClip item in list2)
					{
						if (!((Object)(object)item == (Object)null))
						{
							string text11 = ((Object)item).name.ToLowerInvariant().Replace("_", "").Replace("-", "")
								.Replace(" ", "");
							if (text11 == text10 || (string.Equals(text2, "sneak_walk", StringComparison.OrdinalIgnoreCase) && text11.EndsWith(text10)))
							{
								val12 = item;
								break;
							}
						}
					}
				}
				if ((Object)(object)val12 != (Object)nu