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 AllowMansion; public static ConfigEntry AllowMineshaft; public static ConfigEntry AllowFactory; public static ConfigEntry EnableSingleItemDay; public static ConfigEntry PredictionChat; public static ConfigEntry ForcedSingleItem; public static ConfigEntry ForceMeteors; public static ConfigEntry ForceInfestation; public static ConfigEntry InfestationType; public static ConfigEntry ScrapAmountMultiplier; public static ConfigEntry ScrapValueMultiplier; public static ConfigEntry 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("Dungeon Generation", "Mansion", true, "Allow Mansion dungeon"); AllowMineshaft = ((BaseUnityPlugin)this).Config.Bind("Dungeon Generation", "Mineshaft", true, "Allow Mineshaft dungeon"); AllowFactory = ((BaseUnityPlugin)this).Config.Bind("Dungeon Generation", "Factory", true, "Allow Factory dungeon"); EnableSingleItemDay = ((BaseUnityPlugin)this).Config.Bind("Single Item Day", "Enabled", false, "Force Single Item Day"); PredictionChat = ((BaseUnityPlugin)this).Config.Bind("Single Item Day", "PredictionChat", true, "Show predicted item in chat"); ForcedSingleItem = ((BaseUnityPlugin)this).Config.Bind("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("Events", "Force Meteors", false, "Always enable meteor shower."); ForceInfestation = ((BaseUnityPlugin)this).Config.Bind("Events", "Force Infestation", false, "Force enemy infestation."); InfestationType = ((BaseUnityPlugin)this).Config.Bind("Events", "Infestation Type", 0, "0 = Random, 1 = Nutcracker, 2 = Hoarding bug."); ScrapAmountMultiplier = ((BaseUnityPlugin)this).Config.Bind("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("Scrap Modifiers", "Scrap Value Multiplier", 1f, "Multiplier for the value of scrap. 1 = Vanilla, 2 = Double, 0.5 = Half."); BlockedEnemies = ((BaseUnityPlugin)this).Config.Bind("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 list = new List(); 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 spawnableScrap = __instance.currentLevel.spawnableScrap; if (spawnableScrap == null || spawnableScrap.Count == 0) { return true; } if (!HostTools.EnableSingleItemDay.Value) { return true; } List list = new List(); 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)spawnableScrap).FirstOrDefault((Func)((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: " + item.itemName + "", -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(); List list = new List(); List list2 = new List(); List usedSpawns = new List(); int num2 = 0; for (int i = 0; i < num; i++) { List 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(item.spawnPrefab, val2, Quaternion.identity); GrabbableObject component = val3.GetComponent(); 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(); 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; } } } }