Decompiled source of AccessoryBending v1.2.5

Mods/AccessoryBending.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using AccessoryBending;
using HarmonyLib;
using Il2CppExitGames.Client.Photon;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppPhoton.Pun;
using Il2CppPhoton.Realtime;
using Il2CppRUMBLE.Managers;
using Il2CppRUMBLE.Players;
using Il2CppRUMBLE.Utilities;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Preferences;
using RumbleModdingAPI.RMAPI;
using UIFramework;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Main), "AccessoryBending", "1.2.5", "UlvakSkillz", "https://thunderstore.io/c/rumble/p/UlvakSkillz/AccessoryBending/")]
[assembly: MelonGame("Buckethead Entertainment", "RUMBLE")]
[assembly: MelonColor(255, 195, 0, 255)]
[assembly: MelonAuthorColor(255, 195, 0, 255)]
[assembly: VerifyLoaderVersion(0, 7, 0, true)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("AccessoryBending")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+0ed99750755b536de0ce383880c740c0ea2c156e")]
[assembly: AssemblyProduct("AccessoryBending")]
[assembly: AssemblyTitle("AccessoryBending")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AccessoryBending;

public static class BuildInfo
{
	public const string ModName = "AccessoryBending";

	public const string ModVersion = "1.2.5";

	public const string Author = "UlvakSkillz";
}
public class AssetInfo
{
	private GameObject assetToUse;

	private string boneToAttachTo;

	private Vector3 positionOffset;

	private Quaternion rotationOffset;

	private Vector3 localScale;

	private int layer;

	private string childPath;

	public AssetInfo(GameObject asset, string bone, Vector3 pOffset, Quaternion rOffset, Vector3 scale, int chosenLayer, string childsPath = "")
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		childPath = childsPath;
		assetToUse = asset;
		boneToAttachTo = bone;
		positionOffset = pOffset;
		rotationOffset = rOffset;
		localScale = scale;
		layer = chosenLayer;
	}

	public GameObject GetAssetToUse()
	{
		return assetToUse;
	}

	public string GetBoneToAttachTo()
	{
		return boneToAttachTo;
	}

	public Vector3 GetPositionOffset()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		return positionOffset;
	}

	public Quaternion GetRotationOffset()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		return rotationOffset;
	}

	public Vector3 GetLocalScale()
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		return localScale;
	}

	public int GetLayer()
	{
		return layer;
	}

	public string GetChildsPath()
	{
		return childPath;
	}

	public string GetAssetInfo()
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		return $"{((Object)assetToUse).name}|{boneToAttachTo}|{positionOffset.x.ToString(CultureInfo.InvariantCulture)}:{positionOffset.y.ToString(CultureInfo.InvariantCulture)}:{positionOffset.z.ToString(CultureInfo.InvariantCulture)}|{((Quaternion)(ref rotationOffset)).eulerAngles.x.ToString(CultureInfo.InvariantCulture)}:{((Quaternion)(ref rotationOffset)).eulerAngles.y.ToString(CultureInfo.InvariantCulture)}:{((Quaternion)(ref rotationOffset)).eulerAngles.z.ToString(CultureInfo.InvariantCulture)}|{localScale.x.ToString(CultureInfo.InvariantCulture)}:{localScale.y.ToString(CultureInfo.InvariantCulture)}:{localScale.z.ToString(CultureInfo.InvariantCulture)}|0|{childPath}";
	}
}
public class Main : MelonMod
{
	[HarmonyPatch(typeof(PlayerController), "Initialize", new Type[] { typeof(Player) })]
	public static class playerSpawn
	{
		private static void Postfix(ref PlayerController __instance, ref Player player)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			if ((int)__instance.controllerType == 1)
			{
				for (int i = 0; i < assetInfos.Count; i++)
				{
					if (Preferences.PrefAccessoriesEnabled[i].Value)
					{
						PlaceAsset(__instance, assetInfos[i]);
					}
				}
			}
			else
			{
				SendRPCString();
			}
		}
	}

	[HarmonyPatch(typeof(PlayerManager), "RemovePlayer", new Type[] { typeof(Player) })]
	public static class playerLeave
	{
		private static void Prefix(ref Player player)
		{
			Player playerByActorNo = Players.GetPlayerByActorNo(player.ActorNumber);
			for (int i = 0; i < playersLoaded.Count; i++)
			{
				if (!(playersLoaded[i] == playerByActorNo.Data.GeneralData.PlayFabMasterId))
				{
					continue;
				}
				while (accessoriesToNuke[i].Count != 0)
				{
					if ((Object)(object)accessoriesToNuke[i][0] != (Object)null)
					{
						Log("Removing Their Accessory: " + ((Object)accessoriesToNuke[i][0]).name);
						Object.Destroy((Object)(object)accessoriesToNuke[i][0]);
					}
					else
					{
						Log($"accessoriesToNuke[{i}][0] is null on player leave — accessory was destroyed before bookkeeping cleanup");
					}
					accessoriesToNuke[i].RemoveAt(0);
				}
				playersLoaded.RemoveAt(i);
				accessoriesToNuke.RemoveAt(i);
				break;
			}
		}
	}

	internal static List<AssetInfo> assetInfos = new List<AssetInfo>();

	private static byte myEventCode = 16;

	private static RaiseEventOptions eventOptions = new RaiseEventOptions
	{
		Receivers = (ReceiverGroup)0,
		CachingOption = (EventCaching)4
	};

	private GameObject parentObject;

	private static List<List<GameObject>> accessoriesToNuke = new List<List<GameObject>>();

	private static List<string> playersLoaded = new List<string>();

	private static Shader URPUnlit;

	private static bool urpUnlitLookupDone = false;

	private static bool eventReceivedRegistered = false;

	private static void Log(string msg)
	{
		if (Preferences.PrefDebugging.Value)
		{
			Melon<Main>.Logger.Msg(msg);
		}
	}

	private static void Warn(string msg)
	{
		Melon<Main>.Logger.Warning(msg);
	}

	private static void Err(string msg)
	{
		Melon<Main>.Logger.Error(msg);
	}

	private static void Err(Exception e)
	{
		Melon<Main>.Logger.Error((object)e);
	}

	public override void OnInitializeMelon()
	{
		Preferences.InitGlobalPrefs();
		CheckFiles();
		Preferences.InitAccessoryPrefs();
		Preferences.StoreLastSavedPrefs();
		((ModelModItem)UI.Register((MelonBase)(object)this, (MelonPreferences_Category[])(object)new MelonPreferences_Category[2]
		{
			Preferences.AccessoryBendingCategory,
			Preferences.AccessoriesCategory
		})).OnModSaved += Save;
	}

	public override void OnLateInitializeMelon()
	{
		Actions.onMapInitialized += MapInit;
	}

	public override void OnSceneWasLoaded(int buildIndex, string sceneName)
	{
		playersLoaded.Clear();
		accessoriesToNuke.Clear();
	}

	private void Save()
	{
		Preferences.StoreLastSavedPrefs();
	}

	internal static void NukeOthersAccessories()
	{
		for (int i = 0; i < playersLoaded.Count; i++)
		{
			while (accessoriesToNuke[i].Count > 0)
			{
				if ((Object)(object)accessoriesToNuke[i][0] != (Object)null)
				{
					Object.Destroy((Object)(object)accessoriesToNuke[i][0]);
				}
				accessoriesToNuke[i].RemoveAt(0);
			}
		}
		accessoriesToNuke.Clear();
		playersLoaded.Clear();
	}

	private void MapInit(string map)
	{
		if (!eventReceivedRegistered)
		{
			LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient;
			networkingClient.EventReceived += Action<EventData>.op_Implicit((Action<EventData>)OnEvent);
			eventReceivedRegistered = true;
		}
		if (map == "Gym")
		{
			CreateDressingRoomObjects();
		}
	}

	public void OnEvent(EventData eventData)
	{
		if (Preferences.PrefShowOthers.Value && eventData.Code == myEventCode)
		{
			string text = eventData.CustomData.ToString();
			string[] array = text.Split(';');
			if (!playersLoaded.Contains(array[0]))
			{
				Log("Recieved Player Accessories:" + Environment.NewLine + text);
				playersLoaded.Add(array[0]);
				MelonCoroutines.Start(ProcessItems(array));
			}
		}
	}

	private IEnumerator ProcessItems(string[] processedString)
	{
		yield return (object)new WaitForSeconds(1f);
		bool playerFound = false;
		for (int i = 1; i < Singleton<PlayerManager>.instance.AllPlayers.Count; i++)
		{
			if (!(Singleton<PlayerManager>.instance.AllPlayers[i].Data.GeneralData.PlayFabMasterId == processedString[0]))
			{
				continue;
			}
			playerFound = true;
			PlayerController controller = Singleton<PlayerManager>.instance.AllPlayers[i].Controller;
			foreach (string assetStringToLoad in processedString)
			{
				if (processedString[0] == assetStringToLoad)
				{
					Log("Processing For: " + assetStringToLoad + " " + controller.assignedPlayer.Data.GeneralData.PublicUsername);
					accessoriesToNuke.Add(new List<GameObject>());
					continue;
				}
				string[] assetInfo = assetStringToLoad.Split("|");
				if (assetInfo[0].Length == 0)
				{
					continue;
				}
				bool assetFound = false;
				for (int j = 0; j < assetInfos.Count; j++)
				{
					if (((Object)assetInfos[j].GetAssetToUse()).name == assetInfo[0])
					{
						assetFound = true;
						GameObject asset = assetInfos[j].GetAssetToUse();
						try
						{
							string bone = assetInfo[1];
							string[] pOffsetString = assetInfo[2].Split(":");
							string[] rOffsetString = assetInfo[3].Split(":");
							string[] scaleString = assetInfo[4].Split(":");
							Vector3 pOffset = new Vector3(float.Parse(pOffsetString[0], CultureInfo.InvariantCulture), float.Parse(pOffsetString[1], CultureInfo.InvariantCulture), float.Parse(pOffsetString[2], CultureInfo.InvariantCulture));
							Quaternion rOffset = Quaternion.Euler(float.Parse(rOffsetString[0], CultureInfo.InvariantCulture), float.Parse(rOffsetString[1], CultureInfo.InvariantCulture), float.Parse(rOffsetString[2], CultureInfo.InvariantCulture));
							Vector3 scale = new Vector3(float.Parse(scaleString[0], CultureInfo.InvariantCulture), float.Parse(scaleString[1], CultureInfo.InvariantCulture), float.Parse(scaleString[2], CultureInfo.InvariantCulture));
							int.Parse(assetInfo[5]);
							string childsPath = ((assetInfo.Length == 7) ? assetInfo[6] : "");
							AssetInfo newAsset = new AssetInfo(asset, bone, pOffset, rOffset, scale, 0, childsPath);
							PlaceAsset(controller, newAsset);
							Log(string.Concat(str3: childsPath.Split("/")[^1], str0: "Accessory ", str1: assetInfo[0], str2: " Placed on "));
						}
						catch (Exception ex)
						{
							Exception e = ex;
							Err("ERROR READING INCOMING STRING FOR PLAYER: " + processedString[0]);
							Err(e);
						}
						break;
					}
				}
				if (!assetFound)
				{
					Warn("Accessory Not Found: " + assetInfo[0]);
				}
			}
			break;
		}
		if (!playerFound)
		{
			Warn("Received accessory data for player not in AllPlayers: " + processedString[0]);
			playersLoaded.Remove(processedString[0]);
		}
	}

	private void CreateDressingRoomObjects()
	{
		for (int i = 0; i < assetInfos.Count; i++)
		{
			if (Preferences.PrefAccessoriesEnabled[i].Value)
			{
				PlaceDressingRoomAsset(assetInfos[i]);
			}
		}
	}

	private void CheckFiles()
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Expected O, but got Unknown
		//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_05dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0562: Unknown result type (might be due to invalid IL or missing references)
		//IL_0579: Unknown result type (might be due to invalid IL or missing references)
		//IL_0590: Unknown result type (might be due to invalid IL or missing references)
		if (!Directory.Exists("UserData\\AccessoryBending"))
		{
			Directory.CreateDirectory("UserData\\AccessoryBending");
			return;
		}
		string[] files = Directory.GetFiles("UserData\\AccessoryBending");
		if (files.Length == 0)
		{
			return;
		}
		List<string> list = new List<string>();
		parentObject = new GameObject();
		((Object)parentObject).name = "AssetBending Cosmetics";
		Object.DontDestroyOnLoad((Object)(object)parentObject);
		string[] array = files;
		foreach (string text in array)
		{
			try
			{
				if (!text.ToLower().EndsWith(".txt") && !text.ToLower().EndsWith(".cfg"))
				{
					list.Add(text);
				}
			}
			catch (Exception e)
			{
				Err(e);
			}
		}
		foreach (string item in list)
		{
			if (!File.Exists(item + ".txt"))
			{
				SaveFile($"Game Object Name{Environment.NewLine}Visuals/Skelington/Bone_Pelvis/Bone_Spine_A{Environment.NewLine}0|0|0{Environment.NewLine}0|0|0{Environment.NewLine}1|1|1{Environment.NewLine}true{Environment.NewLine}true{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}-------------------------------------------------------------------------------------------------------------------------------------------------{Environment.NewLine}{Environment.NewLine}Line 1: Name of Main Game Object (This is the Game Object Name Encompassing the Whole Cosmetic) (Found as Outter Most Object in Unity when Creating){Environment.NewLine}Line 2: The Bone Structure Path to the Spot you want it Parented (Cosmetic will Follow that Object).{Environment.NewLine}Line 3: Local Position Offset (0|0|0 will be in relation to the Parent's Rotation) (x, y, z){Environment.NewLine}Line 4: Local Rotation Offset (0|0|0 will be in relation to the Parent's Rotation) (x, y, z){Environment.NewLine}Line 5: Local Scale (1|1|1 will be the Normal Size) (x, y, z){Environment.NewLine}Line 6: Show in VR Headset (Set \"true\" or \"false\" to have the Cosmetic Visible or Not to the Headset){Environment.NewLine}Line 7: Show in Legacy Camera (Set \"true\" or \"false\" to have the Cosmetic Visible or Not to the Legacy Camera){Environment.NewLine}Line 8: If Something is in this Line, That Game Object will be Parented instead of the Line 1 Game Object. This should be the Line 1 Game Object's Child Path (not Including the Line 1 Game Object Name Itself){Environment.NewLine}", item + ".txt");
			}
			string[] array2 = File.ReadAllLines(item + ".txt");
			if (array2.Length < 7)
			{
				Err("ASSET BUNDLE ERROR: " + item + ".txt HAS TOO FEW LINES!");
				continue;
			}
			string text2 = array2[0];
			string bone = array2[1];
			string[] array3 = array2[2].Split("|");
			string[] array4 = array2[3].Split("|");
			string[] array5 = array2[4].Split("|");
			string value = array2[5];
			string value2 = array2[6];
			string text3 = "";
			if (array2.Length >= 8)
			{
				text3 = array2[7];
			}
			if (array3.Length < 3 || array4.Length < 3 || array5.Length < 3)
			{
				Err("ASSET BUNDLE ERROR: " + item + ".txt DOESNT HAVE ENOUGH DATA FOR POSITION ROTATION OR SCALE!");
				continue;
			}
			float[][] array6 = new float[3][];
			try
			{
				array6[0] = new float[3]
				{
					float.Parse(array3[0], CultureInfo.InvariantCulture),
					float.Parse(array3[1], CultureInfo.InvariantCulture),
					float.Parse(array3[2], CultureInfo.InvariantCulture)
				};
				array6[1] = new float[3]
				{
					float.Parse(array4[0], CultureInfo.InvariantCulture),
					float.Parse(array4[1], CultureInfo.InvariantCulture),
					float.Parse(array4[2], CultureInfo.InvariantCulture)
				};
				array6[2] = new float[3]
				{
					float.Parse(array5[0], CultureInfo.InvariantCulture),
					float.Parse(array5[1], CultureInfo.InvariantCulture),
					float.Parse(array5[2], CultureInfo.InvariantCulture)
				};
			}
			catch (Exception e2)
			{
				Err("ASSET BUNDLE ERROR: " + item + ".txt DATA CONVERSION ERROR: POSITION ROTATION OR SCALE string -> float!");
				Err(e2);
				continue;
			}
			bool[] array7 = new bool[2];
			try
			{
				array7[0] = bool.Parse(value);
				array7[1] = bool.Parse(value2);
			}
			catch (Exception e3)
			{
				Err("ASSET BUNDLE ERROR: " + item + ".txt DATA CONVERSION ERROR: SHOW IN HEADSET SHOW IN LEGACY CAM string -> bool!");
				Err(e3);
				continue;
			}
			GameObject val = SpawnDDOLAsset(item, text2);
			if ((Object)(object)val != (Object)null)
			{
				ChangeShaderLitToUnlit(val);
				AssetInfo assetInfo = ((!(text3 != "")) ? new AssetInfo(val, bone, new Vector3(array6[0][0], array6[0][1], array6[0][2]), Quaternion.Euler(array6[1][0], array6[1][1], array6[1][2]), new Vector3(array6[2][0], array6[2][1], array6[2][2]), GetLayer(array7[0], array7[1])) : new AssetInfo(val, bone, new Vector3(array6[0][0], array6[0][1], array6[0][2]), Quaternion.Euler(array6[1][0], array6[1][1], array6[1][2]), new Vector3(array6[2][0], array6[2][1], array6[2][2]), GetLayer(array7[0], array7[1]), text3));
				assetInfos.Add(assetInfo);
				Log("Accessory Loaded: " + item + " | " + ((Object)assetInfo.GetAssetToUse()).name);
			}
			else
			{
				Err("ASSET ERROR: " + item + " DOESNT HAVE ASSET: " + text2);
			}
		}
	}

	private static void ChangeShaderLitToUnlit(GameObject asset)
	{
		if (!urpUnlitLookupDone)
		{
			URPUnlit = Shader.Find("Universal Render Pipeline/Unlit");
			urpUnlitLookupDone = true;
			if ((Object)(object)URPUnlit == (Object)null)
			{
				Warn("Universal Render Pipeline/Unlit shader not found — accessory shader replacement will be skipped.");
			}
		}
		if ((Object)(object)URPUnlit == (Object)null)
		{
			return;
		}
		Renderer component = asset.GetComponent<Renderer>();
		if ((Object)(object)component != (Object)null)
		{
			for (int i = 0; i < ((Il2CppArrayBase<Material>)(object)component.materials).Length; i++)
			{
				if (((Object)((Il2CppArrayBase<Material>)(object)component.materials)[i].shader).name == "Universal Render Pipeline/Lit")
				{
					((Il2CppArrayBase<Material>)(object)component.materials)[i].shader = URPUnlit;
				}
			}
		}
		foreach (Renderer componentsInChild in asset.GetComponentsInChildren<Renderer>())
		{
			for (int j = 0; j < ((Il2CppArrayBase<Material>)(object)componentsInChild.materials).Length; j++)
			{
				if (((Object)((Il2CppArrayBase<Material>)(object)componentsInChild.materials)[j].shader).name == "Universal Render Pipeline/Lit")
				{
					((Il2CppArrayBase<Material>)(object)componentsInChild.materials)[j].shader = URPUnlit;
				}
			}
		}
	}

	private int GetLayer(bool showInHead, bool showInLegacy)
	{
		if (showInHead && showInLegacy)
		{
			return 0;
		}
		if (!showInHead && showInLegacy)
		{
			return 17;
		}
		if (showInHead && !showInLegacy)
		{
			return 21;
		}
		return 18;
	}

	public GameObject SpawnDDOLAsset(string assetBundlePath, string assetName)
	{
		GameObject val = AssetBundles.LoadAssetFromFile<GameObject>(assetBundlePath, assetName);
		if ((Object)(object)val != (Object)null)
		{
			val = Object.Instantiate<GameObject>(val);
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).name = assetName.Replace("(Clone)", "");
			val.SetActive(false);
			val.transform.parent = parentObject.transform;
		}
		return val;
	}

	private void SaveFile(string textToSave, string file)
	{
		FileStream fileStream = File.Create(file);
		byte[] bytes = Encoding.UTF8.GetBytes(textToSave);
		fileStream.Write(bytes);
		fileStream.Close();
		fileStream.Dispose();
	}

	private static void SendRPCString()
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		string text = Singleton<PlayerManager>.instance.localPlayer.Data.GeneralData.PlayFabMasterId + ";";
		for (int i = 0; i < assetInfos.Count; i++)
		{
			if (Preferences.PrefAccessoriesEnabled[i].Value)
			{
				text += assetInfos[i].GetAssetInfo();
				if (i != assetInfos.Count - 1)
				{
					text += ";";
				}
			}
		}
		PhotonNetwork.RaiseEvent(myEventCode, Object.op_Implicit(text), eventOptions, SendOptions.SendReliable);
	}

	private static void PlaceAsset(PlayerController playerController, AssetInfo assetInfo)
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Invalid comparison between Unknown and I4
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Invalid comparison between Unknown and I4
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		int num = -1;
		for (int i = 0; i < playersLoaded.Count; i++)
		{
			if (playersLoaded[i] == playerController.assignedPlayer.Data.GeneralData.PlayFabMasterId)
			{
				num = i;
				break;
			}
		}
		if (num == -1 && (int)playerController.controllerType == 2)
		{
			Err("REMOTE PLAYER NOT FOUND IN LIST!!!");
			return;
		}
		GameObject val = Object.Instantiate<GameObject>(assetInfo.GetAssetToUse());
		((Object)val).name = ((Object)val).name.Replace("(Clone)", "");
		Utility.SetLayerRecursively(val, assetInfo.GetLayer());
		GameObject val2 = val;
		if (assetInfo.GetChildsPath() != "")
		{
			Transform val3 = val.transform.FindChild(assetInfo.GetChildsPath());
			if ((Object)(object)val3 == (Object)null)
			{
				Err("(" + ((Object)val).name + ") CHILD PATH NOT FOUND ON ACCESSORY: " + assetInfo.GetChildsPath());
				Object.Destroy((Object)(object)val);
				return;
			}
			val2 = ((Component)val3).gameObject;
		}
		if ((int)playerController.controllerType == 2)
		{
			accessoriesToNuke[num].Add(val);
			if ((Object)(object)val != (Object)(object)val2)
			{
				accessoriesToNuke[num].Add(val2);
			}
		}
		Transform val4 = ((Component)playerController).gameObject.transform.FindChild(assetInfo.GetBoneToAttachTo());
		if ((Object)(object)val4 == (Object)null)
		{
			Err("(" + ((Object)val).name + ") BONE PATH NOT FOUND ON PLAYER: " + assetInfo.GetBoneToAttachTo());
			Object.Destroy((Object)(object)val);
			return;
		}
		val.transform.position = val4.position;
		val.transform.rotation = val4.rotation;
		val2.transform.parent = val4;
		val2.transform.localPosition = assetInfo.GetPositionOffset();
		val2.transform.localRotation = assetInfo.GetRotationOffset();
		val2.transform.localScale = assetInfo.GetLocalScale();
		val.SetActive(true);
		val2.SetActive(true);
	}

	private static void PlaceDressingRoomAsset(AssetInfo assetInfo)
	{
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(assetInfo.GetAssetToUse());
		GameObject val2 = val;
		if (assetInfo.GetChildsPath() != "")
		{
			Transform val3 = val.transform.FindChild(assetInfo.GetChildsPath());
			if ((Object)(object)val3 == (Object)null)
			{
				Err("(" + ((Object)val).name + ") CHILD PATH NOT FOUND ON ACCESSORY: " + assetInfo.GetChildsPath());
				Object.Destroy((Object)(object)val);
				return;
			}
			val2 = ((Component)val3).gameObject;
		}
		GameObject gameObject = PreviewPlayerController.GetGameObject();
		if ((Object)(object)gameObject == (Object)null)
		{
			Err("(" + ((Object)val).name + ") DRESSING ROOM PREVIEW PLAYER NOT FOUND — GameObjects.Gym.INTERACTABLES.DressingRoom.PreviewPlayerController is null");
			Object.Destroy((Object)(object)val);
			return;
		}
		Transform val4 = gameObject.transform.FindChild(assetInfo.GetBoneToAttachTo());
		if ((Object)(object)val4 == (Object)null)
		{
			Err($"({((Object)val).name}) DRESSING ROOM PATH NOT CORRECT! THIS IS MOST LIKELY DUE TO DIFFERENCES IN DRESSING ROOM PLAYER RIG AND NOT THE USER! bone='{assetInfo.GetBoneToAttachTo()}'");
			Object.Destroy((Object)(object)val);
		}
		else
		{
			val2.transform.parent = val4;
			val.transform.position = val4.position;
			val.transform.rotation = val4.rotation;
			val2.transform.localPosition = assetInfo.GetPositionOffset();
			val2.transform.localRotation = assetInfo.GetRotationOffset();
			val2.transform.localScale = assetInfo.GetLocalScale();
			val.SetActive(true);
			val2.SetActive(true);
		}
	}
}
public class Preferences
{
	private const string CONFIG_FILE = "config.cfg";

