Decompiled source of WearableTorches v1.0.5

WearableTorches.dll

Decompiled a month 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 BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("WearableTorches")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WearableTorches")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("a614924a-5167-4a9b-96b5-859ddb3331ad")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace WearableTorches;

[BepInPlugin("com.thomas.wearabletorches", "Wearable Torches", "1.0.6")]
public class WearableTorchesPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_harmony = new Harmony("com.thomas.wearabletorches");
		_harmony.PatchAll();
		Log.LogInfo((object)"Wearable Torches loaded (G key, torch required in hand)");
	}

	private void Update()
	{
		if (ZInput.instance == null)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			WearableTorchManager.HandleLocalInput(localPlayer);
		}
		foreach (Player allPlayer in Player.GetAllPlayers())
		{
			WearableTorchManager.SyncBackTorchForPlayer(allPlayer);
		}
	}

	private void OnDestroy()
	{
		WearableTorchManager.ForceDestroyBackTorch();
	}
}
public static class WearableTorchManager
{
	private static readonly Dictionary<long, GameObject> BackTorches = new Dictionary<long, GameObject>();

	public const string ZdoKeyBackTorch = "WearableTorches_BackTorch";

	public const string ZdoKeyBackTorchPrefab = "WearableTorches_BackTorchPrefab";

	private static readonly Vector3 FlameOffset = new Vector3(0f, 0f, 0.61f);

	private static readonly Vector3 LightOffset = new Vector3(0f, 0f, 0.61f);

	private static readonly Quaternion BackRotationOffset = Quaternion.Euler(-80f, 0f, 0f);

