Decompiled source of AppearancePlus v3.8.1

AppearancePlus.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.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using AppearancePlus.Animation;
using AppearancePlus.AssetBundles;
using AppearancePlus.Utils;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Events;
using UnityEngine.Playables;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AppearancePlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+d704071c1f6e04f8189d7a278c45d972d8a30d31")]
[assembly: AssemblyProduct("Template plugin for Atlyss using BepInEx 5")]
[assembly: AssemblyTitle("AppearancePlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AppearancePlus
{
	[BepInPlugin("Nuilescent.AppearancePlus", "Appearance+", "3.8.1")]
	internal class AppearancePlus : BaseUnityPlugin
	{
		public static string DllPath;

		public static ScriptablePlayerRace[] ScriptablePlayerRaces;

		public static Player Player;

		public static List<PlayerRaceModel> PlayerModels = new List<PlayerRaceModel>();

		public static List<PlayerVisual> PlayerVisuals = new List<PlayerVisual>();

		public static Dictionary<string, NetNPC> NamedNPCs = new Dictionary<string, NetNPC>();

		public static List<NetNPC> NetNPCs = new List<NetNPC>();

		public static CameraFunction Camera;

		public static ChatBehaviour Chat;

		public static UnityEvent OnInitialized = new UnityEvent();

		public static UnityEvent OnChatInitialized = new UnityEvent();

		private static PlayerVisual _playerVisual;

		private static PlayerRaceModel _playerModel;

		public static PlayerVisual PlayerVisual
		{
			get
			{
				if ((Object)(object)_playerVisual == (Object)null || !((Component)_playerVisual).gameObject.activeInHierarchy)
				{
					_playerVisual = PlayerVisuals.Find((PlayerVisual pv) => (Object)(object)pv != (Object)null && ((Component)pv).gameObject.activeInHierarchy);
				}
				return _playerVisual;
			}
			set
			{
				_playerVisual = value;
			}
		}

		public static PlayerRaceModel PlayerModel
		{
			get
			{
				if ((Object)(object)_playerModel == (Object)null || !((Component)_playerModel).gameObject.activeInHierarchy)
				{
					_playerModel = PlayerModels.Find((PlayerRaceModel pm) => (Object)(object)pm != (Object)null && ((Component)pm).gameObject.activeInHierarchy);
				}
				return _playerModel;
			}
			set
			{
				_playerModel = value;
			}
		}

		private void Awake()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			DllPath = ((BaseUnityPlugin)this).Info.Location.Replace("AppearancePlus.dll", "");
			Harmony val = new Harmony("AppearancePlus");
			try
			{
				val.PatchAll();
			}
			catch (Exception value)
			{
				System.Console.WriteLine(value);
				throw;
			}
			Console.Initialize(((BaseUnityPlugin)this).Logger);
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void Start()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			Console.Info("A* Location: " + DllPath, LogLocation.ConsoleAndIngame);
			Configuration.LoadValues();
			if (PathUtils.GetDirectory(DllPath, "CustomTextures", out var result))
			{
				Console.Info("CustomTextures folder found at: " + result, LogLocation.ConsoleAndIngame);
				TextureLoader.LoadTextures(result);
			}
			else
			{
				Console.Info("Couldn't find a CustomTextures folder at: " + DllPath, LogLocation.ConsoleAndIngame);
			}
			OnChatInitialized.AddListener(new UnityAction(InitCommands));
			OnInitialized.Invoke();
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			PlayerModels.RemoveAll((PlayerRaceModel prm) => (Object)(object)prm == (Object)null);
			PlayerVisuals.RemoveAll((PlayerVisual pv) => (Object)(object)pv == (Object)null);
			if ((Object)(object)PlayerVisual != (Object)null)
			{
				Configuration.LoadValues(ConfigType.Slider);
				if ((Object)(object)PlayerModel != (Object)null)
				{
					PlayerModel.Apply_CharacterDisplay();
				}
				PlayerAppearanceStruct playerAppearanceStruct = PlayerVisual._playerAppearanceStruct;
				PlayerAppearance_Profile appearanceProfile = ProfileDataManager._current._characterFile._appearanceProfile;
				playerAppearanceStruct._bellyWeight = appearanceProfile._bellyWeight;
				playerAppearanceStruct._boobWeight = appearanceProfile._boobWeight;
				playerAppearanceStruct._bottomWeight = appearanceProfile._bottomWeight;
				playerAppearanceStruct._armWeight = appearanceProfile._armWeight;
				playerAppearanceStruct._heightWeight = appearanceProfile._heightWeight;
				playerAppearanceStruct._widthWeight = appearanceProfile._widthWeight;
				playerAppearanceStruct._muzzleWeight = appearanceProfile._muzzleWeight;
				playerAppearanceStruct._torsoWeight = appearanceProfile._torsoWeight;
				playerAppearanceStruct._voicePitch = appearanceProfile._voicePitch;
				PlayerVisual playerVisual = PlayerVisual;
				PlayerAppearanceStruct playerAppearanceStruct2 = (PlayerVisual.Network_playerAppearanceStruct = playerAppearanceStruct);
				playerVisual._playerAppearanceStruct = playerAppearanceStruct2;
				PlayerVisual.Cmd_SendNew_PlayerAppearanceStruct(playerAppearanceStruct);
				PlayerVisual.Apply_NetworkedCharacterDisplay();
			}
		}

		private void InitCommands()
		{
			Commands.Add(new CommandInfo("help", "Print every command and their description.", "", (Func<bool>)delegate
			{
				Commands.PrintCommands();
				return true;
			}));
			Commands.Add(new CommandInfo("anim player", "", "Play animation clip on player", (Func<bool>)delegate
			{
				Console.Info("Playing Animation DefaultDance.", LogLocation.ConsoleAndIngame);
				return PlayableGraphManager.PlayAnimationClip(PlayerModel, "DefaultDance", loop: false);
			}));
			Commands.Add(new CommandInfo("console", "<true/false> Enable/Disable the in-game console.", "", Console.ToggleConsole));
			Commands.Add(new CommandInfo("size", "<float> Set the size value for this character.", "Applied character's size value successfully.", SliderLoader.SizeCommand));
			Commands.Add(new CommandInfo("zoom", "<float> Set the max zoom.", "Applied max zoom value successfully.", (string p1) => Commands.CmdParseFloat(p1, out Configuration.Zoom.y)));
			Commands.Add(new CommandInfo("reload all", "Reloads the config values & textures and applies everything.", "Reloaded everything.", (Func<bool>)delegate
			{
				Configuration.LoadValues();
				SliderLoader.SetValues();
				DBonesLoader.SetAll();
				TextureLoader.ReloadAllTextures();
				return true;
			}));
			Commands.Add(new CommandInfo("reload config", "Reloads all the config values.", "Reloaded config values. This doesn't apply sliders, dbones or textures! Use /reload all instead.", (Func<bool>)delegate
			{
				Configuration.LoadValues();
				return true;
			}));
			Commands.Add(new CommandInfo("reload sliders", "Reloads the config values for sliders and applies them.", "Applied Slider Values", (Func<bool>)delegate
			{
				Configuration.LoadValues(ConfigType.Slider);
				SliderLoader.SetValues();
				return true;
			}));
			Commands.Add(new CommandInfo("reload dbones", "Reloads the config values and applies new values to dynamic bones.", "Refreshed Dynamic Bones", (Func<bool>)delegate
			{
				Configuration.LoadValues(ConfigType.DynamicBone);
				DBonesLoader.SetAll();
				return true;
			}));
			Commands.Add(new CommandInfo("reload textures", "Reloads Textures in CustomTextures and applies new ones. Does not revert missing ones to default.", "Applied Custom Textures", (Func<bool>)delegate
			{
				TextureLoader.ReloadAllTextures();
				return true;
			}));
			Commands.Add(new CommandInfo("print dbones", "Prints the current dynamic bone values.", "", DBonesLoader.PrintCurrentValues));
			Commands.Add(new CommandInfo("print sliders", "Prints the current slider values for this character.", "", SliderLoader.PrintCurrentValues));
		}

		private void InitEmotes()
		{
			Commands.AddEmote(new EmoteInfo("Fortnite Dance", "fortnite", "DefaultDance", "doing a fortnite", loop: false));
		}

		private void Update()
		{
			Console.Update();
		}
	}
	[HarmonyPatch(typeof(MainMenuManager), "Start")]
	public static class MenuPatch
	{
		[HarmonyPostfix]
		private static void StartPatch(MainMenuManager __instance)
		{
			__instance._versionDisplayText.text = Application.version + " w/ A+";
			Console.Info("Loaded AppearancePlus!");
		}
	}
	[HarmonyPatch(typeof(PlayerVisual), "RenderPlayerModel")]
	public static class PlayerVisualRenderPatch
	{
		[HarmonyPrefix]
		public static bool RenderPlayerModel_Prefx(PlayerVisual __instance)
		{
			if (!Configuration.ShowPlayerAlways)
			{
				return true;
			}
			__instance.Emit_RenderDisplay(true);
			return false;
		}
	}
	[HarmonyPatch(typeof(CameraCollision), "LateUpdate")]
	public static class CameraCollisionLateUpdatePatch
	{
		private static float _lastMaxDistance = 25f;

		[HarmonyPostfix]
		public static void LateUpdate_Postfix(CameraCollision __instance)
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if ((Configuration.Zoom.x == -2f && Configuration.Zoom.y == 60f && !Configuration.ShowPlayerAlways) || !Object.op_Implicit((Object)(object)Player._mainPlayer))
			{
				return;
			}
			float num = 0f;
			float lastMaxDistance = _lastMaxDistance;
			float num2 = _lastMaxDistance;
			if (!Player._mainPlayer._inUI && !Player._mainPlayer._inChat && !Player._mainPlayer._bufferingStatus)
			{
				float axis = Input.GetAxis("Mouse ScrollWheel");
				if (axis != 0f)
				{
					num += axis * 35.5f;
				}
			}
			lastMaxDistance = _lastMaxDistance + num;
			if (__instance.Handle_DetectGroundLayer())
			{
				num2 = ((RaycastHit)(ref __instance.hit)).distance * __instance.step;
			}
			lastMaxDistance = Mathf.Clamp(lastMaxDistance, Configuration.Zoom.x, Configuration.Zoom.y);
			((Component)__instance).transform.localPosition = __instance.dollyDir * Mathf.Min(num2, lastMaxDistance);
			_lastMaxDistance = lastMaxDistance;
		}
	}
	[HarmonyPatch(typeof(CameraFunction), "Awake")]
	public static class CameraFunctionAwakePatch
	{
		[HarmonyPostfix]
		private static void AwakePostfix(CameraFunction __instance)
		{
			if (Object.op_Implicit((Object)(object)Player._mainPlayer))
			{
				AppearancePlus.Camera = __instance;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerVisual), "Start")]
	public static class PlayerVisualsStartPatch
	{
		[HarmonyPostfix]
		public static void Start_Postfix(PlayerVisual __instance)
		{
			if ((Object)(object)__instance._player == (Object)(object)Player._mainPlayer)
			{
				AppearancePlus.PlayerVisual = __instance;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerRaceModel), "Awake")]
	public static class PlayerRaceModelAwakePatch
	{
		[HarmonyPostfix]
		private static void AwakePostfix(PlayerRaceModel __instance)
		{
			AppearancePlus.PlayerModels.Add(__instance);
			DBonesLoader.SetValues(__instance);
			SliderLoader.SetValues();
			if ((Object)(object)__instance._player == (Object)(object)Player._mainPlayer)
			{
				AppearancePlus.PlayerModel = __instance;
			}
		}
	}
	[HarmonyPatch(typeof(CharacterCreationManager), "Awake")]
	public static class CharacterCreationManagerPatch
	{
		[HarmonyPostfix]
		private static void AwakePostfix(CharacterCreationManager __instance)
		{
			AppearancePlus.ScriptablePlayerRaces = __instance._scriptablePlayerRaces;
			DBonesLoader.SetAll();
			SliderLoader.SetValues();
			TextureLoader.ApplyCustomTextures();
		}
	}
	[HarmonyPatch(typeof(NetNPC), "Start")]
	public static class NetNPCStartPatch
	{
		[HarmonyPrefix]
		public static void Start_Prefix(NetNPC __instance)
		{
			AppearancePlus.NetNPCs.Add(__instance);
			TextureLoader.ReplaceNPCTextures(__instance);
		}
	}
	[HarmonyPatch(typeof(CreepBehavior), "Awake")]
	public static class CreepAwakePatch
	{
		[HarmonyPrefix]
		public static void Start_Prefix(CreepBehavior __instance)
		{
			TextureLoader.ReplaceCreepTextures(__instance);
			TextureChangeAnimEvent textureAnim = default(TextureChangeAnimEvent);
			if (((Component)__instance).TryGetComponent<TextureChangeAnimEvent>(ref textureAnim))
			{
				TextureLoader.ReplaceTextureAnim(textureAnim);
			}
		}
	}
	public static class Configuration
	{
		public static Dictionary<string, List<(string, float)>> DynamicBoneValues = new Dictionary<string, List<(string, float)>>();

		public static Dictionary<string, List<(string, (float, float))>> RaceDisplayValues = new Dictionary<string, List<(string, (float, float))>>();

		public static bool IngameConsole = true;

		public static Vector2 Zoom = new Vector2(-2f, 60f);

		public static bool ShowPlayerAlways = false;

		public static bool ConfigEmpty = true;

		public static List<string> races = new List<string> { "imp", "poon", "chang", "kubold", "byrdle" };

		public static List<string> raceProperties = new List<string> { "height", "width", "torso", "chest", "arms", "belly", "bottom", "head", "muzzle", "voice" };

		public static List<string> dbProperties = new List<string> { "damping", "elasticity", "stiffness", "inert" };

		public static void LoadValues(ConfigType configType = ConfigType.Any)
		{
			string[] files = Directory.GetFiles(AppearancePlus.DllPath, "AppearancePlus_Config.txt", SearchOption.AllDirectories);
			if (files.Length == 0)
			{
				Console.Error("Could not find config file! \nMake sure AppearancePlus_Config.txt exists in ATLYSS/BepInEx/plugins/AppearancePlus");
				return;
			}
			if (files.Length > 1)
			{
				Console.Warning("Found multiple AppearancePlus_Config.txt. Only first one will be used!");
			}
			string text = files.First();
			Console.Info("Found config file at: " + text);
			DynamicBoneValues.Clear();
			RaceDisplayValues.Clear();
			StreamReader streamReader = new StreamReader(text);
			string text2 = streamReader.ReadLine();
			int num = 0;
			int num2 = 0;
			StringBuilder stringBuilder = new StringBuilder();
			Console.Info("Reading Config...");
			ConfigEmpty = true;
			string race;
			for (; text2 != null; text2 = streamReader.ReadLine())
			{
				if (Utility.IsNullOrWhiteSpace(text2))
				{
					continue;
				}
				if (ConfigEmpty)
				{
					ConfigEmpty = false;
				}
				List<string> list = text2.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList();
				if (text2.StartsWith("//") || text2 == string.Empty || list.Count == 0)
				{
					continue;
				}
				if (text2.StartsWith("end"))
				{
					break;
				}
				if (configType == ConfigType.Any)
				{
					if (text2.StartsWith("disable console"))
					{
						IngameConsole = false;
						continue;
					}
					if (text2.StartsWith("enable console"))
					{
						IngameConsole = true;
						continue;
					}
					if (text2.StartsWith("zoom"))
					{
						if (list.Count != 2)
						{
							if (list.Count < 1)
							{
								Console.Error("zoom property needs a value.", LogLocation.ConsoleAndIngame);
							}
							else
							{
								Console.Error("Don't write any other values after zoom <true/false>:<min>/<max>.", LogLocation.ConsoleAndIngame);
							}
						}
						string[] array = list.Last().Split(':');
						if (array.Length != 2)
						{
							Console.Error("Incorrect syntax for zoom.", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <true/false>:<min>/<max>", LogLocation.ConsoleAndIngame);
							continue;
						}
						if (!bool.TryParse(array[0], out var result))
						{
							Console.Error("Incorrect syntax for zoom.", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <true/false>:<min>/<max>", LogLocation.ConsoleAndIngame);
							continue;
						}
						string[] array2 = array.Last().Split('/');
						float result2;
						float result3;
						if (array.Length != 2)
						{
							Console.Error("Incorrect syntax for value " + array[1] + " of " + array[0] + ".", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <min>/<max>", LogLocation.ConsoleAndIngame);
							if (text2.Contains(" / "))
							{
								Console.Warning("Do not use spaces on either sides of '/' symbol.", LogLocation.ConsoleAndIngame);
							}
						}
						else if (!float.TryParse(array2[0], NumberStyles.Any, CultureInfo.InvariantCulture, out result2) || !float.TryParse(array2[1], NumberStyles.Any, CultureInfo.InvariantCulture, out result3))
						{
							Console.Error("Cannot parse min/max value " + array[1] + " of " + array[0] + ".", LogLocation.ConsoleAndIngame);
							Console.Warning("Value should be written like: 0.12, no comma.", LogLocation.ConsoleAndIngame);
						}
						else
						{
							ShowPlayerAlways = result;
							Zoom.x = result2;
							Zoom.y = result3;
						}
						continue;
					}
				}
				if (list.First() == "character" && (configType == ConfigType.Any || configType == ConfigType.Slider))
				{
					if (list.Count < 3)
					{
						Console.Error("Invalid syntax for a character edit.", LogLocation.ConsoleAndIngame);
						Console.Warning("Should be: character <race> <property>:<min>/<max>", LogLocation.ConsoleAndIngame);
						continue;
					}
					list.RemoveAt(0);
					race = list.First().ToLower();
					if (races.All((string r) => r != race))
					{
						Console.Error(race + " isn't a valid race. Skipping.", LogLocation.ConsoleAndIngame);
						continue;
					}
					list.RemoveAt(0);
					RaceDisplayValues.Add(race, new List<(string, (float, float))>());
					stringBuilder.Append("\n-> (" + race + ") Saving Properties:");
					foreach (string item in list)
					{
						string[] propertySplit2 = item.Split(':');
						if (propertySplit2.Length != 2)
						{
							Console.Error("Incorrect syntax for " + item + ".", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <property>:<min>/<max>", LogLocation.ConsoleAndIngame);
							break;
						}
						if (raceProperties.All((string p) => p != propertySplit2[0]))
						{
							Console.Error("No matching race slider properties found for " + propertySplit2[0] + ".", LogLocation.ConsoleAndIngame);
							break;
						}
						string[] array3 = propertySplit2.Last().Split('/');
						if (propertySplit2.Length != 2)
						{
							Console.Error("Incorrect syntax for value " + propertySplit2[1] + " of " + propertySplit2[0] + ".", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <min>/<max>");
							if (text2.Contains(" / "))
							{
								Console.Warning("Do not use spaces on either sides of '/' symbol.");
							}
							break;
						}
						if (!float.TryParse(array3[0], NumberStyles.Any, CultureInfo.InvariantCulture, out var result4) || !float.TryParse(array3[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var result5))
						{
							Console.Error("Cannot parse min/max value " + propertySplit2[1] + " of " + propertySplit2[0] + ".");
							Console.Warning("Value should be written like: 0.12, no comma.", LogLocation.ConsoleAndIngame);
							break;
						}
						RaceDisplayValues[race].Add((propertySplit2[0], (result4, result5)));
						stringBuilder.Append($"{propertySplit2[0]}:{result4}/{result5} ✔ | ");
						num2++;
					}
				}
				else
				{
					if (!(list.First() == "bone") || (configType != 0 && configType != ConfigType.DynamicBone))
					{
						continue;
					}
					if (list.Count < 3)
					{
						Console.Error("Invalid syntax for a bone edit.", LogLocation.ConsoleAndIngame);
						Console.Warning("Should be <bone>:<bodypart> <property>:<value>", LogLocation.ConsoleAndIngame);
						break;
					}
					list.RemoveAt(0);
					string text3 = list.First();
					list.RemoveAt(0);
					DynamicBoneValues.Add(text3, new List<(string, float)>());
					stringBuilder.Append("\n-> (" + text3 + ") Saving Properties:");
					foreach (string item2 in list)
					{
						string[] propertySplit = item2.Split(':');
						if (propertySplit.Length != 2)
						{
							Console.Error("Invalid syntax for " + propertySplit[0] + ".", LogLocation.ConsoleAndIngame);
							Console.Warning("Should be <property>:<value>.", LogLocation.ConsoleAndIngame);
							if (text2.Contains(" : "))
							{
								Console.Warning("Do not use spaces on either sides of ':' symbol.", LogLocation.ConsoleAndIngame);
							}
							break;
						}
						propertySplit[0] = propertySplit[0].ToLower();
						propertySplit[1] = propertySplit[1].ToLower();
						if (dbProperties.All((string p) => p != propertySplit[0]))
						{
							Console.Warning("No matching dynamic bone properties found for " + propertySplit[0] + ".", LogLocation.ConsoleAndIngame);
							break;
						}
						if (!float.TryParse(propertySplit[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var result6))
						{
							Console.Error("Cannot parse value " + propertySplit[1] + " of " + propertySplit[0] + ". Value should be written like: 0.12, no comma.", LogLocation.ConsoleAndIngame);
							break;
						}
						if (result6 < 0f || result6 > 1f)
						{
							Console.Error("Invalid value " + propertySplit[1] + " of " + propertySplit[0] + ". Value should be between 0 and 1.", LogLocation.ConsoleAndIngame);
							break;
						}
						DynamicBoneValues[text3].Add((propertySplit[0], result6));
						stringBuilder.Append(propertySplit[0] + ":" + propertySplit[1] + " ✔ | ");
						num++;
					}
				}
			}
			if (!ConfigEmpty)
			{
				if (configType == ConfigType.Any || configType == ConfigType.Slider)
				{
					Console.Info($"Saved {num2} slider values for {RaceDisplayValues.Keys.Count} races", LogLocation.ConsoleAndIngame);
				}
				if (configType == ConfigType.Any || configType == ConfigType.DynamicBone)
				{
					Console.Info($"Saved {num} dbone values for {DynamicBoneValues.Keys.Count} parts", LogLocation.ConsoleAndIngame);
				}
			}
			else
			{
				Console.Info("Config is empty, disabling console.", LogLocation.ConsoleAndIngame);
				if (IngameConsole)
				{
					IngameConsole = false;
				}
			}
		}
	}
	public enum ConfigType
	{
		Any,
		DynamicBone,
		Slider
	}
	public static class Commands
	{
		[HarmonyPatch(typeof(ChatBehaviour), "OnStartAuthority")]
		public static class AwakePatch
		{
			[HarmonyPostfix]
			public static void OnStartAuthority_Postfix(ChatBehaviour __instance)
			{
				if ((Object)(object)__instance._player != (Object)(object)Player._mainPlayer)
				{
					return;
				}
				chat = __instance;
				baseEmotes = new Dictionary<string, EmoteCommand>();
				commands = new Dictionary<string, CommandInfo>();
				customEmotes = new Dictionary<string, EmoteInfo>();
				if ((Object)(object)__instance._scriptableEmoteList == (Object)null || __instance._scriptableEmoteList._emoteCommandList == null)
				{
					Console.Error("Couldn't read Atlyss' emote list.");
					return;
				}
				__instance._scriptableEmoteList._emoteCommandList.ToList().ForEach(delegate(EmoteCommand e)
				{
					baseEmotes.Add(e._emoteChatCommand, e);
				});
				AppearancePlus.OnChatInitialized.Invoke();
			}
		}

		[HarmonyPatch(typeof(ChatBehaviour), "Send_ChatMessage")]
		public static class AddCommandsPatch
		{
			[HarmonyPrefix]
			public static bool Send_ChatMessage_Prefix(ChatBehaviour __instance, string _message)
			{
				_message = _message.ToLower();
				bool num = _message.StartsWith("/");
				string pattern = "(?i)\\b(true|false)\\b|[-+]?\\b\\d+(\\.\\d+)?\\b|[^\\w\\s]";
				string input = Regex.Replace(_message, pattern, " ");
				input = Regex.Replace(input, "\\s+", " ").Trim();
				if (num && commands.TryGetValue(input, out var value))
				{
					string[] array = _message.Replace("/" + value.Name, "").Split(" ", StringSplitOptions.RemoveEmptyEntries);
					int num2 = ((value.Action == null) ? ((value.Action1 != null) ? 1 : ((value.Action2 != null) ? 2 : (-1))) : 0);
					if (num2 == -1)
					{
						Console.Error("Command " + value.Name + " has not been configured correctly.", LogLocation.ConsoleAndIngame);
						return false;
					}
					if (num2 != array.Length)
					{
						Console.Error($"Command {value.Name} was called with {array.Length} parameter(s) instead of {num2}.", LogLocation.ConsoleAndIngame);
						return false;
					}
					bool flag = false;
					switch (num2)
					{
					case 0:
						flag = value.Action();
						break;
					case 1:
						flag = value.Action1(array[0]);
						break;
					case 2:
						flag = value.Action2(array[0], array[1]);
						break;
					}
					if (flag && !string.IsNullOrEmpty(value.Response))
					{
						SendMessage(value.Response);
					}
					chat._lastMessage = _message;
					__instance._chatInput.text = "";
					return false;
				}
				return true;
			}
		}

		private static ChatBehaviour chat;

		private static Dictionary<string, CommandInfo> commands = new Dictionary<string, CommandInfo>();

		private static Dictionary<string, EmoteCommand> baseEmotes = new Dictionary<string, EmoteCommand>();

		private static Dictionary<string, EmoteInfo> customEmotes = new Dictionary<string, EmoteInfo>();

		public static bool Add(CommandInfo command)
		{
			command.Name = command.Name.ToLower().TrimStart('/').Trim();
			if (CommandExists(command.Name))
			{
				Console.Error("Cannot add /" + command.Name + " as it already exists or an error has occured..");
				return false;
			}
			commands.Add(command.Name, command);
			return true;
		}

		public static bool AddEmote(EmoteInfo emote)
		{
			try
			{
				if (emote.ChatCommand == null)
				{
					Console.Error("Emote has been added without a chat command.");
				}
				emote.ChatCommand = emote.ChatCommand.ToLower().TrimStart('/').Trim();
				if (CommandExists(emote.ChatCommand))
				{
					Console.Error("Cannot add /" + emote.ChatCommand + " as it already exists or an error has occured.");
					return false;
				}
				commands.Add(emote.ChatCommand, new CommandInfo(emote.ChatCommand, "Emote command to play " + emote.Name, emote.Message, () => PlayEmote(emote.ChatCommand)));
				customEmotes.Add(emote.ChatCommand, emote);
				return true;
			}
			catch (Exception ex)
			{
				Console.Error("Cannot add emote: " + ex.Message + ". Check that you have initialized all fields.");
				return false;
			}
		}

		public static bool PlayEmote(string emoteCommand)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)AppearancePlus.PlayerVisual == (Object)null)
			{
				Console.Error("Main Player Visual has not been found.");
				return false;
			}
			if ((Object)(object)AppearancePlus.PlayerModel == (Object)null)
			{
				Console.Error("Main Player Race Model has not been found.");
				return false;
			}
			if (!customEmotes.ContainsKey(emoteCommand))
			{
				Console.Error("Could not find custom emote " + emoteCommand + ".");
				return false;
			}
			PlayerRaceModel playerModel = AppearancePlus.PlayerModel;
			EmoteInfo emoteInfo = customEmotes[emoteCommand];
			if (PlayableGraphManager.PlayAnimationClip(playerModel, emoteInfo.AnimationTag, emoteInfo.Loop))
			{
				playerModel.Set_MouthCondition(emoteInfo.MouthAnim, -1f);
				playerModel.Set_EyeCondition(emoteInfo.EyeAnim, -1f);
				return true;
			}
			return false;
		}

		public static bool CommandExists(string commandName)
		{
			if (commands == null)
			{
				Console.Error("Commands not initialized.");
				return true;
			}
			if (baseEmotes == null)
			{
				Console.Error("Base emotes not initialized");
				return true;
			}
			if (!commands.ContainsKey(commandName))
			{
				return baseEmotes.ContainsKey("/" + commandName);
			}
			return true;
		}

		public static void SendMessage(string message)
		{
			chat.New_ChatMessage("<color=#ea8e09>[A+] " + message + "</color>");
		}

		public static void PrintCommands()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Commands:");
			foreach (KeyValuePair<string, CommandInfo> command in commands)
			{
				stringBuilder.AppendLine("\n" + command.Key + ": " + command.Value.Description);
			}
			SendMessage(stringBuilder.ToString());
		}

		public static bool CmdParseFloat(string input, out float value)
		{
			if (!float.TryParse(input, out value))
			{
				Console.Warning("Couldn't parse " + input + ". Use float value like 3 or 3.6", LogLocation.ConsoleAndIngame);
				return false;
			}
			return true;
		}

		public static bool CmdParseBool(string input, out bool value)
		{
			if (!bool.TryParse(input, out value))
			{
				Console.Warning("Couldn't parse " + input + ". Use bool value like true or false.", LogLocation.ConsoleAndIngame);
				return false;
			}
			return true;
		}
	}
	public struct CommandInfo
	{
		public string Name;

		public string Description;

		public Func<bool> Action;

		public Func<string, bool> Action1;

		public Func<string, string, bool> Action2;

		public string Response;

		public CommandInfo(string chatCommand, string description, string response)
		{
			Action = null;
			Action1 = null;
			Action2 = null;
			Name = chatCommand;
			Description = description;
			Response = response;
		}

		public CommandInfo(string chatCommand, string description, string response, Func<bool> action)
			: this(chatCommand, description, response)
		{
			Action = action;
		}

		public CommandInfo(string chatCommand, string description, string response, Func<string, bool> action)
			: this(chatCommand, description, response)
		{
			Action1 = action;
			Response = response;
		}

		public CommandInfo(string chatCommand, string description, string response, Func<string, string, bool> action)
			: this(chatCommand, description, response)
		{
			Action2 = action;
			Response = response;
		}
	}
	public struct EmoteInfo
	{
		public string Name;

		public string ChatCommand;

		public string AnimationTag;

		public string Message;

		public bool Loop;

		public EyeCondition EyeAnim;

		public MouthCondition MouthAnim;

		public EmoteInfo(string name, string chatCommand, string animationTag, string message, bool loop)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			EyeAnim = (EyeCondition)0;
			MouthAnim = (MouthCondition)0;
			Name = name;
			ChatCommand = chatCommand;
			AnimationTag = animationTag;
			Message = message;
			Loop = loop;
		}
	}
	public static class Console
	{
		public struct LogInfo
		{
			public LogLevel Type;

			public string Text;

			public float Timestamp;

			public LogInfo(LogLevel level, string message)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				Timestamp = Time.realtimeSinceStartup;
				Type = level;
				Text = message;
			}
		}

		[HarmonyPatch(typeof(SettingsManager), "OnGUI")]
		public static class SettingsManagerPatch
		{
			[HarmonyPostfix]
			private static void OnGUIPatch(SettingsManager __instance)
			{
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_019a: 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_0156: Unknown result type (might be due to invalid IL or missing references)
				//IL_015d: 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)
				if (_logs.Count == 0)
				{
					return;
				}
				GUIStyle label = GUI.skin.label;
				label.richText = true;
				label.fontSize = 30;
				float num = 800f;
				float num2 = 45f;
				int count = _logs.Count;
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor((float)Screen.width * 0.01f, (float)Screen.height * 0.5f);
				Color color = GUI.color;
				GUI.Box(new Rect(val.x - 20f, val.y - (float)(count - 1) * num2 - 20f, num + 40f, num2 * (float)_logs.Count + 40f), "");
				for (int num3 = _logs.Count - 1; num3 >= 0; num3--)
				{
					Color color2 = _logColors[_logs[num3].Type];
					float num4 = Time.realtimeSinceStartup - _logs[num3].Timestamp;
					float num5 = _timeout[_logs[num3].Type];
					if (num4 <= 0.33f)
					{
						color2.a = num4 * 3f;
					}
					else
					{
						color2.a = Mathf.Clamp(num5 - num4, 0f, 0.33f) * 3f;
					}
					GUI.color = color2;
					GUI.Label(new Rect(val.x, val.y - (float)(count - num3 - 1) * num2, num, num2), _logs[num3].Text, label);
				}
				GUI.color = color;
			}
		}

		private static List<LogInfo> _logs = new List<LogInfo>();

		private const int MaxLogs = 10;

		private static ManualLogSource _logger;

		private static Dictionary<LogLevel, Color> _logColors = new Dictionary<LogLevel, Color>
		{
			[(LogLevel)32] = new Color(0.929f, 0.929f, 0.929f),
			[(LogLevel)16] = new Color(1f, 0.606f, 0.094f),
			[(LogLevel)4] = new Color(0.961f, 0.859f, 0.208f),
			[(LogLevel)2] = new Color(0.969f, 0.298f, 0.035f)
		};

		private static Dictionary<LogLevel, float> _timeout = new Dictionary<LogLevel, float>
		{
			{
				(LogLevel)32,
				10f
			},
			{
				(LogLevel)16,
				15f
			},
			{
				(LogLevel)4,
				15f
			},
			{
				(LogLevel)2,
				20f
			}
		};

		private static float _lastLogTimestamp;

		private static bool IngameConsole => Configuration.IngameConsole;

		public static void Initialize(ManualLogSource logger)
		{
			_logger = logger;
		}

		public static void Update()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			while (num < _logs.Count)
			{
				LogInfo logInfo = _logs[num];
				if (Time.realtimeSinceStartup - logInfo.Timestamp > _timeout[logInfo.Type])
				{
					_logs.RemoveAt(num);
				}
				else
				{
					num++;
				}
			}
		}

		public static bool ToggleConsole(string text)
		{
			if (!bool.TryParse(text, out var result))
			{
				Error("Couldn't parse parameter. Use true or false.");
				return false;
			}
			Configuration.IngameConsole = result;
			Commands.SendMessage((result ? "Enabled" : "Disabled") + " ingame console.");
			return true;
		}

		public static void Log(LogLevel level, string message, LogLocation location = LogLocation.Console)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (location == LogLocation.Console || location == LogLocation.ConsoleAndIngame)
			{
				_logger.Log(level, (object)(message ?? ""));
			}
			if ((location == LogLocation.Ingame || location == LogLocation.ConsoleAndIngame) && Configuration.IngameConsole)
			{
				LogInfo item = new LogInfo(level, message);
				_logs.Add(item);
				_lastLogTimestamp = item.Timestamp;
				if (_logs.Count > 10)
				{
					_logs.RemoveAt(0);
				}
			}
		}

		public static void Debug(string message, LogLocation location = LogLocation.Console)
		{
			Log((LogLevel)32, message, location);
		}

		public static void Info(string message, LogLocation location = LogLocation.Console)
		{
			Log((LogLevel)16, message, location);
		}

		public static void Warning(string message, LogLocation location = LogLocation.Console)
		{
			Log((LogLevel)4, message, location);
		}

		public static void Error(string message, LogLocation location = LogLocation.Console)
		{
			Log((LogLevel)2, message, location);
		}
	}
	public enum LogLocation
	{
		Console,
		Ingame,
		ConsoleAndIngame
	}
	public static class DBonesLoader
	{
		public static int SetValues(PlayerRaceModel __instance)
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			List<DynamicBone> list = ((Component)__instance).GetComponentsInChildren<DynamicBone>().ToList();
			foreach (DynamicBone item in list)
			{
				StringBuilder stringBuilder = new StringBuilder(((Object)item).name);
				stringBuilder.Replace("Base", "");
				stringBuilder.Replace("base", "");
				stringBuilder.Replace(" ", "");
				stringBuilder.Replace(".l", "");
				stringBuilder.Replace(".r", "");
				string text = stringBuilder.ToString().ToLower();
				if (!Configuration.DynamicBoneValues.ContainsKey(text))
				{
					continue;
				}
				foreach (var item2 in Configuration.DynamicBoneValues[text])
				{
					switch (item2.Item1)
					{
					case "damping":
						item.m_Damping = item2.Item2;
						break;
					case "elasticity":
						item.m_Elasticity = item2.Item2;
						break;
					case "stiffness":
						item.m_Stiffness = item2.Item2;
						break;
					case "inert":
						item.m_Inert = item2.Item2;
						break;
					default:
						Console.Error("Could not apply property " + item2.Item1 + " to " + text + ".", LogLocation.ConsoleAndIngame);
						num3++;
						continue;
					}
					num2++;
				}
				num++;
			}
			list.ForEach(delegate(DynamicBone d)
			{
				d.UpdateParameters();
			});
			if (num3 > 0)
			{
				Console.Info($"Loaded {num2} properties in {num} parts.", LogLocation.ConsoleAndIngame);
				Console.Info($"Failed to load {num3} properties.", LogLocation.ConsoleAndIngame);
				Console.Warning("Check BepInEx console for more details.", LogLocation.Ingame);
			}
			return num;
		}

		public static void SetAll()
		{
			int num = 0;
			int num2 = 0;
			while (num2 < AppearancePlus.PlayerModels.Count)
			{
				PlayerRaceModel val = AppearancePlus.PlayerModels[num2];
				if ((Object)(object)val != (Object)null)
				{
					num += SetValues(val);
					num2++;
				}
				else
				{
					AppearancePlus.PlayerModels.RemoveAt(num2);
				}
			}
			Console.Info($"Loaded properties in {num} parts.", LogLocation.ConsoleAndIngame);
		}

		public static bool PrintCurrentValues()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Printing current dynamic bone values:");
			foreach (KeyValuePair<string, List<(string, float)>> dynamicBoneValue in Configuration.DynamicBoneValues)
			{
				try
				{
					stringBuilder.AppendLine("\n" + dynamicBoneValue.Key + ":");
					foreach (var item in dynamicBoneValue.Value)
					{
						stringBuilder.AppendLine($" {item.Item1}:{item.Item2}");
					}
				}
				catch (Exception ex)
				{
					Console.Error(ex.ToString(), LogLocation.ConsoleAndIngame);
					return false;
				}
			}
			Commands.SendMessage(stringBuilder.ToString());
			return true;
		}
	}
	public static class SliderLoader
	{
		[HarmonyPatch(typeof(ScriptablePlayerRace), "Init_ParamsCheck")]
		public static class ScriptablePlayerRaceInitPatch
		{
			[HarmonyPrefix]
			public static bool Init_ParamsCheck_Prefix(ScriptablePlayerRace __instance, ref PlayerAppearance_Profile __result, PlayerAppearance_Profile _aP)
			{
				__result = _aP;
				return false;
			}
		}

		public static void SetValues()
		{
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			ScriptablePlayerRace[] scriptablePlayerRaces = AppearancePlus.ScriptablePlayerRaces;
			Dictionary<string, List<(string, (float, float))>> raceDisplayValues = Configuration.RaceDisplayValues;
			ScriptablePlayerRace[] array = scriptablePlayerRaces;
			foreach (ScriptablePlayerRace val in array)
			{
				string text = val._raceName.ToLower();
				if (raceDisplayValues.ContainsKey(text))
				{
					num++;
					num2 += ModifyCharacterParams(ref val._raceDisplayParams, text);
				}
			}
			if (num3 > 0)
			{
				Console.Info($"Loaded {num2} properties in {num} races.", LogLocation.ConsoleAndIngame);
				Console.Error($"Failed to load {num3} properties.", LogLocation.ConsoleAndIngame);
				Console.Warning("Check BepInEx console for more details.", LogLocation.Ingame);
			}
			else
			{
				Console.Info($"Loaded all {num2} properties in {num} races.", LogLocation.ConsoleAndIngame);
			}
		}

		public static int ModifyCharacterParams(ref CharacterParamsGroup currentProperties, string raceName)
		{
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: 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_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (var item in Configuration.RaceDisplayValues[raceName])
			{
				switch (item.Item1)
				{
				case "height":
					currentProperties._heightRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "width":
					currentProperties._widthRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "chest":
					currentProperties._boobRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "arms":
					currentProperties._armRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "belly":
					currentProperties._bellyRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "bottom":
					currentProperties._bottomRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "torso":
					currentProperties._torsoRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "head":
					currentProperties._headWidthRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "muzzle":
					currentProperties._headModRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				case "voice":
					currentProperties._pitchRange = new Vector2(item.Item2.Item1, item.Item2.Item2);
					break;
				default:
					continue;
				}
				num++;
			}
			return num;
		}

		public static bool PrintCurrentValues()
		{
			StringBuilder stringBuilder = new StringBuilder();
			PlayerRaceModel playerModel = AppearancePlus.PlayerModel;
			if ((Object)(object)playerModel == (Object)null)
			{
				Commands.SendMessage("Couldn't find player!");
				return false;
			}
			stringBuilder.AppendLine("Printing current slider values:");
			stringBuilder.AppendLine($"\nVoice: {playerModel._muzzleWeight}");
			stringBuilder.AppendLine($"\nHead: {playerModel._headWidth}");
			stringBuilder.AppendLine($"\nMuzzle: {playerModel._muzzleWeight}");
			stringBuilder.AppendLine($"\nArms: {playerModel._armWeight}");
			stringBuilder.AppendLine($"\nChest: {playerModel._boobWeight}");
			stringBuilder.AppendLine($"\nTorso: {playerModel._torsoWeight}");
			stringBuilder.AppendLine($"\nBelly: {playerModel._bellyWeight}");
			stringBuilder.AppendLine($"\nBottom: {playerModel._bottomWeight}");
			stringBuilder.AppendLine($"\nHeight: {playerModel._heightWeight}");
			stringBuilder.AppendLine($"\nWidth: {playerModel._widthWeight}");
			Commands.SendMessage(stringBuilder.ToString());
			return true;
		}

		public static bool SizeCommand(string parameter)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			if (!float.TryParse(parameter, out var result))
			{
				Console.Warning("Couldn't parse parameter. Use float value like 3 or 3.6", LogLocation.ConsoleAndIngame);
				return false;
			}
			PlayerVisual playerVisual = AppearancePlus.PlayerVisual;
			if ((Object)(object)playerVisual == (Object)null)
			{
				Console.Warning("Couldn't find player's visual.", LogLocation.ConsoleAndIngame);
				return false;
			}
			PlayerRaceModel playerModel = AppearancePlus.PlayerModel;
			if ((Object)(object)playerModel == (Object)null)
			{
				Console.Warning("Couldn't find player's race model.", LogLocation.ConsoleAndIngame);
				return false;
			}
			float num = result / playerModel._heightWeight;
			float widthWeight = playerModel._widthWeight * num;
			CharacterParamsGroup raceDisplayParams = playerModel._scriptablePlayerRace._raceDisplayParams;
			PlayerAppearanceStruct playerAppearanceStruct = playerVisual._playerAppearanceStruct;
			playerAppearanceStruct._heightWeight = result;
			if (playerAppearanceStruct._heightWeight > raceDisplayParams._heightRange.y)
			{
				raceDisplayParams._heightRange.y = playerAppearanceStruct._heightWeight;
			}
			else if (playerAppearanceStruct._heightWeight < raceDisplayParams._heightRange.x)
			{
				raceDisplayParams._heightRange.x = playerAppearanceStruct._heightWeight;
			}
			playerAppearanceStruct._widthWeight = widthWeight;
			if (playerAppearanceStruct._widthWeight > raceDisplayParams._widthRange.y)
			{
				raceDisplayParams._widthRange.y = playerAppearanceStruct._widthWeight;
			}
			else if (playerAppearanceStruct._widthWeight < raceDisplayParams._widthRange.x)
			{
				raceDisplayParams._widthRange.x = playerAppearanceStruct._widthWeight;
			}
			playerModel._heightWeight = result;
			playerModel._widthWeight = widthWeight;
			playerVisual._playerAppearanceStruct = playerAppearanceStruct;
			playerVisual.Cmd_SendNew_PlayerAppearanceStruct(playerAppearanceStruct);
			playerVisual.Apply_NetworkedCharacterDisplay();
			Commands.SendMessage($"Updated height to {playerModel._heightWeight} and width to {playerModel._widthWeight} for main player.");
			return true;
		}
	}
	public static class TextureLoader
	{
		internal static Dictionary<string, Texture2D> NonReplacedTextures = new Dictionary<string, Texture2D>();

		private static Dictionary<string, Texture> OriginalTextures = new Dictionary<string, Texture>();

		private static Dictionary<string, Dictionary<string, Texture2D>> TextureCache = new Dictionary<string, Dictionary<string, Texture2D>>();

		private static Dictionary<string, Texture2D> CustomTextureCache = new Dictionary<string, Texture2D>();

		public static void LoadTextures(string texturefolder)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			int num = 0;
			int num2 = 0;
			bool flag = texturefolder.Contains("CustomTextures");
			if (!flag && !TextureCache.ContainsKey(texturefolder))
			{
				TextureCache.Add(texturefolder, new Dictionary<string, Texture2D>());
			}
			try
			{
				string[] files = Directory.GetFiles(texturefolder, "*.png", SearchOption.AllDirectories);
				foreach (string text in files)
				{
					try
					{
						if (text.Contains("IgnoredFiles"))
						{
							continue;
						}
						byte[] array = File.ReadAllBytes(text);
						Texture2D val = new Texture2D(4, 4, (TextureFormat)4, false);
						((Texture)val).anisoLevel = 16;
						if (ImageConversion.LoadImage(val, array))
						{
							((Object)val).name = Path.GetFileNameWithoutExtension(text);
							if (flag)
							{
								SetSingleTextureFilteringMode(val);
								CustomTextureCache[((Object)val).name] = val;
								num2++;
								continue;
							}
							if (TextureCache[texturefolder].ContainsKey(((Object)val).name))
							{
								Console.Warning(((Object)val).name + " is already in use. Swapping.");
							}
							TextureCache[texturefolder][((Object)val).name] = val;
						}
						else
						{
							Console.Error("Failed to load texture: " + text);
						}
					}
					catch (Exception ex)
					{
						Console.Error("Error loading texture file '" + text + "': " + ex.Message);
					}
				}
			}
			catch (Exception ex2)
			{
				Console.Error("Error loading textures: " + ex2.Message);
			}
			if (flag && num2 > 0)
			{
				Console.Info($"Loaded {num2} custom textures successfully!", LogLocation.ConsoleAndIngame);
			}
			else if (num > 0)
			{
				Console.Info($"Loaded {num2} textures successfully!", LogLocation.ConsoleAndIngame);
			}
		}

		private static void SetCustomTexturesFilteringMod()
		{
			if (CustomTextureCache.Count == 0)
			{
				return;
			}
			foreach (Texture2D value in CustomTextureCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					SetSingleTextureFilteringMode(value);
				}
				else
				{
					Console.Warning("Null texture found in PreloadedTextures.");
				}
			}
		}

		private static void SetSingleTextureFilteringMode(Texture2D texture)
		{
			if (!((Texture)texture).isReadable)
			{
				Console.Warning("Texture '" + ((Object)texture).name + "' is not readable. Skipping.");
				return;
			}
			if ((Object)(object)SettingsManager._current == (Object)null || SettingsManager._current._settingsProfile == null)
			{
				Console.Error("SettingsManager or its profile is null. Cannot set texture filtering mode.");
				return;
			}
			switch (SettingsManager._current._settingsProfile._textureFilterSetting)
			{
			case 0:
				((Texture)texture).anisoLevel = 16;
				((Texture)texture).filterMode = (FilterMode)1;
				break;
			case 1:
				((Texture)texture).filterMode = (FilterMode)0;
				break;
			default:
				Console.Warning("Unsupported texture filter setting. Defaulting to Point.");
				((Texture)texture).filterMode = (FilterMode)0;
				break;
			}
		}

		private static void SwapCustomTextures()
		{
			if (CustomTextureCache.Count == 0)
			{
				return;
			}
			NonReplacedTextures = new Dictionary<string, Texture2D>(CustomTextureCache);
			int num = 0;
			ScriptablePlayerRace[] scriptablePlayerRaces = AppearancePlus.ScriptablePlayerRaces;
			foreach (ScriptablePlayerRace val in scriptablePlayerRaces)
			{
				string raceName = val._raceName;
				SkinTextureGroup[] skinTextureGroups = val._skinTextureGroups;
				foreach (SkinTextureGroup val2 in skinTextureGroups)
				{
					if (ReplaceTexture(ref val2._headTexture, "Head", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val2._bodyTexture, "Body", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val2._legTexture, "Leg", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val2._tailTexture, "Tail", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val2._earTexture, "Ear", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val2._hairTexture, "Hair", raceName))
					{
						num++;
					}
				}
				MouthTextureGroup[] mouthTextures = val._mouthTextures;
				foreach (MouthTextureGroup val3 in mouthTextures)
				{
					if (ReplaceTexture(ref val3._open, "Open", "Mouth", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val3._closed, "Closed", "Mouth", raceName))
					{
						num++;
					}
				}
				EyeTextureGroup[] eyeTextures = val._eyeTextures;
				foreach (EyeTextureGroup val4 in eyeTextures)
				{
					if (ReplaceTexture(ref val4._center, "Center", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._pissed, "Pissed", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._hurt, "Hurt", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._left, "Left", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._right, "Right", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._up, "Up", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._down, "Down", "Eye", raceName))
					{
						num++;
					}
					if (ReplaceTexture(ref val4._closed, "Closed", "Eye", raceName))
					{
						num++;
					}
				}
			}
			AppearancePlus.NetNPCs.RemoveAll((NetNPC npc) => (Object)(object)npc == (Object)null);
			List<NetNPC> list = new List<NetNPC>(AppearancePlus.NetNPCs);
			for (int k = 0; k < list.Count; k++)
			{
				num += ReplaceNPCTextures(list[k]);
			}
			if (NonReplacedTextures.Count > 0)
			{
				if (num > 0)
				{
					Console.Info($"Replaced {num} textures successfully!", LogLocation.ConsoleAndIngame);
				}
				Console.Warning($"Didn't find a match (in active entities) for {NonReplacedTextures.Count} textures.", LogLocation.ConsoleAndIngame);
				Console.Warning("(This is normal for NPCs & Enemies)", LogLocation.ConsoleAndIngame);
				Console.Warning("Check BepInEx console for more details.", LogLocation.Ingame);
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine($"{NonReplacedTextures.Count} Non-Replaced Textures:");
				foreach (KeyValuePair<string, Texture2D> nonReplacedTexture in NonReplacedTextures)
				{
					stringBuilder.AppendLine("- " + nonReplacedTexture.Key);
				}
				Console.Info(stringBuilder.ToString());
			}
			else if (num > 0)
			{
				Console.Info($"Replaced all textures in {num} instances successfully!", LogLocation.ConsoleAndIngame);
			}
		}

		public static void DumpInfo()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Texture Info Dump:");
			foreach (KeyValuePair<string, Texture> originalTexture in OriginalTextures)
			{
				stringBuilder.AppendLine($"\n {originalTexture.Key}: {originalTexture.Value.filterMode}|{originalTexture.Value.graphicsFormat}|{originalTexture.Value.anisoLevel}");
			}
			Console.Info(stringBuilder.ToString());
		}

		public static bool ReplaceTexture(ref Texture texture, params string[] keywords)
		{
			if ((Object)(object)texture == (Object)null)
			{
				Console.Warning(((Object)texture).name + " is null");
				return false;
			}
			if (CustomTextureCache.TryGetValue(((Object)texture).name, out var value))
			{
				OriginalTextures.TryAdd(((Object)texture).name, texture);
				texture = (Texture)(object)value;
				NonReplacedTextures.Remove(((Object)texture).name);
				return true;
			}
			if (OriginalTextures.TryGetValue(((Object)texture).name, out var value2))
			{
				texture = value2;
				return false;
			}
			return false;
		}

		public static bool ReplaceRendererTexture(Renderer renderer, Texture2D customTexture = null)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return false;
			}
			if ((Object)(object)renderer.material == (Object)null)
			{
				return false;
			}
			if (!renderer.material.HasTexture("_MainTex") || (Object)(object)renderer.material.mainTexture == (Object)null)
			{
				return false;
			}
			Texture mainTexture = renderer.material.mainTexture;
			if ((Object)(object)customTexture == (Object)null && !CustomTextureCache.TryGetValue(((Object)mainTexture).name, out customTexture))
			{
				if (OriginalTextures.TryGetValue(((Object)mainTexture).name, out var value))
				{
					renderer.material.mainTexture = value;
				}
				return false;
			}
			OriginalTextures.TryAdd(((Object)mainTexture).name, mainTexture);
			renderer.material.mainTexture = (Texture)(object)customTexture;
			NonReplacedTextures.Remove(((Object)mainTexture).name);
			return true;
		}

		public static int ReplaceCreepTextures(CreepBehavior creep)
		{
			if (CustomTextureCache.Count == 0)
			{
				return 0;
			}
			int num = 0;
			try
			{
				if ((Object)(object)creep == (Object)null)
				{
					Console.Warning("Creep instance is null.");
				}
				else
				{
					Renderer[] componentsInChildren = ((Component)creep).GetComponentsInChildren<Renderer>();
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						if (ReplaceRendererTexture(componentsInChildren[i]))
						{
							num++;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Console.Error("Error in OnNpcStart: " + ex.Message);
			}
			return num;
		}

		public static int ReplaceNPCTextures(NetNPC npc)
		{
			if (CustomTextureCache.Count == 0)
			{
				return 0;
			}
			int num = 0;
			try
			{
				if ((Object)(object)npc == (Object)null)
				{
					Console.Warning("NetNPC instance is null.");
				}
				else
				{
					Renderer[] componentsInChildren = ((Component)npc).GetComponentsInChildren<Renderer>();
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						if (ReplaceRendererTexture(componentsInChildren[i]))
						{
							num++;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Console.Error("Error in OnNpcStart: " + ex.Message);
			}
			return num;
		}

		public static void ReplaceTextureAnim(TextureChangeAnimEvent textureAnim)
		{
			if (CustomTextureCache.Count == 0)
			{
				return;
			}
			int num = 0;
			try
			{
				if ((Object)(object)textureAnim == (Object)null)
				{
					Console.Warning("Texture Anim instance is null.");
					return;
				}
				TextureChangeAnimStruct[] array = (TextureChangeAnimStruct[])textureAnim._textureStructs.Clone();
				for (int i = 0; i < array.Length; i++)
				{
					Texture value2;
					if (CustomTextureCache.TryGetValue(((Object)array[i]._texture).name, out var value))
					{
						OriginalTextures.TryAdd(((Object)array[i]._texture).name, array[i]._texture);
						array[i]._texture = (Texture)(object)value;
						num++;
					}
					else if (OriginalTextures.TryGetValue(((Object)array[i]._texture).name, out value2))
					{
						array[i]._texture = value2;
					}
				}
				textureAnim._textureStructs = array;
			}
			catch (Exception ex)
			{
				Console.Error("Error in CreepBehaviour Start: " + ex.Message);
			}
		}

		public static void ApplyCustomTextures()
		{
			SetCustomTexturesFilteringMod();
			SwapCustomTextures();
		}

		public static void ReloadAllTextures()
		{
			CustomTextureCache.Clear();
			foreach (string key in TextureCache.Keys)
			{
				LoadTextures(key);
			}
			if (PathUtils.GetDirectory(AppearancePlus.DllPath, "CustomTextures", out var result))
			{
				LoadTextures(result);
				ApplyCustomTextures();
			}
		}
	}
}
namespace AppearancePlus.Utils
{
	internal class ComponentDump
	{
		public static void DumpComponentToFile(Component targetComponent)
		{
			if ((Object)(object)targetComponent == (Object)null)
			{
				Debug.LogWarning((object)"Target component is not set.");
				return;
			}
			string text = Path.Combine(Paths.PluginPath, "Logs");
			string path = SanitizeFileName(((Object)targetComponent).name + ".txt");
			string text2 = Path.Combine(text, path);
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			try
			{
				File.WriteAllText(text2, DumpComponent(targetComponent));
				Debug.Log((object)("Component data dumped to " + text2));
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Failed to dump component data: " + ex.Message));
			}
		}

		private static string SanitizeFileName(string fileName)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				fileName = fileName.Replace(oldChar, '_');
			}
			return fileName;
		}

		private static string DumpComponent(Component component)
		{
			Type type = ((object)component).GetType();
			string text = "Component Type: " + type.Name + "\n\n";
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				text += $"{fieldInfo.Name}: {fieldInfo.GetValue(component)}\n";
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.CanRead)
				{
					try
					{
						text += $"{propertyInfo.Name}: {propertyInfo.GetValue(component)}\n";
					}
					catch
					{
						text = text + propertyInfo.Name + ": [Error]\n";
					}
				}
			}
			return text;
		}
	}
	public class PathUtils
	{
		public static bool GetDirectory(string path, string searchPattern, out string result)
		{
			result = Path.Combine(path, searchPattern);
			if (Directory.Exists(result))
			{
				return true;
			}
			result = "";
			string[] directories = Directory.GetDirectories(path, searchPattern, SearchOption.AllDirectories);
			if (directories.Length == 0)
			{
				Console.Warning(searchPattern + " folder at " + path + " not found.", LogLocation.ConsoleAndIngame);
				return false;
			}
			if (directories.Length > 1)
			{
				string[] directories2 = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
				if (directories2.Length == 0)
				{
					result = directories.First();
				}
				else
				{
					result = directories2.First();
				}
				Console.Warning("Multiple " + searchPattern + " folder folders found. Using " + result + ".", LogLocation.ConsoleAndIngame);
			}
			if (Utility.IsNullOrWhiteSpace(result))
			{
				result = directories.First();
			}
			return true;
		}
	}
}
namespace AppearancePlus.AssetBundles
{
	internal class AssetBundleLoader
	{
		private static readonly ManualLogSource Logger;

