Decompiled source of PeakItemRandomizer v1.0.3

peak-mod.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("peak-mod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("peak-mod")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ca4fd68f-ad66-42be-952a-50365774478d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PeakItemRandomizer;

[HarmonyPatch(typeof(BerryBush), "SpawnItems")]
internal static class BerryBushPatch
{
	private static bool Prefix(BerryBush __instance, List<Transform> spawnSpots, ref List<PhotonView> __result)
	{
		//IL_0066: 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_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		if (!PeakItemRandomizer.ModEnabled.Value || !PeakItemRandomizer.RandomizeNature.Value)
		{
			return true;
		}
		__result = new List<PhotonView>();
		if (!PhotonNetwork.IsMasterClient)
		{
			return false;
		}
		if (spawnSpots == null || spawnSpots.Count == 0)
		{
			return false;
		}
		GameObject randomAllowedPrefab = RandomizerCore.GetRandomAllowedPrefab(((Spawner)__instance).spawnPool);
		if ((Object)(object)randomAllowedPrefab == (Object)null)
		{
			ModLog.Warn("BerryBush had no prefab to spawn.");
			return false;
		}
		List<Transform> list = new List<Transform>(spawnSpots);
		float num = Mathf.Pow(Random.value, __instance.randomPow);
		int num2 = Mathf.RoundToInt(Mathf.Lerp(__instance.possibleBerries.x, __instance.possibleBerries.y, num));
		num2 = Mathf.Clamp(num2, 0, spawnSpots.Count);
		for (int i = 0; i < num2; i++)
		{
			int index = Random.Range(0, list.Count);
			Transform val = list[index];
			list.RemoveAt(index);
			Item component = PhotonNetwork.InstantiateItemRoom(((Object)randomAllowedPrefab).name, val.position, Quaternion.identity).GetComponent<Item>();
			__result.Add(((Component)component).GetComponent<PhotonView>());
			if ((Object)(object)((Spawner)__instance).spawnUpTowardsTarget != (Object)null)
			{
				Transform transform = ((Component)component).transform;
				Vector3 val2 = ((Spawner)__instance).spawnUpTowardsTarget.position - ((Component)component).transform.position;
				transform.up = ((Vector3)(ref val2)).normalized;
				((Component)component).transform.Rotate(Vector3.up, Random.Range(0f, 360f), (Space)1);
			}
			if (((Spawner)__instance).spawnTransformIsSpawnerTransform)
			{
				((Component)component).transform.rotation = val.rotation;
				((Component)component).transform.Rotate(Vector3.up, Random.Range(0f, 360f), (Space)1);
			}
			((Component)component).GetComponent<PhotonView>().RPC("SetKinematicRPC", (RpcTarget)3, new object[3]
			{
				true,
				((Component)component).transform.position,
				((Component)component).transform.rotation
			});
		}
		ModLog.Info($"BerryBush spawned {num2}x {((Object)randomAllowedPrefab).name}");
		return false;
	}
}
[HarmonyPatch(typeof(BerryVine), "SpawnItems")]
internal static class BerryVinePatch
{
	private static bool Prefix(BerryVine __instance, List<Transform> spawnSpots, ref List<PhotonView> __result)
	{
		//IL_0066: 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_0112: 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_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		if (!PeakItemRandomizer.ModEnabled.Value || !PeakItemRandomizer.RandomizeNature.Value)
		{
			return true;
		}
		__result = new List<PhotonView>();
		if (!PhotonNetwork.IsMasterClient)
		{
			return false;
		}
		if (spawnSpots == null || spawnSpots.Count == 0)
		{
			return false;
		}
		GameObject randomAllowedPrefab = RandomizerCore.GetRandomAllowedPrefab(((Spawner)__instance).spawnPool);
		if ((Object)(object)randomAllowedPrefab == (Object)null)
		{
			ModLog.Warn("BerryVine had no prefab to spawn.");
			return false;
		}
		List<Transform> list = new List<Transform>(spawnSpots);
		float num = Mathf.Pow(Random.value, __instance.randomPow);
		int num2 = Mathf.RoundToInt(Mathf.Lerp(__instance.possibleBerries.x, __instance.possibleBerries.y, num));
		num2 = Mathf.Clamp(num2, 0, spawnSpots.Count);
		for (int i = 0; i < num2; i++)
		{
			int index = Random.Range(0, list.Count);
			Transform val = list[index];
			list.RemoveAt(index);
			Item component = PhotonNetwork.InstantiateItemRoom(((Object)randomAllowedPrefab).name, val.position + __instance.spawnOffsetWorldSpace, Quaternion.identity).GetComponent<Item>();
			__result.Add(((Component)component).GetComponent<PhotonView>());
			if ((Object)(object)((Spawner)__instance).spawnUpTowardsTarget != (Object)null)
			{
				Transform transform = ((Component)component).transform;
				Vector3 val2 = ((Spawner)__instance).spawnUpTowardsTarget.position - ((Component)component).transform.position;
				transform.up = ((Vector3)(ref val2)).normalized;
			}
			((Component)component).transform.rotation = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f);
			((Component)component).GetComponent<PhotonView>().RPC("SetKinematicRPC", (RpcTarget)3, new object[3]
			{
				true,
				((Component)component).transform.position,
				((Component)component).transform.rotation
			});
		}
		ModLog.Info($"BerryVine spawned {num2}x {((Object)randomAllowedPrefab).name}");
		return false;
	}
}
internal static class ItemSpawnConfig
{
	private static readonly Dictionary<ushort, ConfigEntry<bool>> ItemToggles = new Dictionary<ushort, ConfigEntry<bool>>();