	private const string USER_DATA = "UserData/AccessoryBending/";

	internal static Dictionary<MelonPreferences_Entry, object> LastSavedValues = new Dictionary<MelonPreferences_Entry, object>();

	internal static MelonPreferences_Category AccessoryBendingCategory;

	internal static MelonPreferences_Entry<bool> PrefShowOthers;

	internal static MelonPreferences_Entry<bool> PrefDebugging;

	internal static MelonPreferences_Category AccessoriesCategory;

	internal static List<MelonPreferences_Entry<bool>> PrefAccessoriesEnabled;

	internal static void InitGlobalPrefs()
	{
		if (!Directory.Exists("UserData/AccessoryBending/"))
		{
			Directory.CreateDirectory("UserData/AccessoryBending/");
		}
		AccessoryBendingCategory = MelonPreferences.CreateCategory("AccessoryBending", "Toggles");
		AccessoryBendingCategory.SetFilePath(Path.Combine("UserData/AccessoryBending/", "config.cfg"));
		PrefShowOthers = AccessoryBendingCategory.CreateEntry<bool>("ShowOthers", true, "Show Others Accessories", "Toggling ON will have others Accessories Shown that you have installed. (Will not Remove Accessories Already Loaded)", false, false, (ValueValidator)null, (string)null);
		UI.CreateButtonEntry(AccessoryBendingCategory, "Nuke", "Nuke Others Accessories", "Click to Remove all current Accessories from Players in the Scene. (Accessories will Come Back when a Player Enters the Room)", (Action)delegate
		{
			Main.NukeOthersAccessories();
		});
		PrefDebugging = AccessoryBendingCategory.CreateEntry<bool>("Debugging", false, "Debugging", "Toggling ON will print extensive diagnostic messages to the MelonLoader console.", false, false, (ValueValidator)null, (string)null);
	}