		public static readonly List<AssetBundle> LoadedBundles;

		static AssetBundleLoader()
		{
			LoadedBundles = new List<AssetBundle>();
			Logger = Logger.CreateLogSource("AtlyssAnimationManager");
		}

		public static void LoadAssetBundles(string assetBundlesFolder, string extension)
		{
			try
			{
				string[] files = Directory.GetFiles(assetBundlesFolder, "*." + extension);
				Logger.LogInfo((object)$"Found {files.Length} AssetBundle(s) in {assetBundlesFolder}");
				string[] array = files;
				foreach (string text in array)
				{
					AssetBundle val = AssetBundle.LoadFromFile(text);
					if ((Object)(object)val != (Object)null)
					{
						LoadedBundles.Add(val);
						Console.Warning("Successfully loaded AssetBundle: " + Path.GetFileName(text));
					}
					else
					{
						Logger.LogError((object)("Failed to load AssetBundle: " + Path.GetFileName(text)));
					}
				}
				Console.Info($"Loaded {LoadedBundles.Count} AssetBundles");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error loading AssetBundles: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		public static void UnloadAllAssetBundles(bool unloadAllLoadedObjects = false)
		{
			foreach (AssetBundle loadedBundle in LoadedBundles)
			{
				Logger.LogInfo((object)$"Unloading AssetBundle: {((Object)loadedBundle).name}, UnloadAllObjects={unloadAllLoadedObjects}");
				loadedBundle.Unload(unloadAllLoadedObjects);
			}
			LoadedBundles.Clear();
		}
	}
}
namespace AppearancePlus.Animation
{
	internal class AnimationLoaderNpcPatch
	{
		[HarmonyPatch(typeof(NetNPC), "Start")]
		public static class NetNPCStartPatch
		{
			[HarmonyPostfix]
			public static void Postfix(NetNPC __instance)
			{
			}
		}
	}
	internal class AnimationLoaderPlayerPatch
	{
		[HarmonyPatch(typeof(PlayerRaceModel), "Awake")]
		public static class PlayerRaceModelAwakePatch
		{
			[HarmonyPostfix]
			public static void Awake_Postfix(PlayerRaceModel __instance)
			{
			}
		}
	}
	internal class AnimationLoader
	{
		private static readonly ManualLogSource Logger;

