Decompiled source of TophatAccessoryLoader v1.0.1

BepInEx/plugins/TophatAccessoryLoader/Tophat.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using Mirror;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Tophat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Tophat")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f02060ea-11ae-4930-be41-06bbb4ef1c09")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.morsecodeguy.tophataccessoryloader", "Tophat Accessory Loader", "1.0.0")]
public class HatAccessoryLoader : BaseUnityPlugin
{
	private static ManualLogSource Logger;

	private GameObject hatPrefab;

	private GameObject currentPlayer;

	private string storedPlayerName;

	private string selectedAccessory;

	private string previousAccessory;

	private string[] accessoryFiles;

	private Vector2 scrollPosition;

	private bool isAccessorySaved = false;

	private bool hasStoredPlayerName = false;

	private AssetBundle currentAssetBundle;

	private bool showAccessoryMenu = false;

	private void Awake()
	{
		Logger = ((BaseUnityPlugin)this).Logger;
		LoadAccessoryAssetBundles();
		Logger.LogInfo((object)"HatAccessoryLoader initialized.");
		SceneManager.sceneLoaded += OnSceneLoaded;
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		((MonoBehaviour)this).StartCoroutine(WaitForLocalPlayerAndAttachHat());
		if (!string.IsNullOrEmpty(selectedAccessory))
		{
			SendHatInfoToAll();
		}
	}

	private void LoadAccessoryAssetBundles()
	{
		string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		string text = Path.Combine(directoryName, "Accessorys");
		if (!Directory.Exists(text))
		{
			Logger.LogWarning((object)("Accessory folder not found: " + text));
			return;
		}
		accessoryFiles = Directory.GetFiles(text, "*.ac", SearchOption.AllDirectories);
		Logger.LogInfo((object)$"Found {accessoryFiles.Length} accessory files.");
		if (accessoryFiles.Length != 0)
		{
			selectedAccessory = accessoryFiles[0];
		}
	}

	private IEnumerator WaitForLocalPlayerAndAttachHat()
	{
		while (true)
		{
			if (!hasStoredPlayerName && string.IsNullOrEmpty(storedPlayerName))
			{
				storedPlayerName = FindLocalPlayerName();
				if (!string.IsNullOrEmpty(storedPlayerName))
				{
					hasStoredPlayerName = true;
				}
			}
			if (!string.IsNullOrEmpty(storedPlayerName))
			{
				GameObject playerObject = FindPlayerObjectByName(storedPlayerName);
				if ((Object)(object)playerObject != (Object)null)
				{
					if (!HatAlreadyAttached(playerObject))
					{
						AttachHat(playerObject, "PlayerModelPhysics");
						currentPlayer = playerObject;
					}
				}
				else
				{
					currentPlayer = null;
				}
			}
			yield return (object)new WaitForSeconds(1f);
		}
	}

	private string FindLocalPlayerName()
	{
		PlayerMultiplayerInputManager[] array = Object.FindObjectsOfType<PlayerMultiplayerInputManager>();
		PlayerMultiplayerInputManager[] array2 = array;
		foreach (PlayerMultiplayerInputManager val in array2)
		{
			if (((NetworkBehaviour)val).isLocalPlayer)
			{
				return val.playerName;
			}
		}
		return null;
	}

	private GameObject FindPlayerObjectByName(string playerName)
	{
		IEnumerable<GameObject> enumerable = from go in Object.FindObjectsOfType<GameObject>()
			where ((Object)go).name == "PlayerCharacterMultiplayer(Clone)"
			select go;
		foreach (GameObject item in enumerable)
		{
			Transform val = item.transform.Find("PlayerModelPhysics/HIP/PlayerName(Clone)");
			if ((Object)(object)val != (Object)null)
			{
				TextMesh component = ((Component)val).GetComponent<TextMesh>();
				if ((Object)(object)component != (Object)null && component.text == playerName)
				{
					return item;
				}
			}
		}
		return null;
	}

