Decompiled source of Expelliarmus v1.0.9

plugins/Expelliarmus/Expelliarmus.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using Photon.Pun;
using UnityEngine;
using Zorro.Core;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Expelliarmus;

[BepInPlugin("com.dawwnforu.expelliarmus", "Expelliarmus", "1.0.9")]
[BepInProcess("PEAK.exe")]
public class Plugin : BaseUnityPlugin
{
	private void Awake()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Expelliarmus v1.0.9 loading...");
		ExpelliarmusBehaviour.Initialize(((BaseUnityPlugin)this).Logger);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Expelliarmus loaded successfully!");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"  Right click while aiming at a teammate's held item = steal it into your hand.");
	}

	private void OnDestroy()
	{
		ExpelliarmusBehaviour.Shutdown();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Expelliarmus unloaded");
	}
}
public static class PluginInfo
{
	public const string GUID = "com.dawwnforu.expelliarmus";

	public const string Name = "Expelliarmus";

	public const string Version = "1.0.9";
}
public class ExpelliarmusBehaviour : MonoBehaviour
{
	private const float MaxRange = 7.5f;

	private const float AimAngle = 25f;

	private const float SyncTimeout = 4f;

	private static ExpelliarmusBehaviour instance;

	private ManualLogSource logger;

	private bool busy;

	private bool usedThisPress;

	private float nextAttempt;

	private Item droppedItem;

	private Item handoffItem;

	private void ReleaseHandoff()
	{
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		Item val = handoffItem;
		handoffItem = null;
		if ((Object)(object)val != (Object)null && val.data != null && IsGroundItem(val, val.data.guid) && (Object)(object)PhotonNetwork.GetPhotonView(((MonoBehaviourPun)val).photonView.ViewID) == (Object)(object)((MonoBehaviourPun)val).photonView)
		{
			((MonoBehaviourPun)val).photonView.RPC("SetKinematicRPC", (RpcTarget)5, new object[3]
			{
				false,
				val.transform.position,
				val.transform.rotation
			});
		}
	}

	private void OnDisable()
	{
		((MonoBehaviour)this).StopAllCoroutines();
		ReleaseHandoff();
		busy = false;
	}

