Decompiled source of Better Dvergr Lantern v1.0.0

BepInEx/plugins/BetterDvergrLantern/BetterDvergrLantern.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[BepInPlugin("com.betterdvergrlantern", "Better Dvergr lantern", "1.0.0")]
public sealed class BetterDvergrLantern : BaseUnityPlugin
{
	private delegate GameObject AttachBackItem(VisEquipment equipment, int hash, int variant, bool rightHand, int quality);

	private delegate void DrainDurability(Humanoid humanoid, ItemData item, float dt);

	private delegate InventoryElement GetGridElement(InventoryGrid grid, int x, int y, int width);

	private delegate void RefreshLodGroup(VisEquipment equipment);

	private sealed class Belt
	{
		public ItemData Item;

		public GameObject Model;

		public int ModelQuality;

		public int ModelVariant;

		public bool VisualFailed;

		public VisEquipment Equipment;

		public void RemoveModel()
		{
			if (Object.op_Implicit((Object)(object)Model))
			{
				Model.SetActive(false);
				Object.Destroy((Object)(object)Model);
				if (Object.op_Implicit((Object)(object)Equipment))
				{
					refreshLodGroup(Equipment);
				}
			}
			Model = null;
			VisualFailed = false;
		}
	}

	[HarmonyPatch(typeof(Humanoid), "EquipItem")]
	private static class HandEquip
	{
		private static void Prefix(Humanoid __instance, ItemData ___m_hiddenRightItem, ItemData ___m_hiddenLeftItem, out ItemData __state)
		{
			__state = null;
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && !((Object)(object)__instance != (Object)(object)localPlayer))
			{
				if (IsLantern(___m_hiddenRightItem))
				{
					__state = ___m_hiddenRightItem;
				}
				else if (IsLantern(___m_hiddenLeftItem))
				{
					__state = ___m_hiddenLeftItem;
				}
			}
		}

