using System;
using System.Collections;
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_Fixed")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CosmeticResync_Fixed")]
[assembly: AssemblyCopyright("Copyright © 1101trash 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("eb3c5a88-48ff-431d-9961-15eee8223f66")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
namespace CosmeticResync
{
[BepInPlugin("1101trash.CosmeticResync_Fixed", "CosmeticResync_Fixed", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class CosmeticResync : BaseUnityPlugin
{
internal const string Name = "CosmeticResync_Fixed";
internal const string Author = "1101trash";
internal const string ID = "1101trash.CosmeticResync_Fixed";
internal const string Version = "1.1.0";
internal static CosmeticResync Instance;
internal static ManualLogSource Logger;
public void Awake()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Expected O, but got Unknown
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Expected O, but got Unknown
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
Harmony val = new Harmony("1101trash.CosmeticResync_Fixed");
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 text = PlayerPrefs.GetString(prefKey);
if (!string.IsNullOrWhiteSpace(text))
{
for (int i = 0; i < options.Length; i++)
{
if (((Object)options[i]).name == text)
{
num = i;
break;
}
}
if (num != -1)
{
Debug.Log((object)$"[CosmeticResync] Detected {steamStatType} {text} as #{num}");
}
else
{
CosmeticResync.Logger.LogWarning((object)$"{steamStatType} {text} 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
{
private enum RestoreResult
{
Restored,
Retry,
NoSavedData,
InvalidData
}
internal static BaseUnityPlugin MultiCosmetic;
private static FieldInfo _currentData;
private static bool _restoreQueued;
private static bool _restorePending;
private static bool _pendingSaveLogged;
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;
_restorePending = PlayerPrefs.HasKey("CosmeticResync_MultiCosmetic");
return true;
}
internal static bool PrefixMCDataFromString()
{
if ((Object)(object)MultiCosmetic == (Object)null)
{
CosmeticResync.Logger.LogError((object)"Missing MultiCosmetic instance, cannot resync MultiCosmetic");
return true;
}
if (_currentData == null)
{
CosmeticResync.Logger.LogError((object)"MultiCosmetic.currentData field not found, cannot Resync Multicosmetic");
return true;
}
string[] missingAccessories;
string[] missingHats;
return TryRestoreSavedCosmetics(out missingAccessories, out missingHats) != RestoreResult.Restored;
}
internal static void PostfixUpdateCustomPropertiesValue()
{
if ((Object)(object)MultiCosmetic == (Object)null)
{
CosmeticResync.Logger.LogError((object)"Missing MultiCosmetic instance? Cannot save MultiCosmetic names");
return;
}
if (_currentData == null)
{
CosmeticResync.Logger.LogError((object)"MultiCosmetic.currentData field not found, cannot save MultiCosmetic names");
return;
}
if (_restorePending)
{
if (!_pendingSaveLogged)
{
CosmeticResync.Logger.LogInfo((object)"Skipping MultiCosmetic save while saved cosmetic names are awaiting restoration");
_pendingSaveLogged = true;
}
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);
string[] names;
string[] names2;
if (array == null)
{
CosmeticResync.Logger.LogError((object)"MultiCosmetic.currentData is null");
}
else if (array.Length != 2)
{
CosmeticResync.Logger.LogError((object)$"Expected MultiCosmetic.Plugin.currentData to contain 2 int[], not {array.Length}");
}
else if (array[0] == null || array[1] == null)
{
CosmeticResync.Logger.LogError((object)"MultiCosmetic.currentData contains a null array");
}
else if (TryGetCosmeticNames(instance.accessories, array[0], "Accessory", out names) && TryGetCosmeticNames(instance.hats, array[1], "Hat", out names2))
{
string text = JsonConvert.SerializeObject((object)new string[2][] { names, names2 });
PlayerPrefs.SetString("CosmeticResync_MultiCosmetic", text);
PlayerPrefs.Save();
_pendingSaveLogged = false;
CosmeticResync.Logger.LogInfo((object)$"Saved {names.Length} accessories and {names2.Length} hats");
}
}
[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");
if (!_restoreQueued)
{
_restoreQueued = true;
CosmeticResync.Logger.LogInfo((object)"Queued MultiCosmetic restore; waiting for cosmetic options to become available");
((MonoBehaviour)CosmeticResync.Instance).StartCoroutine(RestoreWhenReady());
}
}
else
{
CosmeticResync.Logger.LogError((object)"PassportManager not with Customization? Cannot resync MultiCosmetic");
}
}
private static IEnumerator RestoreWhenReady()
{
string[] missingAccessories = new string[0];
string[] missingHats = new string[0];
int attempt = 0;
while (attempt < 30)
{
switch (TryRestoreSavedCosmetics(out missingAccessories, out missingHats))
{
case RestoreResult.NoSavedData:
CosmeticResync.Logger.LogInfo((object)"No saved MultiCosmetic names found; keeping MultiCosmetic's current data");
_restoreQueued = false;
yield break;
default:
_restoreQueued = false;
_pendingSaveLogged = false;
yield break;
case RestoreResult.Retry:
yield return (object)new WaitForSecondsRealtime(1f);
attempt++;
break;
}
}
string[] array = missingAccessories;
foreach (string text in array)
{
CosmeticResync.Logger.LogWarning((object)("Accessory " + text + " is still unavailable after waiting for cosmetic registration"));
}
array = missingHats;
foreach (string text2 in array)
{
CosmeticResync.Logger.LogWarning((object)("Hat " + text2 + " is still unavailable after waiting for cosmetic registration"));
}
if (missingAccessories.Length == 0 && missingHats.Length == 0)
{
CosmeticResync.Logger.LogError((object)"Customization was not ready in time; could not resync MultiCosmetic");
}
else
{
CosmeticResync.Logger.LogError((object)"Could not resync every saved cosmetic after 30 seconds; preserving saved names and skipping MultiCosmetic saves");
}
_restoreQueued = false;
}
private static RestoreResult TryRestoreSavedCosmetics(out string[] missingAccessories, out string[] missingHats)
{
missingAccessories = new string[0];
missingHats = new string[0];
if ((Object)(object)MultiCosmetic == (Object)null || _currentData == null)
{
CosmeticResync.Logger.LogError((object)"MultiCosmetic is not ready; cannot restore saved cosmetics");
return RestoreResult.InvalidData;
}
if (!PlayerPrefs.HasKey("CosmeticResync_MultiCosmetic"))
{
_restorePending = false;
return RestoreResult.NoSavedData;
}
string text = PlayerPrefs.GetString("CosmeticResync_MultiCosmetic");
if (string.IsNullOrWhiteSpace(text))
{
CosmeticResync.Logger.LogWarning((object)"CosmeticResync_MultiCosmetic has no data, nothing to resync");
_restorePending = false;
return RestoreResult.InvalidData;
}
try
{
string[][] array = JsonConvert.DeserializeObject<string[][]>(text);
if (array == null || array.Length != 2 || array[0] == null || array[1] == null)
{
CosmeticResync.Logger.LogWarning((object)"CosmeticResync_MultiCosmetic is malformed; expected two name arrays");
_restorePending = false;
return RestoreResult.InvalidData;
}
Customization instance = Singleton<Customization>.Instance;
if (!Object.op_Implicit((Object)(object)instance))
{
return RestoreResult.Retry;
}
int[] indices;
bool flag = TryGetCosmeticIndices(instance.accessories, array[0], out indices, out missingAccessories);
int[] indices2;
bool flag2 = TryGetCosmeticIndices(instance.hats, array[1], out indices2, out missingHats);
if (!flag || !flag2)
{
return RestoreResult.Retry;
}
_currentData.SetValue(MultiCosmetic, new int[2][] { indices, indices2 });
_restorePending = false;
CosmeticResync.Logger.LogInfo((object)$"Loaded {indices.Length} accessories and {indices2.Length} hats");
return RestoreResult.Restored;
}
catch (JsonException)
{
CosmeticResync.Logger.LogWarning((object)"Failed to deserialize CosmeticResync_MultiCosmetic");
_restorePending = false;
return RestoreResult.InvalidData;
}
}
private static bool TryGetCosmeticIndices(CustomizationOption[] options, string[] names, out int[] indices, out string[] missingNames)
{
Dictionary<string, int> dictionary = new Dictionary<string, int>();
if (options != null)
{
for (int i = 0; i < options.Length; i++)
{
CustomizationOption val = options[i];
if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name))
{
dictionary[((Object)val).name] = i;
}
}
}
List<int> list = new List<int>();
List<string> list2 = new List<string>();
foreach (string text in names)
{
if (!string.IsNullOrEmpty(text) && dictionary.TryGetValue(text, out var value))
{
list.Add(value);
}
else
{
list2.Add(text ?? "<null>");
}
}
indices = list.ToArray();
missingNames = list2.ToArray();
return missingNames.Length == 0;
}
private static bool TryGetCosmeticNames(CustomizationOption[] options, int[] indices, string cosmeticType, out string[] names)
{
List<string> list = new List<string>();
names = new string[0];
if (options == null || indices == null)
{
CosmeticResync.Logger.LogError((object)(cosmeticType + " options or indices are null; cannot save MultiCosmetic names"));
return false;
}
int num = options.Length;
foreach (int num2 in indices)
{
if (num2 >= 0 && num2 < num && (Object)(object)options[num2] != (Object)null && !string.IsNullOrEmpty(((Object)options[num2]).name))
{
list.Add(((Object)options[num2]).name);
continue;
}
CosmeticResync.Logger.LogError((object)$"{cosmeticType} index #{num2} cannot be resolved; preserving previously saved MultiCosmetic names");
return false;
}
names = list.ToArray();
return true;
}
}
}