Decompiled source of ShrineOfDisorder v1.1.5

ShrineOfDisorder.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using On.RoR2;
using R2API.Utils;
using RoR2;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;

[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("ShrineOfDisorder")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5+6262c21f4e90eac30b9c107451b935ba9cef7043")]
[assembly: AssemblyProduct("ShrineOfDisorder")]
[assembly: AssemblyTitle("ShrineOfDisorder")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ShrineOfDisorder
{
	public enum ShrineBehavior
	{
		RandomizeEachStack,
		RandomizeEachItem,
		SwapOneInventory,
		SwapAllInventories
	}
	public class ShrineConfig
	{
		public ConfigEntry<bool> lunarItemsCfg;

		public ConfigEntry<bool> bossItemsCfg;

		public ConfigEntry<bool> voidItemsCfg;

		public ConfigEntry<bool> voidBossItemsCfg;

		public ConfigEntry<ShrineBehavior> shrineBehaviorCfg;

		public ConfigEntry<bool> preserveStackCountCfg;

		public ConfigEntry<bool> onlyObtainedItemsCfg;

		public ConfigEntry<bool> shrineOnAllMapsCfg;

		public ConfigEntry<float> shrineSpawnMultiplierCfg;

		public bool lunarItems => lunarItemsCfg.Value;

		public bool bossItems => bossItemsCfg.Value;

		public bool voidItems => voidItemsCfg.Value;

		public bool voidBossItems => voidBossItemsCfg.Value;

		public ShrineBehavior shrineBehavior => shrineBehaviorCfg.Value;

		public bool preserveStackCount => preserveStackCountCfg.Value;

		public bool onlyObtainedItems => onlyObtainedItemsCfg.Value;

		public bool shrineOnAllMaps => shrineOnAllMapsCfg.Value;

		public float shrineSpawnMultiplier => shrineSpawnMultiplierCfg.Value;

		public ShrineConfig(ConfigFile cfg)
		{
			lunarItemsCfg = cfg.Bind<bool>("Items", "LunarItems", false, "Allow the shrine to randomize lunar items.");
			voidItemsCfg = cfg.Bind<bool>("Items", "VoidItems", false, "Allow the shrine to randomize void items.");
			bossItemsCfg = cfg.Bind<bool>("Items", "BossItems", false, "Allow the shrine to randomize boss items.");
			voidBossItemsCfg = cfg.Bind<bool>("Items", "VoidBossItems", false, "Allow the shrine to randomize void items.");
			shrineBehaviorCfg = cfg.Bind<ShrineBehavior>("Behavior", "ShrineBehavior", ShrineBehavior.RandomizeEachStack, "The behavior of the shrine. The inventory swapping behavior is only enabled for games with 2 or more players. Otherwise, the default behavior will be used.");
			preserveStackCountCfg = cfg.Bind<bool>("Behavior", "PreserveStackCount", true, "Preserve the number of unique stacks when using the RandomizeEachStack behavior. If disabled, the same item can be randomly selected for multiple stacks, effectively merging them.");
			onlyObtainedItemsCfg = cfg.Bind<bool>("Behavior", "OnlyObtainedItems", false, "When determining which items to give the player, only pick from the list of items that they already have in their inventory.");
			shrineOnAllMapsCfg = cfg.Bind<bool>("Behavior", "ShrineOnAllMaps", true, "Allow the shrine to spawn on all maps.");
			shrineSpawnMultiplierCfg = cfg.Bind<float>("Behavior", "ShrineSpawnMultiplier", 1f, "A multiplier on the shrine's spawn weight.");
		}
	}
	internal static class Log
	{
		internal static ManualLogSource _logSource;

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

		internal static void LogDebug(object data)
		{
			_logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			_logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			_logSource.LogFatal(data);
		}

		internal static void LogInfo(object data)
		{
			_logSource.LogInfo(data);
		}

		internal static void LogMessage(object data)
		{
			_logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			_logSource.LogWarning(data);
		}
	}
	public static class DccsExtensions
	{
		public static int FindCategoryIndexByName_WorkingVersion(this DirectorCardCategorySelection dccs, string categoryName)
		{
			for (int i = 0; i < dccs.categories.Length; i++)
			{
				if (dccs.categories[i].name == categoryName)
				{
					return i;
				}
			}
			return -1;
		}

		public static DirectorCard GetCard(this DirectorCardCategorySelection dccs, int categoryIndex, string cardName)
		{
			DirectorCard[] cards = dccs.categories[categoryIndex].cards;
			foreach (DirectorCard val in cards)
			{
				if (((Object)val.spawnCard).name.StartsWith(cardName))
				{
					return val;
				}
			}
			return null;
		}

		public static bool HasCard(this DirectorCardCategorySelection dccs, int categoryIndex, string cardName)
		{
			return dccs.GetCard(categoryIndex, cardName) != null;
		}

		public static int GetWeight(this DirectorCardCategorySelection dccs, int categoryIndex, string cardName)
		{
			return dccs.GetCard(categoryIndex, cardName)?.selectionWeight ?? (-1);
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("cbrl.ShrineOfDisorder", "ShrineOfDisorder", "1.0.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ShrineOfDisorder : BaseUnityPlugin
	{
		public const string PluginGUID = "cbrl.ShrineOfDisorder";

		public const string PluginAuthor = "cbrl";

		public const string PluginName = "ShrineOfDisorder";

		public const string PluginVersion = "1.0.0";

		public ShrineConfig config;

		private HashSet<ItemTier> enabledTiers = new HashSet<ItemTier>();

		private static Dictionary<ItemTier, List<ItemDef>> dropLists;

		private readonly string[] bannedStageNames = new string[4] { "bazaar", "artifactworld", "mysteryspace", "limbo" };

		private readonly string[] searchWeights = new string[3] { "iscShrineBoss", "iscShrineBlood", "iscShrineCombat" };

		private const int defaultShrineWeight = 3;

		public void Awake()
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			Log.Init(((BaseUnityPlugin)this).Logger);
			config = new ShrineConfig(((BaseUnityPlugin)this).Config);
			enabledTiers.Add((ItemTier)0);
			enabledTiers.Add((ItemTier)1);
			enabledTiers.Add((ItemTier)2);
			if (config.lunarItems)
			{
				enabledTiers.Add((ItemTier)3);
			}
			if (config.bossItems)
			{
				enabledTiers.Add((ItemTier)4);
			}
			if (config.voidBossItems)
			{
				enabledTiers.Add((ItemTier)9);
			}
			if (config.voidItems)
			{
				enabledTiers.Add((ItemTier)6);
				enabledTiers.Add((ItemTier)7);
				enabledTiers.Add((ItemTier)8);
			}
			Run.Start += new hook_Start(Run_Start);
			Inventory.ShrineRestackInventory += (hook_ShrineRestackInventory)delegate(orig_ShrineRestackInventory orig, Inventory self, Xoroshiro128Plus rng)
			{
				RestackBehavior(self, rng);
			};
			if (config.shrineOnAllMaps)
			{
				SceneDirector.onGenerateInteractableCardSelection += SceneDirector_onGenerateInteractableCardSelection;
			}
			Log.LogInfo("Awake done.");
		}

		private void SceneDirector_onGenerateInteractableCardSelection(SceneDirector director, DirectorCardCategorySelection selection)
		{
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			if (!NetworkServer.active || bannedStageNames.Contains(((Object)Stage.instance).name))
			{
				return;
			}
			int index = selection.FindCategoryIndexByName_WorkingVersion("Shrines");
			if (index >= 0 && !selection.HasCard(index, "iscShrineRestack"))
			{
				int num = searchWeights.Select((string search) => selection.GetWeight(index, search)).FirstOrDefault((int weight) => weight != -1);
				if (num == 0)
				{
					num = 3;
				}
				DirectorCard val = new DirectorCard
				{
					spawnCard = Addressables.LoadAssetAsync<SpawnCard>((object)"RoR2/Base/ShrineRestack/iscShrineRestack.asset").WaitForCompletion(),
					selectionWeight = (int)((float)num * config.shrineSpawnMultiplier)
				};
				selection.AddCard(index, val);
				Log.LogInfo($"Added card with weight: {val.selectionWeight}");
			}
			else if (index < 0)
			{
				Log.LogWarning("Could not find 'Shrines' category in stage " + ((Object)Stage.instance).name + ". The Shrine of Order will not be added to this stage.");
			}
			Category[] categories = selection.categories;
			for (int i = 0; i < categories.Length; i++)
			{
				Category cat = categories[i];
				string arg = string.Join("\n    ", cat.cards.Select((DirectorCard card) => $"{cat.name}.{((Object)card.spawnCard).name} weight: {card.selectionWeight}"));
				Log.LogDebug($"{cat.name} weight: {cat.selectionWeight}\n    {arg}");
			}
		}

		private void Run_Start(orig_Start orig, Run self)
		{
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			dropLists = new Dictionary<ItemTier, List<ItemDef>>
			{
				{
					(ItemTier)0,
					Run.instance.availableTier1DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)1,
					Run.instance.availableTier2DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)2,
					Run.instance.availableTier3DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)3,
					Run.instance.availableLunarItemDropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)4,
					Run.instance.availableBossDropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)6,
					Run.instance.availableVoidTier1DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)7,
					Run.instance.availableVoidTier2DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)8,
					Run.instance.availableVoidTier3DropList.ConvertAll(GetItemDef)
				},
				{
					(ItemTier)9,
					Run.instance.availableVoidBossDropList.ConvertAll(GetItemDef)
				}
			};
			foreach (KeyValuePair<ItemTier, List<ItemDef>> dropList in dropLists)
			{
				Log.LogDebug(string.Format("{0} Drop List: {1}", dropList.Key, string.Join(", ", dropList.Value)));
			}
		}

		private void Update()
		{
		}

		private void RestackBehavior(Inventory self, Xoroshiro128Plus rng)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if (NetworkUser.readOnlyInstancesList.Count < 2)
			{
				if (config.shrineBehavior == ShrineBehavior.RandomizeEachItem)
				{
					RandomizeItems(self, rng);
				}
				else
				{
					RandomizeItemStacks(self, rng);
				}
				return;
			}
			switch (config.shrineBehavior)
			{
			case ShrineBehavior.RandomizeEachItem:
				RandomizeItems(self, rng);
				break;
			case ShrineBehavior.RandomizeEachStack:
				RandomizeItemStacks(self, rng);
				break;
			case ShrineBehavior.SwapOneInventory:
				SwapOneInventory(self, rng);
				break;
			case ShrineBehavior.SwapAllInventories:
				SwapAllInventories(rng);
				break;
			default:
				RandomizeItemStacks(self, rng);
				break;
			}
		}

		private static void ResetItems(Inventory inventory, List<ItemDef> items)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemDef item in items)
			{
				inventory.ResetItem(item);
				inventory.itemAcquisitionOrder.Remove(item.itemIndex);
			}
		}

		private static Dictionary<ItemDef, int> GiveRandomItems(Inventory inventory, List<ItemDef> dropList, int count, Xoroshiro128Plus rng)
		{
			Dictionary<ItemDef, int> dictionary = new Dictionary<ItemDef, int>();
			for (int i = 0; i < count; i++)
			{
				ItemDef val = rng.NextElementUniform<ItemDef>(dropList);
				inventory.GiveItem(val, 1);
				if (!dictionary.ContainsKey(val))
				{
					dictionary[val] = 0;
				}
				dictionary[val]++;
			}
			return dictionary;
		}

		private static ItemDef GiveRandomStack(Inventory inventory, List<ItemDef> dropList, int count, Xoroshiro128Plus rng)
		{
			ItemDef val = rng.NextElementUniform<ItemDef>(dropList);
			inventory.GiveItem(val, count);
			return val;
		}

		private Dictionary<ItemTier, Dictionary<ItemDef, int>> GetItemCounts(Inventory inventory)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ItemTier, Dictionary<ItemDef, int>> dictionary = new Dictionary<ItemTier, Dictionary<ItemDef, int>>();
			foreach (ItemTier key in dropLists.Keys)
			{
				foreach (ItemDef item in dropLists[key])
				{
					int itemCount = inventory.GetItemCount(item.itemIndex);
					if (itemCount > 0)
					{
						if (!dictionary.ContainsKey(key))
						{
							dictionary.Add(key, new Dictionary<ItemDef, int>());
						}
						dictionary[key][item] = itemCount;
					}
				}
			}
			return dictionary;
		}

		private void RandomizeItems(Inventory self, Xoroshiro128Plus rng)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ItemTier, Dictionary<ItemDef, int>> itemCounts = GetItemCounts(self);
			foreach (ItemTier enabledTier in enabledTiers)
			{
				ResetItems(self, dropLists[enabledTier]);
			}
			((NetworkBehaviour)self).SetDirtyBit(8u);
			foreach (KeyValuePair<ItemTier, Dictionary<ItemDef, int>> item in itemCounts.Where((KeyValuePair<ItemTier, Dictionary<ItemDef, int>> pair) => enabledTiers.Contains(pair.Key)))
			{
				List<ItemDef> dropList = (config.onlyObtainedItems ? item.Value.Keys.ToList() : dropLists[item.Key]);
				int count = item.Value.Sum((KeyValuePair<ItemDef, int> pair) => pair.Value);
				GiveRandomItems(self, dropList, count, rng);
			}
		}

		private void RandomizeItemStacks(Inventory self, Xoroshiro128Plus rng)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<ItemTier, Dictionary<ItemDef, int>> itemCounts = GetItemCounts(self);
			foreach (ItemTier enabledTier in enabledTiers)
			{
				ResetItems(self, dropLists[enabledTier]);
			}
			((NetworkBehaviour)self).SetDirtyBit(8u);
			foreach (KeyValuePair<ItemTier, Dictionary<ItemDef, int>> item2 in itemCounts.Where((KeyValuePair<ItemTier, Dictionary<ItemDef, int>> pair) => enabledTiers.Contains(pair.Key)))
			{
				ItemTier key = item2.Key;
				Dictionary<ItemDef, int> value = item2.Value;
				List<ItemDef> list = null;
				list = ((!config.preserveStackCount) ? (config.onlyObtainedItems ? value.Keys.ToList() : dropLists[key]) : new List<ItemDef>(config.onlyObtainedItems ? value.Keys.ToList() : dropLists[key]));
				foreach (KeyValuePair<ItemDef, int> item3 in value)
				{
					ItemDef item = GiveRandomStack(self, list, item3.Value, rng);
					if (config.preserveStackCount)
					{
						list.Remove(item);
					}
				}
			}
		}

		private void SwapOneInventory(Inventory self, Xoroshiro128Plus rng)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			List<Inventory> list = PlayerCharacterMasterController.instances.Select((PlayerCharacterMasterController user) => user.master.inventory).ToList();
			Inventory val = new Inventory();
			Inventory val2 = rng.NextElementUniform<Inventory>(list);
			val.CopyItemsFrom(self);
			self.CopyItemsFrom(val2);
			val2.CopyItemsFrom(val);
		}

		private void SwapAllInventories(Xoroshiro128Plus rng)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			List<Inventory> list = PlayerCharacterMasterController.instances.Select((PlayerCharacterMasterController user) => user.master.inventory).ToList();
			Inventory val = new Inventory();
			IOrderedEnumerable<Inventory> second = list.OrderBy((Inventory n) => rng.Next());
			foreach (var (val2, val3) in list.Zip(second, (Inventory a, Inventory b) => (a, b)))
			{
				val.CopyItemsFrom(val2);
				val2.CopyItemsFrom(val3);
				val3.CopyItemsFrom(val);
			}
		}

		private static ItemDef GetItemDef(PickupIndex index)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ItemCatalog.GetItemDef(PickupCatalog.GetPickupDef(index).itemIndex);
		}
	}
}