	public static void Initialize(ManualLogSource log)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Expected O, but got Unknown
		if (!((Object)(object)instance != (Object)null))
		{
			GameObject val = new GameObject("ExpelliarmusManager");
			Object.DontDestroyOnLoad((Object)(object)val);
			instance = val.AddComponent<ExpelliarmusBehaviour>();
			instance.logger = log;
		}
	}

	public static void Shutdown()
	{
		if ((Object)(object)instance != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)instance).gameObject);
		}
		instance = null;
	}

	private void Update()
	{
		Character localCharacter = Character.localCharacter;
		if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.input == (Object)null)
		{
			return;
		}
		if (!localCharacter.input.useSecondaryIsPressed)
		{
			usedThisPress = false;
		}
		else
		{
			if (busy || usedThisPress || Time.unscaledTime < nextAttempt || !CanAct(localCharacter))
			{
				return;
			}
			nextAttempt = Time.unscaledTime + 0.1f;
			Character val = FindTarget(localCharacter);
			if (!((Object)(object)val == (Object)null))
			{
				Item currentItem = val.data.currentItem;
				ItemSlot val2 = HeldSlot(val, currentItem);
				if (val2 != null && val2.itemSlotID <= 2)
				{
					usedThisPress = true;
					busy = true;
					((MonoBehaviour)this).StartCoroutine(Transfer(localCharacter, val, currentItem));
				}
			}
		}
	}

	private static bool CanAct(Character character)
	{
		if (PhotonNetwork.InRoom && (Object)(object)character != (Object)null && character.IsLocal && (Object)(object)character.data != (Object)null && character.data.fullyConscious && !character.data.isClimbingAnything && character.refs != null && (Object)(object)character.refs.items != (Object)null && (Object)(object)character.player != (Object)null && (Object)(object)GUIManager.instance != (Object)null && !GUIManager.instance.windowBlockingInput)
		{
			return !GUIManager.instance.wheelActive;
		}
		return false;
	}

	private static Character FindTarget(Character local)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Invalid comparison between Unknown and I4
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			return null;
		}
		RaycastHit[] array = Physics.RaycastAll(new Ray(((Component)main).transform.position, ((Component)main).transform.forward), 7.5f, -1, (QueryTriggerInteraction)1);
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		RaycastHit[] array2 = array;
		for (int num = 0; num < array2.Length; num++)
		{
			RaycastHit val = array2[num];
			Item componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Item>();
			Character val2 = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.trueHolderCharacter != (Object)null)
			{
				val2 = componentInParent.trueHolderCharacter;
			}
			if (!((Object)(object)val2 == (Object)(object)local))
			{
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2.data == (Object)null)
				{
					return null;
				}
				Item currentItem = val2.data.currentItem;
				if ((Object)(object)currentItem == (Object)null || (int)currentItem.itemState != 1)
				{
					return null;
				}
				Vector3 val3 = currentItem.transform.position - ((Component)main).transform.position;
				if (((Vector3)(ref val3)).magnitude > 7.5f)
				{
					return null;
				}
				return ((Object)(object)componentInParent == (Object)(object)currentItem || Vector3.Angle(((Component)main).transform.forward, val3) <= 25f) ? val2 : null;
			}
		}
		return null;
	}

	private static ItemSlot HeldSlot(Character character, Item item)
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.items == (Object)null || (Object)(object)character.player == (Object)null || (Object)(object)item == (Object)null || item.data == null || item.data.guid == Guid.Empty || (Object)(object)character.data.currentItem != (Object)(object)item || (Object)(object)item.trueHolderCharacter != (Object)(object)character || !item.UIData.canDrop)
		{
			return null;
		}
		Optionable<byte> currentSelectedSlot = character.refs.items.currentSelectedSlot;
		if (currentSelectedSlot.IsNone)
		{
			return null;
		}
		ItemSlot itemSlot = character.player.GetItemSlot(currentSelectedSlot.Value);
		if (itemSlot == null || itemSlot.IsEmpty() || itemSlot.data == null || itemSlot.prefab.itemID != item.itemID || !(itemSlot.data.guid == item.data.guid))
		{
			return null;
		}
		return itemSlot;
	}

	private IEnumerator Transfer(Character local, Character target, Item original)
	{
		try
		{
			Guid guid = original.data.guid;
			Item localItem = local.data.currentItem;
			if ((Object)(object)localItem != (Object)null)
			{
				yield return DropHeldItem(local, localItem);
				if ((Object)(object)droppedItem == (Object)null)
				{
					yield break;
				}
			}
			if (!CanAct(local) || (Object)(object)local.data.currentItem != (Object)null || (Object)(object)original == (Object)null || original.data.guid != guid || HeldSlot(target, original) == null || !local.player.HasEmptySlot(original.itemID))
			{
				yield break;
			}
			Camera camera = Camera.main;
			if ((Object)(object)camera == (Object)null)
			{
				yield break;
			}
			Vector3 handPosition = ((Component)camera).transform.position + ((Component)camera).transform.forward * 0.6f + Vector3.down * 0.25f;
			yield return DropHeldItem(target, original, handPosition);
			Item ground = droppedItem;
			if ((Object)(object)ground == (Object)null || !CanAct(local) || (Object)(object)local.data.currentItem != (Object)null || !local.player.HasEmptySlot(ground.itemID) || !IsGroundItem(ground, guid))
			{
				yield break;
			}
			((MonoBehaviourPun)ground).photonView.RPC("RequestPickup", (RpcTarget)2, new object[1] { ((MonoBehaviourPun)local).photonView });
			float deadline = Time.unscaledTime + 4f;
			while (Time.unscaledTime < deadline && (Object)(object)local != (Object)null && (Object)(object)local.player != (Object)null)
			{
				if (InventoryContains(local.player, guid))
				{
					logger.LogInfo((object)"Expelliarmus: inventory pickup confirmed.");
					yield break;
				}
				yield return (object)new WaitForSecondsRealtime(0.05f);
			}
			logger.LogWarning((object)"Expelliarmus: pickup not confirmed; no retry or replacement item created.");
		}
		finally
		{
			ReleaseHandoff();
			busy = false;
			nextAttempt = Time.unscaledTime + 0.4f;
		}
	}

	private IEnumerator DropHeldItem(Character character, Item original, Vector3? handPosition = null)
	{
		droppedItem = null;
		ItemSlot slot = HeldSlot(character, original);
		if (slot == null)
		{
			yield break;
		}
		Guid guid = original.data.guid;
		int originalViewID = ((MonoBehaviourPun)original).photonView.ViewID;
		if (originalViewID <= 0)
		{
			yield break;
		}
		CharacterItems characterItems = character.refs.items;
		((MonoBehaviourPun)characterItems).photonView.RPC("DropItemFromSlotRPC", (RpcTarget)2, new object[2]
		{
			slot.itemSlotID,
			(object)(Vector3)(((??)handPosition) ?? (original.transform.position + Vector3.down * 0.2f))
		});
		float deadline = Time.unscaledTime + 4f;
		Item ground = null;
		while (Time.unscaledTime < deadline)
		{
			ground = FindGroundItem(guid);
			if ((Object)(object)ground != (Object)null && handPosition.HasValue && (Object)(object)handoffItem == (Object)null)
			{
				handoffItem = ground;
				((MonoBehaviourPun)ground).photonView.RPC("SetKinematicRPC", (RpcTarget)5, new object[3]
				{
					true,
					handPosition.Value,
					ground.transform.rotation
				});
			}
			if ((Object)(object)ground != (Object)null && (Object)(object)character != (Object)null && (Object)(object)character.player != (Object)null && !InventoryContains(character.player, guid))
			{
				break;
			}
			yield return null;
		}
		if ((Object)(object)ground == (Object)null || (Object)(object)character == (Object)null || (Object)(object)character.player == (Object)null || InventoryContains(character.player, guid))
		{
			logger.LogWarning((object)"Expelliarmus: drop not confirmed; held object was not removed by this mod.");
			yield break;
		}
		if ((Object)(object)character.data.currentItem == (Object)(object)original && (Object)(object)original != (Object)null && ((MonoBehaviourPun)original).photonView.ViewID == originalViewID)
		{
			if (character.IsLocal)
			{
				characterItems.EquipSlot(Optionable<byte>.None);
			}
			else
			{
				((MonoBehaviourPun)characterItems).photonView.RPC("EquipSlotRpc", (RpcTarget)5, new object[2] { -1, -1 });
			}
		}
		deadline = Time.unscaledTime + 4f;
		while ((Object)(object)PhotonNetwork.GetPhotonView(originalViewID) != (Object)null && Time.unscaledTime < deadline)
		{
			yield return null;
		}
		if ((Object)(object)PhotonNetwork.GetPhotonView(originalViewID) != (Object)null)
		{
			logger.LogWarning((object)"Expelliarmus: owner release not confirmed; pickup cancelled, ground item retained.");
		}
		else
		{
			droppedItem = FindGroundItem(guid);
		}
	}

	private static bool InventoryContains(Player player, Guid guid)
	{
		ItemSlot[] itemSlots = player.itemSlots;
		foreach (ItemSlot slot in itemSlots)
		{
			if (SlotContains(slot, guid))
			{
				return true;
			}
		}
		if (!SlotContains(player.GetItemSlot((byte)3), guid))
		{
			return SlotContains(player.GetItemSlot((byte)250), guid);
		}
		return true;
	}

	private static bool SlotContains(ItemSlot slot, Guid guid)
	{
		if (slot != null && !slot.IsEmpty() && slot.data != null)
		{
			return slot.data.guid == guid;
		}
		return false;
	}

	private static Item FindGroundItem(Guid guid)
	{
		foreach (Item aLL_ITEM in Item.ALL_ITEMS)
		{
			if (IsGroundItem(aLL_ITEM, guid))
			{
				return aLL_ITEM;
			}
		}
		return null;
	}

	private static bool IsGroundItem(Item item, Guid guid)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)item != (Object)null && item.data != null && item.data.guid == guid && (int)item.itemState == 0 && (Object)(object)item.trueHolderCharacter == (Object)null && (Object)(object)((MonoBehaviourPun)item).photonView != (Object)null && ((MonoBehaviourPun)item).photonView.IsRoomView)
		{
			return ((MonoBehaviourPun)item).photonView.ViewID > 0;
		}
		return false;
	}
}