using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [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("DangerGift")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DangerGift")] [assembly: AssemblyTitle("DangerGift")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 DangerGift { internal static class ConfigSettings { public static ConfigEntry Enabled; public static ConfigEntry SpawnChance; public static ConfigEntry PreventOpeningOnShip; public static ConfigEntry SpawnMonsters; public static ConfigEntry SpawnTraps; public static ConfigEntry MonstersSpawnChance; public static ConfigEntry TrapsSpawnChance; public static ConfigEntry SpawnDelay; public static ConfigEntry EnemyBlocklist; public static ConfigEntry IsAllowlist; public static ConfigEntry EnemyAllowlist; public static ConfigEntry AllowOutsideSpawnInside; public static ConfigEntry AllowInsideSpawnOutside; public static ConfigEntry IgnoreInsideOutsideRule; public static ConfigEntry SpawnMines; public static ConfigEntry SpawnTurrets; public static ConfigEntry SpawnSpikeTraps; public static ConfigEntry MoonsToIgnore; public static ConfigEntry EnableLogging; public static HashSet BlocklistSet { get; private set; } public static HashSet AllowlistSet { get; private set; } public static HashSet IgnoredMoonsSet { get; private set; } public static void Init(ConfigFile cfg) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown Enabled = cfg.Bind("General", "Enabled", true, "Enable or disable the whole mod."); SpawnChance = cfg.Bind("General", "SpawnChance", 0.15f, new ConfigDescription("Base chance (0.0 - 1.0) that opening a Present spawns a monster/trap instead of loot.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PreventOpeningOnShip = cfg.Bind("General", "PreventOpeningOnShip", false, "If true, presents can ONLY be opened while landed on a moon and standing outside the ship (on the surface or in the facility). Opening is blocked aboard the ship and while in orbit / after take-off (not on a moon). The present is not consumed — it can still be opened later in a valid spot."); SpawnMonsters = cfg.Bind("Spawning", "SpawnMonsters", true, "Allow presents to spawn monsters."); SpawnTraps = cfg.Bind("Spawning", "SpawnTraps", true, "Allow presents to spawn traps."); MonstersSpawnChance = cfg.Bind("Spawning", "MonstersSpawnChance", -1f, new ConfigDescription("Separate chance for monsters. Set to -1 to just use the general SpawnChance. If either this or TrapsSpawnChance is >= 0, monsters and traps are rolled independently.", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 1f), Array.Empty())); TrapsSpawnChance = cfg.Bind("Spawning", "TrapsSpawnChance", -1f, new ConfigDescription("Separate chance for traps. Set to -1 to just use the general SpawnChance.", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 1f), Array.Empty())); SpawnDelay = cfg.Bind("Spawning", "SpawnDelay", 0.7f, new ConfigDescription("Delay, in seconds, between opening the present and the entity actually appearing. Gives players a brief window to react.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); EnemyBlocklist = cfg.Bind("Monsters", "EnemyBlocklist", "", "Comma-separated internal enemy names that must NEVER spawn (used when IsAllowlist = false). Example: \"Flowerman,SandSpider\". Enable logging to print the exact internal names."); IsAllowlist = cfg.Bind("Monsters", "IsAllowlist", true, "If true, ONLY monsters in EnemyAllowlist can spawn. If false, all monsters EXCEPT those in EnemyBlocklist can spawn."); EnemyAllowlist = cfg.Bind("Monsters", "EnemyAllowlist", "Manticoil,RoamingLocust,RedLocust,HoardingBug,GunkFish,Slime,TulipSnake,Maneater", "Comma-separated internal enemy names allowed when IsAllowlist = true. Names are matched leniently (case/space insensitive) against the game's enemy names."); AllowOutsideSpawnInside = cfg.Bind("Monsters", "AllowOutsideSpawnInside", false, "If true, outdoor monsters may also spawn from presents opened inside the facility. Off by default because outdoor AI can misbehave on the indoor navmesh."); AllowInsideSpawnOutside = cfg.Bind("Monsters", "AllowInsideSpawnOutside", false, "If true, indoor monsters may also spawn from presents opened outside."); IgnoreInsideOutsideRule = cfg.Bind("Monsters", "IgnoreInsideOutsideRule", false, "If true, the inside/outside rule is ignored entirely: BOTH facility (indoor) and outdoor monsters can spawn no matter where the present is opened. Overrides AllowOutsideSpawnInside / AllowInsideSpawnOutside."); SpawnMines = cfg.Bind("Traps", "SpawnMines", true, "Allow landmines to be spawned from presents."); SpawnTurrets = cfg.Bind("Traps", "SpawnTurrets", false, "Allow turrets to be spawned from presents."); SpawnSpikeTraps = cfg.Bind("Traps", "SpawnSpikeTraps", false, "Allow spike roof traps to be spawned. EXPERIMENTAL: these are designed to hang from ceilings, so a floor-spawned one may look/behave oddly."); MoonsToIgnore = cfg.Bind("Moons", "MoonsToIgnore", "", "Comma-separated moon names on which the mod is DISABLED. Matched against the planet name, so \"Titan\" matches \"8 Titan\". Leave empty to run on every moon."); EnableLogging = cfg.Bind("Debug", "EnableLogging", false, "Verbose logging to the BepInEx console (also prints every available enemy/trap name)."); RebuildCaches(); EnemyBlocklist.SettingChanged += delegate { RebuildCaches(); }; EnemyAllowlist.SettingChanged += delegate { RebuildCaches(); }; MoonsToIgnore.SettingChanged += delegate { RebuildCaches(); }; } private static void RebuildCaches() { BlocklistSet = ParseList(EnemyBlocklist.Value); AllowlistSet = ParseList(EnemyAllowlist.Value); IgnoredMoonsSet = ParseList(MoonsToIgnore.Value); } private static HashSet ParseList(string raw) { HashSet hashSet = new HashSet(); if (string.IsNullOrWhiteSpace(raw)) { return hashSet; } string[] array = raw.Split(','); for (int i = 0; i < array.Length; i++) { string text = Normalize(array[i]); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } public static string Normalize(string s) { if (string.IsNullOrEmpty(s)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(s.Length); foreach (char c in s) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } } [HarmonyPatch(typeof(GiftBoxItem))] internal static class GiftBoxPatches { private static readonly FieldInfo ExecStageField = typeof(NetworkBehaviour).GetField("__rpc_exec_stage", BindingFlags.Instance | BindingFlags.NonPublic); [HarmonyPatch("ItemActivate", new Type[] { typeof(bool), typeof(bool) })] [HarmonyPrefix] private static bool ItemActivatePrefix(GiftBoxItem __instance, bool buttonDown) { try { if (!ConfigSettings.Enabled.Value) { return true; } if (!ConfigSettings.PreventOpeningOnShip.Value) { return true; } if (CanOpenHere(__instance)) { return true; } if (buttonDown) { ShowCannotOpenTip(); } return false; } catch (Exception arg) { Plugin.Log.LogError((object)$"ItemActivate prefix error: {arg}"); return true; } } [HarmonyPatch("OpenGiftBoxServerRpc")] [HarmonyPrefix] private static bool OpenGiftBoxPrefix(GiftBoxItem __instance) { try { if (!ConfigSettings.Enabled.Value) { return true; } if (IsIgnoredMoon()) { return true; } if (!IsServerExecutionStage((NetworkBehaviour)(object)__instance)) { return true; } if (ConfigSettings.PreventOpeningOnShip.Value && !CanOpenHere(__instance)) { return true; } return !PresentReplacementManager.TryReplace(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"OpenGiftBox prefix error: {arg}"); return true; } } private static bool CanOpenHere(GiftBoxItem box) { if (ShipHasLanded()) { return !IsHolderInShip(box); } return false; } private static bool IsHolderInShip(GiftBoxItem box) { if ((Object)(object)((GrabbableObject)box).playerHeldBy != (Object)null) { return ((GrabbableObject)box).playerHeldBy.isInHangarShipRoom; } return false; } private static bool ShipHasLanded() { if ((Object)(object)StartOfRound.Instance != (Object)null) { return StartOfRound.Instance.shipHasLanded; } return false; } private static void ShowCannotOpenTip() { try { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Present", "Presents can only be opened out on the moon.", false, false, "LC_Tip1"); } } catch { } } private static bool IsServerExecutionStage(NetworkBehaviour nb) { if (ExecStageField == null) { return nb.IsServer; } try { object value = ExecStageField.GetValue(nb); string text = value.ToString(); if (text == "Execute" || text == "Server") { return true; } return Convert.ToInt32(value) == 1; } catch { return nb.IsServer; } } internal static void SetRpcExecStageToSend(NetworkBehaviour nb) { if (ExecStageField == null) { return; } try { ExecStageField.SetValue(nb, Enum.ToObject(ExecStageField.FieldType, 0)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not reset RPC exec stage: " + ex.Message)); } } private static bool IsIgnoredMoon() { HashSet ignoredMoonsSet = ConfigSettings.IgnoredMoonsSet; if (ignoredMoonsSet == null || ignoredMoonsSet.Count == 0) { return false; } SelectableLevel val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.currentLevel : null); if ((Object)(object)val == (Object)null) { return false; } string text = ConfigSettings.Normalize(val.PlanetName); foreach (string item in ignoredMoonsSet) { if (text.Contains(item)) { return true; } } return false; } } [HarmonyPatch(typeof(StartOfRound))] internal static class RoundResetPatch { [HarmonyPatch("StartGame")] [HarmonyPostfix] private static void OnStartGame() { PresentReplacementManager.Reset(); } } [BepInPlugin("Timofey.DangerGift", "DangerGift", "1.0.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { public const string GUID = "Timofey.DangerGift"; public const string NAME = "DangerGift"; public const string VERSION = "1.0.0"; private readonly Harmony _harmony = new Harmony("Timofey.DangerGift"); public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigSettings.Init(((BaseUnityPlugin)this).Config); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"DangerGift v1.0.0 loaded. Some presents bite back."); } } internal static class PresentReplacementManager { private class SpawnJob { public bool IsMonster; public EnemyType Enemy; public SpawnHelper.TrapTarget Trap; public Vector3 Position; } private static readonly Dictionary _decisions = new Dictionary(); private static readonly Random Rng = new Random(); public static bool TryReplace(GiftBoxItem box) { ulong networkObjectId = ((NetworkBehaviour)box).NetworkObjectId; if (_decisions.TryGetValue(networkObjectId, out var value)) { return value; } bool flag; try { flag = Decide(box); } catch (Exception arg) { Plugin.Log.LogError((object)$"Present replacement failed, falling back to normal loot: {arg}"); flag = false; } _decisions[networkObjectId] = flag; return flag; } private static bool Decide(GiftBoxItem box) { //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_0089: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) bool isInFactory = ((GrabbableObject)box).isInFactory; Vector3 position = ((Component)box).transform.position; RollCategories(out var monster, out var trap); if (!monster && !trap) { return false; } List list = new List(2); if (monster && ConfigSettings.SpawnMonsters.Value) { EnemyType val = SpawnHelper.ResolveMonster(isInFactory); if ((Object)(object)val != (Object)null && SpawnHelper.TryGetMonsterPosition(position, out var position2)) { list.Add(new SpawnJob { IsMonster = true, Enemy = val, Position = position2 }); } } if (trap && ConfigSettings.SpawnTraps.Value) { SpawnHelper.TrapTarget trapTarget = SpawnHelper.ResolveTrap(position); if (trapTarget != null) { list.Add(new SpawnJob { IsMonster = false, Trap = trapTarget, Position = trapTarget.Position }); } } if (list.Count == 0) { return false; } SpawnJob job = list[Rng.Next(list.Count)]; OpenBoxWithoutLoot(box); if ((Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(SpawnAfterDelay(job)); } else { ExecuteJob(job); } return true; } private static void OpenBoxWithoutLoot(GiftBoxItem box) { try { GiftBoxPatches.SetRpcExecStageToSend((NetworkBehaviour)(object)box); box.OpenGiftBoxNoPresentClientRpc(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to open present cleanly: {arg}"); } } private static void RollCategories(out bool monster, out bool trap) { monster = false; trap = false; bool flag = ConfigSettings.MonstersSpawnChance.Value >= 0f; bool flag2 = ConfigSettings.TrapsSpawnChance.Value >= 0f; float value = ConfigSettings.SpawnChance.Value; if (!flag && !flag2) { if (Rng.NextDouble() >= (double)value) { return; } bool value2 = ConfigSettings.SpawnMonsters.Value; bool value3 = ConfigSettings.SpawnTraps.Value; if (value2 && value3) { if (Rng.NextDouble() < 0.5) { monster = true; } else { trap = true; } } else if (value2) { monster = true; } else if (value3) { trap = true; } } else { float num = ((!ConfigSettings.SpawnMonsters.Value) ? 0f : (flag ? ConfigSettings.MonstersSpawnChance.Value : value)); float num2 = ((!ConfigSettings.SpawnTraps.Value) ? 0f : (flag2 ? ConfigSettings.TrapsSpawnChance.Value : value)); monster = Rng.NextDouble() < (double)num; trap = Rng.NextDouble() < (double)num2; } } private static IEnumerator SpawnAfterDelay(SpawnJob job) { yield return (object)new WaitForSeconds(Mathf.Max(0f, ConfigSettings.SpawnDelay.Value)); ExecuteJob(job); } private static void ExecuteJob(SpawnJob job) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) try { if (job.IsMonster) { SpawnHelper.SpawnMonster(job.Enemy, job.Position); } else { SpawnHelper.SpawnTrap(job.Trap); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to spawn present entity: {arg}"); } } public static void Reset() { _decisions.Clear(); } } internal static class SpawnHelper { public class TrapTarget { public GameObject Prefab; public Vector3 Position; public Quaternion Rotation; } private static readonly Random Rng = new Random(); private static GameObject _minePrefab; private static GameObject _turretPrefab; private static GameObject _spikeTrapPrefab; private static bool _trapsScanned; private static bool _dumpedAllEnemies; public static EnemyType ResolveMonster(bool insideFacility) { List list = new List(); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); List list2 = new List(); EnemyType[] array = Resources.FindObjectsOfTypeAll(); foreach (EnemyType val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.enemyPrefab == (Object)null) && !string.IsNullOrWhiteSpace(val.enemyName) && hashSet.Add(val.enemyName)) { list2.Add(val.enemyName); if (PassesListFilter(val) && PassesInsideOutside(val, insideFacility)) { list.Add(val); } } } if (ConfigSettings.EnableLogging.Value && !_dumpedAllEnemies) { _dumpedAllEnemies = true; list2.Sort(StringComparer.OrdinalIgnoreCase); Plugin.Log.LogInfo((object)string.Format("[Enemies] all loaded ({0}): {1}", list2.Count, string.Join(", ", list2))); } if (list.Count == 0) { if (ConfigSettings.EnableLogging.Value) { Plugin.Log.LogInfo((object)$"[Enemies] inside={insideFacility} allowed=0 (nothing to spawn)"); } return null; } EnemyType val2 = list[Rng.Next(list.Count)]; if (ConfigSettings.EnableLogging.Value) { List list3 = new List(list.Count); foreach (EnemyType item in list) { list3.Add(item.enemyName); } Plugin.Log.LogInfo((object)($"[Enemies] inside={insideFacility} allowed={list.Count} " + "=> [" + string.Join(", ", list3) + "] chosen='" + val2.enemyName + "'")); } return val2; } private static bool PassesInsideOutside(EnemyType et, bool insideFacility) { if (ConfigSettings.IgnoreInsideOutsideRule.Value) { return true; } bool flag = et.isOutsideEnemy || et.isDaytimeEnemy; bool flag2 = !et.isOutsideEnemy && !et.isDaytimeEnemy; if (insideFacility) { if (!flag2) { return ConfigSettings.AllowOutsideSpawnInside.Value; } return true; } if (!flag) { return ConfigSettings.AllowInsideSpawnOutside.Value; } return true; } private static bool PassesListFilter(EnemyType et) { bool value = ConfigSettings.IsAllowlist.Value; HashSet set = (value ? ConfigSettings.AllowlistSet : ConfigSettings.BlocklistSet); bool flag = NameMatchesSet(et, set); if (!value) { return !flag; } return flag; } private static bool NameMatchesSet(EnemyType et, HashSet set) { if (set == null || set.Count == 0) { return false; } List list = new List(3); if (!string.IsNullOrEmpty(et.enemyName)) { list.Add(ConfigSettings.Normalize(et.enemyName)); } if ((Object)(object)et.enemyPrefab != (Object)null) { list.Add(ConfigSettings.Normalize(((Object)et.enemyPrefab).name)); } list.Add(ConfigSettings.Normalize(((Object)et).name)); foreach (string item in set) { foreach (string item2 in ExpandAliases(item)) { if (item2.Length == 0) { continue; } foreach (string item3 in list) { if (item3.Length != 0 && (item3 == item2 || item3.Contains(item2) || item2.Contains(item3))) { return true; } } } } return false; } private static IEnumerable ExpandAliases(string normalized) { yield return normalized; if (normalized == null) { yield break; } switch (normalized.Length) { case 9: switch (normalized[0]) { default: yield break; case 'm': if (normalized == "manticoil") { yield return "doublewing"; } yield break; case 'r': break; } if (!(normalized == "redlocust")) { break; } goto IL_01cd; case 8: switch (normalized[0]) { case 'g': if (normalized == "gunkfish") { yield return "gutfish"; yield return "fish"; } break; case 'm': if (normalized == "maneater") { yield return "cavedweller"; yield return "caveddweller"; } break; } break; case 13: if (!(normalized == "roaminglocust")) { break; } goto IL_01cd; case 11: if (normalized == "hoardingbug") { yield return "hoarderbug"; yield return "hoarding"; } break; case 12: if (normalized == "kidnapperfox") { yield return "bushwolf"; yield return "fox"; } break; case 5: if (normalized == "slime") { yield return "hygrodere"; yield return "blob"; } break; case 10: { if (normalized == "tulipsnake") { yield return "flowersnake"; yield return "snake"; } break; } IL_01cd: yield return "redlocustbees"; yield return "docilelocust"; yield return "locust"; break; } } public static void SpawnMonster(EnemyType enemyType, Vector3 position) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)RoundManager.Instance == (Object)null) && !((Object)(object)enemyType == (Object)null)) { float num = (float)(Rng.NextDouble() * 360.0); RoundManager.Instance.SpawnEnemyGameObject(position, num, -1, enemyType); if (ConfigSettings.EnableLogging.Value) { Plugin.Log.LogInfo((object)$"[Spawn] Monster '{enemyType.enemyName}' at {position}"); } } } private static void ScanTrapPrefabs() { if (_trapsScanned) { return; } _trapsScanned = true; try { List list = new List(); SelectableLevel val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.currentLevel : null); if ((Object)(object)val != (Object)null && val.spawnableMapObjects != null) { list.Add(val.spawnableMapObjects); } SelectableLevel[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.levels : null); if (array != null) { SelectableLevel[] array2 = array; foreach (SelectableLevel val2 in array2) { if ((Object)(object)val2 != (Object)null && val2.spawnableMapObjects != null) { list.Add(val2.spawnableMapObjects); } } } foreach (SpawnableMapObject[] item in list) { for (int i = 0; i < item.Length; i++) { GameObject val3 = item[i]?.prefabToSpawn; if (!((Object)(object)val3 == (Object)null)) { if ((Object)(object)_minePrefab == (Object)null && (Object)(object)val3.GetComponentInChildren() != (Object)null) { _minePrefab = val3; } if ((Object)(object)_turretPrefab == (Object)null && (Object)(object)val3.GetComponentInChildren() != (Object)null) { _turretPrefab = val3; } if ((Object)(object)_spikeTrapPrefab == (Object)null && (Object)(object)val3.GetComponentInChildren() != (Object)null) { _spikeTrapPrefab = val3; } } } if ((Object)(object)_minePrefab != (Object)null && (Object)(object)_turretPrefab != (Object)null && (Object)(object)_spikeTrapPrefab != (Object)null) { break; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Trap prefab scan failed: " + ex.Message)); } if (ConfigSettings.EnableLogging.Value) { Plugin.Log.LogInfo((object)$"[Traps] mine={(Object)(object)_minePrefab != (Object)null} turret={(Object)(object)_turretPrefab != (Object)null} spike={(Object)(object)_spikeTrapPrefab != (Object)null}"); } } public static TrapTarget ResolveTrap(Vector3 near) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) ScanTrapPrefabs(); List list = new List(); if (ConfigSettings.SpawnMines.Value && (Object)(object)_minePrefab != (Object)null) { list.Add(_minePrefab); } if (ConfigSettings.SpawnTurrets.Value && (Object)(object)_turretPrefab != (Object)null) { list.Add(_turretPrefab); } if (ConfigSettings.SpawnSpikeTraps.Value && (Object)(object)_spikeTrapPrefab != (Object)null) { list.Add(_spikeTrapPrefab); } if (list.Count == 0) { return null; } if (!TryGetGroundPosition(near, out var position, out var normal)) { return null; } GameObject prefab = list[Rng.Next(list.Count)]; Quaternion rotation = Quaternion.FromToRotation(Vector3.up, normal) * Quaternion.Euler(0f, (float)(Rng.NextDouble() * 360.0), 0f); return new TrapTarget { Prefab = prefab, Position = position, Rotation = rotation }; } public static void SpawnTrap(TrapTarget target) { //IL_0019: 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_008e: Unknown result type (might be due to invalid IL or missing references) if (target == null || (Object)(object)target.Prefab == (Object)null) { return; } GameObject val = Object.Instantiate(target.Prefab, target.Position, target.Rotation); NetworkObject component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogWarning((object)("Trap prefab '" + ((Object)target.Prefab).name + "' has no NetworkObject; aborting spawn.")); Object.Destroy((Object)(object)val); return; } component.Spawn(true); if (ConfigSettings.EnableLogging.Value) { Plugin.Log.LogInfo((object)$"[Spawn] Trap '{((Object)target.Prefab).name}' at {target.Position}"); } } public static bool TryGetGroundPosition(Vector3 origin, out Vector3 position, out Vector3 normal) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //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_0013: 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_0022: 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_0057: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) position = origin; normal = Vector3.up; RaycastHit val = default(RaycastHit); if (Physics.Raycast(origin + Vector3.up * 0.5f, Vector3.down, ref val, 12f, -1, (QueryTriggerInteraction)1)) { position = ((RaycastHit)(ref val)).point; normal = ((RaycastHit)(ref val)).normal; } NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(position, ref val2, 3f, -1)) { position = ((NavMeshHit)(ref val2)).position + Vector3.up * 0.05f; return true; } return false; } public static bool TryGetMonsterPosition(Vector3 origin, out Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (TryGetGroundPosition(origin, out position, out var _)) { return true; } position = origin; return true; } } }