	public static void BuildItemConfig(ConfigFile config)
	{
		ItemToggles.Clear();
		if ((Object)(object)SingletonAsset<ItemDatabase>.Instance == (Object)null)
		{
			ModLog.Warn("ItemDatabase was not ready. Could not build item toggle config.");
			return;
		}
		foreach (KeyValuePair<ushort, Item> item in SingletonAsset<ItemDatabase>.Instance.itemLookup)
		{
			Item value = item.Value;
			if (!((Object)(object)value == (Object)null))
			{
				LootData component = ((Component)value).GetComponent<LootData>();
				if (!((Object)(object)component == (Object)null))
				{
					string safeConfigName = GetSafeConfigName(value);
					ConfigEntry<bool> value2 = config.Bind<bool>("Items - Spawn Toggles", safeConfigName, true, $"Allow this item to spawn. Prefab: {((Object)((Component)value).gameObject).name} | Item ID: {item.Key}");
					ItemToggles[item.Key] = value2;
				}
			}
		}
		ModLog.Info($"Created {ItemToggles.Count} in-game item spawn toggles.");
	}

	public static bool IsItemEnabled(ushort itemId, Item item)
	{
		if (ItemToggles.Count == 0 && (Object)(object)PeakItemRandomizer.Instance != (Object)null)
		{
			BuildItemConfig(((BaseUnityPlugin)PeakItemRandomizer.Instance).Config);
		}
		if (ItemToggles.TryGetValue(itemId, out var value))
		{
			return value.Value;
		}
		ModLog.Warn($"No toggle found for item ID {itemId}. Blocking by default.");
		return false;
	}

	private static string GetSafeConfigName(Item item)
	{
		string text = ((Object)((Component)item).gameObject).name ?? "UnknownItem";
		string text2 = ((item.UIData != null) ? (item.UIData.itemName ?? "") : "");
		string input = (string.IsNullOrWhiteSpace(text2) ? text : (text2 + " (" + text + ")"));
		input = Regex.Replace(input, "[^a-zA-Z0-9_\\-() ]", "");
		return Regex.Replace(input, "\\s+", " ");
	}
}
[HarmonyPatch(typeof(LootData), "PopulateLootData")]
internal static class LootDataPatch
{
	private static void Postfix()
	{
		try
		{
			RandomizerCore.RebuildRandomizedPools();
		}
		catch (Exception ex)
		{
			ModLog.Error("LootData patch failed: " + ex);
		}
	}
}
internal static class ModLog
{
	internal static ManualLogSource Log;

	internal static void Init(ManualLogSource source)
	{
		Log = source;
		Info("Logger initialized.");
	}