		private static void Postfix(Humanoid __instance, ItemData item, bool __result, ItemData ___m_hiddenRightItem, ItemData ___m_hiddenLeftItem, ItemData __state)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!__result || !Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)__instance != (Object)(object)localPlayer)
			{
				return;
			}
			if (IsLantern(item) && Belts.TryGetValue(localPlayer, out var value) && RefreshBelt(localPlayer, value) == item)
			{
				ClearBelt(localPlayer, value);
			}
			if (__state != null && __state != item && (((Humanoid)localPlayer).RightItem == item || ((Humanoid)localPlayer).LeftItem == item) && __state != ___m_hiddenRightItem && __state != ___m_hiddenLeftItem && ((Humanoid)localPlayer).GetInventory().ContainsItem(__state) && CanLight(__state))
			{
				EquipBelt(localPlayer, Belts.GetValue(localPlayer, (Player _) => new Belt()), __state);
			}
		}
	}

	[HarmonyPatch(typeof(Player), "Load")]
	private static class RestoreBelt
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && Belts.TryGetValue(__instance, out var value))
			{
				ClearBelt(__instance, value);
			}
		}

		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __instance.m_customData.TryGetValue("com.betterdvergrlantern.belt", out var value))
			{
				Belt value2 = Belts.GetValue(__instance, (Player _) => new Belt());
				value2.RemoveModel();
				value2.Item = FindSavedLantern(__instance, value);
				if (value2.Item == null || !CanLight(value2.Item) || ((Humanoid)__instance).IsItemEquiped(value2.Item))
				{
					ClearBelt(__instance, value2);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Player), "Save")]
	private static class SaveBelt
	{
		private static void Prefix(Player __instance)
		{
			if (Belts.TryGetValue(__instance, out var value))
			{
				RefreshBelt(__instance, value);
			}
		}
	}

	[HarmonyPatch(typeof(Humanoid), "UpdateEquipment")]
	private static class BeltDurability
	{
		private static void Postfix(Humanoid __instance, float dt)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)__instance != (Object)(object)localPlayer || ((Character)localPlayer).IsDead() || !Belts.TryGetValue(localPlayer, out var value))
			{
				return;
			}
			ItemData val = RefreshBelt(localPlayer, value);
			if (val != null && val.m_shared.m_useDurability)
			{
				drainDurability((Humanoid)(object)localPlayer, val, dt);
				if (!CanLight(val))
				{
					ClearBelt(localPlayer, value);
				}
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "UpdateEquipmentVisuals")]
	private static class BeltVisual
	{
		private static void Postfix(VisEquipment __instance, ZNetView ___m_nview)
		{
			Player component = ((Component)__instance).GetComponent<Player>();
			if (!Object.op_Implicit((Object)(object)component) || (Object)(object)((Humanoid)component).GetVisEquipment() != (Object)(object)__instance)
			{
				return;
			}
			ZDO val = (Object.op_Implicit((Object)(object)___m_nview) ? ___m_nview.GetZDO() : null);
			Belt value;
			long num;
			if ((Object)(object)component == (Object)(object)Player.m_localPlayer)
			{
				value = Belts.GetValue(component, (Player _) => new Belt());
				ItemData val2 = RefreshBelt(component, value);
				num = ((val2 != null && !((Character)component).IsDead()) ? (((long)Mathf.Max(1, val2.m_quality) << 32) | (uint)val2.m_variant) : 0);
				if (val != null && ___m_nview.IsOwner())
				{
					val.Set(NetworkBeltKey, num);
				}
			}
			else
			{
				num = ((val != null) ? val.GetLong(NetworkBeltKey, 0L) : 0);
				if (!Belts.TryGetValue(component, out value))
				{
					if (num == 0L)
					{
						return;
					}
					value = Belts.GetValue(component, (Player _) => new Belt());
				}
			}
			if (num == 0L || ((Character)component).IsDead())
			{
				value.RemoveModel();
				return;
			}
			int num2 = Mathf.Max(1, (int)(num >> 32));
			int num3 = (int)num;
			if (((Object.op_Implicit((Object)(object)value.Model) || value.VisualFailed) && value.ModelQuality == num2 && value.ModelVariant == num3) || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ObjectDB.instance.GetItemPrefab(LanternHash)))
			{
				return;
			}
			value.RemoveModel();
			value.Equipment = __instance;
			value.Model = attachBackItem(__instance, LanternHash, num3, rightHand: false, num2);
			value.ModelQuality = num2;
			value.ModelVariant = num3;
			if (Object.op_Implicit((Object)(object)value.Model))
			{
				AddSway(value.Model, component);
				Light[] componentsInChildren = value.Model.GetComponentsInChildren<Light>(true);
				foreach (Light obj in componentsInChildren)
				{
					((Behaviour)obj).enabled = true;
					Transform val3 = ((Component)obj).transform;
					while ((Object)(object)val3 != (Object)(object)value.Model.transform)
					{
						((Component)val3).gameObject.SetActive(true);
						val3 = val3.parent;
					}
				}
				refreshLodGroup(__instance);
			}
			else
			{
				value.VisualFailed = true;
				Debug.LogWarning((object)"Better Dvergr lantern: could not attach the vanilla lantern model.");
			}
		}
	}

	[HarmonyPatch(typeof(VisEquipment), "AttachBackItem")]
	private static class StowedLanternSway
	{
		private static void Postfix(VisEquipment __instance, int hash, GameObject __result)
		{
			Player component = ((Component)__instance).GetComponent<Player>();
			if (hash == LanternHash && Object.op_Implicit((Object)(object)__result) && Object.op_Implicit((Object)(object)component) && (Object)(object)((Humanoid)component).GetVisEquipment() == (Object)(object)__instance)
			{
				AddSway(__result, component);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	private static class BeltIndicator
	{
		private static void Postfix(InventoryGrid __instance, Player player)
		{
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || __instance.GetInventory() != ((Humanoid)player).GetInventory() || !Belts.TryGetValue(player, out var value))
			{
				return;
			}
			ItemData val = RefreshBelt(player, value);
			if (val != null)
			{
				InventoryElement val2 = getGridElement(__instance, val.m_gridPos.x, val.m_gridPos.y, ((Humanoid)player).GetInventory().GetWidth());
				if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.m_equiped))
				{
					((Behaviour)val2.m_equiped).enabled = true;
				}
			}
		}
	}

	private const string Id = "com.betterdvergrlantern";

	private const string Prefab = "Lantern";

	private const string BeltKey = "com.betterdvergrlantern.belt";

	private static readonly int LanternHash = StringExtensionMethods.GetStableHashCode("Lantern");

	private static readonly int NetworkBeltKey = StringExtensionMethods.GetStableHashCode("com.betterdvergrlantern.visual");

	private static readonly ConditionalWeakTable<Player, Belt> Belts = new ConditionalWeakTable<Player, Belt>();

	private static AttachBackItem attachBackItem;

	private static DrainDurability drainDurability;

	private static GetGridElement getGridElement;

	private static RefreshLodGroup refreshLodGroup;

	private Harmony harmony;

	private void Awake()
	{
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Expected O, but got Unknown
		attachBackItem = AccessTools.MethodDelegate<AttachBackItem>(AccessTools.DeclaredMethod(typeof(VisEquipment), "AttachBackItem", (Type[])null, (Type[])null), (object)null, true);
		drainDurability = AccessTools.MethodDelegate<DrainDurability>(AccessTools.DeclaredMethod(typeof(Humanoid), "DrainEquipedItemDurability", (Type[])null, (Type[])null), (object)null, true);
		getGridElement = AccessTools.MethodDelegate<GetGridElement>(AccessTools.DeclaredMethod(typeof(InventoryGrid), "GetElement", (Type[])null, (Type[])null), (object)null, true);
		refreshLodGroup = AccessTools.MethodDelegate<RefreshLodGroup>(AccessTools.DeclaredMethod(typeof(VisEquipment), "UpdateLodgroup", (Type[])null, (Type[])null), (object)null, true);
		harmony = new Harmony("com.betterdvergrlantern");
		try
		{
			harmony.PatchAll(typeof(BetterDvergrLantern).Assembly);
		}
		catch
		{
			harmony.UnpatchSelf();
			throw;
		}
	}

	private void OnDestroy()
	{
		foreach (Player allPlayer in Player.GetAllPlayers())
		{
			if (Object.op_Implicit((Object)(object)allPlayer) && Belts.TryGetValue(allPlayer, out var value))
			{
				value.RemoveModel();
			}
		}
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	private static bool IsLantern(ItemData item)
	{
		if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
		{
			return ((Object)item.m_dropPrefab).name == "Lantern";
		}
		return false;
	}

	private static bool CanLight(ItemData item)
	{
		if (item.m_shared.m_useDurability)
		{
			return item.m_durability > 0f;
		}
		return true;
	}

	private static void ClearBelt(Player player, Belt belt)
	{
		belt.Item?.m_customData.Remove("com.betterdvergrlantern.belt");
		player.m_customData.Remove("com.betterdvergrlantern.belt");
		belt.Item = null;
		belt.RemoveModel();
	}

	private static void EquipBelt(Player player, Belt belt, ItemData item)
	{
		ClearBelt(player, belt);
		string value = Guid.NewGuid().ToString("N");
		item.m_customData["com.betterdvergrlantern.belt"] = value;
		player.m_customData["com.betterdvergrlantern.belt"] = value;
		belt.Item = item;
	}

	private static ItemData FindSavedLantern(Player player, string token)
	{
		foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
		{
			if (IsLantern(allItem) && allItem.m_stack > 0 && allItem.m_customData.TryGetValue("com.betterdvergrlantern.belt", out var value) && token == value)
			{
				return allItem;
			}
		}
		return null;
	}

	private static ItemData RefreshBelt(Player player, Belt belt)
	{
		ItemData val = belt.Item;
		if (val == null)
		{
			return null;
		}
		if (val.m_stack <= 0 || !((Humanoid)player).GetInventory().ContainsItem(val))
		{
			val = (player.m_customData.TryGetValue("com.betterdvergrlantern.belt", out var value) ? FindSavedLantern(player, value) : null);
			if (val != null)
			{
				belt.Item = val;
			}
		}
		if (val == null || !CanLight(val))
		{
			ClearBelt(player, belt);
			return null;
		}
		return val;
	}

	private static void AddSway(GameObject model, Player player)
	{
		LanternBeltSway lanternBeltSway = default(LanternBeltSway);
		if (!model.TryGetComponent<LanternBeltSway>(ref lanternBeltSway))
		{
			lanternBeltSway = model.AddComponent<LanternBeltSway>();
		}
		lanternBeltSway.Player = player;
	}
}
internal sealed class LanternBeltSway : MonoBehaviour
{
	public Player Player;

	private Quaternion restRotation;

	private float phase;

	private float amplitude;

	private void Awake()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		restRotation = ((Component)this).transform.localRotation;
	}

	private void LateUpdate()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: 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_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)Player))
		{
			Vector3 velocity = ((Character)Player).GetVelocity();
			float num = Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
			float num2 = ((((Character)Player).IsOnGround() || (!((Character)Player).IsOwner() && !((Character)Player).IsSwimming())) ? Mathf.InverseLerp(0.15f, 4.5f, num) : 0f);
			float deltaTime = Time.deltaTime;
			amplitude = Mathf.MoveTowards(amplitude, num2, 3f * deltaTime);
			phase = Mathf.Repeat(phase + Mathf.Lerp(7f, 13f, num2) * deltaTime, (float)Math.PI * 2f);
			float num3 = 3f * amplitude * Mathf.Sin(2f * phase);
			float num4 = 10f * amplitude * Mathf.Sin(phase);
			((Component)this).transform.localRotation = restRotation * Quaternion.Euler(num3, 0f, num4);
		}
	}
}