	private static long GetPlayerKey(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return 0L;
		}
		return player.GetPlayerID();
	}

	private static GameObject FindExistingBackTorchObject(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return null;
		}
		Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if (((Object)val).name == "BackTorchObject")
			{
				return ((Component)val).gameObject;
			}
		}
		return null;
	}

	public static void HandleLocalInput(Player player)
	{
		ZNetView nView = GetNView(player);
		if ((Object)(object)nView == (Object)null || !nView.IsOwner() || !ZInput.GetKeyDown((KeyCode)103, true))
		{
			return;
		}
		ZDO zDO = nView.GetZDO();
		if (zDO == null)
		{
			return;
		}
		if (!zDO.GetBool("WearableTorches_BackTorch", false))
		{
			ItemData torchInHands = GetTorchInHands(player);
			if (torchInHands == null)
			{
				WearableTorchesPlugin.Log.LogInfo((object)("Back torch: no torch in hand, toggle ignored for " + player.GetPlayerName()));
				return;
			}
			GameObject dropPrefab = torchInHands.m_dropPrefab;
			if ((Object)(object)dropPrefab == (Object)null)
			{
				WearableTorchesPlugin.Log.LogWarning((object)("Back torch: torch in hand has no dropPrefab for " + player.GetPlayerName()));
				return;
			}
			string name = ((Object)dropPrefab).name;
			if (!string.IsNullOrEmpty(name))
			{
				zDO.Set("WearableTorches_BackTorchPrefab", name);
				zDO.Set("WearableTorches_BackTorch", true);
				HideVanillaTorchVisuals(player, hide: true);
				WearableTorchesPlugin.Log.LogInfo((object)("Back torch ON (G key, from hand) for " + player.GetPlayerName() + " prefab=" + name));
			}
		}
		else
		{
			zDO.Set("WearableTorches_BackTorch", false);
			zDO.Set("WearableTorches_BackTorchPrefab", "");
			HideVanillaTorchVisuals(player, hide: false);
			WearableTorchesPlugin.Log.LogInfo((object)("Back torch OFF (G key) for " + player.GetPlayerName()));
		}
	}

	public static void SyncBackTorchForPlayer(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		ZNetView nView = GetNView(player);
		if ((Object)(object)nView == (Object)null)
		{
			return;
		}
		ZDO zDO = nView.GetZDO();
		if (zDO == null)
		{
			return;
		}
		bool @bool = zDO.GetBool("WearableTorches_BackTorch", false);
		string @string = zDO.GetString("WearableTorches_BackTorchPrefab", "");
		long playerKey = GetPlayerKey(player);
		if (playerKey == 0L)
		{
			return;
		}
		BackTorches.TryGetValue(playerKey, out var value);
		if (@bool && !string.IsNullOrEmpty(@string))
		{
			if ((Object)(object)value != (Object)null)
			{
				return;
			}
			GameObject val = FindExistingBackTorchObject(player);
			if ((Object)(object)val != (Object)null)
			{
				BackTorches[playerKey] = val;
				return;
			}
			GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(@string) : null);
			if ((Object)(object)val2 == (Object)null)
			{
				WearableTorchesPlugin.Log.LogWarning((object)("Back torch: prefab '" + @string + "' not found in ZNetScene"));
				return;
			}
			GameObject val3 = CreateBackTorchVisual(player, val2);
			if ((Object)(object)val3 != (Object)null)
			{
				BackTorches[playerKey] = val3;
			}
		}
		else if ((Object)(object)value != (Object)null)
		{
			Object.Destroy((Object)(object)value);
			BackTorches.Remove(playerKey);
		}
		else
		{
			GameObject val4 = FindExistingBackTorchObject(player);
			if ((Object)(object)val4 != (Object)null)
			{
				Object.Destroy((Object)(object)val4);
			}
		}
	}

	private static ZNetView GetNView(Player player)
	{
		if (!((Object)(object)player != (Object)null))
		{
			return null;
		}
		return ((Component)player).GetComponent<ZNetView>();
	}

	internal static bool IsTorch(ItemData item)
	{
		if (item == null)
		{
			return false;
		}
		return ((item.m_shared != null) ? item.m_shared.m_name : "").ToLower().Contains("torch");
	}

	private static ItemData GetTorchInHands(Player player)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			MethodInfo method = typeof(Player).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.NonPublic);
			MethodInfo method2 = typeof(Player).GetMethod("GetLeftItem", BindingFlags.Instance | BindingFlags.NonPublic);
			ItemData val = ((!(method != null)) ? ((ItemData)null) : ((ItemData)method.Invoke(player, null)));
			ItemData val2 = ((!(method2 != null)) ? ((ItemData)null) : ((ItemData)method2.Invoke(player, null)));
			if (IsTorch(val))
			{
				return val;
			}
			if (IsTorch(val2))
			{
				return val2;
			}
			return null;
		}
		catch (Exception ex)
		{
			WearableTorchesPlugin.Log.LogError((object)("GetTorchInHands reflection error: " + ex));
			return null;
		}
	}

	private static GameObject CreateBackTorchVisual(Player player, GameObject prefab)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)prefab == (Object)null)
		{
			return null;
		}
		GameObject val = FindExistingBackTorchObject(player);
		if ((Object)(object)val != (Object)null)
		{
			return val;
		}
		Transform val2 = FindBackAttach(player);
		GameObject val3 = new GameObject("BackTorchObject");
		val3.transform.SetParent(val2, false);
		val3.transform.localRotation = BackRotationOffset;
		val3.transform.localPosition = new Vector3(-0.0026f, -0.002f, -0.0017f);
		Vector3 lossyScale = val2.lossyScale;
		val3.transform.localScale = new Vector3((lossyScale.x != 0f) ? (1f / lossyScale.x) : 1f, (lossyScale.y != 0f) ? (1f / lossyScale.y) : 1f, (lossyScale.z != 0f) ? (1f / lossyScale.z) : 1f);
		MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			((Object)Object.Instantiate<GameObject>(((Component)componentsInChildren[i]).gameObject, val3.transform, false)).name = "BackTorchMesh";
		}
		GameObject val4 = FindTorchFlamesOnPlayer(player);
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = FindTorchFlamesInPrefab(prefab);
		}
		if ((Object)(object)val4 != (Object)null)
		{
			GameObject obj = Object.Instantiate<GameObject>(val4, val3.transform, false);
			((Object)obj).name = "BackTorchFlames";
			obj.transform.localRotation = Quaternion.identity;
			obj.transform.localPosition = FlameOffset;
		}
		GameObject val5 = new GameObject("BackTorchLight");
		val5.transform.SetParent(val3.transform, false);
		val5.transform.localRotation = Quaternion.identity;
		val5.transform.localPosition = LightOffset;
		Light obj2 = val5.AddComponent<Light>();
		obj2.type = (LightType)2;
		obj2.color = new Color(1f, 0.52f, 0.22f);
		obj2.range = 14f;
		obj2.intensity = 1.35f;
		obj2.shadows = (LightShadows)2;
		return val3;
	}

	internal static void HideVanillaTorchVisuals(Player player, bool hide)
	{
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		MeshRenderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val in componentsInChildren)
		{
			Transform transform = ((Component)val).transform;
			if (!IsUnderBackTorchObject(transform))
			{
				string text = ((Object)transform).name.ToLower();
				string text2 = (((Object)(object)transform.parent != (Object)null) ? ((Object)transform.parent).name.ToLower() : "");
				if (text.Contains("torch") || text2.Contains("torch"))
				{
					((Renderer)val).enabled = !hide;
				}
			}
		}
		SkinnedMeshRenderer[] componentsInChildren2 = ((Component)player).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val2 in componentsInChildren2)
		{
			Transform transform2 = ((Component)val2).transform;
			if (!IsUnderBackTorchObject(transform2))
			{
				string text3 = ((Object)transform2).name.ToLower();
				string text4 = (((Object)(object)transform2.parent != (Object)null) ? ((Object)transform2.parent).name.ToLower() : "");
				if (text3.Contains("torch") || text4.Contains("torch"))
				{
					((Renderer)val2).enabled = !hide;
				}
			}
		}
	}

	private static bool IsUnderBackTorchObject(Transform t)
	{
		while ((Object)(object)t != (Object)null)
		{
			if (((Object)t).name == "BackTorchObject")
			{
				return true;
			}
			t = t.parent;
		}
		return false;
	}

	private static Transform FindBackAttach(Player player)
	{
		string[] array = new string[3] { "Visual/Armature/Hips/Spine/Spine1/Spine2", "Visual/Armature/Hips/Spine/Spine1", "Visual/Armature/Hips/Spine" };
		foreach (string text in array)
		{
			Transform val = ((Component)player).transform.Find(text);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		return ((Component)player).transform;
	}

	private static GameObject FindTorchFlamesOnPlayer(Player player)
	{
		Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if (((Object)val).name.ToLower().Contains("torch") && !((Object)(object)((Component)val).GetComponentInChildren<ParticleSystem>(true) == (Object)null) && !((Object)(object)((Component)val).GetComponentInChildren<MeshRenderer>(true) != (Object)null) && !((Object)(object)((Component)val).GetComponentInChildren<SkinnedMeshRenderer>(true) != (Object)null))
			{
				return ((Component)val).gameObject;
			}
		}
		return null;
	}

	private static GameObject FindTorchFlamesInPrefab(GameObject prefab)
	{
		if ((Object)(object)prefab == (Object)null)
		{
			return null;
		}
		ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystem>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Transform transform = ((Component)componentsInChildren[i]).transform;
			MeshRenderer component = ((Component)transform).GetComponent<MeshRenderer>();
			SkinnedMeshRenderer component2 = ((Component)transform).GetComponent<SkinnedMeshRenderer>();
			if ((Object)(object)component == (Object)null && (Object)(object)component2 == (Object)null)
			{
				return ((Component)transform).gameObject;
			}
		}
		return null;
	}

	private static void DestroyBackTorch()
	{
		foreach (KeyValuePair<long, GameObject> backTorch in BackTorches)
		{
			if ((Object)(object)backTorch.Value != (Object)null)
			{
				Object.Destroy((Object)(object)backTorch.Value);
			}
		}
		BackTorches.Clear();
	}

	public static void ForceDestroyBackTorch()
	{
		DestroyBackTorch();
	}

	public static void RemoveBackTorch(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return;
		}
		long playerKey = GetPlayerKey(player);
		if (playerKey != 0L && BackTorches.TryGetValue(playerKey, out var value))
		{
			if ((Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)value);
			}
			BackTorches.Remove(playerKey);
		}
		GameObject val = FindExistingBackTorchObject(player);
		if ((Object)(object)val != (Object)null)
		{
			Object.Destroy((Object)(object)val);
		}
	}
}
[HarmonyPatch(typeof(Player), "OnDestroy")]
public static class Player_OnDestroy_Patch
{
	private static void Prefix(Player __instance)
	{
		WearableTorchManager.RemoveBackTorch(__instance);
	}
}