	private void AttachHat(GameObject character, string rootBone)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)hatPrefab == (Object)null)
		{
			return;
		}
		Transform val = FindBoneInHierarchy(character.transform, rootBone, "HIP", "SPINE1", "SPINE2", "NECK", "MeshHead");
		if ((Object)(object)val != (Object)null && !HatAlreadyAttached(character))
		{
			GameObject val2 = Object.Instantiate<GameObject>(hatPrefab, val);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			((Object)val2).name = ((Object)hatPrefab).name;
			val2.layer = LayerMask.NameToLayer("Default");
			MeshRenderer componentInChildren = val2.GetComponentInChildren<MeshRenderer>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((Renderer)componentInChildren).enabled = true;
			}
		}
	}

	private bool HatAlreadyAttached(GameObject character)
	{
		Transform val = FindBoneInHierarchy(character.transform, "PlayerModelPhysics", "HIP", "SPINE1", "SPINE2", "NECK", "MeshHead");
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Transform val2 = ((IEnumerable<Transform>)((Component)val).GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)delegate(Transform t)
		{
			int result;
			if ((Object)(object)t != (Object)null)
			{
				string name = ((Object)t).name;
				GameObject obj = hatPrefab;
				result = ((name == ((obj != null) ? ((Object)obj).name : null)) ? 1 : 0);
			}
			else
			{
				result = 0;
			}
			return (byte)result != 0;
		});
		return (Object)(object)val2 != (Object)null;
	}

	private Transform FindBoneInHierarchy(Transform root, params string[] boneNames)
	{
		Transform val = root;
		foreach (string text in boneNames)
		{
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			val = val.Find(text);
		}
		return val;
	}

	private void Update()
	{
		if (Input.GetKeyDown((KeyCode)285))
		{
			showAccessoryMenu = !showAccessoryMenu;
		}
	}

	private void OnGUI()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		if (showAccessoryMenu)
		{
			GUILayout.Window(1, new Rect((float)(Screen.width / 2 - 150), 50f, 300f, 400f), new WindowFunction(DrawAccessoryMenu), "Accessory Selection", Array.Empty<GUILayoutOption>());
		}
	}

	private void DrawAccessoryMenu(int windowID)
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.Label("Selected Accessory: " + Path.GetFileNameWithoutExtension(selectedAccessory) + " " + (isAccessorySaved ? "(Saved)" : "(Unsaved)"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) });
		scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(280f),
			GUILayout.Height(250f)
		});
		string[] array = accessoryFiles;
		foreach (string path in array)
		{
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
			if (GUILayout.Button(fileNameWithoutExtension, Array.Empty<GUILayoutOption>()))
			{
				selectedAccessory = path;
				isAccessorySaved = false;
			}
		}
		GUILayout.EndScrollView();
		if (GUILayout.Button("Select", Array.Empty<GUILayoutOption>()) && !string.IsNullOrEmpty(selectedAccessory))
		{
			LoadSelectedAccessory();
			isAccessorySaved = true;
			SendHatInfoToAll();
		}
	}

	private void LoadSelectedAccessory()
	{
		if (!string.IsNullOrEmpty(previousAccessory) && (Object)(object)currentAssetBundle != (Object)null)
		{
			currentAssetBundle.Unload(true);
		}
		AssetBundle val = AssetBundle.LoadFromFile(selectedAccessory);
		if ((Object)(object)val != (Object)null)
		{
			currentAssetBundle = val;
			hatPrefab = val.LoadAsset<GameObject>("HatPrefab");
			if ((Object)(object)hatPrefab != (Object)null && (Object)(object)currentPlayer != (Object)null)
			{
				AttachHat(currentPlayer, "PlayerModelPhysics");
			}
			previousAccessory = selectedAccessory;
		}
	}

	[Command]
	private void CmdUpdateHatInfo(string playerName, string accessoryFileName)
	{
		RpcReceiveHatInfo(playerName, accessoryFileName);
	}

	[ClientRpc]
	private void RpcReceiveHatInfo(string playerName, string accessoryFileName)
	{
		GameObject val = FindPlayerObjectByName(playerName);
		if (!((Object)(object)val != (Object)null))
		{
			return;
		}
		string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		string text = Path.Combine(directoryName, "Accessorys", accessoryFileName);
		AssetBundle val2 = AssetBundle.LoadFromFile(text);
		if ((Object)(object)val2 != (Object)null)
		{
			GameObject val3 = val2.LoadAsset<GameObject>("HatPrefab");
			if ((Object)(object)val3 != (Object)null)
			{
				AttachHat(val, "PlayerModelPhysics");
			}
		}
	}

	private void SendHatInfoToAll()
	{
		if ((Object)(object)hatPrefab != (Object)null && !string.IsNullOrEmpty(storedPlayerName))
		{
			string fileName = Path.GetFileName(selectedAccessory);
			CmdUpdateHatInfo(storedPlayerName, fileName);
		}
	}
}