		public static readonly List<AnimationClip> LoadedAnimationClips;

		static AnimationLoader()
		{
			LoadedAnimationClips = new List<AnimationClip>();
			Logger = Logger.CreateLogSource("AtlyssAnimationManager");
		}

		public static void LoadAllAnimationClips()
		{
			if (AssetBundleLoader.LoadedBundles.Count == 0)
			{
				Logger.LogWarning((object)"No AssetBundles are currently loaded. Ensure bundles are loaded before calling this method.");
				return;
			}
			Logger.LogInfo((object)$"Attempting to load AnimationClips from {AssetBundleLoader.LoadedBundles.Count} AssetBundles.");
			foreach (AssetBundle loadedBundle in AssetBundleLoader.LoadedBundles)
			{
				GetAllAnimationsFromBundle(loadedBundle);
			}
			Logger.LogInfo((object)$"Total loaded AnimationClips: {LoadedAnimationClips.Count}");
		}

		public static List<AnimationClip> GetAllAnimationsFromBundle(AssetBundle bundle)
		{
			List<AnimationClip> list = new List<AnimationClip>();
			try
			{
				string[] allAssetNames = bundle.GetAllAssetNames();
				foreach (string text in allAssetNames)
				{
					Object val = bundle.LoadAsset(text);
					AnimationClip clip = (AnimationClip)(object)((val is AnimationClip) ? val : null);
					if (clip != null)
					{
						if (!LoadedAnimationClips.Exists((AnimationClip c) => ((Object)c).name == ((Object)clip).name))
						{
							LoadedAnimationClips.Add(clip);
							list.Add(clip);
							Logger.LogInfo((object)("Loaded AnimationClip: " + ((Object)clip).name + " from AssetBundle: " + ((Object)bundle).name));
						}
						else
						{
							Logger.LogDebug((object)("Duplicate AnimationClip skipped: " + ((Object)clip).name));
						}
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Error extracting AnimationClips from AssetBundle " + ((Object)bundle).name + ": " + ex.Message + "\n" + ex.StackTrace));
			}
			return list;
		}

		public static List<AnimationClip> GetLoadedAnimationClips()
		{
			return new List<AnimationClip>(LoadedAnimationClips);
		}
	}
	internal class PlayableGraphManager
	{
		public static Dictionary<Animator, PlayableGraph> CharacterPlayableGraphs = new Dictionary<Animator, PlayableGraph>();

		private static Dictionary<string, AnimationClipPlayable> PlayableClips = new Dictionary<string, AnimationClipPlayable>();

		public static void PreloadPlayables(PlayableGraph graph)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			Console.Info("Preloading AnimationClipPlayables...");
			foreach (AnimationClip loadedAnimationClip in AnimationLoader.GetLoadedAnimationClips())
			{
				if (!PlayableClips.ContainsKey(((Object)loadedAnimationClip).name))
				{
					AnimationClipPlayable value = AnimationClipPlayable.Create(graph, loadedAnimationClip);
					PlayableClips.Add(((Object)loadedAnimationClip).name, value);
					Console.Info("Preloaded clip: " + ((Object)loadedAnimationClip).name);
				}
			}
		}

		public static void InitCharacterAnimations(PlayerRaceModel character)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character._raceAnimator == (Object)null)
			{
				Console.Error("Character or Animator is null. Cannot add character.");
				return;
			}
			Console.Info("AddCharacter called for " + ((Object)character).name);
			PlayableGraph val = PlayableGraph.Create(((Object)character).name + "_PlayableGraph");
			try
			{
				AnimationPlayableOutput.Create(val, "AnimationOutput", character._raceAnimator);
				Console.Info("AnimationPlayableOutput created for " + ((Object)character).name + ".");
				if (AnimationLoader.GetLoadedAnimationClips().Count > 0)
				{
					Console.Info($"Loaded animation clips: {AnimationLoader.GetLoadedAnimationClips().Count}");
					Console.Info("Preloading playables for " + ((Object)character).name + "...");
					PreloadPlayables(val);
					CharacterPlayableGraphs.Add(character._raceAnimator, val);
					Console.Info("PlayableGraph for " + ((Object)character).name + " added.");
					((PlayableGraph)(ref val)).Play();
					Console.Info("PlayableGraph for " + ((Object)character).name + " started.");
				}
				else
				{
					Console.Warning("No animation clips loaded. PlayableGraph for " + ((Object)character).name + " not initialized with playables.");
				}
			}
			catch (Exception ex)
			{
				Console.Error("Error initializing PlayableGraph for " + ((Object)character).name + ": " + ex.Message);
			}
		}

