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 AnIntruder v1.0.1
plugins/AnIntruder/AnIntruder.dll
Decompiled an hour agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using AnIntruder.NetcodePatcher; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExampleEnemy.Configuration; using GameNetcodeStuff; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.Rendering; [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("AnIntruder")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+2cebfc334b5807858d1a69d8bd01561e7cb2b465")] [assembly: AssemblyProduct("AnIntruder")] [assembly: AssemblyTitle("AnIntruder")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] 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 ExampleEnemy { internal class ExampleEnemyAI : EnemyAI { public Material? scareMaterial; public AudioClip? scareClip; public AudioClip? warningClip; private const float MaxLookDistance = 15f; private AudioSource? screenAudio; private Material? activeFace; private Material? fallbackFace; private Material? blendInstance; private float nextRollTime; private int scaresDone; private bool sequenceRunning; private bool bestiaryUnlocked; public override void Start() { ((EnemyAI)this).Start(); if ((Object)(object)base.creatureVoice != (Object)null) { base.creatureVoice.Stop(); base.creatureVoice.loop = false; base.creatureVoice.mute = true; } if (((NetworkBehaviour)this).IsServer) { nextRollTime = Time.time + Plugin.BoundConfig.FirstScareDelay.Value; } } public override void DoAIInterval() { ((EnemyAI)this).DoAIInterval(); if (!((NetworkBehaviour)this).IsServer || sequenceRunning || base.isEnemyDead || Time.time < nextRollTime) { return; } int value = Plugin.BoundConfig.MaxScaresPerSpawn.Value; if (value <= 0 || scaresDone < value) { ScheduleNextRoll(); ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; if (!((Object)(object)mapScreen == (Object)null) && IsMapOn(mapScreen) && AnyoneInShip() && !(Random.value > Plugin.BoundConfig.ScareChance.Value)) { scaresDone++; StartScareClientRpc(); } } } private void ScheduleNextRoll() { nextRollTime = Time.time + Plugin.BoundConfig.RollInterval.Value; } private static bool InShip(PlayerControllerB p) { //IL_000a: 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) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = StartOfRound.Instance.shipInnerRoomBounds.bounds; return ((Bounds)(ref bounds)).Contains(((Component)p).transform.position); } private static bool AnyoneInShip() { PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (val.isPlayerControlled && !val.isPlayerDead && InShip(val)) { return true; } } return false; } [ClientRpc] public void StartScareClientRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)((NetworkBehaviour)this).__rpc_exec_stage != 1 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val2 = default(ClientRpcParams); FastBufferWriter val = ((NetworkBehaviour)this).__beginSendClientRpc(1156206395u, val2, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendClientRpc(ref val, 1156206395u, val2, (RpcDelivery)0); } if ((int)((NetworkBehaviour)this).__rpc_exec_stage == 1 && (networkManager.IsClient || networkManager.IsHost)) { ((NetworkBehaviour)this).__rpc_exec_stage = (__RpcExecStage)0; if (!sequenceRunning) { ((MonoBehaviour)this).StartCoroutine(ScareSequence()); } } } private IEnumerator ScareSequence() { sequenceRunning = true; ManualCameraRenderer map = StartOfRound.Instance.mapScreen; int slot = Array.IndexOf(((Renderer)map.mesh).sharedMaterials, map.onScreenMat); if (slot < 0) { Plugin.Logger.LogWarning((object)"Map screen material not found. Scare skipped."); Finish(); yield break; } if ((Object)(object)scareMaterial == (Object)null && (Object)(object)fallbackFace == (Object)null) { fallbackFace = new Material(map.offScreenMat); } activeFace = (((Object)(object)scareMaterial != (Object)null) ? scareMaterial : fallbackFace); EnsureAudio(map); Vector3 screenCenter = GetScreenCenter(map.mesh, slot); bool blendMode = activeFace.HasProperty("_Blend") && activeFace.HasProperty("_MapTex") && (Object)(object)map.mapCamera != (Object)null && (Object)(object)map.mapCamera.targetTexture != (Object)null; if (blendMode) { Material val = new Material(activeFace); val.SetTexture("_MapTex", (Texture)(object)map.mapCamera.targetTexture); val.SetFloat("_Blend", 0f); if ((Object)(object)blendInstance != (Object)null) { Object.Destroy((Object)(object)blendInstance); } blendInstance = val; activeFace = val; SetSlot(map, slot, val); } float warn = Plugin.BoundConfig.WarningSeconds.Value; if ((Object)(object)warningClip != (Object)null) { screenAudio.PlayOneShot(warningClip); } float flash; float gap; for (float elapsed = 0f; elapsed < warn; elapsed += flash + gap) { if (TurnedOff(map, slot)) { Cancel(map, slot, screenOff: true); yield break; } float progress = elapsed / warn; if (blendMode) { activeFace.SetFloat("_Blend", Mathf.Lerp(0.15f, 1f, progress * progress)); } else { SetSlot(map, slot, activeFace); } flash = Mathf.Lerp(0.04f, 0.12f, progress) * Random.Range(0.8f, 1.2f); yield return (object)new WaitForSeconds(flash); if (TurnedOff(map, slot)) { Cancel(map, slot, screenOff: true); yield break; } if (blendMode) { activeFace.SetFloat("_Blend", 0f); } else { SetSlot(map, slot, map.onScreenMat); } gap = Mathf.Lerp(0.8f, 0.06f, progress) * Random.Range(0.6f, 1.4f); yield return (object)new WaitForSeconds(gap); } if (TurnedOff(map, slot)) { Cancel(map, slot, screenOff: true); yield break; } if (blendMode) { activeFace.SetFloat("_Blend", 1f); } else { SetSlot(map, slot, activeFace); } if ((Object)(object)scareClip != (Object)null) { screenAudio.PlayOneShot(scareClip); } if (((NetworkBehaviour)this).IsServer) { UnlockBestiary(); } PlayerControllerB me = GameNetworkManager.Instance.localPlayerController; float value = Plugin.BoundConfig.ScareSeconds.Value; float end = Time.time + value; bool killed = false; while (Time.time < end) { if (TurnedOff(map, slot)) { Cancel(map, slot, screenOff: true); yield break; } if (!killed && IsLookingAtScreen(me, screenCenter)) { killed = true; me.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false); } yield return null; } Cancel(map, slot, screenOff: false); } private void UnlockBestiary() { if (bestiaryUnlocked) { return; } Terminal val = Object.FindObjectOfType<Terminal>(); if ((Object)(object)val == (Object)null) { return; } TerminalNode val2 = val.enemyFiles.Find((TerminalNode n) => (Object)(object)n != (Object)null && n.creatureName == "An intruder"); if ((Object)(object)val2 == (Object)null) { Plugin.Logger.LogWarning((object)"Bestiary entry not found."); return; } bestiaryUnlocked = true; if (!val.scannedEnemyIDs.Contains(val2.creatureFileID)) { HUDManager.Instance.ScanNewCreatureServerRpc(val2.creatureFileID); } } private static bool IsMapOn(ManualCameraRenderer map) { return Array.IndexOf(((Renderer)map.mesh).sharedMaterials, map.onScreenMat) >= 0; } private static bool TurnedOff(ManualCameraRenderer map, int slot) { return (Object)(object)((Renderer)map.mesh).sharedMaterials[slot] == (Object)(object)map.offScreenMat; } private void Cancel(ManualCameraRenderer map, int slot, bool screenOff) { SetSlot(map, slot, screenOff ? map.offScreenMat : map.onScreenMat); Finish(); } private void Finish() { sequenceRunning = false; if (((NetworkBehaviour)this).IsServer) { ScheduleNextRoll(); } } private static void SetSlot(ManualCameraRenderer map, int slot, Material mat) { Material[] sharedMaterials = ((Renderer)map.mesh).sharedMaterials; sharedMaterials[slot] = mat; ((Renderer)map.mesh).sharedMaterials = sharedMaterials; } private void EnsureAudio(ManualCameraRenderer map) { if (!((Object)(object)screenAudio != (Object)null)) { screenAudio = ((Component)map.mesh).gameObject.AddComponent<AudioSource>(); screenAudio.spatialBlend = 1f; screenAudio.rolloffMode = (AudioRolloffMode)1; screenAudio.maxDistance = 25f; screenAudio.outputAudioMixerGroup = StartOfRound.Instance.shipAmbianceAudio.outputAudioMixerGroup; } } private static Vector3 GetScreenCenter(MeshRenderer renderer, int slot) { //IL_0069: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0056: 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) MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>(); Bounds bounds; if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null && slot < component.sharedMesh.subMeshCount) { SubMeshDescriptor subMesh = component.sharedMesh.GetSubMesh(slot); bounds = ((SubMeshDescriptor)(ref subMesh)).bounds; Vector3 center = ((Bounds)(ref bounds)).center; return ((Component)renderer).transform.TransformPoint(center); } Plugin.Logger.LogWarning((object)"Submesh lookup failed, using whole monitor bounds."); bounds = ((Renderer)renderer).bounds; return ((Bounds)(ref bounds)).center; } private bool IsLookingAtScreen(PlayerControllerB p, Vector3 target) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_003b: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0078: 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_0084: 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) if ((Object)(object)p == (Object)null || p.isPlayerDead || !p.isPlayerControlled || !InShip(p)) { return false; } Transform transform = ((Component)p.gameplayCamera).transform; Vector3 val = target - transform.position; if (((Vector3)(ref val)).magnitude > 15f) { return false; } if (Vector3.Angle(transform.forward, val) > Plugin.BoundConfig.LookAngle.Value) { return false; } Vector3 val2 = target - ((Vector3)(ref val)).normalized * 0.3f; return !Physics.Linecast(transform.position, val2, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); } public override void OnDestroy() { if (sequenceRunning && (Object)(object)activeFace != (Object)null && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.mapScreen != (Object)null) { ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; int num = Array.IndexOf(((Renderer)mapScreen.mesh).sharedMaterials, activeFace); if (num >= 0) { SetSlot(mapScreen, num, mapScreen.onScreenMat); } } if ((Object)(object)screenAudio != (Object)null) { Object.Destroy((Object)(object)screenAudio); } if ((Object)(object)fallbackFace != (Object)null) { Object.Destroy((Object)(object)fallbackFace); } if ((Object)(object)blendInstance != (Object)null) { Object.Destroy((Object)(object)blendInstance); } ((EnemyAI)this).OnDestroy(); } protected override void __initializeVariables() { ((EnemyAI)this).__initializeVariables(); } protected override void __initializeRpcs() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown ((NetworkBehaviour)this).__registerRpc(1156206395u, new RpcReceiveHandler(__rpc_handler_1156206395), "StartScareClientRpc"); ((EnemyAI)this).__initializeRpcs(); } private static void __rpc_handler_1156206395(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0029: 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) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { target.__rpc_exec_stage = (__RpcExecStage)1; ((ExampleEnemyAI)(object)target).StartScareClientRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "ExampleEnemyAI"; } } [BepInPlugin("AnIntruder", "AnIntruder", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; public static AssetBundle? ModAssets; internal static PluginConfig BoundConfig { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config); InitializeNetworkBehaviours(); string path = "anintruder"; ModAssets = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), path)); if ((Object)(object)ModAssets == (Object)null) { Logger.LogError((object)"Failed to load custom assets."); return; } EnemyType val = ModAssets.LoadAsset<EnemyType>("ExampleEnemy"); TerminalNode val2 = ModAssets.LoadAsset<TerminalNode>("ExampleEnemyTN"); TerminalKeyword val3 = ModAssets.LoadAsset<TerminalKeyword>("ExampleEnemyTK"); NetworkPrefabs.RegisterNetworkPrefab(val.enemyPrefab); float m = BoundConfig.SpawnWeightMultiplier.Value; Dictionary<LevelTypes, int> dictionary = new Dictionary<LevelTypes, int> { { (LevelTypes)4, W(1) }, { (LevelTypes)8, W(1) }, { (LevelTypes)16, W(1) }, { (LevelTypes)32, W(2) }, { (LevelTypes)64, W(2) }, { (LevelTypes)2048, W(2) }, { (LevelTypes)128, W(9) }, { (LevelTypes)256, W(7) }, { (LevelTypes)512, W(9) }, { (LevelTypes)4096, W(6) }, { (LevelTypes)8192, W(3) }, { (LevelTypes)1024, W(4) } }; Enemies.RegisterEnemy(val, dictionary, (Dictionary<string, int>)null, val2, val3); Logger.LogInfo((object)"Plugin AnIntruder is loaded!"); int W(int baseWeight) { return Math.Max(0, (int)Math.Round((float)baseWeight * m)); } } private static void InitializeNetworkBehaviours() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } } } public static class PluginInfo { public const string PLUGIN_GUID = "AnIntruder"; public const string PLUGIN_NAME = "AnIntruder"; public const string PLUGIN_VERSION = "1.0.1"; } } namespace ExampleEnemy.Configuration { public class PluginConfig { public ConfigEntry<float> SpawnWeightMultiplier; public ConfigEntry<float> FirstScareDelay; public ConfigEntry<float> RollInterval; public ConfigEntry<float> ScareChance; public ConfigEntry<int> MaxScaresPerSpawn; public ConfigEntry<float> WarningSeconds; public ConfigEntry<float> ScareSeconds; public ConfigEntry<float> LookAngle; public PluginConfig(ConfigFile cfg) { SpawnWeightMultiplier = cfg.Bind<float>("Spawning", "Spawn weight multiplier", 1f, "Scales the per-moon spawn weights. Defaults are tuned to be about as rare as the Ghost Girl. 0 disables spawning, 2 doubles it."); FirstScareDelay = cfg.Bind<float>("Scare", "First scare delay", 120f, "Seconds after it spawns before it can attempt anything."); RollInterval = cfg.Bind<float>("Scare", "Roll interval", 45f, "Seconds between attempts to start a scare."); ScareChance = cfg.Bind<float>("Scare", "Scare chance", 0.15f, "Chance per attempt (0 to 1). Only rolls while someone is in the ship and the monitor is on."); MaxScaresPerSpawn = cfg.Bind<int>("Scare", "Max scares per spawn", 2, "How many times one spawned intruder can trigger before going quiet for the rest of the day. 0 means unlimited."); WarningSeconds = cfg.Bind<float>("Scare", "Warning seconds", 5f, "How long the face flickers before taking the screen."); ScareSeconds = cfg.Bind<float>("Scare", "Scare seconds", 1f, "How long the face holds the screen. Looking at it during this window kills."); LookAngle = cfg.Bind<float>("Scare", "Look angle", 20f, "Degrees off the center of your view that still counts as looking at the screen."); ClearUnusedEntries(cfg); } private void ClearUnusedEntries(ConfigFile cfg) { PropertyInfo property = ((object)cfg).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic); Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(cfg, null); dictionary.Clear(); cfg.Save(); } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { } } } namespace AnIntruder.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }