Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HostTools v1.0.2
plugins/navivon.HostTools.dll
Decompiled 4 hours agousing 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; } } } }