Decompiled source of HostTools v1.0.2

plugins/navivon.HostTools.dll

Decompiled 4 hours 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 HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[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("navivon.HostTools")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("HostTools")]
[assembly: AssemblyTitle("navivon.HostTools")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 HostTools
{
	[BepInPlugin("navivon.HostTools", "HostTools", "1.0.2")]
	public class HostTools : BaseUnityPlugin
	{
		public static ConfigEntry<bool> AllowMansion;

		public static ConfigEntry<bool> AllowMineshaft;

		public static ConfigEntry<bool> AllowFactory;

		public static ConfigEntry<bool> EnableSingleItemDay;

		public static ConfigEntry<bool> PredictionChat;

		public static ConfigEntry<string> ForcedSingleItem;

		public static ConfigEntry<bool> ForceMeteors;

		public static ConfigEntry<bool> ForceInfestation;

		public static ConfigEntry<int> InfestationType;

		public static ConfigEntry<float> ScrapAmountMultiplier;

		public static ConfigEntry<float> ScrapValueMultiplier;

		public static ConfigEntry<string> BlockedEnemies;

		public static HostTools Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony? Harmony { get; set; }

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			SetupConfig();
			Patch();
			Logger.LogInfo((object)"navivon.HostTools v1.0.2 has loaded!");
		}

		internal static void Patch()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("navivon.HostTools");
			}
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll();
			Logger.LogDebug((object)"Finished patching!");
		}

		internal static void Unpatch()
		{
			Logger.LogDebug((object)"Unpatching...");
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogDebug((object)"Finished unpatching!");
		}

		private void SetupConfig()
		{
			AllowMansion = ((BaseUnityPlugin)this).Config.Bind<bool>("Dungeon Generation", "Mansion", true, "Allow Mansion dungeon");
			AllowMineshaft = ((BaseUnityPlugin)this).Config.Bind<bool>("Dungeon Generation", "Mineshaft", true, "Allow Mineshaft dungeon");
			AllowFactory = ((BaseUnityPlugin)this).Config.Bind<bool>("Dungeon Generation", "Factory", true, "Allow Factory dungeon");
			EnableSingleItemDay = ((BaseUnityPlugin)this).Config.Bind<bool>("Single Item Day", "Enabled", false, "Force Single Item Day");
			PredictionChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Single Item Day", "PredictionChat", true, "Show predicted item in chat");
			ForcedSingleItem = ((BaseUnityPlugin)this).Config.Bind<string>("Single Item Day", "ForcedItem", "", "Force specific scrap item. Leave empty for random. Examples: Gift, Zed Dog, Easter egg, Gold bar, Perfume bottle.");
			ForceMeteors = ((BaseUnityPlugin)this).Config.Bind<bool>("Events", "Force Meteors", false, "Always enable meteor shower.");
			ForceInfestation = ((BaseUnityPlugin)this).Config.Bind<bool>("Events", "Force Infestation", false, "Force enemy infestation.");
			InfestationType = ((BaseUnityPlugin)this).Config.Bind<int>("Events", "Infestation Type", 0, "0 = Random, 1 = Nutcracker, 2 = Hoarding bug.");
			ScrapAmountMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scrap Modifiers", "Scrap Amount Multiplier", 1f, "Multiplier for the total amount of scrap spawned. 1 = Vanilla, 2 = Double, 0.5 = Half.");
			ScrapValueMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scrap Modifiers", "Scrap Value Multiplier", 1f, "Multiplier for the value of scrap. 1 = Vanilla, 2 = Double, 0.5 = Half.");
			BlockedEnemies = ((BaseUnityPlugin)this).Config.Bind<string>("Enemy Blocker", "Blocked Enemies", "", "Enemies that will be removed instantly after spawning.\r\n                Leave empty for vanilla behavior.\r\n\r\n                Example:\r\n                Girl, Clay Surgeon, Butler Bees\r\n\r\n                See EnemyList.txt for all available enemy names.");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "navivon.HostTools";

		public const string PLUGIN_NAME = "HostTools";

		public const string PLUGIN_VERSION = "1.0.2";
	}
}
namespace HostTools.Patches
{
	[HarmonyPatch(typeof(StartOfRound))]
	public class DungeonPatch
	{
		private static bool IsDungeonAllowed(int id)
		{
			return id switch
			{
				0 => HostTools.AllowFactory.Value, 
				1 => HostTools.AllowMansion.Value, 
				4 => HostTools.AllowMineshaft.Value, 
				_ => true, 
			};
		}

