Decompiled source of ThreeChoiceChests v1.0.0

ThreeChoiceChests/ThreeChoiceChests.dll

Decompiled 10 hours ago
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.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using On.RoR2;
using RoR2;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExamplePlugin")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ExamplePlugin")]
[assembly: AssemblyTitle("ExamplePlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 ExamplePlugin
{
	internal static class Log
	{
		private static ManualLogSource _logSource;

		internal static void Init(ManualLogSource logSource)
		{
			_logSource = logSource;
		}

		private static string Format(object data, string file, int line)
		{
			string fileName = Path.GetFileName(file);
			return $"[{fileName}:{line}] {data}";
		}

		internal static void Debug(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogDebug((object)Format(data, file, line));
		}

		internal static void Error(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogError((object)Format(data, file, line));
		}

		internal static void Fatal(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogFatal((object)Format(data, file, line));
		}

		internal static void Info(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogInfo((object)Format(data, file, line));
		}

		internal static void Message(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogMessage((object)Format(data, file, line));
		}

		internal static void Warning(object data, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0)
		{
			_logSource.LogWarning((object)Format(data, file, line));
		}
	}
}
namespace ThreeChoiceChests
{
	[BepInPlugin("com.local.threechoicechests", "ThreeChoiceChests", "1.0.0")]
	public class ThreeChoiceChestsPlugin : BaseUnityPlugin
	{
		[HarmonyPatch]
		private static class CreatePickupDropletPatch
		{
			private static MethodBase TargetMethod()
			{
				return typeof(PickupDropletController).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo method)
				{
					if (method.Name != "CreatePickupDroplet")
					{
						return false;
					}
					ParameterInfo[] parameters = method.GetParameters();
					return parameters.Length == 3 && parameters[0].ParameterType == typeof(CreatePickupInfo) && parameters[1].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(Vector3);
				});
			}

			private static bool Prefix(ref CreatePickupInfo __0, Vector3 __1, Vector3 __2)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				bool flag = TryCreateThreeChoicePicker(ref __0, __1);
				return !flag;
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static hook_OnInteractionBegin <0>__PurchaseInteraction_OnInteractionBegin;
		}

		public const string PluginGUID = "com.local.threechoicechests";

		public const string PluginName = "ThreeChoiceChests";

		public const string PluginVersion = "1.0.0";

		private Harmony harmony;

		private static GameObject commandCubePrefab;

		private static readonly Queue<PendingChoice> pendingChoices = new Queue<PendingChoice>();

		private static bool pickerActive;

		private static ThreeChoiceChestsPlugin instance;

		private void Awake()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			instance = this;
			MarkChest("RoR2/Base/Chest1/Chest1.prefab", ThreeChoiceChestCategory.General);
			MarkChest("RoR2/Base/CategoryChest/CategoryChestDamage.prefab", ThreeChoiceChestCategory.Damage);
			MarkChest("RoR2/Base/CategoryChest/CategoryChestHealing.prefab", ThreeChoiceChestCategory.Healing);
			MarkChest("RoR2/Base/CategoryChest/CategoryChestUtility.prefab", ThreeChoiceChestCategory.Utility);
			MarkChest("RoR2/DLC1/CategoryChest2/CategoryChest2Damage Variant.prefab", ThreeChoiceChestCategory.Damage);
			MarkChest("RoR2/DLC1/CategoryChest2/CategoryChest2Healing Variant.prefab", ThreeChoiceChestCategory.Healing);
			MarkChest("RoR2/DLC1/CategoryChest2/CategoryChest2Utility Variant.prefab", ThreeChoiceChestCategory.Utility);
			MarkChest("RoR2/Base/Chest2/Chest2.prefab", ThreeChoiceChestCategory.General);
			MarkChest("RoR2/Base/GoldChest/GoldChest.prefab", ThreeChoiceChestCategory.General);
			MarkChest("RoR2/Base/Chest1StealthedVariant/Chest1StealthedVariant.prefab", ThreeChoiceChestCategory.General);
			MarkChest("RoR2/Base/EquipmentBarrel/EquipmentBarrel.prefab", ThreeChoiceChestCategory.General);
			commandCubePrefab = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Command/CommandCube.prefab").WaitForCompletion();
			if ((Object)(object)commandCubePrefab == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not load CommandCube prefab.");
				return;
			}
			object obj = <>O.<0>__PurchaseInteraction_OnInteractionBegin;
			if (obj == null)
			{
				hook_OnInteractionBegin val = PurchaseInteraction_OnInteractionBegin;
				<>O.<0>__PurchaseInteraction_OnInteractionBegin = val;
				obj = (object)val;
			}
			PurchaseInteraction.OnInteractionBegin += (hook_OnInteractionBegin)obj;
			harmony = new Harmony("com.local.threechoicechests");
			harmony.PatchAll(typeof(CreatePickupDropletPatch));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ThreeChoiceChests 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			object obj = <>O.<0>__PurchaseInteraction_OnInteractionBegin;
			if (obj == null)
			{
				hook_OnInteractionBegin val = PurchaseInteraction_OnInteractionBegin;
				<>O.<0>__PurchaseInteraction_OnInteractionBegin = val;
				obj = (object)val;
			}
			PurchaseInteraction.OnInteractionBegin -= (hook_OnInteractionBegin)obj;
			Harmony obj2 = harmony;
			if (obj2 != null)
			{
				obj2.UnpatchSelf();
			}
			pendingChoices.Clear();
			pickerActive = false;
			instance = null;
		}

		private void MarkChest(string address, ThreeChoiceChestCategory category)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)address).WaitForCompletion();
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not load chest prefab: " + address));
				return;
			}
			ThreeChoiceChestMarker threeChoiceChestMarker = val.GetComponent<ThreeChoiceChestMarker>();
			if ((Object)(object)threeChoiceChestMarker == (Object)null)
			{
				threeChoiceChestMarker = val.AddComponent<ThreeChoiceChestMarker>();
			}
			threeChoiceChestMarker.category = category;
		}

		private static void PurchaseInteraction_OnInteractionBegin(orig_OnInteractionBegin orig, PurchaseInteraction self, Interactor activator)
		{
			ThreeChoiceChestMarker component = ((Component)self).GetComponent<ThreeChoiceChestMarker>();
			if ((Object)(object)component != (Object)null && self.CanBeAffordedByInteractor(activator))
			{
				component.lastInteractor = activator;
			}
			orig.Invoke(self, activator);
		}

		private static bool TryCreateThreeChoicePicker(ref CreatePickupInfo pickupInfo, Vector3 position)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active)
			{
				return false;
			}
			ChestBehavior chest = pickupInfo.chest;
			if ((Object)(object)chest == (Object)null)
			{
				return false;
			}
			ThreeChoiceChestMarker component = ((Component)chest).GetComponent<ThreeChoiceChestMarker>();
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			if ((Object)(object)component.lastInteractor == (Object)null)
			{
				return false;
			}
			UniquePickup pickup = ((CreatePickupInfo)(ref pickupInfo)).pickup;
			if (!((UniquePickup)(ref pickup)).isValid)
			{
				return false;
			}
			Option[] array = BuildThreeOptions(pickup, component.category);
			if (array == null || array.Length == 0)
			{
				return false;
			}
			Interactor lastInteractor = component.lastInteractor;
			component.lastInteractor = null;
			pendingChoices.Enqueue(new PendingChoice
			{
				firstPickup = pickup,
				options = array,
				activator = lastInteractor,
				position = position,
				rotation = pickupInfo.rotation
			});
			if (!pickerActive)
			{
				OpenNextPendingChoice();
			}
			return true;
		}

		private static void OpenNextPendingChoice()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			if (!NetworkServer.active || pickerActive || pendingChoices.Count == 0)
			{
				return;
			}
			PendingChoice pendingChoice = pendingChoices.Dequeue();
			if ((Object)(object)pendingChoice.activator == (Object)null)
			{
				OpenNextPendingChoice();
				return;
			}
			GameObject pickerObject = Object.Instantiate<GameObject>(commandCubePrefab, pendingChoice.position, pendingChoice.rotation);
			HideCommandCubePrefab(pickerObject);
			PickupPickerController component = pickerObject.GetComponent<PickupPickerController>();
			PickupIndexNetworker component2 = pickerObject.GetComponent<PickupIndexNetworker>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component.networkUIPromptController == (Object)null)
			{
				Object.Destroy((Object)(object)pickerObject);
				OpenNextPendingChoice();
				return;
			}
			component2.NetworkpickupState = pendingChoice.firstPickup;
			pickerActive = true;
			NetworkServer.Spawn(pickerObject);
			bool finished = false;
			component.networkUIPromptController.onDisplayEnd += delegate(NetworkUIPromptController controller, LocalUser localUser, CameraRigController cameraRigController)
			{
				if (!finished)
				{
					finished = true;
					controller.SetParticipantMaster((CharacterMaster)null);
					if (NetworkServer.active && (Object)(object)pickerObject != (Object)null)
					{
						NetworkServer.Destroy(pickerObject);
					}
					pickerActive = false;
					if ((Object)(object)instance != (Object)null)
					{
						((MonoBehaviour)instance).StartCoroutine(OpenNextChoiceNextFrame());
					}
				}
			};
			component.SetOptionsServer(pendingChoice.options);
			if ((Object)(object)instance != (Object)null)
			{
				((MonoBehaviour)instance).StartCoroutine(OpenPickerAfterSpawn(component, pendingChoice.activator));
			}
		}

		private static IEnumerator OpenNextChoiceNextFrame()
		{
			yield return null;
			OpenNextPendingChoice();
		}

		private static IEnumerator OpenPickerAfterSpawn(PickupPickerController picker, Interactor activator)
		{
			yield return (object)new WaitForSecondsRealtime(0.1f);
			if (!((Object)(object)picker == (Object)null) && !((Object)(object)activator == (Object)null))
			{
				picker.OnInteractionBegin(activator);
			}
		}

		private static Option[] BuildThreeOptions(UniquePickup firstPickup, ThreeChoiceChestCategory category)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			PickupIndex pickupIndex = firstPickup.pickupIndex;
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef == null || (Object)(object)Run.instance == (Object)null)
			{
				return MakeOptions(new List<UniquePickup> { firstPickup });
			}
			List<PickupIndex> list = new List<PickupIndex>();
			if ((int)pickupDef.equipmentIndex != -1)
			{
				AddMatchingPickups(Run.instance.availableEquipmentDropList, pickupDef, category, equipmentMode: true, list);
			}
			else
			{
				AddMatchingPickups(Run.instance.availableTier1DropList, pickupDef, category, equipmentMode: false, list);
				AddMatchingPickups(Run.instance.availableTier2DropList, pickupDef, category, equipmentMode: false, list);
				AddMatchingPickups(Run.instance.availableTier3DropList, pickupDef, category, equipmentMode: false, list);
			}
			List<UniquePickup> list2 = new List<UniquePickup>();
			list2.Add(firstPickup);
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].value == pickupIndex.value)
				{
					list.RemoveAt(num);
				}
			}
			while (list2.Count < 3 && list.Count > 0)
			{
				int index = Random.Range(0, list.Count);
				PickupIndex val = list[index];
				list.RemoveAt(index);
				list2.Add(new UniquePickup(val));
			}
			return MakeOptions(list2);
		}

		private static void AddMatchingPickups(List<PickupIndex> source, PickupDef firstDef, ThreeChoiceChestCategory category, bool equipmentMode, List<PickupIndex> destination)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if (source == null)
			{
				return;
			}
			foreach (PickupIndex item in source)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(item);
				if (pickupDef == null)
				{
					continue;
				}
				if (equipmentMode)
				{
					if ((int)pickupDef.equipmentIndex == -1)
					{
						continue;
					}
				}
				else if ((int)pickupDef.itemIndex == -1 || pickupDef.itemTier != firstDef.itemTier || !MatchesCategory(pickupDef, category))
				{
					continue;
				}
				bool flag = false;
				foreach (PickupIndex item2 in destination)
				{
					if (item2.value == item.value)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					destination.Add(item);
				}
			}
		}

		private static bool MatchesCategory(PickupDef pickupDef, ThreeChoiceChestCategory category)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (category == ThreeChoiceChestCategory.General)
			{
				return true;
			}
			if ((int)pickupDef.itemIndex == -1)
			{
				return false;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
			if ((Object)(object)itemDef == (Object)null)
			{
				return false;
			}
			return category switch
			{
				ThreeChoiceChestCategory.Damage => itemDef.ContainsTag((ItemTag)1), 
				ThreeChoiceChestCategory.Healing => itemDef.ContainsTag((ItemTag)2), 
				ThreeChoiceChestCategory.Utility => itemDef.ContainsTag((ItemTag)3), 
				_ => true, 
			};
		}

		private static Option[] MakeOptions(List<UniquePickup> pickups)
		{
			//IL_0016: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Option[] array = (Option[])(object)new Option[pickups.Count];
			for (int i = 0; i < pickups.Count; i++)
			{
				array[i] = new Option
				{
					pickup = pickups[i],
					available = true
				};
			}
			return array;
		}

		private static void HideCommandCubePrefab(GameObject prefab)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				val.enabled = false;
			}
			Light[] componentsInChildren2 = prefab.GetComponentsInChildren<Light>(true);
			Light[] array2 = componentsInChildren2;
			foreach (Light val2 in array2)
			{
				((Behaviour)val2).enabled = false;
			}
			ParticleSystem[] componentsInChildren3 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			ParticleSystem[] array3 = componentsInChildren3;
			foreach (ParticleSystem val3 in array3)
			{
				EmissionModule emission = val3.emission;
				((EmissionModule)(ref emission)).enabled = false;
				val3.Stop(true, (ParticleSystemStopBehavior)0);
			}
			AudioSource[] componentsInChildren4 = prefab.GetComponentsInChildren<AudioSource>(true);
			AudioSource[] array4 = componentsInChildren4;
			foreach (AudioSource val4 in array4)
			{
				val4.playOnAwake = false;
				((Behaviour)val4).enabled = false;
			}
		}
	}
	public class PendingChoice
	{
		public UniquePickup firstPickup;

		public Option[] options;

		public Interactor activator;

		public Vector3 position;

		public Quaternion rotation;
	}
	public enum ThreeChoiceChestCategory
	{
		General,
		Damage,
		Healing,
		Utility
	}
	public class ThreeChoiceChestMarker : MonoBehaviour
	{
		public ThreeChoiceChestCategory category;

		public Interactor lastInteractor;
	}
}