Decompiled source of CosmeticResync v1.0.0

plugins/CosmeticResync.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using CosmeticResync.Patches;
using HarmonyLib;
using Newtonsoft.Json;
using UnityEngine;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CosmeticResync")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CosmeticResync")]
[assembly: AssemblyCopyright("Copyright © BlueAmulet 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("eb3c5a88-48ff-431d-9961-15eee8223f66")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace CosmeticResync
{
	[BepInPlugin("BlueAmulet.CosmeticResync", "CosmeticResync", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class CosmeticResync : BaseUnityPlugin
	{
		internal const string Name = "CosmeticResync";

		internal const string Author = "BlueAmulet";

		internal const string ID = "BlueAmulet.CosmeticResync";

		internal const string Version = "1.0.0";

		internal static ManualLogSource Logger;

		public void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Harmony val = new Harmony("BlueAmulet.CosmeticResync");
			Logger.LogInfo((object)"Applying Harmony patches");
			val.PatchAll(Assembly.GetExecutingAssembly());
			if (Chainloader.PluginInfos.TryGetValue("com.github.Spider-XD-Gaming.Multi-Cosmetic", out var value))
			{
				MultiCosmeticPatch.MultiCosmetic = value.Instance;
				if (MultiCosmeticPatch.GetCurrentDataField())
				{
					Type type = ((object)value.Instance).GetType();
					MethodInfo methodInfo = AccessTools.Method(type, "dataFromString", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						val.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(MultiCosmeticPatch), "PrefixMCDataFromString", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					else
					{
						Logger.LogError((object)"Failed to find Multi_Cosmetic.Plugin.dataFromString()");
					}
					methodInfo = AccessTools.Method(type, "UpdateCustomPropertiesValue", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(MultiCosmeticPatch), "PostfixUpdateCustomPropertiesValue", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					}
					else
					{
						Logger.LogError((object)"Failed to find Multi_Cosmetic.Plugin.UpdateCustomPropertiesValue()");
					}
				}
			}
			int num = 0;
			foreach (MethodBase patchedMethod in val.GetPatchedMethods())
			{
				Logger.LogInfo((object)("Patched " + patchedMethod.DeclaringType.FullName + "." + patchedMethod.Name));
				num++;
			}
			Logger.LogInfo((object)(num + " patches applied"));
		}
	}
}
namespace CosmeticResync.Patches
{
	[HarmonyPatch(typeof(CharacterCustomization))]
	internal static class CosmeticPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch("TryGetCosmeticsFromSteam")]
		private static bool PrefixTryGetCosmeticsFromSteam(ref CharacterCustomization __instance)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot Resync cosmetics");
				return true;
			}
			int cosmeticFromPrefsOrSteam = GetCosmeticFromPrefsOrSteam("CosmeticResync_Skin", (STEAMSTATTYPE)7, instance.skins);
			if (cosmeticFromPrefsOrSteam > 0)
			{
				CharacterCustomization.SetCharacterSkinColor(cosmeticFromPrefsOrSteam);
			}
			else
			{
				__instance.SetRandomSkinColor();
			}
			int cosmeticFromPrefsOrSteam2 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Eyes", (STEAMSTATTYPE)8, instance.eyes);
			if (cosmeticFromPrefsOrSteam2 > 0)
			{
				CharacterCustomization.SetCharacterEyes(cosmeticFromPrefsOrSteam2);
			}
			else
			{
				__instance.SetRandomEyes();
			}
			int cosmeticFromPrefsOrSteam3 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Mouth", (STEAMSTATTYPE)9, instance.mouths);
			if (cosmeticFromPrefsOrSteam3 > 0)
			{
				CharacterCustomization.SetCharacterMouth(cosmeticFromPrefsOrSteam3);
			}
			else
			{
				__instance.SetRandomMouth();
			}
			int cosmeticFromPrefsOrSteam4 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Accessory", (STEAMSTATTYPE)10, instance.accessories);
			if (cosmeticFromPrefsOrSteam4 > 0)
			{
				CharacterCustomization.SetCharacterAccessory(cosmeticFromPrefsOrSteam4);
			}
			else
			{
				__instance.SetRandomAccessory();
			}
			int cosmeticFromPrefsOrSteam5 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Outfit", (STEAMSTATTYPE)11, instance.fits);
			if (cosmeticFromPrefsOrSteam5 > 0)
			{
				CharacterCustomization.SetCharacterOutfit(cosmeticFromPrefsOrSteam5);
			}
			else
			{
				__instance.SetRandomOutfit();
			}
			int cosmeticFromPrefsOrSteam6 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Hat", (STEAMSTATTYPE)12, instance.hats);
			if (cosmeticFromPrefsOrSteam6 > 0)
			{
				CharacterCustomization.SetCharacterHat(cosmeticFromPrefsOrSteam6);
			}
			else
			{
				__instance.SetRandomHat();
			}
			int cosmeticFromPrefsOrSteam7 = GetCosmeticFromPrefsOrSteam("CosmeticResync_Sash", (STEAMSTATTYPE)17, instance.sashes);
			if (cosmeticFromPrefsOrSteam7 > 0)
			{
				CharacterCustomization.SetCharacterSash(cosmeticFromPrefsOrSteam7);
			}
			else
			{
				CharacterCustomization.SetCharacterSash(0);
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterSkinColor")]
		private static void PostfixSetCharacterSkinColor(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save skin color");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Skin", instance.skins);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterEyes")]
		private static void PostfixSetCharacterEyes(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save eyes");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Eyes", instance.eyes);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterMouth")]
		private static void PostfixSetCharacterMouth(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save mouth");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Mouth", instance.mouths);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterAccessory")]
		private static void PostfixSetCharacterAccessory(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save accessory name");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Accessory", instance.accessories);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterOutfit")]
		private static void PostfixSetCharacterOutfit(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save outfit name");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Outfit", instance.fits);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterHat")]
		private static void PostfixSetCharacterHat(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save hat name");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Hat", instance.hats);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("SetCharacterSash")]
		private static void PostfixSetCharacterSash(int index)
		{
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save sash name");
			}
			else
			{
				ValidateAndSaveCosmetic(index, "CosmeticResync_Sash", instance.sashes);
			}
		}

		private static int GetCosmeticFromPrefsOrSteam(string prefKey, STEAMSTATTYPE steamStatType, CustomizationOption[] options)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			int num = -1;
			if (PlayerPrefs.HasKey(prefKey))
			{
				string @string = PlayerPrefs.GetString(prefKey);
				if (!string.IsNullOrWhiteSpace(@string))
				{
					for (int i = 0; i < options.Length; i++)
					{
						if (((Object)options[i]).name == @string)
						{
							num = i;
							break;
						}
					}
					if (num != -1)
					{
						Debug.Log((object)$"[CosmeticResync] Detected {steamStatType} {@string} as #{num}");
					}
					else
					{
						CosmeticResync.Logger.LogWarning((object)$"{steamStatType} {@string} is no longer available, picking a random option");
					}
				}
			}
			else if (Singleton<AchievementManager>.Instance.GetSteamStatInt(steamStatType, ref num))
			{
				if (num >= options.Length)
				{
					num = -1;
				}
			}
			else
			{
				num = -1;
			}
			return num;
		}

		private static void ValidateAndSaveCosmetic(int index, string prefKey, CustomizationOption[] options)
		{
			if (index < 0 || index >= options.Length)
			{
				CosmeticResync.Logger.LogError((object)$"Customization index #{index} invalid? Cannot save customization for {prefKey}");
			}
			else
			{
				PlayerPrefs.SetString(prefKey, ((Object)options[index]).name);
			}
		}
	}
	[HarmonyPatch]
	internal static class MultiCosmeticPatch
	{
		internal static BaseUnityPlugin MultiCosmetic;

		private static FieldInfo _currentData;

		internal static bool GetCurrentDataField()
		{
			if ((Object)(object)MultiCosmetic == (Object)null)
			{
				CosmeticResync.Logger.LogError((object)"Missing MultiCosmetic instance");
				return false;
			}
			FieldInfo fieldInfo = AccessTools.Field(((object)MultiCosmetic).GetType(), "currentData");
			if (fieldInfo == null)
			{
				CosmeticResync.Logger.LogError((object)"MultiCosmetic missing currentData field");
				return false;
			}
			if (fieldInfo.FieldType != typeof(int[][]))
			{
				CosmeticResync.Logger.LogError((object)"MultiCosmetic.currentData is no longer an int[][]");
				return false;
			}
			_currentData = fieldInfo;
			return true;
		}

		internal static bool PrefixMCDataFromString()
		{
			if ((Object)(object)MultiCosmetic == (Object)null)
			{
				CosmeticResync.Logger.LogError((object)"Missing MultiCosmetic instance, cannot resync MultiCosmetic");
				return true;
			}
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized, cannot resync MultiCosmetic");
				return true;
			}
			if (!PlayerPrefs.HasKey("CosmeticResync_MultiCosmetic"))
			{
				return true;
			}
			string @string = PlayerPrefs.GetString("CosmeticResync_MultiCosmetic");
			if (string.IsNullOrWhiteSpace(@string))
			{
				CosmeticResync.Logger.LogWarning((object)"CosmeticResync_MultiCosmetic has no data, nothing to resync");
				return true;
			}
			try
			{
				string[][] array = JsonConvert.DeserializeObject<string[][]>(@string);
				if (array.Length != 2)
				{
					CosmeticResync.Logger.LogWarning((object)$"CosmeticResync_MultiCosmetic is malformed, expected 2 arrays, got {array.Length}");
					return true;
				}
				int[] cosmeticIndices = GetCosmeticIndices(instance.accessories, array[0], "Accessory");
				int[] cosmeticIndices2 = GetCosmeticIndices(instance.hats, array[1], "Hat");
				CosmeticResync.Logger.LogInfo((object)$"Loaded {cosmeticIndices.Length} accessories and {cosmeticIndices2.Length} hats");
				_currentData.SetValue(MultiCosmetic, new int[2][] { cosmeticIndices, cosmeticIndices2 });
				return false;
			}
			catch (JsonException)
			{
				CosmeticResync.Logger.LogWarning((object)"Failed to deserialize CosmeticResync_MultiCosmetic");
				return true;
			}
		}

		internal static void PostfixUpdateCustomPropertiesValue()
		{
			if ((Object)(object)MultiCosmetic == (Object)null)
			{
				CosmeticResync.Logger.LogError((object)"Missing MultiCosmetic instance? Cannot save MultiCosmetic names");
				return;
			}
			Customization instance = Singleton<Customization>.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				CosmeticResync.Logger.LogError((object)"Customization not initialized? Cannot save MultiCosmetic names");
				return;
			}
			int[][] array = (int[][])_currentData.GetValue(MultiCosmetic);
			if (array.Length != 2)
			{
				CosmeticResync.Logger.LogError((object)$"Expected MultiCosmetic.Plugin.currentData to contain 2 int[], not {array.Length}");
				return;
			}
			string[] cosmeticNames = GetCosmeticNames(instance.accessories, array[0], "Accessory");
			string[] cosmeticNames2 = GetCosmeticNames(instance.hats, array[1], "Hat");
			string text = JsonConvert.SerializeObject((object)new string[2][] { cosmeticNames, cosmeticNames2 });
			PlayerPrefs.SetString("CosmeticResync_MultiCosmetic", text);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PassportManager), "Awake")]
		internal static void Awake(PassportManager __instance)
		{
			Customization component = ((Component)__instance).GetComponent<Customization>();
			if (Object.op_Implicit((Object)(object)component))
			{
				Singleton<Customization>._instance = component;
				CosmeticResync.Logger.LogInfo((object)"Manually updating MultiCosmetic");
				PrefixMCDataFromString();
			}
			else
			{
				CosmeticResync.Logger.LogError((object)"PassportManager not with Customization? Cannot resync MultiCosmetic");
			}
		}

		private static int[] GetCosmeticIndices(CustomizationOption[] options, string[] names, string cosmeticType)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(0);
			for (int i = 0; i < options.Length; i++)
			{
				CustomizationOption val = options[i];
				dictionary[((Object)val).name] = i;
			}
			List<int> list = new List<int>();
			foreach (string text in names)
			{
				if (dictionary.TryGetValue(text, out var value))
				{
					list.Add(value);
				}
				else
				{
					CosmeticResync.Logger.LogWarning((object)(cosmeticType + " " + text + " is no longer available"));
				}
			}
			return list.ToArray();
		}

		private static string[] GetCosmeticNames(CustomizationOption[] options, int[] indices, string cosmeticType)
		{
			List<string> list = new List<string>();
			int num = options.Length;
			foreach (int num2 in indices)
			{
				if (num2 >= 0 && num2 < num)
				{
					list.Add(((Object)options[num2]).name);
				}
				else
				{
					CosmeticResync.Logger.LogWarning((object)$"{cosmeticType} #{num2} is out of range");
				}
			}
			return list.ToArray();
		}
	}
}