	internal static void Info(string msg)
	{
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogInfo((object)msg);
		}
	}

	internal static void Warn(string msg)
	{
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogWarning((object)msg);
		}
	}

	internal static void Error(string msg)
	{
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogError((object)msg);
		}
	}

	internal static void Debug(string msg)
	{
		ManualLogSource log = Log;
		if (log != null)
		{
			log.LogDebug((object)msg);
		}
	}
}
[BepInPlugin("com.yourname.peakitemrandomizer", "PeakItemRandomizer", "1.1.0")]
public sealed class PeakItemRandomizer : BaseUnityPlugin
{
	public const string PluginGuid = "com.yourname.peakitemrandomizer";

	public const string PluginName = "PeakItemRandomizer";

	public const string PluginVersion = "1.1.0";

	internal static PeakItemRandomizer Instance;

	private Harmony harmony;

	internal static ConfigEntry<bool> ModEnabled;

	internal static ConfigEntry<bool> EqualChance;

	internal static ConfigEntry<bool> RandomizeLuggage;

	internal static ConfigEntry<bool> RandomizeNature;

	internal static ConfigEntry<bool> KeepRespawnStatuesVanilla;

	internal static ConfigEntry<string> ExtraBlockedNames;

	internal static ConfigEntry<string> AllowedNamesOnly;

	private void Awake()
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Expected O, but got Unknown
		Instance = this;
		ModLog.Init(((BaseUnityPlugin)this).Logger);
		ModLog.Info("Starting PeakItemRandomizer...");
		ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle for the item randomizer.");
		EqualChance = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EqualChance", true, "Every allowed item gets equal spawn chance.");
		RandomizeLuggage = ((BaseUnityPlugin)this).Config.Bind<bool>("Pools", "RandomizeLuggage", true, "Randomize luggage pools.");
		RandomizeNature = ((BaseUnityPlugin)this).Config.Bind<bool>("Pools", "RandomizeNature", true, "Randomize bushes, vines, trees, and nature pools.");
		KeepRespawnStatuesVanilla = ((BaseUnityPlugin)this).Config.Bind<bool>("Pools", "KeepRespawnStatuesVanilla", true, "Do not randomize respawn chests/statues/coffins.");
		ExtraBlockedNames = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "BlockedNameContains", "chess,prop,cheat,cheater,debug,test,guidebook, stick, Infinite, Pawn, Stone, Queen, King, Rook, Bishop, Knight", "Comma-separated item name fragments to block from spawning.");
		AllowedNamesOnly = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "AllowedNamesOnly", "", "Optional whitelist. Leave blank to allow every valid item except blocked ones.");
		harmony = new Harmony("com.yourname.peakitemrandomizer");
		harmony.PatchAll();
		ModLog.Info("Harmony patches applied.");
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		ModLog.Warn("PeakItemRandomizer unloaded.");
	}

	internal static HashSet<string> SplitConfig(ConfigEntry<string> entry)
	{
		return (from s in entry.Value.Split(new char[3] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries)
			select s.Trim().ToLowerInvariant() into s
			where !string.IsNullOrWhiteSpace(s)
			select s).ToHashSet();
	}
}
internal static class RandomizerCore
{
	private static readonly SpawnPool[] NaturePools;

	private static readonly SpawnPool[] LuggagePools;

	public static void RebuildRandomizedPools()
	{
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		if (!PeakItemRandomizer.ModEnabled.Value)
		{
			ModLog.Warn("Mod disabled. Skipping pool rebuild.");
			return;
		}
		if (LootData.AllSpawnWeightData == null)
		{
			ModLog.Warn("LootData.AllSpawnWeightData was null. Skipping pool rebuild.");
			return;
		}
		List<ushort> allowedItemIds = GetAllowedItemIds();
		if (allowedItemIds.Count == 0)
		{
			ModLog.Error("No allowed items found. Randomizer will not change pools.");
			return;
		}
		int itemWeight = (PeakItemRandomizer.EqualChance.Value ? 1 : 10);
		Dictionary<ushort, int> dictionary = allowedItemIds.ToDictionary((ushort id) => id, (ushort _) => itemWeight);
		foreach (SpawnPool item in GetPoolsToRandomize())
		{
			LootData.AllSpawnWeightData[item] = new Dictionary<ushort, int>(dictionary);
			ModLog.Info($"Randomized pool: {item} | items: {dictionary.Count} | weight each: {itemWeight}");
		}
		LootData.AllSpawnWeightData[(SpawnPool)134217728] = new Dictionary<ushort, int>(dictionary);
		ModLog.Info($"SpawnPool.All rebuilt with {dictionary.Count} allowed items.");
	}

