Decompiled source of Mystery Box v2.0.0

EmpressMysteryBox.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Omniscye / Empress")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("3.2.0.0")]
[assembly: AssemblyInformationalVersion("3.2.0")]
[assembly: AssemblyProduct("EmpressMysteryBox")]
[assembly: AssemblyTitle("EmpressMysteryBox")]
[assembly: AssemblyVersion("3.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Empress.REPO.MysteryBox
{
	[BepInPlugin("com.empress.repo.mysterybox", "Empress Mystery Box", "3.2.0")]
	public sealed class EmpressMysteryBoxPlugin : BaseUnityPlugin, IOnEventCallback
	{
		public const string PluginGuid = "com.empress.repo.mysterybox";

		public const string PluginName = "Empress Mystery Box";

		public const string PluginVersion = "3.2.0";

		public const byte MysteryBoxEventCode = 110;

		private bool _eventsRegistered;

		private bool _bindingStarted;

		private int _sceneHandle = -1;

		internal static EmpressMysteryBoxPlugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			Log.LogInfo((object)"Empress Mystery Box v3.2.0 loaded.");
		}

		private void OnDisable()
		{
			if (_eventsRegistered)
			{
				PhotonNetwork.RemoveCallbackTarget((object)this);
				_eventsRegistered = false;
			}
		}

		private void Update()
		{
			UpdateEventRegistration();
			UpdateLevelBinding();
		}

		private void UpdateEventRegistration()
		{
			if (PhotonNetwork.InRoom && !_eventsRegistered)
			{
				PhotonNetwork.AddCallbackTarget((object)this);
				_eventsRegistered = true;
			}
			else if (!PhotonNetwork.InRoom && _eventsRegistered)
			{
				PhotonNetwork.RemoveCallbackTarget((object)this);
				_eventsRegistered = false;
			}
		}

		private void UpdateLevelBinding()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!MysteryBoxAccess.CanBindToCurrentLevel())
			{
				_bindingStarted = false;
				_sceneHandle = -1;
				return;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			int handle = ((Scene)(ref activeScene)).handle;
			if (handle != _sceneHandle)
			{
				_sceneHandle = handle;
				_bindingStarted = false;
				((MonoBehaviour)this).StopAllCoroutines();
			}
			if (!_bindingStarted)
			{
				_bindingStarted = true;
				((MonoBehaviour)this).StartCoroutine(MysteryBoxStationBinder.WaitAndBind());
			}
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 110 || !(photonEvent.CustomData is object[] array) || array.Length < 2)
			{
				return;
			}
			string text = array[0] as string;
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			GameObject val = GameObject.Find(text);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MysteryBoxStationLogic component = val.GetComponent<MysteryBoxStationLogic>();
			if (!((Object)(object)component == (Object)null))
			{
				if (((array[1] is int num) ? num : 0) == -1)
				{
					component.PlayRollVisuals();
				}
				else
				{
					component.StopRollAndShowPrize();
				}
			}
		}

		internal static void RaiseMysteryBoxEvent(string stationName, int result)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.InRoom)
			{
				RaiseEventOptions val = new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)1
				};
				PhotonNetwork.RaiseEvent((byte)110, (object)new object[2] { stationName, result }, val, SendOptions.SendReliable);
			}
		}
	}
	internal static class MysteryBoxAccess
	{
		private static readonly FieldRef<StatsManager, Dictionary<string, Item>> ItemDictionaryRef = AccessTools.FieldRefAccess<StatsManager, Dictionary<string, Item>>("itemDictionary");

		private static readonly FieldRef<Item, PrefabRef> ItemPrefabRef = AccessTools.FieldRefAccess<Item, PrefabRef>("prefab");

		private static readonly FieldRef<Item, bool> ItemDisabledRef = AccessTools.FieldRefAccess<Item, bool>("disabled");

		private static readonly FieldRef<PhysGrabObject, List<PhysGrabber>> PlayerGrabbingRef = AccessTools.FieldRefAccess<PhysGrabObject, List<PhysGrabber>>("playerGrabbing");

		private static readonly FieldRef<ChargingStation, Transform> ChargingStationChargeAreaRef = AccessTools.FieldRefAccess<ChargingStation, Transform>("chargeArea");

		public static Dictionary<string, Item> GetItemDictionary()
		{
			if (!((Object)(object)StatsManager.instance != (Object)null))
			{
				return null;
			}
			return ItemDictionaryRef.Invoke(StatsManager.instance);
		}

		public static PrefabRef GetItemPrefab(Item item)
		{
			if (!((Object)(object)item != (Object)null))
			{
				return null;
			}
			return ItemPrefabRef.Invoke(item);
		}

		public static bool IsItemDisabled(Item item)
		{
			if ((Object)(object)item != (Object)null)
			{
				return ItemDisabledRef.Invoke(item);
			}
			return false;
		}

		public static bool IsGrabbed(PhysGrabObject physGrabObject)
		{
			if ((Object)(object)physGrabObject == (Object)null)
			{
				return false;
			}
			List<PhysGrabber> list = PlayerGrabbingRef.Invoke(physGrabObject);
			if (list != null)
			{
				return list.Count > 0;
			}
			return false;
		}

		public static Transform GetChargeArea(ChargingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return null;
			}
			Transform val = ChargingStationChargeAreaRef.Invoke(station);
			if (!((Object)(object)val != (Object)null))
			{
				return ((Component)station).transform.Find("Charge Area");
			}
			return val;
		}

		public static bool CanBindToCurrentLevel()
		{
			if ((Object)(object)LevelGenerator.Instance == (Object)null)
			{
				return false;
			}
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null)
			{
				return false;
			}
			return !IsBlockedLevel();
		}

		public static bool IsBlockedLevel()
		{
			try
			{
				if (SemiFunc.MenuLevel() || SemiFunc.RunIsLobbyMenu() || SemiFunc.RunIsTutorial())
				{
					return true;
				}
				RunManager instance = RunManager.instance;
				Level val = (((Object)(object)instance != (Object)null) ? instance.levelCurrent : null);
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				string text = (val.NarrativeName ?? string.Empty).Trim().ToLowerInvariant();
				string text2 = (((Object)val).name ?? string.Empty).Trim().ToLowerInvariant();
				return text.Contains("lobby") || text2.Contains("lobby") || text.Contains("menu") || text2.Contains("menu") || text.Contains("splash") || text2.Contains("splash");
			}
			catch
			{
				return true;
			}
		}
	}
	internal sealed class MysteryBoxLootEntry
	{
		public GameObject DisplayPrefab;

		public string NetworkPath;
	}
	internal static class MysteryBoxLootPool
	{
		private static readonly List<MysteryBoxLootEntry> Loot = new List<MysteryBoxLootEntry>();

		public static int Count => Loot.Count;

		public static MysteryBoxLootEntry RandomEntry()
		{
			Populate();
			if (Loot.Count <= 0)
			{
				return null;
			}
			return Loot[Random.Range(0, Loot.Count)];
		}

		public static void Populate()
		{
			if (Loot.Count > 0)
			{
				return;
			}
			Dictionary<string, Item> itemDictionary = MysteryBoxAccess.GetItemDictionary();
			if (itemDictionary == null)
			{
				return;
			}
			foreach (Item value in itemDictionary.Values)
			{
				if ((Object)(object)value == (Object)null || MysteryBoxAccess.IsItemDisabled(value))
				{
					continue;
				}
				PrefabRef itemPrefab = MysteryBoxAccess.GetItemPrefab(value);
				if (itemPrefab != null && itemPrefab.IsValid())
				{
					GameObject prefab = itemPrefab.Prefab;
					string resourcePath = itemPrefab.ResourcePath;
					if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrEmpty(resourcePath) && !((Object)(object)prefab.GetComponent<PhotonView>() == (Object)null))
					{
						Loot.Add(new MysteryBoxLootEntry
						{
							DisplayPrefab = prefab,
							NetworkPath = resourcePath
						});
					}
				}
			}
			EmpressMysteryBoxPlugin.Log.LogInfo((object)("Empress Mystery Box loot pool populated with " + Loot.Count + " items."));
		}
	}
	internal static class MysteryBoxStationBinder
	{
		public static IEnumerator WaitAndBind()
		{
			float timer = 0f;
			while (((Object)(object)LevelGenerator.Instance == (Object)null || !LevelGenerator.Instance.Generated) && timer <= 60f)
			{
				timer += Time.deltaTime;
				yield return null;
			}
			if ((Object)(object)LevelGenerator.Instance == (Object)null || !LevelGenerator.Instance.Generated)
			{
				yield break;
			}
			yield return (object)new WaitForSeconds(1f);
			ChargingStation[] array = Object.FindObjectsOfType<ChargingStation>();
			if (array == null || array.Length == 0)
			{
				if (!MysteryBoxAccess.IsBlockedLevel())
				{
					EmpressMysteryBoxPlugin.Log.LogWarning((object)"Empress Mystery Box found no charging station in this level.");
				}
				yield break;
			}
			foreach (ChargingStation val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)MysteryBoxAccess.GetChargeArea(val) == (Object)null))
				{
					if (((Object)((Component)val).gameObject).name == "ChargingStation(Clone)")
					{
						GameObject gameObject = ((Component)val).gameObject;
						Vector3 position = ((Component)val).transform.position;
						((Object)gameObject).name = "EmpressMysteryBoxStation_" + Mathf.Abs(((Vector3)(ref position)).sqrMagnitude).ToString("0.000");
					}
					if ((Object)(object)((Component)val).gameObject.GetComponent<MysteryBoxStationLogic>() == (Object)null)
					{
						((Component)val).gameObject.AddComponent<MysteryBoxStationLogic>();
						EmpressMysteryBoxPlugin.Log.LogInfo((object)"Empress Mystery Box bound to charging station.");
					}
				}
			}
		}
	}
	internal sealed class MysteryBoxStationLogic : MonoBehaviour
	{
		private bool _busy;

		private GameObject _ghostModel;

		private Coroutine _rollCoroutine;

		private Transform _chargeArea;

		private ChargingStation _station;

		private void Start()
		{
			_station = ((Component)this).GetComponent<ChargingStation>();
			_chargeArea = MysteryBoxAccess.GetChargeArea(_station);
			MysteryBoxLootPool.Populate();
			((MonoBehaviour)this).StartCoroutine(ScanRoutine());
		}

		private IEnumerator ScanRoutine()
		{
			if ((Object)(object)_chargeArea == (Object)null)
			{
				yield break;
			}
			while (true)
			{
				if (SemiFunc.IsMasterClientOrSingleplayer() && !_busy)
				{
					TryAcceptValuable();
				}
				yield return (object)new WaitForSeconds(0.2f);
			}
		}

		private void TryAcceptValuable()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapBox(_chargeArea.position, _chargeArea.lossyScale * 0.5f, _chargeArea.rotation, LayerMask.op_Implicit(SemiFunc.LayerMaskGetPhysGrabObject()));
			for (int i = 0; i < array.Length; i++)
			{
				EnemyValuable val = (((Object)(object)array[i] != (Object)null) ? ((Component)array[i]).GetComponentInParent<EnemyValuable>() : null);
				if (!((Object)(object)val == (Object)null))
				{
					PhysGrabObject component = ((Component)val).GetComponent<PhysGrabObject>();
					if (!((Object)(object)component == (Object)null) && !MysteryBoxAccess.IsGrabbed(component))
					{
						StartMysteryBoxEvent(component);
						break;
					}
				}
			}
		}

		private void StartMysteryBoxEvent(PhysGrabObject obj)
		{
			_busy = true;
			DestroyAcceptedObject(obj);
			if (PhotonNetwork.InRoom)
			{
				EmpressMysteryBoxPlugin.RaiseMysteryBoxEvent(((Object)((Component)this).gameObject).name, -1);
			}
			else
			{
				PlayRollVisuals();
			}
			((MonoBehaviour)this).StartCoroutine(ServerProcessRoutine());
		}

		private static void DestroyAcceptedObject(PhysGrabObject obj)
		{
			if (!((Object)(object)obj == (Object)null) && !((Object)(object)((Component)obj).gameObject == (Object)null))
			{
				PhotonView component = ((Component)obj).GetComponent<PhotonView>();
				if (PhotonNetwork.InRoom && (Object)(object)component != (Object)null)
				{
					PhotonNetwork.Destroy(((Component)obj).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)obj).gameObject);
				}
			}
		}

		private IEnumerator ServerProcessRoutine()
		{
			yield return (object)new WaitForSeconds(4.5f);
			MysteryBoxLootEntry mysteryBoxLootEntry = MysteryBoxLootPool.RandomEntry();
			if (mysteryBoxLootEntry != null)
			{
				Vector3 val = _chargeArea.position + Vector3.up * 0.5f;
				GameObject val2;
				if (PhotonNetwork.InRoom)
				{
					val2 = PhotonNetwork.Instantiate(mysteryBoxLootEntry.NetworkPath, val, Quaternion.identity, (byte)0, (object[])null);
					PhotonView val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<PhotonView>() : null);
					EmpressMysteryBoxPlugin.RaiseMysteryBoxEvent(((Object)((Component)this).gameObject).name, ((Object)(object)val3 != (Object)null) ? val3.ViewID : 0);
				}
				else
				{
					val2 = Object.Instantiate<GameObject>(mysteryBoxLootEntry.DisplayPrefab, val, Quaternion.identity);
					StopRollAndShowPrize();
				}
				yield return ((MonoBehaviour)this).StartCoroutine(PrizeCountdown(val2));
			}
			else if (PhotonNetwork.InRoom)
			{
				EmpressMysteryBoxPlugin.RaiseMysteryBoxEvent(((Object)((Component)this).gameObject).name, -999);
			}
			else
			{
				StopRollAndShowPrize();
			}
			_busy = false;
		}

		private IEnumerator PrizeCountdown(GameObject prize)
		{
			float timer = 0f;
			while (timer < 10f)
			{
				if ((Object)(object)prize == (Object)null)
				{
					yield break;
				}
				PhysGrabObject component = prize.GetComponent<PhysGrabObject>();
				if ((Object)(object)component != (Object)null && MysteryBoxAccess.IsGrabbed(component))
				{
					yield break;
				}
				timer += Time.deltaTime;
				yield return null;
			}
			if (!((Object)(object)prize == (Object)null))
			{
				PhotonView component2 = prize.GetComponent<PhotonView>();
				if (PhotonNetwork.InRoom && (Object)(object)component2 != (Object)null)
				{
					PhotonNetwork.Destroy(prize);
				}
				else
				{
					Object.Destroy((Object)(object)prize);
				}
			}
		}

		public void PlayRollVisuals()
		{
			if (_rollCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_rollCoroutine);
			}
			_rollCoroutine = ((MonoBehaviour)this).StartCoroutine(RollAnimation());
		}

		public void StopRollAndShowPrize()
		{
			if (_rollCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_rollCoroutine);
			}
			if ((Object)(object)_ghostModel != (Object)null)
			{
				Object.Destroy((Object)(object)_ghostModel);
			}
			_rollCoroutine = null;
			_ghostModel = null;
		}

		private IEnumerator RollAnimation()
		{
			if ((Object)(object)_chargeArea == (Object)null)
			{
				yield break;
			}
			MysteryBoxLootPool.Populate();
			if (MysteryBoxLootPool.Count == 0)
			{
				yield break;
			}
			float speed = 0.1f;
			float elapsed = 0f;
			float spinAngle = 0f;
			Vector3 visualPosition = _chargeArea.position + Vector3.up * 0.5f;
			while (true)
			{
				if ((Object)(object)_ghostModel != (Object)null)
				{
					Object.Destroy((Object)(object)_ghostModel);
				}
				MysteryBoxLootEntry mysteryBoxLootEntry = MysteryBoxLootPool.RandomEntry();
				if (mysteryBoxLootEntry != null && (Object)(object)mysteryBoxLootEntry.DisplayPrefab != (Object)null)
				{
					spinAngle += 90f;
					_ghostModel = Object.Instantiate<GameObject>(mysteryBoxLootEntry.DisplayPrefab, visualPosition, Quaternion.Euler(0f, spinAngle, 0f));
					StripRuntimeComponents(_ghostModel);
				}
				yield return (object)new WaitForSeconds(speed);
				elapsed += speed;
				if (elapsed > 3f)
				{
					speed += 0.05f;
				}
			}
		}

		private static void StripRuntimeComponents(GameObject target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return;
			}
			MonoBehaviour[] componentsInChildren = target.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((Object)(object)componentsInChildren[i] != (Object)null)
				{
					Object.Destroy((Object)(object)componentsInChildren[i]);
				}
			}
			Rigidbody[] componentsInChildren2 = target.GetComponentsInChildren<Rigidbody>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				if ((Object)(object)componentsInChildren2[j] != (Object)null)
				{
					Object.Destroy((Object)(object)componentsInChildren2[j]);
				}
			}
			Collider[] componentsInChildren3 = target.GetComponentsInChildren<Collider>(true);
			for (int k = 0; k < componentsInChildren3.Length; k++)
			{
				if ((Object)(object)componentsInChildren3[k] != (Object)null)
				{
					Object.Destroy((Object)(object)componentsInChildren3[k]);
				}
			}
			Joint[] componentsInChildren4 = target.GetComponentsInChildren<Joint>(true);
			for (int l = 0; l < componentsInChildren4.Length; l++)
			{
				if ((Object)(object)componentsInChildren4[l] != (Object)null)
				{
					Object.Destroy((Object)(object)componentsInChildren4[l]);
				}
			}
		}
	}
}