Decompiled source of HTCCL v1.0.3

plugins/HTCCL.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HTCCL.API;
using HTCCL.API.Events;
using HTCCL.API.Types;
using HTCCL.Animation;
using HTCCL.Content;
using HTCCL.Internal;
using HTCCL.Managers;
using HTCCL.Patches;
using HTCCL.Saves;
using HTCCL.Updates;
using HTCCL.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HTCCL")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+fd176ba0622dc5f734a2fb044889732842088834")]
[assembly: AssemblyProduct("HTCCL")]
[assembly: AssemblyTitle("HTCCL")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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 HTTCL.API
{
	public static class Promos
	{
		public static int RegisterPromo(PromoData data, Func<int, PromoLine> pageHandler = null)
		{
			CodePromoManager.PromosData.Add(data);
			CodePromoManager.PageHandlers.Add(pageHandler);
			return CodePromoManager.PromosData.Count - 1;
		}

		public static void RiskPromo(Character character, int id, int variable = 0, int risk = 0)
		{
			if (id >= 2000000)
			{
				id -= 2000000;
			}
			jiqjqsXRll.qQskwFRaxf(character).gLJKAdlRuo(id + 2000000, variable, risk);
		}
	}
}
namespace HTCCL
{
	public static class Locations
	{
		public static DirectoryInfo Root { get; } = new DirectoryInfo(Paths.PluginPath);


		public static DirectoryInfo Export { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Export"));


		public static DirectoryInfo DeletedCharacters { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Purgatory"));


		public static DirectoryInfo Cache { get; } = new DirectoryInfo(Path.Combine(Plugin.PersistentDataPath, ".cache"));


		public static DirectoryInfo Debug { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Debug"));


		public static DirectoryInfo Data { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Data"));


		public static DirectoryInfo Meta { get; } = new DirectoryInfo(Path.Combine(Plugin.PersistentDataPath, "Meta.meta"));


		public static FileInfo SaveFileVanilla { get; } = new FileInfo(Path.Combine(Application.persistentDataPath, "Save.bytes"));


		public static FileInfo SaveFile { get; } = new FileInfo(Path.Combine(Application.persistentDataPath, Plugin.SaveFileName.Value + ".bytes"));


		public static DirectoryInfo ContentMappings { get; } = new DirectoryInfo(Path.Combine(Plugin.PersistentDataPath, "ContentMappings.mappings"));


		public static DirectoryInfo CharacterMappings { get; } = new DirectoryInfo(Path.Combine(Plugin.PersistentDataPath, "CharacterMappings.mappings"));


		internal static void CreateDirectories()
		{
			if (Plugin.CacheEnabled.Value && !Cache.Exists)
			{
				Cache.Create();
			}
			else if (Plugin.CacheEnabled.Value && Cache.Attributes.HasFlag(FileAttributes.Hidden))
			{
				Cache.Attributes &= ~FileAttributes.Hidden;
			}
			else if (!Plugin.CacheEnabled.Value && Cache.Exists)
			{
				Cache.Delete(recursive: true);
			}
			Debug.Create();
		}

		internal static void MoveLegacyLocations()
		{
			LegacyLocations.MoveLegacyLocations();
		}

		public static void LoadData()
		{
			RuntimeAnimatorController? obj = AssetBundle.LoadFromFile(Path.Combine(Data.FullName, "animationcontroller")).LoadAllAssets<RuntimeAnimatorController>().FirstOrDefault();
			if ((Object)(object)obj == (Object)null)
			{
				throw new Exception("Failed to load data. Please make sure you copied the 'Data' folder alongside the plugin if installed manually.");
			}
			AO.AnimationController = obj;
		}
	}
	internal static class LegacyLocations
	{
		public static DirectoryInfo OldCache { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, ".cache"));


		public static DirectoryInfo OldMetadata { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Meta.meta"));


		public static DirectoryInfo OldMappings { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "ContentMappings.mappings"));


		public static DirectoryInfo OldMetadata2 { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "CustomConfigsSaveFile.json"));


		public static DirectoryInfo OldMappings2 { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "CustomContentSaveFile.json"));


		public static DirectoryInfo OldMetadata3 { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "Meta.json"));


		public static DirectoryInfo OldMappings3 { get; } = new DirectoryInfo(Path.Combine(Plugin.PluginPath, "ContentMappings.json"));


		public static void MoveLegacyLocations()
		{
			if (OldCache.Exists)
			{
				if (!Locations.Cache.Exists)
				{
					OldCache.MoveTo(Locations.Cache.FullName);
				}
				else
				{
					OldCache.Delete(recursive: true);
				}
			}
			if (OldMetadata.Exists)
			{
				if (!Locations.Meta.Exists)
				{
					OldMetadata.MoveTo(Locations.Meta.FullName);
				}
				else
				{
					OldMetadata.Delete(recursive: true);
				}
			}
			if (OldMappings.Exists)
			{
				if (!Locations.ContentMappings.Exists)
				{
					OldMappings.MoveTo(Locations.ContentMappings.FullName);
				}
				else
				{
					OldMappings.Delete(recursive: true);
				}
			}
			if (OldMetadata2.Exists)
			{
				if (!Locations.Meta.Exists)
				{
					OldMetadata2.MoveTo(Locations.Meta.FullName);
				}
				else
				{
					OldMetadata2.Delete(recursive: true);
				}
			}
			if (OldMappings2.Exists)
			{
				if (!Locations.ContentMappings.Exists)
				{
					OldMappings2.MoveTo(Locations.ContentMappings.FullName);
				}
				else
				{
					OldMappings2.Delete(recursive: true);
				}
			}
			if (OldMetadata3.Exists)
			{
				if (!Locations.Meta.Exists)
				{
					OldMetadata3.MoveTo(Locations.Meta.FullName);
				}
				else
				{
					OldMetadata3.Delete(recursive: true);
				}
			}
			if (OldMappings3.Exists)
			{
				if (!Locations.ContentMappings.Exists)
				{
					OldMappings3.MoveTo(Locations.ContentMappings.FullName);
				}
				else
				{
					OldMappings3.Delete(recursive: true);
				}
			}
		}
	}
	[BepInPlugin("IngoH.HardTime.HTCCL", "HTCCL", "1.0.3")]
	[HarmonyPatch]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "IngoH.HardTime.HTCCL";

		public const string PluginName = "HTCCL";

		public const string PluginVer = "1.0.3";

		public const string PluginPatchVer = "";

		public const string PluginVerLong = "v1.0.3";

		public const float PluginVersion = 1.03f;

		public static readonly float GameVersion = mviJfvMgFE.lwLyPFhqLx;

		public const bool PreRelease = false;

		public static string[] PreReleaseReasons = new string[1] { "Testing" };

		internal static ManualLogSource Log;

		internal static readonly Harmony Harmony = new Harmony("IngoH.HardTime.HTCCL");

		internal static string PluginPath;

		internal static string PersistentDataPath;

		internal static Plugin Instance { get; private set; }

		internal static ConfigEntry<bool> AutoExportCharacters { get; set; }

		internal static ConfigEntry<bool> EnableOverrides { get; set; }

		internal static ConfigEntry<bool> EnableCustomContent { get; set; }

		internal static ConfigEntry<bool> UseFullQualityTextures { get; set; }

		internal static ConfigEntry<bool> AllowImportingCharacters { get; set; }

		internal static ConfigEntry<bool> DeleteImportedCharacters { get; set; }

		internal static ConfigEntry<bool> EnableCharacterSearchScreen { get; set; }

		internal static ConfigEntry<bool> EnableGameUnityLog { get; set; }

		internal static ConfigEntry<string> GameUnityLogLevel { get; set; }

		internal static ConfigEntry<int> MaxBackups { get; set; }

		internal static ConfigEntry<bool> CacheEnabled { get; set; }

		internal static ConfigEntry<bool> Debug { get; set; }

		internal static ConfigEntry<bool> DebugRender { get; set; }

		internal static ConfigEntry<string> SaveFileName { get; set; }

		internal static ConfigEntry<string> PersistentDataOverride { get; set; }

		private void Awake()
		{
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			try
			{
				Log = ((BaseUnityPlugin)this).Logger;
				Instance = this;
				PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty;
				PersistentDataOverride = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PersistentDataOverride", "", "Override the persistent data path, which is used for storing the cache and mappings. This is useful if you want to use a different drive for the cache and mappings, since they can get quite large. Note that this will not move the existing cache and mappings, so you will have to move them manually. Leave this empty to use the default persistent data path: " + Path.Combine(Application.persistentDataPath, "HTCCL").Replace('/', '\\'));
				PersistentDataPath = (string.IsNullOrEmpty(PersistentDataOverride.Value) ? Path.Combine(Application.persistentDataPath, "HTCCL") : PersistentDataOverride.Value);
				if (!Directory.Exists(PersistentDataPath))
				{
					Directory.CreateDirectory(PersistentDataPath);
				}
				AutoExportCharacters = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoExportCharacters", true, "Automatically export characters to /Export when the game is saved.");
				EnableOverrides = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableOverrides", true, "Enable custom content overrides from /Overrides.");
				EnableCustomContent = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableCustomContent", true, "Enable custom content loading from /Assets.");
				UseFullQualityTextures = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseFullQualityTextures", false, "(EXPERIMENTAL) Allow HTCCL to use the full resolution textures without scaling them down (the game will still change the aspect ratio to fit the texture).");
				AllowImportingCharacters = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowImportingCharacters", true, "Allow importing characters from /Import");
				DeleteImportedCharacters = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DeleteImportedCharacters", false, "Delete imported characters from /Import after importing them (and saving the game).");
				EnableCharacterSearchScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableCharacterSearchScreen", true, "Enable the character search screen in the roster menu.");
				EnableGameUnityLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableGameUnityLog", true, "Enable Unity log messages sent by the game itself. If you don't know what this is, leave it enabled.");
				GameUnityLogLevel = ((BaseUnityPlugin)this).Config.Bind<string>("General", "GameUnityLogLevel", "Warning", new ConfigDescription("The log level for Unity log messages sent by the game itself. If you don't know what this is, leave it at Warning.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Error", "Warning", "Info" }), Array.Empty<object>()));
				MaxBackups = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxBackups", 100, "The maximum number of backups to keep. Set to 0 to disable backups. Set to -1 to keep all backups.");
				CacheEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CacheEnabled", true, "Enable caching of custom content. This will speed up loading times with the downside of more disk space usage. The cache is stored in the .cache folder, which is hidden by default. Disabling this will automatically delete the cache on startup.");
				Debug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Debug", false, "Enable debug mode. This will create debugging files in the /Debug folder.");
				DebugRender = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugRender", false, "Enable debug rendering. This will render debug information on the screen, such as collision boxes.");
				SaveFileName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SaveFileName", "ModdedSave", "The name of the save file to save to. Set to 'Save' to use the vanilla save file (not recommended). If no modded save file exists, the vanilla save file contents will be copied to a new modded save file. Note that changing this would require manually renaming the save file if you want to continue using it.");
				if (!Directory.Exists(Locations.Data.FullName))
				{
					throw new DirectoryNotFoundException("Data directory not found. Please make sure you copied the Data folder to the same directory as the HTCCL DLL.");
				}
				Locations.LoadData();
				AnimationActions.Initialize();
				if (GameVersion != 1.03f)
				{
					if (GameVersion > 1.03f)
					{
						LogUtils.LogWarning($"Your game version ({GameVersion}) is newer than HTCCL's target version ({1.03f}). Keep in mind that it may not work as intended on this version. Check the Steam Workshop page for updates.");
					}
					else
					{
						LogUtils.LogWarning($"Your game version ({GameVersion}) is older than HTCCL's target version ({1.03f}). Keep in mind that it may not work as intended on this version. Check for updates in the game's properties on Steam.");
					}
				}
				string easterEgg = Secrets.GetEasterEgg();
				if (easterEgg != null)
				{
					Log.LogInfo((object)easterEgg);
				}
				Locations.MoveLegacyLocations();
				Locations.CreateDirectories();
				((MonoBehaviour)this).StartCoroutine(LoadContent.Load());
				((BaseUnityPlugin)(object)this).RegisterCustomButton("Reset Imported Characters", delegate
				{
					int count = CharacterMappings.CharacterMap.PreviouslyImportedCharacters.Count;
					CharacterMappings.CharacterMap.PreviouslyImportedCharacters.Clear();
					CharacterMappings.CharacterMap.PreviouslyImportedCharacterIds.Clear();
					CharacterMappings.CharacterMap.Save();
					UGAgOkqhVA.FNuBXViguc(UGAgOkqhVA.JUDFxYwUWn);
					return (count == 0) ? "No reset needed" : string.Format("Reset {0} imported character{1}", count, (count == 1) ? "" : "s");
				}, extraConfirmation: true);
				((BaseUnityPlugin)(object)this).RegisterCustomButton("Unlock All Characters", delegate
				{
					for (int n = 0; n < Progress.charUnlock.Length; n++)
					{
						Progress.charUnlock[n] = 1;
					}
					EJwOnKEXJs.kmAySyLFZd = 1;
					return "All characters unlocked!";
				}, extraConfirmation: true);
				((BaseUnityPlugin)(object)this).RegisterCustomButton("Unlock All Maps", delegate
				{
					for (int m = 0; m < Progress.mapUnlock.Length; m++)
					{
						Progress.mapUnlock[m] = 1;
					}
					EJwOnKEXJs.kmAySyLFZd = 1;
					return "All maps unlocked!";
				}, extraConfirmation: true);
				((BaseUnityPlugin)(object)this).RegisterCustomButton("Unlock All Trophies", delegate
				{
					for (int l = 0; l < Progress.trophy.Length; l++)
					{
						Progress.trophy[l] = 1;
					}
					EJwOnKEXJs.kmAySyLFZd = 1;
					return "All tropies unlocked!";
				}, extraConfirmation: true);
				((BaseUnityPlugin)(object)this).RegisterCustomButton("Unlock Everything", delegate
				{
					for (int i = 0; i < Progress.charUnlock.Length; i++)
					{
						Progress.charUnlock[i] = 1;
					}
					for (int j = 0; j < Progress.mapUnlock.Length; j++)
					{
						Progress.mapUnlock[j] = 1;
					}
					for (int k = 0; k < Progress.trophy.Length; k++)
					{
						Progress.trophy[k] = 1;
					}
					EJwOnKEXJs.kmAySyLFZd = 1;
					return "Everything unlocked!";
				}, extraConfirmation: true);
			}
			catch (Exception message)
			{
				LogUtils.LogError(message);
			}
		}

		private void OnEnable()
		{
			string fullName = Locations.SaveFile.FullName;
			if (!File.Exists(fullName))
			{
				string fullName2 = Locations.SaveFileVanilla.FullName;
				if (File.Exists(fullName2))
				{
					File.Copy(fullName2, fullName);
				}
				else
				{
					GLPGLJAJJOP.NJMFCPGCKNL();
					GLPGLJAJJOP.OIIAHNGBNIF(0);
				}
			}
			try
			{
				Harmony.PatchAll();
			}
			catch (Exception message)
			{
				LogUtils.LogError("Failed to patch with Harmony. This is likely caused by the game version being incompatible with the plugin version. The current plugin version is v" + 1.03f);
				LogUtils.LogError(message);
				Harmony.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded HTCCL!");
		}

		private void OnDisable()
		{
			Harmony.UnpatchSelf();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Unloaded HTCCL!");
		}

		internal static void CreateBackups()
		{
			if (MaxBackups.Value == 0)
			{
				return;
			}
			string fullName = Locations.SaveFile.FullName;
			if (!File.Exists(fullName))
			{
				return;
			}
			string fullName2 = Locations.CharacterMappings.FullName;
			string fullName3 = Locations.ContentMappings.FullName;
			string fullName4 = Locations.Meta.FullName;
			string text = Path.Combine(Application.persistentDataPath, "backups", DateTime.Now.ToString("Save-yyyy-MM-dd_HH-mm-ss") + ".zip");
			string directoryName = Path.GetDirectoryName(text);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			if (Directory.GetFiles(directoryName, "Save-*.*").Length == 0 && !File.Exists(Path.Combine(directoryName, "InitialSave.zip")))
			{
				using ZipArchive destination = ZipFile.Open(Path.Combine(directoryName, "InitialSave.zip"), ZipArchiveMode.Create);
				destination.CreateEntryFromFile(fullName, Path.GetFileName(fullName));
				if (File.Exists(fullName2))
				{
					destination.CreateEntryFromFile(fullName2, Path.GetFileName(fullName2));
				}
				if (File.Exists(fullName3))
				{
					destination.CreateEntryFromFile(fullName3, Path.GetFileName(fullName3));
				}
				if (File.Exists(fullName4))
				{
					destination.CreateEntryFromFile(fullName4, Path.GetFileName(fullName4));
				}
			}
			using (ZipArchive destination2 = ZipFile.Open(text, ZipArchiveMode.Create))
			{
				destination2.CreateEntryFromFile(fullName, Path.GetFileName(fullName));
				if (File.Exists(fullName2))
				{
					destination2.CreateEntryFromFile(fullName2, Path.GetFileName(fullName2));
				}
				if (File.Exists(fullName3))
				{
					destination2.CreateEntryFromFile(fullName3, Path.GetFileName(fullName3));
				}
				if (File.Exists(fullName4))
				{
					destination2.CreateEntryFromFile(fullName4, Path.GetFileName(fullName4));
				}
			}
			string[] files = Directory.GetFiles(directoryName, "Save-*.*");
			if (MaxBackups.Value >= 0 && files.Length > MaxBackups.Value)
			{
				Array.Sort(files);
				for (int i = 0; i < files.Length - MaxBackups.Value; i++)
				{
					File.Delete(files[i]);
				}
			}
		}

		public static string GetNonDefaultConfigValues()
		{
			string text = "";
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)((BaseUnityPlugin)Instance).Config).Select((KeyValuePair<ConfigDefinition, ConfigEntryBase> x) => new KeyValuePair<ConfigDefinition, ConfigEntryBase>(x.Key, x.Value)))
			{
				if (!(item.Value.BoxedValue.ToString() == item.Value.DefaultValue.ToString()))
				{
					text += $"{item.Key.Key}={item.Value.BoxedValue}\n";
				}
			}
			return text;
		}
	}
}
namespace HTCCL.Utils
{
	public class AllMods
	{
		private static AllMods _instance;