	internal static void InitAccessoryPrefs()
	{
		AccessoriesCategory = MelonPreferences.CreateCategory("Accessories", "Accessories");
		AccessoriesCategory.SetFilePath(Path.Combine("UserData/AccessoryBending/", "config.cfg"));
		if (PrefAccessoriesEnabled != null)
		{
			foreach (MelonPreferences_Entry<bool> item in PrefAccessoriesEnabled)
			{
				AccessoriesCategory.DeleteEntry(((MelonPreferences_Entry)item).Identifier);
			}
		}
		PrefAccessoriesEnabled = new List<MelonPreferences_Entry<bool>>();
		foreach (AssetInfo assetInfo in Main.assetInfos)
		{
			PrefAccessoriesEnabled.Add(AccessoriesCategory.CreateEntry<bool>(((Object)assetInfo.GetAssetToUse()).name, false, ((Object)assetInfo.GetAssetToUse()).name, "Toggling ON will have this Accessory Shown.", false, false, (ValueValidator)null, (string)null));
		}
	}

	internal static void StoreLastSavedPrefs()
	{
		List<MelonPreferences_Entry> list = new List<MelonPreferences_Entry>();
		list.AddRange(AccessoryBendingCategory.Entries);
		list.AddRange(AccessoriesCategory.Entries);
		foreach (MelonPreferences_Entry item in list)
		{
			LastSavedValues[item] = item.BoxedValue;
		}
	}

	public static bool AnyPrefsChanged()
	{
		foreach (KeyValuePair<MelonPreferences_Entry, object> lastSavedValue in LastSavedValues)
		{
			if (!lastSavedValue.Key.BoxedValue.Equals(lastSavedValue.Value))
			{
				return true;
			}
		}
		return false;
	}

	public static bool IsPrefChanged(MelonPreferences_Entry entry)
	{
		if (LastSavedValues.TryGetValue(entry, out var value))
		{
			return !entry.BoxedValue.Equals(value);
		}
		return false;
	}
}