		public static void InitCharacterAnimations(NetNPC character)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character._animator == (Object)null)
			{
				Console.Error("Character or Animator is null. Cannot add character.");
				return;
			}
			Console.Info("AddCharacter called for " + ((Object)character).name);
			PlayableGraph val = PlayableGraph.Create(((Object)character).name + "_PlayableGraph");
			try
			{
				AnimationPlayableOutput.Create(val, "AnimationOutput", character._animator);
				Console.Info("AnimationPlayableOutput created for " + ((Object)character).name + ".");
				if (AnimationLoader.GetLoadedAnimationClips().Count > 0)
				{
					Console.Info($"Loaded animation clips: {AnimationLoader.GetLoadedAnimationClips().Count}");
					Console.Info("Preloading playables for " + ((Object)character).name + "...");
					PreloadPlayables(val);
					CharacterPlayableGraphs.Add(character._animator, val);
					Console.Info("PlayableGraph for " + ((Object)character).name + " added.");
					Console.Info("PlayableGraph for " + ((Object)character).name + " started.");
				}
				else
				{
					Console.Warning("No animation clips loaded. PlayableGraph for " + ((Object)character).name + " not initialized with playables.");
				}
			}
			catch (Exception ex)
			{
				Console.Error("Error initializing PlayableGraph for " + ((Object)character).name + ": " + ex.Message);
			}
		}