		public static AllMods Instance => _instance ?? (_instance = new AllMods());

		public List<PluginInfo> Mods { get; private set; } = new List<PluginInfo>();


		public int NumMods => Mods.Count;

		public void LoadMods()
		{
			foreach (PluginInfo item in Chainloader.PluginInfos.Values.OrderBy((PluginInfo x) => x.Metadata.Name))
			{
				Mods.Add(item);
			}
		}

		public void ReloadMods()
		{
			Mods.Clear();
			LoadMods();
		}

		public AllMods()
		{
			LoadMods();
		}
	}
	public static class ArrayUtils
	{
		public static int[] GenerateArrayForNum(int characters)
		{
			if (characters <= 0)
			{
				return new int[1] { -1 };
			}
			int[] array = new int[characters + 1];
			for (int i = 1; i <= characters; i++)
			{
				array[i] = i;
			}
			return array;
		}

		public static IEnumerable<Character> SortBy(this IEnumerable<Character> c, int propertyId)
		{
			if (propertyId >= 3)
			{
				if (propertyId <= 8)
				{
					return c.OrderByDescending((Character x) => x.stat[propertyId - 2]);
				}
				switch (propertyId)
				{
				case 9:
					return c.OrderByDescending((Character x) => x.cell);
				case 10:
					return c.OrderByDescending((Character x) => x.age);
				case 11:
					return c.OrderBy((Character x) => x.age);
				}
			}
			else
			{
				switch (propertyId)
				{
				case 1:
					return c.OrderBy((Character x) => x.name);
				case 2:
					return c.OrderByDescending((Character x) => x.health);
				}
			}
			return c;
		}
	}
	public class CharacterUtils
	{
		public static void SaveAsBackup(int id)
		{
			NonSavedData.DeletedCharacters.Add(Characters.c[id]);
		}

		public static void DeleteCharacter(int id)
		{
			if (id < 1 || id >= Characters.c.Length)
			{
				throw new IndexOutOfRangeException($"Character ID {id} is out of range!");
			}
			Character character = Characters.c[id];
			CharacterEvents.InvokeBeforeCharacterRemoved(id, character);
			try
			{
				SaveAsBackup(id);
				if (Characters.star == id)
				{
					Characters.star = 1;
				}
				else if (Characters.star > id)
				{
					Characters.star--;
				}
				if (Progress.missionClient == id)
				{
					Progress.missionClient = 1;
				}
				else if (Progress.missionClient > id)
				{
					Progress.missionClient--;
				}
				if (Progress.missionTarget == id)
				{
					Progress.missionTarget = 1;
				}
				else if (Progress.missionTarget > id)
				{
					Progress.missionTarget--;
				}
				for (int i = 1; i < Progress.hiChar.Length; i++)
				{
					if (Progress.hiChar[i] == id)
					{
						Progress.hiChar[i] = 1;
					}
					else if (Progress.hiChar[i] > id)
					{
						Progress.hiChar[i]--;
					}
				}
				for (int j = 1; j < QWdlfqtpNK.AtzbNPYJrL.Length; j++)
				{
					if (QWdlfqtpNK.AtzbNPYJrL[j] != null)
					{
						if (QWdlfqtpNK.AtzbNPYJrL[j].owner == id)
						{
							QWdlfqtpNK.AtzbNPYJrL[j].owner = 1;
						}
						else if (QWdlfqtpNK.AtzbNPYJrL[j].owner > id)
						{
							Stock obj = QWdlfqtpNK.AtzbNPYJrL[j];
							obj.owner--;
						}
					}
				}
				for (int k = 1; k < FQEAAyldlY.dqnjQjQCcg.Length; k++)
				{
					if (FQEAAyldlY.dqnjQjQCcg[k] != null)
					{
						if (FQEAAyldlY.dqnjQjQCcg[k].owner == id)
						{
							FQEAAyldlY.dqnjQjQCcg[k].owner = 1;
						}
						else if (FQEAAyldlY.dqnjQjQCcg[k].owner > id)
						{
							Stock obj2 = FQEAAyldlY.dqnjQjQCcg[k];
							obj2.owner--;
						}
					}
				}
				Character[] c = Characters.c;
				foreach (Character val in c)
				{
					if (val == null)
					{
						continue;
					}
					for (int m = 1; m < val.relation.Length - 1; m++)
					{
						if (m >= id)
						{
							val.relation[m] = val.relation[m + 1];
						}
					}
					for (int n = 1; n < val.costume.Length; n++)
					{
						if (val.costume[n] != null && val.costume[n].charID > id)
						{
							Costume obj3 = val.costume[n];
							obj3.charID--;
						}
					}
					if (val.grudge == id)
					{
						val.grudge = 1;
					}
					else if (val.grudge > id)
					{
						val.grudge--;
					}
					if (val.team == id)
					{
						val.team = 1;
					}
					else if (val.team > id)
					{
						val.team--;
					}
				}
				for (int num = id; num < Characters.c.Length - 1; num++)
				{
					Characters.c[num] = Characters.c[num + 1];
					Characters.c[num].id = num;
				}
				for (int num2 = id; num2 < Progress.charUnlock.Length - 1; num2++)
				{
					Progress.charUnlock[num2] = Progress.charUnlock[num2 + 1];
				}
				Characters.no_chars--;
				Array.Resize(ref Characters.c, Characters.no_chars + 1);
				Array.Resize(ref Progress.charUnlock, Characters.no_chars + 1);
				Array.Resize(ref GLPGLJAJJOP.APPDIBENDAH.savedChars, Characters.no_chars + 1);
				Array.Resize(ref GLPGLJAJJOP.APPDIBENDAH.charUnlock, Characters.no_chars + 1);
				for (int num3 = 1; num3 <= Characters.no_chars; num3++)
				{
					if (Characters.c[num3] != null)
					{
						Array.Resize(ref Characters.c[num3].relation, Characters.no_chars + 1);
					}
				}
				CharacterEvents.InvokeAfterCharacterRemoved(id, character);
			}
			catch (Exception innerException)
			{
				CharacterEvents.InvokeAfterCharacterRemovedFailure(id, Characters.c[id]);
				throw new Exception($"Failed to delete character {id} ({Characters.c[id].name})!", innerException);
			}
		}

		public static void CreateRandomCharacter()
		{
			try
			{
				Character val = wElizvXQHV.MxIiAIuwdL<Character>(Characters.c[1]);
				CharacterEvents.InvokeBeforeCharacterAdded(Characters.no_chars + 1, val);
				Characters.no_chars++;
				Array.Resize(ref Characters.c, Characters.no_chars + 1);
				Array.Resize(ref Progress.charUnlock, Characters.no_chars + 1);
				Array.Resize(ref GLPGLJAJJOP.APPDIBENDAH.savedChars, Characters.no_chars + 1);
				Array.Resize(ref GLPGLJAJJOP.APPDIBENDAH.charUnlock, Characters.no_chars + 1);
				for (int i = 1; i <= Characters.no_chars; i++)
				{
					if (Characters.c[i] != null)
					{
						Array.Resize(ref Characters.c[i].relation, Characters.no_chars + 1);
					}
				}
				Progress.charUnlock[Characters.no_chars] = 1;
				Characters.c[Characters.no_chars] = val;
				jiqjqsXRll.qQskwFRaxf(Characters.c[Characters.no_chars]).qrSwpxVOGc(Characters.no_chars);
				jiqjqsXRll.qQskwFRaxf(Characters.c[Characters.no_chars]).cAfWNanIba = "";
				Character[] c = Characters.c;
				for (int j = 0; j < c.Length; j++)
				{
					_ = c[j];
				}
				CharacterEvents.InvokeAfterCharacterAdded(Characters.no_chars, Characters.c[Characters.no_chars]);
			}
			catch (Exception innerException)
			{
				CharacterEvents.InvokeAfterCharacterAddedFailure(Characters.no_chars, Characters.c[Characters.no_chars]);
				throw new Exception($"Failed to create random character {Characters.no_chars}!", innerException);
			}
		}
	}
	public class Checksum
	{
		public static string GetChecksum(byte[] bytes)
		{
			return BitConverter.ToString(MD5.Create().ComputeHash(bytes));
		}
	}
	public class ContentList : List<string>
	{
		public new string this[int index]
		{
			get
			{
				return base[index];
			}
			set
			{
				if (Aliases.AliasMap.TryGetValue(value, out var value2))
				{
					base[index] = value2;
				}
				else
				{
					base[index] = value;
				}
			}
		}