		[HarmonyPatch("ChooseNewRandomMapSeed")]
		[HarmonyPostfix]
		private static void ChooseNewRandomMapSeed(StartOfRound __instance)
		{
			SelectableLevel currentLevel = RoundManager.Instance.currentLevel;
			if ((Object)(object)currentLevel == (Object)null)
			{
				return;
			}
			IntWithRarity[] dungeonFlowTypes = currentLevel.dungeonFlowTypes;
			if (dungeonFlowTypes == null || dungeonFlowTypes.Length == 0 || (HostTools.AllowFactory.Value && HostTools.AllowMansion.Value && HostTools.AllowMineshaft.Value))
			{
				return;
			}
			List<int> list = new List<int>();
			IntWithRarity[] array = dungeonFlowTypes;
			foreach (IntWithRarity val in array)
			{
				list.Add(val.rarity);
			}
			bool flag = false;
			IntWithRarity[] array2 = dungeonFlowTypes;
			foreach (IntWithRarity val2 in array2)
			{
				if (IsDungeonAllowed(val2.id))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				HostTools.Logger.LogWarning((object)"No dungeons enabled. Using normal generation.");
				return;
			}
			for (int k = 0; k < 5000; k++)
			{
				int num = Random.Range(1, 100000000);
				Random random = new Random(num);
				int randomWeightedIndex = RoundManager.Instance.GetRandomWeightedIndex(list.ToArray(), random);
				if (IsDungeonAllowed(dungeonFlowTypes[randomWeightedIndex].id))
				{
					__instance.randomMapSeed = num;
					HostTools.Logger.LogInfo((object)$"Dungeon forced: ID {dungeonFlowTypes[randomWeightedIndex].id}");
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI))]
	internal class EnemyBlockerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void EnemyStartPatch(EnemyAI __instance)
		{
			if (!NetworkManager.Singleton.IsHost || (Object)(object)__instance.enemyType == (Object)null)
			{
				return;
			}
			string enemyName = __instance.enemyType.enemyName;
			string value = HostTools.BlockedEnemies.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return;
			}
			string[] array = (from x in value.Split(',')
				select x.Trim() into x
				where !string.IsNullOrWhiteSpace(x)
				select x).ToArray();
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (text.Equals(enemyName, StringComparison.OrdinalIgnoreCase))
				{
					HostTools.Logger.LogInfo((object)("Blocked enemy: " + enemyName));
					__instance.thisNetworkObject.Despawn(true);
					break;
				}
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	internal class InfestationPatch
	{
		[HarmonyPatch("RefreshEnemiesList")]
		[HarmonyPostfix]
		private static void ForceInfestation(ref SelectableLevel ___currentLevel, ref int ___enemyRushIndex, ref float ___currentMaxInsidePower)
		{
			if (!HostTools.ForceInfestation.Value || !((NetworkBehaviour)StartOfRound.Instance).IsHost)
			{
				return;
			}
			int num = -1;
			switch (HostTools.InfestationType.Value)
			{
			case 0:
			{
				Random random = new Random();
				if (random.Next(0, 100) < 50)
				{
					num = FindEnemy(___currentLevel, "Nutcracker");
					if (num != -1)
					{
						___currentMaxInsidePower = 20f;
					}
				}
				else
				{
					num = FindEnemy(___currentLevel, "Hoarding bug");
					if (num != -1)
					{
						___currentMaxInsidePower = 30f;
					}
				}
				break;
			}
			case 1:
				num = FindEnemy(___currentLevel, "Nutcracker");
				if (num != -1)
				{
					___currentMaxInsidePower = 20f;
				}
				break;
			case 2:
				num = FindEnemy(___currentLevel, "Hoarding bug");
				if (num != -1)
				{
					___currentMaxInsidePower = 30f;
				}
				break;
			}
			if (num != -1)
			{
				___enemyRushIndex = num;
				HostTools.Logger.LogInfo((object)("Forced infestation: " + ___currentLevel.Enemies[num].enemyType.enemyName));
			}
		}

		private static int FindEnemy(SelectableLevel level, string enemyName)
		{
			if ((Object)(object)level == (Object)null)
			{
				return -1;
			}
			for (int i = 0; i < level.Enemies.Count; i++)
			{
				if (level.Enemies[i].enemyType.enemyName.Equals(enemyName, StringComparison.OrdinalIgnoreCase))
				{
					return i;
				}
			}
			return -1;
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	[HarmonyPriority(0)]
	internal class SingleItemDayPatch
	{
		private static bool chatSent;

		private static int originalMinScrap;

		private static int originalMaxScrap;

		[HarmonyPatch("FinishGeneratingNewLevelClientRpc")]
		[HarmonyPostfix]
		private static void Reset()
		{
			chatSent = false;
		}

		[HarmonyPatch("SpawnScrapInLevel")]
		[HarmonyPrefix]
		private static bool SpawnScrapInLevel(RoundManager __instance)
		{
			try
			{
				if (!((NetworkBehaviour)StartOfRound.Instance).IsHost)
				{
					return true;
				}
				if ((Object)(object)__instance.currentLevel == (Object)null)
				{
					return true;
				}
				originalMinScrap = __instance.currentLevel.minScrap;
				originalMaxScrap = __instance.currentLevel.maxScrap;
				if (HostTools.ScrapAmountMultiplier.Value != 1f)
				{
					__instance.currentLevel.minScrap = Mathf.RoundToInt((float)originalMinScrap * HostTools.ScrapAmountMultiplier.Value);
					__instance.currentLevel.maxScrap = Mathf.RoundToInt((float)originalMaxScrap * HostTools.ScrapAmountMultiplier.Value);
				}
				List<SpawnableItemWithRarity> spawnableScrap = __instance.currentLevel.spawnableScrap;
				if (spawnableScrap == null || spawnableScrap.Count == 0)
				{
					return true;
				}
				if (!HostTools.EnableSingleItemDay.Value)
				{
					return true;
				}
				List<int> list = new List<int>();
				foreach (SpawnableItemWithRarity item in spawnableScrap)
				{
					list.Add(Mathf.Max(1, item.rarity));
				}
				Item val = null;
				string forcedName = HostTools.ForcedSingleItem.Value;
				if (!string.IsNullOrWhiteSpace(forcedName))
				{
					val = ((IEnumerable<SpawnableItemWithRarity>)spawnableScrap).FirstOrDefault((Func<SpawnableItemWithRarity, bool>)((SpawnableItemWithRarity x) => (Object)(object)x.spawnableItem != (Object)null && x.spawnableItem.itemName.Equals(forcedName, StringComparison.OrdinalIgnoreCase)))?.spawnableItem;
				}
				if ((Object)(object)val == (Object)null)
				{
					Random random = new Random(Guid.NewGuid().GetHashCode());
					int randomWeightedIndex = __instance.GetRandomWeightedIndex(list.ToArray(), random);
					if (randomWeightedIndex < 0 || randomWeightedIndex >= spawnableScrap.Count)
					{
						return true;
					}
					val = spawnableScrap[randomWeightedIndex].spawnableItem;
				}
				if ((Object)(object)val == (Object)null)
				{
					return true;
				}
				HostTools.Logger.LogInfo((object)("Single Item Day: " + val.itemName));
				SendPredictionChat(val);
				SpawnAllAsSingleItem(__instance, val);
				return false;
			}
			catch (Exception ex)
			{
				HostTools.Logger.LogError((object)ex);
				return true;
			}
		}

		[HarmonyPatch("SpawnScrapInLevel")]
		[HarmonyPostfix]
		private static void RestoreScrapValues(RoundManager __instance)
		{
			if (!((Object)(object)__instance.currentLevel == (Object)null))
			{
				__instance.currentLevel.minScrap = originalMinScrap;
				__instance.currentLevel.maxScrap = originalMaxScrap;
			}
		}

		private static void SendPredictionChat(Item item)
		{
			try
			{
				if (HostTools.PredictionChat.Value && !chatSent)
				{
					HUDManager.Instance.AddTextToChatOnServer("Today's scrap: <color=#00BFFF>" + item.itemName + "</color>", -1);
					chatSent = true;
				}
			}
			catch (Exception ex)
			{
				HostTools.Logger.LogError((object)ex);
			}
		}

		private static void SpawnAllAsSingleItem(RoundManager rm, Item item)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(0, rm.AnomalyRandom.Next(rm.currentLevel.minScrap, rm.currentLevel.maxScrap));
			if (rm.currentDungeonType == 4)
			{
				num += 6;
			}
			RandomScrapSpawn[] source = Object.FindObjectsOfType<RandomScrapSpawn>();
			List<NetworkObjectReference> list = new List<NetworkObjectReference>();
			List<int> list2 = new List<int>();
			List<RandomScrapSpawn> usedSpawns = new List<RandomScrapSpawn>();
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				List<RandomScrapSpawn> list3 = ((item.spawnPositionTypes == null || item.spawnPositionTypes.Count == 0) ? source.ToList() : source.Where((RandomScrapSpawn x) => item.spawnPositionTypes.Contains(x.spawnableItems) && !x.spawnUsed).ToList());
				if (list3.Count == 0)
				{
					break;
				}
				list3.RemoveAll((RandomScrapSpawn x) => usedSpawns.Contains(x));
				if (list3.Count == 0)
				{
					usedSpawns.Clear();
					i--;
					continue;
				}
				RandomScrapSpawn val = list3[rm.AnomalyRandom.Next(0, list3.Count)];
				usedSpawns.Add(val);
				Vector3 val2 = (((Object)(object)val.spawnWithParent != (Object)null) ? ((Component)val.spawnWithParent).transform.position : ((Component)val).transform.position);
				GameObject val3 = Object.Instantiate<GameObject>(item.spawnPrefab, val2, Quaternion.identity);
				GrabbableObject component = val3.GetComponent<GrabbableObject>();
				component.scrapValue = Mathf.RoundToInt((float)rm.AnomalyRandom.Next(item.minValue, item.maxValue) * rm.scrapValueMultiplier * HostTools.ScrapValueMultiplier.Value);
				list2.Add(component.scrapValue);
				num2 += component.scrapValue;
				NetworkObject component2 = val3.GetComponent<NetworkObject>();
				component2.Spawn(false);
				list.Add(NetworkObjectReference.op_Implicit(component2));
			}
			rm.totalScrapValueInLevel = num2;
			rm.scrapCollectedInLevel = 0;
			rm.valueOfFoundScrapItems = 0;
			rm.SyncScrapValuesClientRpc(list.ToArray(), list2.ToArray());
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	internal class UnrandomizerPatch
	{
		[HarmonyPatch(typeof(TimeOfDay), "DecideRandomDayEvents")]
		[HarmonyPrefix]
		private static void Meteors(ref int ___overrideMeteorChance)
		{
			if (((NetworkBehaviour)StartOfRound.Instance).IsHost && HostTools.ForceMeteors.Value)
			{
				___overrideMeteorChance = 1000;
			}
		}
	}
}