		public static bool PlayAnimationClip(PlayerRaceModel character, string clipName, bool loop)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character._raceAnimator == (Object)null)
			{
				Console.Error("Character or Animator is null. Cannot play animation.");
				return false;
			}
			if (!CharacterPlayableGraphs.TryGetValue(character._raceAnimator, out var value))
			{
				Console.Error("PlayableGraph for " + ((Object)character).name + " not found.");
				return false;
			}
			if (!PlayableClips.TryGetValue(clipName, out var value2))
			{
				Console.Error("AnimationClipPlayable with name '" + clipName + "' not found.");
				Console.Info("Available clips: " + string.Join(", ", PlayableClips.Keys));
				return false;
			}
			try
			{
				((PlayableGraph)(ref value)).Play();
				PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationClipPlayable>((AnimationPlayableOutput)((PlayableGraph)(ref value)).GetOutput(0), value2);
				PlayableExtensions.SetTime<AnimationClipPlayable>(value2, 0.0);
				((MonoBehaviour)character).StartCoroutine(MonitorAnimationPlayback(value, value2, loop));
				Console.Info("Playing clip '" + clipName + "' on " + ((Object)character).name + ".");
				return true;
			}
			catch (Exception ex)
			{
				Console.Error("Error playing clip '" + clipName + "' on " + ((Object)character).name + ": " + ex.Message);
			}
			return false;
		}

		public static bool PlayAnimationClip(NetNPC character, string clipName, bool loop)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character._animator == (Object)null)
			{
				Console.Error("Character or Animator is null. Cannot play animation.");
				return false;
			}
			if (!CharacterPlayableGraphs.TryGetValue(character._animator, out var value))
			{
				Console.Error("PlayableGraph for " + ((Object)character).name + " not found.");
				return false;
			}
			if (!PlayableClips.TryGetValue(clipName, out var value2))
			{
				Console.Error("AnimationClipPlayable with name '" + clipName + "' not found.");
				Console.Info("Available clips: " + string.Join(", ", PlayableClips.Keys));
				return false;
			}
			try
			{
				((PlayableGraph)(ref value)).Play();
				PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationClipPlayable>((AnimationPlayableOutput)((PlayableGraph)(ref value)).GetOutput(0), value2);
				PlayableExtensions.SetTime<AnimationClipPlayable>(value2, 0.0);
				((MonoBehaviour)character).StartCoroutine(MonitorAnimationPlayback(value, value2, loop));
				Console.Info("Playing clip '" + clipName + "' on " + ((Object)character).name + ".");
				return true;
			}
			catch (Exception ex)
			{
				Console.Error("Error playing clip '" + clipName + "' on " + ((Object)character).name + ": " + ex.Message);
			}
			return false;
		}

		private static IEnumerator MonitorAnimationPlayback(PlayableGraph graph, AnimationClipPlayable clipPlayable, bool loop)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			while (PlayableExtensions.GetTime<AnimationClipPlayable>(clipPlayable) < (double)((AnimationClipPlayable)(ref clipPlayable)).GetAnimationClip().length)
			{
				yield return null;
			}
			if (!loop)
			{
				((PlayableGraph)(ref graph)).Stop();
				Console.Info("Animation finished and graph stopped.");
			}
			else
			{
				PlayableExtensions.SetTime<AnimationClipPlayable>(clipPlayable, 0.0);
			}
		}

		public static void StopAnimationClip(PlayerRaceModel character)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (CharacterPlayableGraphs.TryGetValue(character._raceAnimator, out var value))
			{
				_ = (AnimationPlayableOutput)((PlayableGraph)(ref value)).GetOutput(0);
				((PlayableGraph)(ref value)).Stop();
			}
		}

		public static void StopAnimationClip(NetNPC character)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (CharacterPlayableGraphs.TryGetValue(character._animator, out var value))
			{
				_ = (AnimationPlayableOutput)((PlayableGraph)(ref value)).GetOutput(0);
				((PlayableGraph)(ref value)).Stop();
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}