		public new void Add(string item)
		{
			if (Aliases.AliasMap.TryGetValue(item, out var value))
			{
				base.Add(value);
			}
			else
			{
				base.Add(item);
			}
		}

		public new void AddRange(IEnumerable<string> collection)
		{
			foreach (string item in collection)
			{
				if (Aliases.AliasMap.TryGetValue(item, out var value))
				{
					base.Add(value);
				}
				else
				{
					base.Add(item);
				}
			}
		}

		public new void Insert(int index, string item)
		{
			if (Aliases.AliasMap.TryGetValue(item, out var value))
			{
				base.Insert(index, value);
			}
			else
			{
				base.Insert(index, item);
			}
		}

		public new void InsertRange(int index, IEnumerable<string> collection)
		{
			foreach (string item in collection)
			{
				if (Aliases.AliasMap.TryGetValue(item, out var value))
				{
					base.Insert(index, value);
				}
				else
				{
					base.Insert(index, item);
				}
			}
		}

		public new bool Remove(string item)
		{
			if (Aliases.AliasMap.TryGetValue(item, out var value))
			{
				return base.Remove(value);
			}
			return base.Remove(item);
		}
	}
	public static class FileNameUtils
	{
		public static string Escape(string fileName)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				fileName = fileName.Replace(oldChar, '_');
			}
			return fileName;
		}

		public static string FindPluginName(DirectoryInfo source)
		{
			while (source.Name != "plugins" && source.Parent != null)
			{
				source = source.Parent;
			}
			if (source.Parent?.Name == "BepInEx")
			{
				return "Assets";
			}
			return source.Parent?.Name ?? "Assets";
		}
	}
	public static class GoogleTranslate
	{
		public static string Translate(string text, string from, string to)
		{
			string address = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" + from + "&tl=" + to + "&dt=t&q=" + Uri.EscapeUriString(text);
			return ToText(new WebClient().DownloadString(address));
		}

		private static string ToText(string result)
		{
			int num = result.IndexOf("\"", StringComparison.Ordinal) + 1;
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			for (int i = num; i < result.Length; i++)
			{
				char c = result[i];
				switch (c)
				{
				case '"':
					if (flag)
					{
						flag = false;
						continue;
					}
					break;
				case '\\':
					if (flag)
					{
						stringBuilder.Append('\\');
						flag = false;
					}
					else
					{
						flag = true;
					}
					continue;
				default:
					stringBuilder.Append(c);
					continue;
				}
				break;
			}
			return stringBuilder.ToString();
		}
	}
	public class Indices
	{
		public static Dictionary<string, int> CrowdAudio = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Train", 0 },
			{ "Oh", 1 },
			{ "Cheer", 2 },
			{ "Boo", 3 },
			{ "Yay", 4 },
			{ "Groan", 5 },
			{ "Excitement", 6 },
			{ "Murmur", 7 },
			{ "Laughter", 8 },
			{ "Applause", 9 },
			{ "Chant_Generic", 10 },
			{ "Stomping", 11 },
			{ "Chant_Yes", 12 },
			{ "Chant_Sucks", 13 },
			{ "Chant_Got", 14 },
			{ "Chant_Awesome", 15 },
			{ "Chant_CW", 16 },
			{ "Chant_Holy", 17 },
			{ "Chant_Fucked", 18 },
			{ "Chant_Wrestle", 19 },
			{ "Chant_Bullshit", 20 },
			{ "Chant_Boring", 21 },
			{ "Chant_USA", 22 },
			{ "Countdown", 30 },
			{ "Chant_Count01", 31 },
			{ "Chant_Count02", 32 },
			{ "Chant_Count03", 33 },
			{ "Chant_Count04", 34 },
			{ "Chant_Count05", 35 },
			{ "Chant_Count06", 36 },
			{ "Chant_Count07", 37 },
			{ "Chant_Count08", 38 },
			{ "Chant_Count09", 39 },
			{ "Chant_Count10", 40 },
			{ "Oh02", 41 },
			{ "Cheer02", 42 },
			{ "Boo02", 43 },
			{ "Yay02", 44 },
			{ "Groan02", 45 },
			{ "Excitement02", 46 },
			{ "Murmur02", 47 },
			{ "Laughter02", 48 },
			{ "Applause02", 49 },
			{ "Oh03", 51 },
			{ "Cheer03", 52 },
			{ "Boo03", 53 },
			{ "Yay03", 54 },
			{ "Groan03", 55 },
			{ "Excitement03", 56 },
			{ "Murmur03", 57 },
			{ "Laughter03", 58 },
			{ "Applause03", 59 }
		};

		public static Dictionary<string, int> TauntAnims = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
		{
			{ "[None]", 0 },
			{ "Wave", 1 },
			{ "Fist Palm", 2 },
			{ "Bring It", 3 },
			{ "Footwork", 4 },
			{ "Come Here", 5 },
			{ "Bicep Flex", 6 },
			{ "Wrist Fiddle", 7 },
			{ "Prayer", 8 },
			{ "Calm Down", 9 },
			{ "Fist Palm Down", 10 },
			{ "Rule Out", 11 },
			{ "Point At Ground", 12 },
			{ "Get Out Of My Face", 13 },
			{ "Single Count", 14 },
			{ "Double Count", 15 },
			{ "Disqualify", 16 },
			{ "Separate", 17 },
			{ "Resume", 18 },
			{ "Punch Air", 19 },
			{ "Make Decision", 20 },
			{ "Go Ahead", 21 },
			{ "Shake Raised Arms", 22 },
			{ "Pat Chest", 23 },
			{ "Go Away", 24 },
			{ "Folded Arms", 25 },
			{ "Can't See Me", 26 },
			{ "Invite Applause", 27 },
			{ "Ask The Question", 28 },
			{ "Speech Loop", 29 },
			{ "Self Abuse", 30 },
			{ "Wind Up", 31 },
			{ "Hands On Hips", 32 },
			{ "Disappointment", 33 },
			{ "Shake Fist", 34 },
			{ "Shake Trophy", 35 },
			{ "Shake Finger", 36 },
			{ "Point Forwards", 37 },
			{ "Point To Side", 38 },
			{ "Clap", 39 },
			{ "Raise Arm", 40 },
			{ "Raised Arms", 41 },
			{ "Outstretched Arms", 42 },
			{ "Dare To Hit", 43 },
			{ "Middle Fingers", 44 },
			{ "Gun Fingers", 45 },
			{ "Fancy Cupped Ear", 46 },
			{ "Crotch Chop", 47 },
			{ "X Sign", 48 },
			{ "Diamond Sign", 49 },
			{ "Power From Above", 50 },
			{ "Raise The Roof", 51 },
			{ "Fist Pump", 52 },
			{ "Overhead Fist Pump", 53 },
			{ "Throat Slice", 54 },
			{ "Beat Chest", 55 },
			{ "Emotional", 56 },
			{ "Salute", 57 },
			{ "Surrender", 58 },
			{ "Go To Sleep", 59 },
			{ "Belt Around Waist", 60 },
			{ "Waist Fiddle", 61 },
			{ "Pat Stomach", 62 },
			{ "Belt Over Shoulder", 63 },
			{ "Pat Shoulder", 64 },
			{ "Powerful Stance", 65 },
			{ "Speech B", 66 },
			{ "Thinking", 67 },
			{ "Hand On Chest", 68 },
			{ "Shrug Shoulders", 69 },
			{ "Stay Back", 70 },
			{ "Present", 71 },
			{ "Raise Hand", 72 },
			{ "Fist In Palm", 73 },
			{ "Fist On Palm", 74 },
			{ "Static Bicep Flex", 75 },
			{ "Pray Down", 76 },
			{ "Pray Up", 77 },
			{ "No Problem", 78 },
			{ "Yes Movement", 79 },
			{ "Pointed Fingers", 80 },
			{ "Point Upward", 81 },
			{ "Stay Separate", 82 },
			{ "Crossed Fingers", 83 },
			{ "Receive Applause", 84 },
			{ "Constant Disappointment", 85 },
			{ "Hold Trophy", 86 },
			{ "Raised Finger", 87 },
			{ "Point Straight Forwards", 88 },
			{ "Point Straight To Side", 89 },
			{ "Hands Together", 90 },
			{ "Middle Finger", 91 },
			{ "Cupped Ear", 92 },
			{ "Crotch Cross", 93 },
			{ "Clenched Fists", 94 },
			{ "Clenched Fist", 95 },
			{ "Raised Fist", 96 },
			{ "Head In Hands", 97 },
			{ "Microphone Speech", 98 },
			{ "Hold Camera (Right)", 99 },
			{ "Hold Camera (Left)", 100 },
			{ "Make Point", 101 },
			{ "Point At Chest", 102 },
			{ "Here Or There (Left)", 103 },
			{ "Point At Face", 104 },
			{ "Point At Head", 105 },
			{ "Thumb Shoulders", 106 },
			{ "Thumb Chest", 107 },
			{ "Thumb Raised", 108 },
			{ "Thumbs Up", 109 },
			{ "Thumb Outstretched", 110 },
			{ "Thumbs Down", 111 },
			{ "Here Or There (Right)", 112 },
			{ "Rub Fingers", 113 },
			{ "Roar", 114 },
			{ "Woo", 115 },
			{ "Unbelievable", 116 },
			{ "Grind Hips", 117 },
			{ "Grind Hip", 118 },
			{ "Grind Side To Side", 119 },
			{ "Muscle Pose A", 120 },
			{ "Muscle Pose B", 121 },
			{ "Muscle Pose C", 122 },
			{ "Muscle Pose Combo", 123 },
			{ "Cover Up", 124 },
			{ "Drink (Right)", 125 },
			{ "Drink (Left)", 126 },
			{ "Title Celebration (Rear Right)", 127 },
			{ "Title Celebration (Front Right)", 128 },
			{ "Title Celebration (Low Right)", 129 },
			{ "Clenched Titles", 130 },
			{ "Title Celebration (Rear Left)", 131 },
			{ "Title Celebration (Front Left)", 132 },
			{ "Hold Sign", 133 },
			{ "Point At Prop", 134 },
			{ "Bicep Curl (Right)", 135 },
			{ "Bicep Curl (Left)", 136 },
			{ "Need To Pee", 137 },
			{ "Need To Crap", 138 },
			{ "Style Hair", 139 },
			{ "Cue Action", 140 },
			{ "Polish Cue", 141 },
			{ "Pocket Right", 142 },
			{ "Pocket Left", 143 },
			{ "Pockets", 144 },
			{ "Pocket Loop", 145 },
			{ "Solemn", 146 },
			{ "Thumb Stampede", 147 },
			{ "Outstretched Edge", 148 },
			{ "Slide Through", 149 },
			{ "Slide Through Loop", 150 },
			{ "Too Sweet", 151 },
			{ "V Sign", 152 },
			{ "Puppetry", 153 },
			{ "Trembling Fingers", 154 },
			{ "Thumbs Into Outstretched", 155 },
			{ "Double Point", 156 },
			{ "Monster Claws", 157 },
			{ "Double Ring Burst", 158 },
			{ "Double Ring Loop", 159 },
			{ "OK Sign", 160 },
			{ "Double V Signs", 161 },
			{ "Two Sweet", 162 },
			{ "3 Fingers", 163 },
			{ "4 Fingers", 164 },
			{ "2 Fingers", 165 },
			{ "Count Fingers", 166 },
			{ "Eat (Left)", 167 },
			{ "Eat (Right)", 168 },
			{ "Examine (Left)", 169 },
			{ "Examine (Right)", 170 },
			{ "Examine Stick (Left)", 171 },
			{ "Examine Stick (Right)", 172 },
			{ "Selfie (Right)", 173 },
			{ "Phone Fiddle (Right)", 174 },
			{ "Selfie (Left)", 175 },
			{ "Phone Fiddle (Left)", 176 },
			{ "Quick Wave (Right)", 177 },
			{ "Quick Wave (Left)", 178 },
			{ "Guitar Strum", 179 },
			{ "Guitar Thrash", 180 },
			{ "Read Book (Right)", 181 },
			{ "Read Book (Left)", 182 },
			{ "Read Tablet (Right)", 183 },
			{ "Read Tablet (Left)", 184 }
		};

		public static int ParseCrowdAudio(string audio)
		{
			if (int.TryParse(audio, out var result))
			{
				if (result >= CrowdAudio.Count)
				{
					throw new Exception($"Crowd audio index out of range: {audio}, max: {CrowdAudio.Count - 1}");
				}
				return result;
			}
			if (CrowdAudio.TryGetValue(audio, out result))
			{
				return result;
			}
			throw new Exception("Unknown crowd audio: " + audio);
		}

		public static int ParseTauntAnim(string anim)
		{
			if (int.TryParse(anim, out var result))
			{
				if (result >= TauntAnims.Count)
				{
					throw new Exception($"Taunt animation index out of range: {anim}, max: {TauntAnims.Count - 1}");
				}
				return result;
			}
			if (TauntAnims.TryGetValue(anim.Replace("_", " "), out result))
			{
				return result;
			}
			throw new Exception("Unknown taunt animation: " + anim);
		}
	}
	public class LimitedDictionary<TKey, TValue> : SortedDictionary<TKey, TValue>
	{
		private readonly int _limit;

		public LimitedDictionary(int limit)
		{
			_limit = limit;
		}

		public new void Add(TKey key, TValue value)
		{
			if (base.Count >= _limit)
			{
				Remove(this.First().Key);
			}
			base.Add(key, value);
		}
	}
	public static class LogUtils
	{
		public static void LogInfo(object message)
		{
			string source = GetSource();
			if (source != null)
			{
				Plugin.Log.LogInfo((object)string.Format("[{1}] {0}", message, source));
			}
			else
			{
				Plugin.Log.LogInfo(message);
			}
		}

		public static void LogWarning(object message)
		{
			string source = GetSource();
			if (source != null)
			{
				Plugin.Log.LogWarning((object)string.Format("[{1}] {0}", message, source));
			}
			else
			{
				Plugin.Log.LogWarning(message);
			}
		}

		public static void LogError(object message)
		{
			string source = GetSource();
			if (source != null)
			{
				Plugin.Log.LogError((object)string.Format("[{1}] {0}", message, source));
			}
			else
			{
				Plugin.Log.LogError(message);
			}
		}

		public static void LogDebug(object message)
		{
			string source = GetSource();
			if (source != null)
			{
				Plugin.Log.LogDebug((object)string.Format("[{1}] {0}", message, source));
			}
			else
			{
				Plugin.Log.LogDebug(message);
			}
		}

		public static void LogFatal(object message)
		{
			string source = GetSource();
			if (source != null)
			{
				Plugin.Log.LogFatal((object)string.Format("[{1}] {0}", message, source));
			}
			else
			{
				Plugin.Log.LogFatal(message);
			}
		}

		private static string GetSource()
		{
			StackFrame[] frames = new StackTrace().GetFrames();
			if (frames == null)
			{
				return null;
			}
			StackFrame[] array = frames;
			for (int i = 0; i < array.Length; i++)
			{
				MethodBase method = array[i].GetMethod();
				if (method == null)
				{
					continue;
				}
				Type declaringType = method.DeclaringType;
				if (declaringType == null)
				{
					continue;
				}
				string name = declaringType.Name;
				if (name != null && !(name == "LogUtils"))
				{
					while (name.StartsWith("<") && declaringType.DeclaringType != null)
					{
						declaringType = declaringType.DeclaringType;
						name = declaringType.Name;
					}
					if (!name.StartsWith("<"))
					{
						return name;
					}
				}
			}
			return null;
		}

		public static T Linfo<T>(T message)
		{
			LogInfo(message.ToString());
			return message;
		}

		public static T Lwarn<T>(T message)
		{
			LogWarning(message.ToString());
			return message;
		}

		public static T Lerr<T>(T message)
		{
			LogError(message.ToString());
			return message;
		}

		public static T Ldbg<T>(T message)
		{
			LogDebug(message.ToString());
			return message;
		}

		public static T Lfat<T>(T message)
		{
			LogFatal(message.ToString());
			return message;
		}
	}
	public static class MenuUtils
	{
		internal static float PrevScale = 1f;

		internal static readonly Dictionary<int, Tuple<int, int, float, int, int>> _optimalLayouts = new Dictionary<int, Tuple<int, int, float, int, int>>();

		public static void FindBestFit(int size, int minX, int minY, int maxX, int maxY, out int rows, out int columns, out float scale, out int startX, out int startY)
		{
			if (_optimalLayouts.TryGetValue(size, out var value))
			{
				rows = value.Item1;
				columns = value.Item2;
				scale = value.Item3;
				startX = value.Item4;
				startY = value.Item5;
				PrevScale = scale;
				return;
			}
			int num = ((size > 35) ? 210 : 245);
			int num2 = ((size > 48) ? 50 : 60);
			int num3 = maxX - minX;
			int num4 = maxY - minY;
			float num5 = 1.25f;
			if (size > 48)
			{
				num5 = 1f;
			}
			int num6;
			int num7;
			int num8;
			int num9;
			int num10;
			int num11;
			while (true)
			{
				num6 = num3 + (int)((float)num * num5);
				num7 = num4 + (int)((float)num2 * num5);
				num8 = (int)((float)num * num5);
				num9 = (int)((float)num2 * num5);
				num10 = num6 / num8;
				num11 = num7 / num9;
				if (num10 * num11 >= size)
				{
					break;
				}
				num5 /= 1.05f;
			}
			rows = num11;
			columns = num10;
			scale = num5;
			int num12 = num10 * num8;
			startX = minX + (num6 - num12) / 2;
			int num13 = num11 * num9;
			startY = maxY - (num7 - num13) / 2;
			LogUtils.LogDebug($"Found best fit for {size} items: {rows} rows, {columns} columns, {scale} scale, {startX} startX, {startY} startY");
			_optimalLayouts.Add(size, new Tuple<int, int, float, int, int>(rows, columns, scale, startX, startY));
			PrevScale = num5;
		}

		public static float Scale(float size)
		{
			return size * PrevScale;
		}
	}
	public static class NumberFormatUtils
	{
		public static NumberFormatInfo Nfi = new NumberFormatInfo
		{
			NumberDecimalSeparator = "."
		};
	}
	public static class OS
	{
		public static OperatingSystemFamily Os => SystemInfo.operatingSystemFamily;

		public static string GetOSString(string def = "other", bool lowercase = false)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected I4, but got Unknown
			OperatingSystemFamily os = Os;
			return (os - 1) switch
			{
				0 => lowercase ? "macos" : "MacOS", 
				1 => lowercase ? "windows" : "Windows", 
				2 => lowercase ? "linux" : "Linux", 
				_ => lowercase ? def.ToLower() : def, 
			};
		}
	}
	internal class SaveRemapper
	{
		internal static void PatchCustomContent(ref SaveData saveData)
		{
			ContentMappings contentMap = ContentMappings.ContentMap;
			ContentMappings contentMappings = SaveFilePatch.LoadPreviousMap();
			if (!VanillaCounts.Data.IsInitialized)
			{
				LogUtils.LogError("Vanilla counts not initialized. Skipping custom content patch.");
				return;
			}
			int num = Mathf.RoundToInt(contentMappings.GameVersion * 100f);
			int num2 = Mathf.RoundToInt(Plugin.GameVersion * 100f);
			VersionDiff versionDiff = null;
			if (num != num2)
			{
				LogUtils.LogInfo($"Game version changed from {num} to {num2}. Updating custom content map.");
				if (ContentMappings.ContentMap.VanillaCounts != null)
				{
					versionDiff = VersionDiff.GetVersionDiff(ContentMappings.ContentMap.VanillaCounts);
				}
			}
			ContentMappings.ContentMap.VanillaCounts = VanillaCounts.Data;
			try
			{
				Character[] savedChars = saveData.savedChars;
				foreach (Character val in savedChars)
				{
					if (val == null)
					{
						continue;
					}
					Costume[] costume = val.costume;
					foreach (Costume val2 in costume)
					{
						if (val2 == null)
						{
							continue;
						}
						for (int k = 0; k < val2.texture.Length; k++)
						{
							if (VanillaCounts.Data.MaterialCounts[k] == 0)
							{
								continue;
							}
							if (versionDiff != null)
							{
								if (versionDiff.MaterialCountsDiff[k] != 0 && val2.texture[k] > VanillaCounts.Data.MaterialCounts[k] - versionDiff.MaterialCountsDiff[k])
								{
									val2.texture[k] += versionDiff.MaterialCountsDiff[k];
								}
								else if (k == 3 && versionDiff.FaceFemaleCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.FaceFemaleCount + versionDiff.FaceFemaleCountDiff)
								{
									val2.texture[k] -= versionDiff.FaceFemaleCountDiff;
								}
								else if (k == 14 && versionDiff.SpecialFootwearCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.SpecialFootwearCount + versionDiff.SpecialFootwearCountDiff)
								{
									val2.texture[k] -= versionDiff.SpecialFootwearCountDiff;
								}
								else if (k == 15 && versionDiff.SpecialFootwearCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.SpecialFootwearCount + versionDiff.SpecialFootwearCountDiff)
								{
									val2.texture[k] -= versionDiff.SpecialFootwearCountDiff;
								}
								else if (k == 17 && versionDiff.TransparentHairMaterialCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.TransparentHairMaterialCount + versionDiff.TransparentHairMaterialCountDiff)
								{
									val2.texture[k] -= versionDiff.TransparentHairMaterialCountDiff;
								}
								else if (k == 24 && versionDiff.KneepadCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.KneepadCount + versionDiff.KneepadCountDiff)
								{
									val2.texture[k] -= versionDiff.KneepadCountDiff;
								}
								else if (k == 25 && versionDiff.KneepadCountDiff != 0 && val2.texture[k] < -VanillaCounts.Data.KneepadCount + versionDiff.KneepadCountDiff)
								{
									val2.texture[k] -= versionDiff.KneepadCountDiff;
								}
							}
							if (val2.texture[k] > VanillaCounts.Data.MaterialCounts[k])
							{
								int num3 = val2.texture[k] - VanillaCounts.Data.MaterialCounts[k] - 1;
								if (num3 >= contentMappings.MaterialNameMap[k].Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num3} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text = contentMappings.MaterialNameMap[k][num3];
								int num4 = contentMap.MaterialNameMap[k].IndexOf(text);
								int num5 = num4 + VanillaCounts.Data.MaterialCounts[k] + 1;
								if (val2.texture[k] != num5)
								{
									LogUtils.LogInfo($"Custom material {text} at index {num3} was remapped to index {num4} (internal index {num5}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num5;
								}
							}
							else if (k == 3 && val2.texture[k] < -VanillaCounts.Data.FaceFemaleCount)
							{
								int num6 = -val2.texture[k] - VanillaCounts.Data.FaceFemaleCount - 1;
								if (num6 >= contentMappings.FaceFemaleNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num6} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text2 = contentMappings.FaceFemaleNameMap[num6];
								int num7 = contentMap.FaceFemaleNameMap.IndexOf(text2);
								int num8 = -num7 - VanillaCounts.Data.FaceFemaleCount - 1;
								if (val2.texture[k] != num8)
								{
									LogUtils.LogInfo($"Custom material {text2} at index {num6} was remapped to index {num7} (internal index {num8}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num8;
								}
							}
							else if (k == 14 && val2.texture[k] < -VanillaCounts.Data.SpecialFootwearCount)
							{
								int num9 = -val2.texture[k] - VanillaCounts.Data.SpecialFootwearCount - 1;
								if (num9 >= contentMappings.SpecialFootwearNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num9} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text3 = contentMappings.SpecialFootwearNameMap[num9];
								int num10 = contentMap.SpecialFootwearNameMap.IndexOf(text3);
								int num11 = -num10 - VanillaCounts.Data.SpecialFootwearCount - 1;
								if (val2.texture[k] != num11)
								{
									LogUtils.LogInfo($"Custom material {text3} at index {num9} was remapped to index {num10} (internal index {num11}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num11;
								}
							}
							else if (k == 15 && val2.texture[k] < -VanillaCounts.Data.SpecialFootwearCount)
							{
								int num12 = -val2.texture[k] - VanillaCounts.Data.SpecialFootwearCount - 1;
								if (num12 >= contentMappings.SpecialFootwearNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num12} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text4 = contentMappings.SpecialFootwearNameMap[num12];
								int num13 = contentMap.SpecialFootwearNameMap.IndexOf(text4);
								int num14 = -num13 - VanillaCounts.Data.SpecialFootwearCount - 1;
								if (val2.texture[k] != num14)
								{
									LogUtils.LogInfo($"Custom material {text4} at index {num12} was remapped to index {num13} (internal index {num14}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num14;
								}
							}
							else if (k == 17 && val2.texture[k] < -VanillaCounts.Data.TransparentHairMaterialCount)
							{
								int num15 = -val2.texture[k] - VanillaCounts.Data.TransparentHairMaterialCount - 1;
								if (num15 >= contentMappings.TransparentHairMaterialNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num15} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text5 = contentMappings.TransparentHairMaterialNameMap[num15];
								int num16 = contentMap.TransparentHairMaterialNameMap.IndexOf(text5);
								int num17 = -num16 - VanillaCounts.Data.TransparentHairMaterialCount - 1;
								if (val2.texture[k] != num17)
								{
									LogUtils.LogInfo($"Custom material {text5} at index {num15} was remapped to index {num16} (internal index {num17}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num17;
								}
							}
							else if (k == 24 && val2.texture[k] < -VanillaCounts.Data.KneepadCount)
							{
								int num18 = -val2.texture[k] - VanillaCounts.Data.KneepadCount - 1;
								if (num18 >= contentMappings.KneepadNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num18} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text6 = contentMappings.KneepadNameMap[num18];
								int num19 = contentMap.KneepadNameMap.IndexOf(text6);
								int num20 = -num19 - VanillaCounts.Data.KneepadCount - 1;
								if (val2.texture[k] != num20)
								{
									LogUtils.LogInfo($"Custom material {text6} at index {num18} was remapped to index {num19} (internal index {num20}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num20;
								}
							}
							else
							{
								if (k != 25 || val2.texture[k] >= -VanillaCounts.Data.KneepadCount)
								{
									continue;
								}
								int num21 = -val2.texture[k] - VanillaCounts.Data.KneepadCount - 1;
								if (num21 >= contentMappings.KneepadNameMap.Count)
								{
									LogUtils.LogWarning($"Custom material {k} index {num21} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.texture[k] = VanillaCounts.Data.MaterialCounts[k];
									continue;
								}
								string text7 = contentMappings.KneepadNameMap[num21];
								int num22 = contentMap.KneepadNameMap.IndexOf(text7);
								int num23 = -num22 - VanillaCounts.Data.KneepadCount - 1;
								if (val2.texture[k] != num23)
								{
									LogUtils.LogInfo($"Custom material {text7} at index {num21} was remapped to index {num22} (internal index {num23}) for material {k} of character {val.name} ({val.id}).");
									val2.texture[k] = num23;
								}
							}
						}
						for (int l = 0; l < val2.flesh.Length; l++)
						{
							if (VanillaCounts.Data.FleshCounts[l] == 0)
							{
								continue;
							}
							if (versionDiff != null)
							{
								if (versionDiff.FleshCountsDiff[l] != 0 && val2.flesh[l] > VanillaCounts.Data.FleshCounts[l] - versionDiff.FleshCountsDiff[l])
								{
									val2.flesh[l] += versionDiff.FleshCountsDiff[l];
								}
								else if (l == 2 && versionDiff.BodyFemaleCountDiff != 0 && val2.flesh[l] < -VanillaCounts.Data.BodyFemaleCount + versionDiff.BodyFemaleCountDiff)
								{
									val2.flesh[l] -= versionDiff.BodyFemaleCountDiff;
								}
							}
							if (val2.flesh[l] > VanillaCounts.Data.FleshCounts[l])
							{
								int num24 = val2.flesh[l] - VanillaCounts.Data.FleshCounts[l] - 1;
								if (num24 >= contentMappings.FleshNameMap[l].Count)
								{
									LogUtils.LogWarning($"Custom flesh index {num24} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.flesh[l] = VanillaCounts.Data.FleshCounts[l];
									continue;
								}
								string text8 = contentMappings.FleshNameMap[l][num24];
								int num25 = contentMap.FleshNameMap[l].IndexOf(text8);
								int num26 = num25 + VanillaCounts.Data.FleshCounts[l] + 1;
								if (val2.flesh[l] != num26)
								{
									LogUtils.LogInfo($"Custom flesh {text8} at index {num24} was remapped to index {num25} (internal index {num26}) for flesh {l} of character {val.name} ({val.id}).");
									val2.flesh[l] = num26;
								}
							}
							else
							{
								if (l != 2 || val2.flesh[l] >= -VanillaCounts.Data.BodyFemaleCount)
								{
									continue;
								}
								int num27 = -val2.flesh[l] - VanillaCounts.Data.BodyFemaleCount - 1;
								if (num27 >= contentMappings.BodyFemaleNameMap.Count)
								{
									LogUtils.LogWarning($"Custom flesh index {num27} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.flesh[l] = VanillaCounts.Data.FleshCounts[l];
									continue;
								}
								string text9 = contentMappings.BodyFemaleNameMap[num27];
								int num28 = contentMap.BodyFemaleNameMap.IndexOf(text9);
								int num29 = -num28 - VanillaCounts.Data.BodyFemaleCount - 1;
								if (val2.flesh[l] != num29)
								{
									LogUtils.LogInfo($"Custom flesh {text9} at index {num27} was remapped to index {num28} (internal index {num29}) for flesh {l} of character {val.name} ({val.id}).");
									val2.flesh[l] = num29;
								}
							}
						}
						for (int m = 0; m < val2.shape.Length; m++)
						{
							if (VanillaCounts.Data.ShapeCounts[m] == 0)
							{
								continue;
							}
							if (versionDiff != null)
							{
								if (versionDiff.ShapeCountsDiff[m] != 0 && val2.shape[m] > VanillaCounts.Data.ShapeCounts[m] - versionDiff.ShapeCountsDiff[m])
								{
									val2.shape[m] += versionDiff.ShapeCountsDiff[m];
								}
								else if (m == 17 && versionDiff.TransparentHairHairstyleCountDiff != 0 && val2.shape[m] < -VanillaCounts.Data.TransparentHairHairstyleCount + versionDiff.TransparentHairHairstyleCountDiff)
								{
									val2.shape[m] -= versionDiff.TransparentHairHairstyleCountDiff;
								}
							}
							if (val2.shape[m] > VanillaCounts.Data.ShapeCounts[m])
							{
								int num30 = val2.shape[m] - VanillaCounts.Data.ShapeCounts[m] - 1;
								if (num30 >= contentMappings.ShapeNameMap[m].Count)
								{
									LogUtils.LogWarning($"Custom shape index {num30} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.shape[m] = VanillaCounts.Data.ShapeCounts[m];
									continue;
								}
								string text10 = contentMappings.ShapeNameMap[m][num30];
								int num31 = contentMap.ShapeNameMap[m].IndexOf(text10);
								int num32 = num31 + VanillaCounts.Data.ShapeCounts[m] + 1;
								if (val2.shape[m] != num32)
								{
									LogUtils.LogInfo($"Custom shape {text10} at index {num30} was remapped to index {num31} (internal index {num32}) for shape {m} of character {val.name} ({val.id}).");
									val2.shape[m] = num32;
								}
							}
							else
							{
								if (m != 17 || val2.shape[m] >= -VanillaCounts.Data.TransparentHairHairstyleCount)
								{
									continue;
								}
								int num33 = -val2.shape[m] - VanillaCounts.Data.TransparentHairHairstyleCount - 1;
								if (num33 >= contentMappings.TransparentHairHairstyleNameMap.Count)
								{
									LogUtils.LogWarning($"Custom shape index {num33} is out of bounds for character {val.name} ({val.id}). Resetting.");
									val2.shape[m] = VanillaCounts.Data.ShapeCounts[m];
									continue;
								}
								string text11 = contentMappings.TransparentHairHairstyleNameMap[num33];
								int num34 = contentMap.TransparentHairHairstyleNameMap.IndexOf(text11);
								int num35 = -num34 - VanillaCounts.Data.TransparentHairHairstyleCount - 1;
								if (val2.shape[m] != num35)
								{
									LogUtils.LogInfo($"Custom shape {text11} at index {num33} was remapped to index {num34} (internal index {num35}) for shape {m} of character {val.name} ({val.id}).");
									val2.shape[m] = num35;
								}
							}
						}
					}
				}
			}
			catch (Exception message)
			{
				LogUtils.LogError("Failed to remap custom content!");
				LogUtils.LogError(message);
			}
			ContentList animationNameMap = contentMappings.AnimationNameMap;
			ContentList animationNameMap2 = contentMap.AnimationNameMap;
			for (int n = 0; n < animationNameMap.Count; n++)
			{
				if (n < animationNameMap2.Count && animationNameMap[n] == animationNameMap2[n])
				{
					continue;
				}
				int num36 = animationNameMap2.IndexOf(animationNameMap[n]);
				if (num36 == -1)
				{
					LogUtils.LogWarning("Animation " + animationNameMap[n] + " not found in new map. Resetting to default.");
				}
				else
				{
					LogUtils.LogInfo("Animation " + animationNameMap[n] + " remapped to " + animationNameMap2[num36] + ".");
				}
				for (int num37 = 1; num37 < saveData.savedChars.Length; num37++)
				{
					if (saveData.savedChars[num37] == null)
					{
						continue;
					}
					for (int num38 = 0; num38 < saveData.savedChars[num37].moveAttack.Length; num38++)
					{
						if (saveData.savedChars[num37].moveAttack[num38] == n + 1000000)
						{
							saveData.savedChars[num37].moveAttack[num38] = ((num36 == -1) ? DefaultMove('a', num38) : (num36 + 1000000));
						}
					}
					for (int num39 = 0; num39 < saveData.savedChars[num37].moveCrush.Length; num39++)
					{
						if (saveData.savedChars[num37].moveCrush[num39] == n + 1000000)
						{
							saveData.savedChars[num37].moveCrush[num39] = ((num36 == -1) ? DefaultMove('c', num39) : (num36 + 1000000));
						}
					}
					for (int num40 = 0; num40 < saveData.savedChars[num37].moveFront.Length; num40++)
					{
						if (saveData.savedChars[num37].moveFront[num40] == n + 1000000)
						{
							saveData.savedChars[num37].moveFront[num40] = ((num36 == -1) ? DefaultMove('f', num40) : (num36 + 1000000));
						}
					}
					for (int num41 = 0; num41 < saveData.savedChars[num37].moveBack.Length; num41++)
					{
						if (saveData.savedChars[num37].moveBack[num41] == n + 1000000)
						{
							saveData.savedChars[num37].moveBack[num41] = ((num36 == -1) ? DefaultMove('b', num41) : (num36 + 1000000));
						}
					}
					for (int num42 = 0; num42 < saveData.savedChars[num37].moveGround.Length; num42++)
					{
						if (saveData.savedChars[num37].moveGround[num42] == n + 1000000)
						{
							saveData.savedChars[num37].moveGround[num42] = ((num36 == -1) ? DefaultMove('g', num42) : (num36 + 1000000));
						}
					}
					for (int num43 = 0; num43 < saveData.savedChars[num37].taunt.Length; num43++)
					{
						if (saveData.savedChars[num37].taunt[num43] == n + 1000000)
						{
							saveData.savedChars[num37].taunt[num43] = ((num36 == -1) ? DefaultMove('t', num43) : (num36 + 1000000));
						}
					}
				}
			}
		}

		private static int DefaultMove(char type, int index)
		{
			switch (type)
			{
			case 'a':
				switch (index)
				{
				case 0:
					return 0;
				case 1:
					return 1002;
				case 2:
					return 1061;
				case 3:
					return 1124;
				case 4:
					return 1111;
				case 5:
					return 1306;
				case 6:
					return 1304;
				case 7:
					return 1302;
				case 8:
					return 1350;
				}
				break;
			case 'c':
				switch (index)
				{
				case 0:
					return 0;
				case 1:
					return 1205;
				case 2:
					return 1201;
				case 3:
					return 1211;
				case 4:
					return 1211;
				case 5:
					return 1350;
				case 6:
					return 1353;
				case 7:
					return 1350;
				case 8:
					return 1350;
				}
				break;
			case 'f':
				switch (index)
				{
				case 0:
					return 291;
				case 1:
					return 278;
				case 2:
					return 603;
				case 3:
					return 272;
				case 4:
					return 257;
				case 5:
					return 281;
				case 6:
					return 235;
				case 7:
					return 253;
				case 8:
					return 298;
				case 9:
					return 280;
				case 10:
					return 299;
				case 11:
					return 604;
				case 12:
					return 219;
				case 13:
					return 299;
				case 14:
					return 280;
				case 15:
					return 280;
				case 16:
					return 512;
				}
				break;
			case 'b':
				switch (index)
				{
				case 0:
					return 328;
				case 1:
					return 325;
				case 2:
					return 320;
				case 3:
					return 313;
				case 4:
					return 311;
				case 5:
					return 337;
				case 6:
					return 327;
				case 7:
					return 334;
				case 8:
					return 334;
				}
				break;
			case 'g':
				switch (index)
				{
				case 0:
					return 0;
				case 1:
					return 412;
				case 2:
					return 417;
				case 3:
					return 413;
				case 4:
					return 471;
				case 5:
					return 464;
				case 6:
					return 456;
				}
				break;
			case 't':
				switch (index)
				{
				case 0:
					return 15;
				case 1:
					return 5;
				case 2:
					return 94;
				case 3:
					return 15;
				}
				break;
			}
			return 0;
		}

		public static void FixBrokenSaveData()
		{
			LogUtils.LogInfo("Validating save data...");
			SaveData aPPDIBENDAH = GLPGLJAJJOP.APPDIBENDAH;
			int num = aPPDIBENDAH.savedChars.Length;
			for (int num2 = aPPDIBENDAH.savedChars.Length - 1; num2 >= 1; num2--)
			{
				if (aPPDIBENDAH.savedChars[num2].id != num2)
				{
					LogUtils.LogWarning($"Character index {num2} does not match ID {aPPDIBENDAH.savedChars[num2].id}. Fixing.");
					aPPDIBENDAH.savedChars[num2].id = num2;
				}
				for (int i = 1; i < aPPDIBENDAH.savedChars[num2].costume.Length; i++)
				{
					if (aPPDIBENDAH.savedChars[num2].costume[i].charID > num)
					{
						LogUtils.LogWarning($"Costume index {i} of character index {num2} has character ID {aPPDIBENDAH.savedChars[num2].costume[i].charID} out of bounds. Resetting to id.");
						aPPDIBENDAH.savedChars[num2].costume[i].charID = num2;
					}
				}
			}
			if (aPPDIBENDAH.star > num)
			{
				LogUtils.LogWarning($"Star index {aPPDIBENDAH.star} is out of bounds. Resetting to 1.");
				aPPDIBENDAH.star = 1;
			}
			if (aPPDIBENDAH.missionClient > num)
			{
				LogUtils.LogWarning($"Mission client index {aPPDIBENDAH.missionClient} is out of bounds. Resetting to 1.");
				aPPDIBENDAH.missionClient = 1;
			}
			if (aPPDIBENDAH.missionTarget > num)
			{
				LogUtils.LogWarning($"Mission target index {aPPDIBENDAH.missionTarget} is out of bounds. Resetting to 1.");
				aPPDIBENDAH.missionTarget = 1;
			}
			if (aPPDIBENDAH.charUnlock.Length != num)
			{
				LogUtils.LogWarning($"Character unlock array length {aPPDIBENDAH.charUnlock.Length} does not match number of characters {num}. Fixing.");
				int num3 = aPPDIBENDAH.charUnlock.Length;
				Array.Resize(ref aPPDIBENDAH.charUnlock, num);
				if (num3 < num)
				{
					for (int j = num3; j < num; j++)
					{
						aPPDIBENDAH.charUnlock[j] = 1;
					}
				}
			}
			for (int k = 1; k < aPPDIBENDAH.hiChar.Length; k++)
			{
				int num4 = aPPDIBENDAH.hiChar[k];
				if (num4 > num)
				{
					LogUtils.LogWarning($"Hi character index {num4} is out of bounds. Resetting to 1.");
					aPPDIBENDAH.hiChar[k] = 1;
				}
			}
			if (aPPDIBENDAH.stockFurniture != null)
			{
				Stock[] stockFurniture = aPPDIBENDAH.stockFurniture;
				foreach (Stock val in stockFurniture)
				{
					if (val != null && val.owner > num)
					{
						LogUtils.LogWarning($"Furniture owner index {val.owner} is out of bounds. Resetting to 1.");
						val.owner = 1;
					}
				}
			}
			if (aPPDIBENDAH.stockWeapons != null)
			{
				Stock[] stockFurniture = aPPDIBENDAH.stockWeapons;
				foreach (Stock val2 in stockFurniture)
				{
					if (val2 != null && val2.owner > num)
					{
						LogUtils.LogWarning($"Weapon owner index {val2.owner} is out of bounds. Resetting to 1.");
						val2.owner = 1;
					}
				}
			}
			Character[] savedChars = aPPDIBENDAH.savedChars;
			foreach (Character val3 in savedChars)
			{
				if (val3 == null)
				{
					continue;
				}
				for (int m = 1; m < val3.relation.Length; m++)
				{
					if (val3.relation[m] > num)
					{
						LogUtils.LogWarning($"Relationship character index {val3.relation[m]} is out of bounds. Resetting to 1.");
						val3.relation[m] = 1;
					}
				}
				if (val3.grudge > num)
				{
					LogUtils.LogWarning($"Grudge character index {val3.grudge} is out of bounds. Resetting to 1.");
					val3.grudge = 1;
				}
				if (val3.team > num)
				{
					LogUtils.LogWarning($"Team character index {val3.team} is out of bounds. Resetting to 1.");
					val3.team = 1;
				}
			}
			LogUtils.LogInfo("Save data validation complete.");
		}
	}
	public static class TextureUtils
	{
		public static Texture2D ResizeTexture(Texture2D original, int width, int height)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			RenderTexture val = (RenderTexture.active = RenderTexture.GetTemporary(width, height));
			Graphics.Blit((Texture)(object)original, val);
			Texture2D val2 = new Texture2D(width, height);
			val2.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
			val2.Apply();
			RenderTexture.active = null;
			RenderTexture.ReleaseTemporary(val);
			return val2;
		}
	}
	public static class TypeUtils
	{
		public static bool IsValid(Type type, string value)
		{
			switch (Type.GetTypeCode(type))
			{
			case TypeCode.Boolean:
				return AnimationParser.ParseBool(value).Item2;
			case TypeCode.Byte:
			{
				byte result8;
				return byte.TryParse(value, out result8);
			}
			case TypeCode.Char:
			{
				char result9;
				return char.TryParse(value, out result9);
			}
			case TypeCode.DateTime:
			{
				DateTime result10;
				return DateTime.TryParse(value, out result10);
			}
			case TypeCode.Decimal:
			{
				decimal result7;
				return decimal.TryParse(value, out result7);
			}
			case TypeCode.Double:
			{
				double result12;
				return double.TryParse(value, out result12);
			}
			case TypeCode.Int16:
			{
				short result11;
				return short.TryParse(value, out result11);
			}
			case TypeCode.Int32:
				if (type.IsEnum)
				{
					bool num = Enum.GetNames(type).Any((string x) => x.Equals(value, StringComparison.OrdinalIgnoreCase));
					int result6;
					bool flag = int.TryParse(value, out result6) && Enum.IsDefined(type, result6);
					return num || flag;
				}
				return AnimationParser.ParseInt(value).Item2;
			case TypeCode.Int64:
			{
				long result5;
				return long.TryParse(value, out result5);
			}
			case TypeCode.SByte:
			{
				sbyte result4;
				return sbyte.TryParse(value, out result4);
			}
			case TypeCode.Single:
				return AnimationParser.ParseFloat(value).Item2;
			case TypeCode.String:
				return true;
			case TypeCode.UInt16:
			{
				ushort result3;
				return ushort.TryParse(value, out result3);
			}
			case TypeCode.UInt32:
			{
				uint result2;
				return uint.TryParse(value, out result2);
			}
			case TypeCode.UInt64:
			{
				ulong result;
				return ulong.TryParse(value, out result);
			}
			case TypeCode.Object:
				return false;
			default:
				return false;
			}
		}
	}
	public static class VectorUtils
	{
		public static Vector3 Round(this Vector3 vector, int decimals)
		{
			//IL_0000: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3((float)Math.Round(vector.x, decimals), (float)Math.Round(vector.y, decimals), (float)Math.Round(vector.z, decimals));
		}
	}
}
namespace HTCCL.Updates
{
	internal class GeneratedVersionDiff : VersionDiff
	{
	}
	internal class VersionData
	{
		public static void WriteVersionData()
		{
			string contents = JsonConvert.SerializeObject((object)new VanillaCounts());
			if (!Directory.Exists(Locations.Debug.FullName))
			{
				Directory.CreateDirectory(Locations.Debug.FullName);
			}
			File.WriteAllText(Path.Combine(Locations.Debug.FullName, "VanillaCounts.Data.json"), contents);
		}
	}
	internal abstract class VersionDiff
	{
		public int BodyFemaleCountDiff;

		public int FaceFemaleCountDiff;

		public List<int> FleshCountsDiff = new List<int>
		{
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0
		};

		public int KneepadCountDiff;

		public List<int> MaterialCountsDiff = new List<int>
		{
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0
		};

		public int MusicCountDiff;

		public List<int> ShapeCountsDiff = new List<int>
		{
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0
		};

		public int SpecialFootwearCountDiff;

		public int TransparentHairHairstyleCountDiff;

		public int TransparentHairMaterialCountDiff;

		public static VersionDiff GetVersionDiff(VanillaCounts contentMapVanillaCounts)
		{
			GeneratedVersionDiff generatedVersionDiff = new GeneratedVersionDiff();
			generatedVersionDiff.MaterialCountsDiff = new List<int>();
			generatedVersionDiff.FleshCountsDiff = new List<int>();
			generatedVersionDiff.ShapeCountsDiff = new List<int>();
			for (int i = 0; i < 40; i++)
			{
				generatedVersionDiff.MaterialCountsDiff.Add(VanillaCounts.Data.MaterialCounts[i] - contentMapVanillaCounts.MaterialCounts[i]);
				generatedVersionDiff.FleshCountsDiff.Add(VanillaCounts.Data.FleshCounts[i] - contentMapVanillaCounts.FleshCounts[i]);
				generatedVersionDiff.ShapeCountsDiff.Add(VanillaCounts.Data.ShapeCounts[i] - contentMapVanillaCounts.ShapeCounts[i]);
			}
			generatedVersionDiff.BodyFemaleCountDiff = VanillaCounts.Data.BodyFemaleCount - contentMapVanillaCounts.BodyFemaleCount;
			generatedVersionDiff.FaceFemaleCountDiff = VanillaCounts.Data.FaceFemaleCount - contentMapVanillaCounts.FaceFemaleCount;
			generatedVersionDiff.SpecialFootwearCountDiff = VanillaCounts.Data.SpecialFootwearCount - contentMapVanillaCounts.SpecialFootwearCount;
			generatedVersionDiff.TransparentHairMaterialCountDiff = VanillaCounts.Data.TransparentHairMaterialCount - contentMapVanillaCounts.TransparentHairMaterialCount;
			generatedVersionDiff.TransparentHairHairstyleCountDiff = VanillaCounts.Data.TransparentHairHairstyleCount - contentMapVanillaCounts.TransparentHairHairstyleCount;
			generatedVersionDiff.KneepadCountDiff = VanillaCounts.Data.KneepadCount - contentMapVanillaCounts.KneepadCount;
			generatedVersionDiff.MusicCountDiff = VanillaCounts.Data.MusicCount - contentMapVanillaCounts.MusicCount;
			return generatedVersionDiff;
		}
	}
	internal class VersionDiffGroup : VersionDiff
	{
		public VersionDiffGroup(params VersionDiff[] diffs)
		{
			foreach (VersionDiff versionDiff in diffs)
			{
				MaterialCountsDiff = MaterialCountsDiff.Zip(versionDiff.MaterialCountsDiff, (int a, int b) => a + b).ToList();
				FleshCountsDiff = FleshCountsDiff.Zip(versionDiff.FleshCountsDiff, (int a, int b) => a + b).ToList();
				ShapeCountsDiff = ShapeCountsDiff.Zip(versionDiff.ShapeCountsDiff, (int a, int b) => a + b).ToList();
				BodyFemaleCountDiff += versionDiff.BodyFemaleCountDiff;
				FaceFemaleCountDiff += versionDiff.FaceFemaleCountDiff;
				SpecialFootwearCountDiff += versionDiff.SpecialFootwearCountDiff;
				TransparentHairMaterialCountDiff += versionDiff.TransparentHairMaterialCountDiff;
				TransparentHairHairstyleCountDiff += versionDiff.TransparentHairHairstyleCountDiff;
				KneepadCountDiff += versionDiff.KneepadCountDiff;
				MusicCountDiff += versionDiff.MusicCountDiff;
			}
		}
	}
}
namespace HTCCL.Saves
{
	internal class BetterCharacterData
	{
		public int? absent;

		public int? age;

		public int? agreement;

		public float? angle;

		public int? anim;

		public float? armMass;

		public float? bodyMass;

		public int? cell;

		public int? chained;

		public BetterCostumeData[] costumeC;

		public int? cuffed;

		public int? dead;

		public float? demeanor;

		public int? gender;

		public int? grudge;

		public float? headSize;

		public float? health;

		public float? healthLimit;

		public float? height;

		public int? home;

		public int? id;

		public int? injury;

		public int? injuryTime;

		public float? legMass;

		public int? location;

		public int?[] moveAttack = new int?[6];

		public int?[] moveBack = new int?[9];

		public int?[] moveCrush = new int?[6];

		public int?[] moveFront = new int?[17];

		public int?[] moveGround = new int?[7];

		public float? muscleMass;

		public string musicC;

		public float? musicSpeed;

		public string name;

		public int? negotiated;

		public int? news;

		public float?[] oldStat = new float?[7];

		public int? platform;

		public int? player;

		public int? possessive;

		public int? pregnant;

		public int? promo;

		public int? promoVariable;

		public int? prop;

		public string[] relationC = new string[7];

		public int? role;

		public int?[] scar = new int?[17];

		public int? seat;

		public float? spirit;

		public int? stance;

		public float?[] stat = new float?[7];

		public int?[] taunt = new int?[4];

		public int? tauntHandshake;

		public int? tauntWave;

		public int? team;

		public string teamName;

		public int? toilet;

		public float? voice;

		public int? worked;

		public int? warrant;

		public int? warrantVariable;

		public int? warrantVictim;

		public int? warrantWitness;

		public float? x;

		public float? y;

		public float? z;

		public string VERSION = "1.0.0-HT";

		public static BetterCharacterData FromRegularCharacter(Character character, Character[] allCharacters, bool ignoreRelations = false)
		{
			BetterCharacterData betterCharacterData = JsonConvert.DeserializeObject<BetterCharacterData>(JsonConvert.SerializeObject((object)character));
			betterCharacterData.costumeC = new BetterCostumeData[character.costume.Length];
			for (int i = 0; i < character.costume.Length; i++)
			{
				betterCharacterData.costumeC[i] = BetterCostumeData.FromRegularCostumeData(character.costume[i]);
			}
			betterCharacterData.relationC = new string[character.relation.Length];
			if (!ignoreRelations)
			{
				for (int j = 0; j < character.relation.Length; j++)
				{
					if (j == 0)
					{
						betterCharacterData.relationC[j] = "0";
					}
					else if (character.relation[j] >= allCharacters.Length)
					{
						betterCharacterData.relationC[j] = "0";
					}
					else
					{
						betterCharacterData.relationC[j] = ((character.relation[j] == 0) ? "0" : (allCharacters[j].name + "=" + character.relation[j]));
					}
				}
			}
			else
			{
				for (int k = 0; k < character.relation.Length; k++)
				{
					betterCharacterData.relationC[k] = "0";
				}
			}
			betterCharacterData.grudge = 0;
			return betterCharacterData;
		}

		public Character ToRegularCharacter(Character[] allCharacters)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Character val = JsonConvert.DeserializeObject<Character>(JsonConvert.SerializeObject((object)this), new JsonSerializerSettings
			{
				NullValueHandling = (NullValueHandling)1
			});
			val.costume = (Costume[])(object)new Costume[costumeC.Length];
			for (int i = 0; i < costumeC.Length; i++)
			{
				if (costumeC[i] == null)
				{
					val.costume[i] = null;
					continue;
				}
				costumeC[i].charID = val.id;
				val.costume[i] = costumeC[i].ToRegularCostume();
			}
			val.relation = new int[Characters.no_chars + 2];
			if (VERSION.EndsWith("-HT"))
			{
				for (int j = 0; j < relationC.Length; j++)
				{
					if (j == 0 || relationC[j] == "0")
					{
						continue;
					}
					string[] array = relationC[j].Split('=');
					string name = array[0];
					try
					{
						int num = allCharacters.Single((Character c) => c != null && c.name != null && c.name == name).id;
						val.relation[num] = int.Parse(array[1]);
					}
					catch (Exception)
					{
						if (j >= val.relation.Length)
						{
							LogUtils.LogWarning("Failed to find character with name " + name + ", skipping because id is out of bounds.");
							continue;
						}
						val.relation[j] = int.Parse(array[1]);
						LogUtils.LogWarning("Failed to find character with name " + name + ", using id instead.");
					}
				}
			}
			val.grudge = 0;
			val.team = 0;
			return val;
		}

		public void MergeIntoCharacter(Character character)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			FieldInfo[] fields = typeof(BetterCharacterData).GetFields();
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!fieldInfo.FieldType.IsArray)
				{
					continue;
				}
				Array array = (Array)fieldInfo.GetValue(this);
				if (array == null)
				{
					continue;
				}
				bool flag = true;
				bool flag2 = true;
				foreach (object item in array)
				{
					if (item != null)
					{
						flag = false;
					}
					else
					{
						flag2 = false;
					}
				}
				if (flag)
				{
					fieldInfo.SetValue(this, null);
				}
				else if (!flag2)
				{
					throw new Exception("It is not possible to merge arrays with both null and non-null elements.");
				}
			}
			JsonConvert.PopulateObject(JsonConvert.SerializeObject((object)this), (object)character, new JsonSerializerSettings
			{
				NullValueHandling = (NullValueHandling)1
			});
			character.grudge = 0;
			character.team = 0;
		}
	}
	internal class BetterCharacterDataFile
	{
		internal string _guid;

		public BetterCharacterData characterData;

		public string findMode;

		public string findName;

		public string overrideMode;

		[JsonIgnore]
		public BetterCharacterData CharacterData
		{
			get
			{
				if (characterData == null)
				{
					return new BetterCharacterData();
				}
				return characterData;
			}
		}

		[JsonIgnore]
		public string OverrideMode
		{
			get
			{
				if (overrideMode == null)
				{
					return "append";
				}
				return overrideMode;
			}
		}

		[JsonIgnore]
		public string FindMode
		{
			get
			{
				if (findMode == null)
				{
					if (!(overrideMode == "append"))
					{
						return "name_then_id";
					}
					return "";
				}
				return findMode;
			}
		}

		[JsonIgnore]
		public string FindName => findName;
	}
	internal class BetterCostumeData
	{
		public float[] b = new float[40];

		public int charID;

		public string[] fleshC = new string[40];

		public float[] g = new float[40];

		public int id;

		public int limb;

		public float[] r = new float[40];

		public string[] shapeC = new string[40];

		public string[] textureC = new string[40];

		public static BetterCostumeData FromRegularCostumeData(Costume costume)
		{
			if (costume == null)
			{
				return null;
			}
			BetterCostumeData betterCostumeData = JsonConvert.DeserializeObject<BetterCostumeData>(JsonConvert.SerializeObject((object)costume));
			for (int i = 0; i < costume.texture.Length; i++)
			{
				if (costume.texture[i] > VanillaCounts.Data.MaterialCounts[i])
				{
					int index = costume.texture[i] - VanillaCounts.Data.MaterialCounts[i] - 1;
					string text = ContentMappings.ContentMap.MaterialNameMap[i][index];
					betterCostumeData.textureC[i] = "Custom/" + text;
				}
				else if (i == 3 && costume.texture[i] < -VanillaCounts.Data.FaceFemaleCount)
				{
					int index2 = -costume.texture[i] - VanillaCounts.Data.FaceFemaleCount - 1;
					string text2 = ContentMappings.ContentMap.FaceFemaleNameMap[index2];
					betterCostumeData.textureC[i] = "Custom/" + text2;
				}
				else if (i == 14 && costume.texture[i] < -VanillaCounts.Data.SpecialFootwearCount)
				{
					int index3 = -costume.texture[i] - VanillaCounts.Data.SpecialFootwearCount - 1;
					string text3 = ContentMappings.ContentMap.SpecialFootwearNameMap[index3];
					betterCostumeData.textureC[i] = "Custom/" + text3;
				}
				else if (i == 15 && costume.texture[i] < -VanillaCounts.Data.SpecialFootwearCount)
				{
					int index4 = -costume.texture[i] - VanillaCounts.Data.SpecialFootwearCount - 1;
					string text4 = ContentMappings.ContentMap.SpecialFootwearNameMap[index4];
					betterCostumeData.textureC[i] = "Custom/" + text4;
				}
				else if (i == 17 && costume.texture[i] < -VanillaCounts.Data.TransparentHairMaterialCount)
				{
					int index5 = -costume.texture[i] - VanillaCounts.Data.TransparentHairMaterialCount - 1;
					string text5 = ContentMappings.ContentMap.TransparentHairMaterialNameMap[index5];
					betterCostumeData.textureC[i] = "Custom/" + text5;
				}
				else if (i == 24 && costume.texture[i] < -VanillaCounts.Data.KneepadCount)
				{
					int index6 = -costume.texture[i] - VanillaCounts.Data.KneepadCount - 1;
					string text6 = ContentMappings.ContentMap.KneepadNameMap[index6];
					betterCostumeData.textureC[i] = "Custom/" + text6;
				}
				else if (i == 25 && costume.texture[i] < -VanillaCounts.Data.KneepadCount)
				{
					int index7 = -costume.texture[i] - VanillaCounts.Data.KneepadCount - 1;
					string text7 = ContentMappings.ContentMap.KneepadNameMap[index7];
					betterCostumeData.textureC[i] = "Custom/" + text7;
				}
				else
				{
					int num = costume.texture[i];
					betterCostumeData.textureC[i] = "Vanilla/" + num;
				}
			}
			for (int j = 0; j < costume.flesh.Length; j++)
			{
				if (j == 17 && costume.flesh[j] == 100)
				{
					int num2 = costume.flesh[j];
					betterCostumeData.fleshC[j] = "Vanilla/" + num2;
				}
				else if (costume.flesh[j] > VanillaCounts.Data.FleshCounts[j])
				{
					int num3 = costume.flesh[j] - VanillaCounts.Data.FleshCounts[j] - 1;
					if (num3 >= ContentMappings.ContentMap.FleshNameMap[j].Count || num3 < 0)
					{
						betterCostumeData.fleshC[j] = "Vanilla/" + costume.flesh[j];
						continue;
					}
					string text8 = ContentMappings.ContentMap.FleshNameMap[j][num3];
					betterCostumeData.fleshC[j] = "Custom/" + text8;
				}
				else if (j == 2 && costume.flesh[j] < -VanillaCounts.Data.BodyFemaleCount)
				{
					int index8 = -costume.flesh[j] - VanillaCounts.Data.BodyFemaleCount - 1;
					string text9 = ContentMappings.ContentMap.BodyFemaleNameMap[index8];
					betterCostumeData.fleshC[j] = "Custom/" + text9;
				}
				else
				{
					int num4 = costume.flesh[j];
					betterCostumeData.fleshC[j] = "Vanilla/" + num4;
				}
			}
			for (int k = 0; k < costume.shape.Length; k++)
			{
				if ((costume.shape[k] > 50 && costume.shape[k] % 10 == 0) || VanillaCounts.Data.ShapeCounts[k] == 0)
				{
					int num5 = costume.shape[k];
					betterCostumeData.shapeC[k] = "Vanilla/" + num5;
				}
				else if (costume.shape[k] > VanillaCounts.Data.ShapeCounts[k])
				{
					int num6 = costume.shape[k] - VanillaCounts.Data.ShapeCounts[k] - 1;
					if (num6 >= ContentMappings.ContentMap.ShapeNameMap[k].Count || num6 < 0)
					{
						betterCostumeData.shapeC[k] = "Vanilla/" + costume.shape[k];
						continue;
					}
					string text10 = ContentMappings.ContentMap.ShapeNameMap[k][num6];
					betterCostumeData.shapeC[k] = "Custom/" + text10;
				}
				else if (k == 17 && costume.shape[k] < -VanillaCounts.Data.TransparentHairHairstyleCount)
				{
					int index9 = -costume.shape[k] - VanillaCounts.Data.TransparentHairHairstyleCount - 1;
					string text11 = ContentMappings.ContentMap.TransparentHairHairstyleNameMap[index9];
					betterCostumeData.shapeC[k] = "Custom/" + text11;
				}
				else
				{
					int num7 = costume.shape[k];
					betterCostumeData.shapeC[k] = "Vanilla/" + num7;
				}
			}
			return betterCostumeData;
		}

		public Costume ToRegularCostume()
		{
			Costume val = JsonConvert.DeserializeObject<Costume>(JsonConvert.SerializeObject((object)this));
			for (int i = 0; i < val.texture.Length; i++)
			{
				if (i == 3 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item = textureC[i].Substring(7);
						int num = ContentMappings.ContentMap.FaceFemaleNameMap.IndexOf(item);
						if (num >= 0)
						{
							val.texture[i] = -num - VanillaCounts.Data.FaceFemaleCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				else if (i == 14 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item2 = textureC[i].Substring(7);
						int num2 = ContentMappings.ContentMap.SpecialFootwearNameMap.IndexOf(item2);
						if (num2 >= 0)
						{
							val.texture[i] = -num2 - VanillaCounts.Data.SpecialFootwearCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				else if (i == 15 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item3 = textureC[i].Substring(7);
						int num3 = ContentMappings.ContentMap.SpecialFootwearNameMap.IndexOf(item3);
						if (num3 >= 0)
						{
							val.texture[i] = -num3 - VanillaCounts.Data.SpecialFootwearCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				else if (i == 17 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item4 = textureC[i].Substring(7);
						int num4 = ContentMappings.ContentMap.TransparentHairMaterialNameMap.IndexOf(item4);
						if (num4 >= 0)
						{
							val.texture[i] = -num4 - VanillaCounts.Data.TransparentHairMaterialCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				else if (i == 24 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item5 = textureC[i].Substring(7);
						int num5 = ContentMappings.ContentMap.KneepadNameMap.IndexOf(item5);
						if (num5 >= 0)
						{
							val.texture[i] = -num5 - VanillaCounts.Data.KneepadCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				else if (i == 25 && textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item6 = textureC[i].Substring(7);
						int num6 = ContentMappings.ContentMap.KneepadNameMap.IndexOf(item6);
						if (num6 >= 0)
						{
							val.texture[i] = -num6 - VanillaCounts.Data.KneepadCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				if (textureC[i].StartsWith("Custom/"))
				{
					try
					{
						string item7 = textureC[i].Substring(7);
						int num7 = ContentMappings.ContentMap.MaterialNameMap[i].IndexOf(item7);
						if (num7 >= 0)
						{
							val.texture[i] = num7 + VanillaCounts.Data.MaterialCounts[i] + 1;
							continue;
						}
						LogUtils.LogWarning("Failed to find material from name " + textureC[i] + ", setting to 0.");
						val.texture[i] = 0;
					}
					catch
					{
						LogUtils.LogWarning("Failed to find material from name " + textureC[i] + ", setting to 0.");
						val.texture[i] = 0;
					}
				}
				else
				{
					string s = textureC[i].Substring(8);
					val.texture[i] = int.Parse(s);
				}
			}
			for (int j = 0; j < val.flesh.Length; j++)
			{
				if (j == 2 && fleshC[j].StartsWith("Custom/"))
				{
					try
					{
						string item8 = fleshC[j].Substring(7);
						int num8 = ContentMappings.ContentMap.BodyFemaleNameMap.IndexOf(item8);
						if (num8 >= 0)
						{
							val.flesh[j] = -num8 - VanillaCounts.Data.BodyFemaleCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				if (fleshC[j].StartsWith("Custom/"))
				{
					try
					{
						string item9 = fleshC[j].Substring(7);
						int num9 = ContentMappings.ContentMap.FleshNameMap[j].IndexOf(item9);
						if (num9 >= 0)
						{
							val.flesh[j] = num9 + VanillaCounts.Data.FleshCounts[j] + 1;
							continue;
						}
						LogUtils.LogWarning("Failed to find flesh from name " + fleshC[j] + ", setting to 0.");
						val.flesh[j] = 0;
					}
					catch
					{
						LogUtils.LogWarning("Failed to find flesh from name " + fleshC[j] + ", setting to 0.");
						val.flesh[j] = 0;
					}
				}
				else
				{
					string s2 = fleshC[j].Substring(8);
					val.flesh[j] = int.Parse(s2);
				}
			}
			for (int k = 0; k < val.shape.Length; k++)
			{
				val.shape[k] = 0;
				if (k == 17 && shapeC[k].StartsWith("Custom/"))
				{
					try
					{
						string item10 = shapeC[k].Substring(7);
						int num10 = ContentMappings.ContentMap.TransparentHairHairstyleNameMap.IndexOf(item10);
						if (num10 >= 0)
						{
							val.shape[k] = -num10 - VanillaCounts.Data.TransparentHairHairstyleCount - 1;
							continue;
						}
					}
					catch
					{
					}
				}
				if (shapeC[k].StartsWith("Custom/"))
				{
					try
					{
						string item11 = shapeC[k].Substring(7);
						int num11 = ContentMappings.ContentMap.ShapeNameMap[k].IndexOf(item11);
						if (num11 >= 0)
						{
							val.shape[k] = num11 + VanillaCounts.Data.ShapeCounts[k] + 1;
							continue;
						}
						LogUtils.LogWarning("Failed to find shape from name " + shapeC[k] + ", setting to 0.");
						val.shape[k] = 0;
					}
					catch
					{
						LogUtils.LogWarning("Failed to find shape from name " + shapeC[k] + ", setting to 0.");
						val.shape[k] = 0;
					}
				}
				else
				{
					string s3 = shapeC[k].Substring(8);
					val.shape[k] = int.Parse(s3);
				}
			}
			return val;
		}
	}
	internal class BetterSaveData
	{
		public static BetterSaveData Instance { get; set; } = new BetterSaveData();


		public List<BetterCharacterData> CharacterData { get; set; } = new List<BetterCharacterData>();


		public void ToRegularSaveData(ref SaveData baseData, Character[] allCharacters)
		{
			baseData.savedChars = (Character[])(object)new Character[CharacterData.Count];
			for (int i = 0; i < CharacterData.Count; i++)
			{
				baseData.savedChars[i] = CharacterData[i].ToRegularCharacter(allCharacters);
			}
		}

		public void FromRegularSaveData(SaveData baseData, Character[] allCharacters)
		{
			CharacterData = new List<BetterCharacterData>(baseData.savedChars.Length);
			for (int i = 0; i < baseData.savedChars.Length; i++)
			{
				CharacterData.Add(BetterCharacterData.FromRegularCharacter(baseData.savedChars[i], allCharacters));
			}
		}
	}
	internal class CharacterMappings
	{
		private static CharacterMappings _instance;

		internal static CharacterMappings CharacterMap
		{
			get
			{
				if (_instance == null)
				{
					_instance = Load();
				}
				return _instance;
			}
		}

		public List<string> PreviouslyImportedCharacters { get; set; } = new List<string>();


		public List<int> PreviouslyImportedCharacterIds { get; set; } = new List<int>();


		public void Save()
		{
			string fullName = Locations.CharacterMappings.FullName;
			string contents = JsonConvert.SerializeObject((object)this, (Formatting)1);
			File.WriteAllText(fullName, contents);
			LogUtils.LogDebug("Saved custom content map to " + fullName + ".");
		}

		public static CharacterMappings Load()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			string fullName = Locations.CharacterMappings.FullName;
			if (!File.Exists(fullName))
			{
				return new CharacterMappings();
			}
			try
			{
				CharacterMappings characterMappings = JsonConvert.DeserializeObject<CharacterMappings>(File.ReadAllText(fullName), new JsonSerializerSettings
				{
					ObjectCreationHandling = (ObjectCreationHandling)2
				});
				for (int i = 0; i < characterMappings.PreviouslyImportedCharacters.Count; i++)
				{
					if (characterMappings.PreviouslyImportedCharacters[i].EndsWith(".json"))
					{
						characterMappings.PreviouslyImportedCharacters[i] = characterMappings.PreviouslyImportedCharacters[i].Substring(0, characterMappings.PreviouslyImportedCharacters[i].Length - 5);
					}
					else if (characterMappings.PreviouslyImportedCharacters[i].EndsWith(".character"))
					{
						characterMappings.PreviouslyImportedCharacters[i] = characterMappings.PreviouslyImportedCharacters[i].Substring(0, characterMappings.PreviouslyImportedCharacters[i].Length - 10);
					}
				}
				return characterMappings;
			}
			catch (Exception arg)
			{
				LogUtils.LogError($"Unable to load custom character map: {arg}");
				return new CharacterMappings();
			}
		}

		public void AddPreviouslyImportedCharacter(string name, int id)
		{
			if (name.EndsWith(".json"))
			{
				name = name.Substring(0, name.Length - 5);
			}
			else if (name.EndsWith(".character"))
			{
				name = name.Substring(0, name.Length - 10);
			}
			if (!PreviouslyImportedCharacters.Contains(name))
			{
				PreviouslyImportedCharacters.Add(name);
				PreviouslyImportedCharacterIds.Add(id);
			}
		}
	}
	internal class ContentMappings
	{
		private static ContentMappings _instance;

		internal static ContentMappings ContentMap => _instance ?? (_instance = new ContentMappings());

		public List<ContentList> MaterialNameMap { get; set; } = new List<ContentList>();


		public List<ContentList> FleshNameMap { get; set; } = new List<ContentList>();


		public List<ContentList> ShapeNameMap { get; set; } = new List<ContentList>();


		public ContentList FaceFemaleNameMap { get; set; } = new ContentList();


		public ContentList BodyFemaleNameMap { get; set; } = new ContentList();


		public ContentList SpecialFootwearNameMap { get; set; } = new ContentList();


		public ContentList TransparentHairMaterialNameMap { get; set; } = new ContentList();


		public ContentList TransparentHairHairstyleNameMap { get; set; } = new ContentList();


		public ContentList KneepadNameMap { get; set; } = new ContentList();


		public ContentList MusicNameMap { get; set; } = new ContentList();


		public ContentList AnimationNameMap { get; set; } = new ContentList();


		public VanillaCounts VanillaCounts { get; set; }

		public float GameVersion { get; set; } = Plugin.GameVersion;


		internal ContentMappings()
		{
			for (int i = 0; i < 40; i++)
			{
				MaterialNameMap.Add(new ContentList());
				FleshNameMap.Add(new ContentList());
				ShapeNameMap.Add(new ContentList());
			}
		}

		public void Save()
		{
			string fullName = Locations.ContentMappings.FullName;
			string contents = JsonConvert.SerializeObject((object)this, (Formatting)1);
			File.WriteAllText(fullName, contents);
			LogUtils.LogDebug("Saved custom content map to " + fullName + ".");
		}

		public static ContentMappings Load()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			string fullName = Locations.ContentMappings.FullName;
			if (!File.Exists(fullName))
			{
				return new ContentMappings();
			}
			try
			{
				return JsonConvert.DeserializeObject<ContentMappings>(File.ReadAllText(fullName), new JsonSerializerSettings
				{
					ObjectCreationHandling = (ObjectCreationHandling)2
				});
			}
			catch (Exception arg)
			{
				LogUtils.LogError($"Unable to load custom content map: {arg}");
				return new ContentMappings();
			}
		}
	}
	internal class MetaFile
	{
		private static MetaFile _instance;

		internal static MetaFile Data => _instance ?? (_instance = Load());

		public List<string> PrefixPriorityOrder { get; set; } = new List<string>();


		public bool HidePriorityScreenNextTime { get; set; }

		public bool FirstLaunch { get; set; } = true;


		public int TimesLaunched { get; set; }

		public string PreviousUser { get; set; } = "";


		public void Save()
		{
			string fullName = Locations.Meta.FullName;
			string contents = JsonConvert.SerializeObject((object)this, (Formatting)1);
			File.WriteAllText(fullName, contents);
			LogUtils.LogDebug("Saved meta file to " + fullName + ".");
		}

		public static MetaFile Load()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			try
			{
				string fullName = Locations.Meta.FullName;
				if (!File.Exists(fullName))
				{
					return new MetaFile().IncrementTimesLaunched();
				}
				return JsonConvert.DeserializeObject<MetaFile>(File.ReadAllText(fullName), new JsonSerializerSettings
				{
					ObjectCreationHandling = (ObjectCreationHandling)2
				}).IncrementTimesLaunched();
			}
			catch (Exception arg)
			{
				LogUtils.LogError($"Unable to load meta file: {arg}");
				return new MetaFile();
			}
		}

		public MetaFile IncrementTimesLaunched()
		{
			if (TimesLaunched != int.MaxValue)
			{
				TimesLaunched++;
			}
			return this;
		}
	}
	internal class NonSavedData
	{
		public static List<Character> DeletedCharacters { get; set; } = new List<Character>();

	}
}
namespace HTCCL.Patches
{
	[HarmonyPatch]
	internal class AnimationPatch
	{
		[HarmonyPatch(typeof(DFOGOCNBECG), "BCHJKLDMDFB")]
		[HarmonyPrefix]
		public static void Player_BCHJKLDMDFB(DFOGOCNBECG __instance)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			vEOoIWAQxH vEOoIWAQxH = vEOoIWAQxH.GrptxBlMwc(__instance);
			Animator val = vEOoIWAQxH.vZWjMbzZnx;
			if ((Object)(object)val == (Object)null || (Object)(object)val.runtimeAnimatorController == (Object)null)
			{
				return;
			}
			AnimatorOverrideController val2 = (AnimatorOverrideController)val.runtimeAnimatorController;
			if (vEOoIWAQxH.pYEyJQeonv >= 1000000)
			{
				if (!((Object)(object)CustomContent.CustomAnimations[vEOoIWAQxH.pYEyJQeonv - 1000000].ReceiveAnim != (Object)null))
				{
					List<KeyValuePair<AnimationClip, AnimationClip>> list = new List<KeyValuePair<AnimationClip, AnimationClip>>();
					((AnimatorOverrideController)val.runtimeAnimatorController).GetOverrides(list);
					if (!list.Exists((KeyValuePair<AnimationClip, AnimationClip> x) => (Object)(object)x.Value != (Object)null) || ((Object)val2["Assist11"]).name != ((Object)CustomContent.CustomAnimations[vEOoIWAQxH.pYEyJQeonv - 1000000].Anim).name)
					{
						val2["Assist11"] = CustomContent.CustomAnimations[vEOoIWAQxH.pYEyJQeonv - 1000000].Anim;
					}
					Animations.DoCustomAnimation(vEOoIWAQxH.QmAmgyRksS(vEOoIWAQxH), vEOoIWAQxH.pYEyJQeonv, CustomContent.CustomAnimations[vEOoIWAQxH.pYEyJQeonv - 1000000].ForwardSpeedMultiplier);
				}
			}
			else
			{
				List<KeyValuePair<AnimationClip, AnimationClip>> list2 = new List<KeyValuePair<AnimationClip, AnimationClip>>();
				((AnimatorOverrideController)val.runtimeAnimatorController).GetOverrides(list2);
				if (vEOoIWAQxH.lcverwpzoI == 0 && list2.Exists((KeyValuePair<AnimationClip, AnimationClip> x) => (Object)(object)x.Value != (Object)null))
				{
					val2["Assist11"] = null;
				}
			}
		}

		[HarmonyPatch(typeof(DFOGOCNBECG), "JPNLADBMDNK")]
		[HarmonyPrefix]
		public static bool Player_JPNLADBMDNK(ref DFOGOCNBECG __instance)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			vEOoIWAQxH vEOoIWAQxH = vEOoIWAQxH.GrptxBlMwc(__instance);
			Animator val = vEOoIWAQxH.vZWjMbzZnx;
			if ((Object)(object)val == (Object)null || (Object)(object)val.runtimeAnimatorController ==