	private static List<ushort> GetAllowedItemIds()
	{
		HashSet<string> source = PeakItemRandomizer.SplitConfig(PeakItemRandomizer.ExtraBlockedNames);
		HashSet<string> hashSet = PeakItemRandomizer.SplitConfig(PeakItemRandomizer.AllowedNamesOnly);
		List<ushort> list = new List<ushort>();
		foreach (KeyValuePair<ushort, Item> item in SingletonAsset<ItemDatabase>.Instance.itemLookup)
		{
			Item value = item.Value;
			if ((Object)(object)value == (Object)null)
			{
				continue;
			}
			LootData component = ((Component)value).GetComponent<LootData>();
			if ((Object)(object)component == (Object)null)
			{
				continue;
			}
			if (!value.IsValidToSpawn())
			{
				ModLog.Debug("Skipped invalid item: " + ((Object)((Component)value).gameObject).name);
				continue;
			}
			string text = ((Object)((Component)value).gameObject).name ?? "";
			string text2 = ((value.UIData != null) ? (value.UIData.itemName ?? "") : "");
			string combinedName = (text + " " + text2).ToLowerInvariant();
			if (source.Any((string blockedText) => combinedName.Contains(blockedText)))
			{
				ModLog.Warn("Blocked item: " + text);
			}
			else if (hashSet.Count > 0 && !hashSet.Any((string allowedText) => combinedName.Contains(allowedText)))
			{
				ModLog.Debug("Skipped because not whitelisted: " + text);
			}
			else
			{
				list.Add(item.Key);
			}
		}
		list = list.Distinct().ToList();
		ModLog.Info($"Allowed item count: {list.Count}");
		return list;
	}

	private static HashSet<SpawnPool> GetPoolsToRandomize()
	{
		//IL_0024: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		HashSet<SpawnPool> hashSet = new HashSet<SpawnPool>();
		if (PeakItemRandomizer.RandomizeNature.Value)
		{
			SpawnPool[] naturePools = NaturePools;
			foreach (SpawnPool item in naturePools)
			{
				hashSet.Add(item);
			}
		}
		if (PeakItemRandomizer.RandomizeLuggage.Value)
		{
			SpawnPool[] luggagePools = LuggagePools;
			foreach (SpawnPool item2 in luggagePools)
			{
				hashSet.Add(item2);
			}
		}
		if (PeakItemRandomizer.KeepRespawnStatuesVanilla.Value)
		{
			hashSet.Remove((SpawnPool)131072);
		}
		return hashSet;
	}

	public static GameObject GetRandomAllowedPrefab(SpawnPool pool)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: 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 (LootData.AllSpawnWeightData == null)
		{
			LootData.PopulateLootData();
		}
		if (!LootData.AllSpawnWeightData.TryGetValue(pool, out var value) || value.Count == 0)
		{
			ModLog.Warn($"Pool {pool} was empty. Falling back to vanilla GetRandomItem.");
			return LootData.GetRandomItem(pool, false);
		}
		List<ushort> list = value.Keys.ToList();
		ushort num = list[Random.Range(0, list.Count)];
		Item val = default(Item);
		if (ItemDatabase.TryGetItem(num, ref val) && (Object)(object)val != (Object)null)
		{
			ModLog.Debug($"Selected item from {pool}: {((Object)((Component)val).gameObject).name}");
			return ((Component)val).gameObject;
		}
		ModLog.Warn($"Failed to resolve item ID {num}. Falling back to vanilla GetRandomItem.");
		return LootData.GetRandomItem(pool, false);
	}

	static RandomizerCore()
	{
		SpawnPool[] array = new SpawnPool[11];
		RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
		NaturePools = (SpawnPool[])(object)array;
		SpawnPool[] array2 = new SpawnPool[9];
		RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
		LuggagePools = (SpawnPool[])(object)array2;
	}
}
[HarmonyPatch(typeof(RespawnChest), "SpawnItems")]
internal static class RespawnChestPatch
{
	private static bool Prefix()
	{
		if (PeakItemRandomizer.KeepRespawnStatuesVanilla.Value)
		{
			ModLog.Debug("RespawnChest left vanilla.");
		}
		return true;
	}
}