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);
}
}
}