using 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 BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using LethalOtis; using LethalOtisMod; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; [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: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("LethalOtis")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LethalOtis")] [assembly: AssemblyTitle("LethalOtis")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] public class MilkBucketItem : PhysicsProp { private ScanNodeProperties _scanNode; private bool _lastHeld; public override void Start() { ((GrabbableObject)this).itemProperties = Object.Instantiate(((GrabbableObject)this).itemProperties); ((GrabbableObject)this).itemProperties.floorYOffset = 0; ((GrabbableObject)this).Start(); ((Component)this).gameObject.layer = 6; ((Component)this).gameObject.tag = "PhysicsProp"; ((GrabbableObject)this).propColliders = ((Component)this).GetComponents(); ((GrabbableObject)this).mainObjectRenderer = ((Component)this).GetComponentInChildren(); AudioSource[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { val.spatialBlend = 1f; } } public override void Update() { ((GrabbableObject)this).Update(); if ((Object)(object)_scanNode == (Object)null) { _scanNode = ((Component)this).GetComponentInChildren(); } if ((Object)(object)_scanNode != (Object)null && ((GrabbableObject)this).isHeld != _lastHeld) { _lastHeld = ((GrabbableObject)this).isHeld; ((Component)_scanNode).gameObject.SetActive(!((GrabbableObject)this).isHeld); } } } public class OtisCurse : NetworkBehaviour { [Header("Curse Settings")] public float shrinkDuration = 60f; public float targetScale = 0.75f; public float curseRadius = 2f; public float shrinkTransitionTime = 10f; private float[] curseProgress; [Header("Stat Debuff Multipliers")] public float targetJump = 13f; public float targetSpeed = 4.6f; [Header("Voice Change Settings")] public float targetPitch = 1.5f; [Header("Sound Effect Logic")] public AudioSource headAudioSource; public AudioClip curseSoundEffect; private OtisRoam roam; private AudioSource debugMicSource; private string selectedMicDevice; private void Awake() { roam = ((Component)this).GetComponent(); } private void OnTriggerEnter(Collider other) { //IL_0046: 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) if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving) { return; } PlayerControllerB componentInParent = ((Component)other).gameObject.GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || Vector3.Distance(((Component)this).transform.position, ((Component)componentInParent).transform.position) > curseRadius || !((NetworkBehaviour)componentInParent).IsOwner) { return; } if ((Object)(object)roam == (Object)null) { roam = ((Component)this).GetComponent(); } if (!((Object)(object)roam == (Object)null)) { int num = 1 << (int)componentInParent.playerClientId; if ((roam.cursedBitmask.Value & num) == 0) { Plugin.logger.LogInfo((object)("[OtisCurse] Local player '" + componentInParent.playerUsername + "' touched Otis — sending curse request.")); roam.CursePlayerSend(componentInParent.playerClientId); } } } public void ApplyShrinkEffect(ulong playerId) { PlayerControllerB playerById = GetPlayerById(playerId); if ((Object)(object)playerById == (Object)null) { Plugin.logger.LogWarning((object)$"ApplyShrinkEffect: could not resolve player {playerId} on this client."); return; } if (((NetworkBehaviour)playerById).IsOwner) { playerById.movementSpeed = targetSpeed; playerById.jumpForce = targetJump; } if ((Object)(object)headAudioSource != (Object)null && (Object)(object)curseSoundEffect != (Object)null) { headAudioSource.PlayOneShot(curseSoundEffect); } Plugin.logger.LogInfo((object)(playerById.playerUsername + " was cursed by Otis!")); } private PlayerControllerB GetPlayerById(ulong playerId) { GameObject[] allPlayerObjects = StartOfRound.Instance.allPlayerObjects; foreach (GameObject val in allPlayerObjects) { PlayerControllerB component = val.GetComponent(); if ((Object)(object)component != (Object)null && component.playerClientId == playerId) { return component; } } return null; } public override void OnNetworkDespawn() { if ((Object)(object)headAudioSource != (Object)null && headAudioSource.isPlaying) { headAudioSource.Stop(); } ((NetworkBehaviour)this).OnNetworkDespawn(); } private void LateUpdate() { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)SoundManager.Instance == (Object)null || StartOfRound.Instance.shipIsLeaving || (Object)(object)roam == (Object)null || roam.cursedBitmask.Value == 0) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; if (curseProgress == null || curseProgress.Length != allPlayerScripts.Length) { curseProgress = new float[allPlayerScripts.Length]; } for (int i = 0; i < allPlayerScripts.Length; i++) { if ((roam.cursedBitmask.Value & (1 << i)) == 0) { continue; } PlayerControllerB val = allPlayerScripts[i]; if ((Object)(object)val == (Object)null || val.disconnectedMidGame) { continue; } curseProgress[i] = Mathf.Min(1f, curseProgress[i] + Time.deltaTime / shrinkTransitionTime); float num = curseProgress[i]; ((Component)val).transform.localScale = Vector3.Lerp(Vector3.one, Vector3.one * targetScale, num); float num2 = Mathf.Lerp(1f, targetPitch, num); SoundManager.Instance.playerVoicePitchTargets[i] = num2; SoundManager.Instance.SetPlayerPitch(num2, i); if ((Object)(object)val.currentVoiceChatAudioSource != (Object)null) { val.currentVoiceChatAudioSource.pitch = num2; } if (((NetworkBehaviour)val).IsOwner && val.isPlayerControlled) { if (val.movementSpeed != targetSpeed) { val.movementSpeed = targetSpeed; } if (val.jumpForce != targetJump) { val.jumpForce = targetJump; } } } } private void StartMicLoopback() { if ((Object)(object)debugMicSource == (Object)null) { debugMicSource = ((Component)this).gameObject.AddComponent(); debugMicSource.spatialBlend = 0f; } string text = 4.ToString(); int num = (int)StartOfRound.Instance.localPlayerController.playerClientId; debugMicSource.pitch = 1.6f; if (Microphone.devices.Length != 0) { selectedMicDevice = Microphone.devices[0]; debugMicSource.clip = Microphone.Start(selectedMicDevice, true, 1, 44100); debugMicSource.loop = true; ((MonoBehaviour)this).StartCoroutine(WaitForMicToStart()); } else { Plugin.logger.LogWarning((object)"No microphone detected for testing!"); } } private IEnumerator WaitForMicToStart() { while (Microphone.GetPosition(selectedMicDevice) <= 0) { yield return null; } debugMicSource.Play(); Plugin.logger.LogInfo((object)$"Mic Test Started! Playing back at Pitch: {debugMicSource.pitch}"); } private void StopMicLoopback() { if ((Object)(object)debugMicSource != (Object)null && debugMicSource.isPlaying) { debugMicSource.Stop(); Microphone.End(selectedMicDevice); Plugin.logger.LogInfo((object)"Mic Test Ended."); } } } public class OtisRoam : EnemyAI { private const string MSG_CURSE_PLAYER = "LethalOtis.CursePlayer"; private const string MSG_MILK_COLLECTED = "LethalOtis.MilkCollected"; private const string MSG_SELF_DESTRUCT = "LethalOtis.TriggerSelfDestruct"; private const string MSG_START_FLASHING = "LethalOtis.StartFlashing"; private const string MSG_EXPLODE = "LethalOtis.Explode"; private const string MSG_SHRINK_PLAYER = "LethalOtis.ShrinkPlayer"; private static int s_instanceCount; [Header("Roaming Settings")] public float detectionRadius = 15f; public float NormalSpeed = 3f; public float StalkSpeed = 5f; [Header("Self-Destruct Settings")] public float selfDestructDelay = 5f; public float explosionKillRadius = 4f; public float explosionDamageRadius = 8f; public int explosionNonLethalDamage = 50; public float otisExplosionForceMin = 0.1f; public float otisExplosionForceMax = 1f; public float otisTimeToDespawn = 8f; public Transform[] explodePieces; [Header("Stalking Settings")] private bool isChasing = false; private float timeSinceLastSeen = 0f; private Vector3 lastKnownPosition; public float giveUpTime = 3f; [Header("Wandering Settings")] public float WanderDistance = 20f; public float MaxWanderTime = 7.5f; private float WanderTimer = 0f; private Vector3 previousPosition; private bool isSelfDestructing = false; private OtisCurse curse; public NetworkVariable cursedBitmask = new NetworkVariable(0, (NetworkVariableReadPermission)0, (NetworkVariableWritePermission)0); public override void Start() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) base.agent = ((Component)this).GetComponent(); base.enemyType = Plugin.OtisEnemyType; ((EnemyAI)this).Start(); curse = ((Component)this).GetComponent(); if ((Object)(object)base.creatureAnimator == (Object)null) { base.creatureAnimator = ((Component)this).GetComponentInChildren(); if ((Object)(object)base.creatureAnimator != (Object)null) { Plugin.logger.LogInfo((object)"Successfully linked Animator!"); } else { Plugin.logger.LogWarning((object)"CRITICAL: No Animator component found!"); } } NavMeshHit val = default(NavMeshHit); if (((NetworkBehaviour)this).IsServer && NavMesh.SamplePosition(((Component)this).transform.position, ref val, 10f, -1)) { base.agent.Warp(((NavMeshHit)(ref val)).position); Plugin.logger.LogInfo((object)"Otis NavMesh position confirmed."); } } public override void OnNetworkSpawn() { ((NetworkBehaviour)this).OnNetworkSpawn(); s_instanceCount++; if (s_instanceCount == 1) { RegisterHandlers(); } } public override void OnNetworkDespawn() { s_instanceCount = Math.Max(0, s_instanceCount - 1); if (s_instanceCount == 0) { UnregisterHandlers(); } ((NetworkBehaviour)this).OnNetworkDespawn(); } public override void Update() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null)) { ((EnemyAI)this).Update(); if ((Object)(object)base.creatureAnimator != (Object)null) { float num = Vector3.Distance(((Component)this).transform.position, previousPosition) / Time.deltaTime; base.creatureAnimator.SetFloat("Speed", num); previousPosition = ((Component)this).transform.position; } } } public override void DoAIInterval() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) ((EnemyAI)this).DoAIInterval(); if (!((NetworkBehaviour)this).IsServer || (Object)(object)base.agent == (Object)null || !base.agent.isOnNavMesh || isSelfDestructing) { return; } Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 1.5f); Collider[] array2 = array; foreach (Collider val in array2) { DoorLock componentInParent = ((Component)val).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && !Traverse.Create((object)componentInParent).Field("isDoorOpened").GetValue() && !componentInParent.isLocked) { componentInParent.OpenDoorAsEnemyServerRpc(); } } PlayerControllerB val2 = null; float num = detectionRadius; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val3 in allPlayerScripts) { if (!val3.isPlayerDead && val3.isInsideFactory && (cursedBitmask.Value & (1 << (int)val3.playerClientId)) == 0) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)val3).transform.position); if (num2 < num) { num = num2; val2 = val3; } } } if ((Object)(object)val2 != (Object)null) { StalkPlayer(val2); } else { HandleWandering(); } } private void StalkPlayer(PlayerControllerB target) { //IL_0007: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (!Physics.Linecast(((Component)this).transform.position, ((Component)target).transform.position, StartOfRound.Instance.collidersAndRoomMask)) { isChasing = true; timeSinceLastSeen = 0f; lastKnownPosition = ((Component)target).transform.position; base.agent.speed = StalkSpeed; base.agent.SetDestination(lastKnownPosition); } else if (isChasing) { timeSinceLastSeen += base.AIIntervalTime; base.agent.SetDestination(lastKnownPosition); if (timeSinceLastSeen >= giveUpTime) { isChasing = false; timeSinceLastSeen = 0f; Plugin.logger.LogInfo((object)"Otis gave up chasing!"); HandleWandering(); } } else { HandleWandering(); } } private void HandleWandering() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_008b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)base.agent == (Object)null) && base.agent.isOnNavMesh) { WanderTimer += base.AIIntervalTime; if (MaxWanderTime <= WanderTimer || base.agent.remainingDistance <= base.agent.stoppingDistance) { Vector3 destination = RandomNavSphere(((Component)this).transform.position, WanderDistance, -1); base.agent.SetDestination(destination); base.agent.speed = NormalSpeed; WanderTimer = 0f; } } } public static Vector3 RandomNavSphere(Vector3 origin, float dist, int layermask) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_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) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) Vector3 val = Random.insideUnitSphere * dist; val += origin; NavMeshHit val2 = default(NavMeshHit); if (NavMesh.SamplePosition(val, ref val2, dist, layermask)) { return ((NavMeshHit)(ref val2)).position; } return origin; } private static void RegisterHandlers() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; customMessagingManager.RegisterNamedMessageHandler("LethalOtis.CursePlayer", new HandleNamedMessageDelegate(HandleCursePlayerMsg)); customMessagingManager.RegisterNamedMessageHandler("LethalOtis.MilkCollected", new HandleNamedMessageDelegate(HandleMilkCollectedMsg)); customMessagingManager.RegisterNamedMessageHandler("LethalOtis.TriggerSelfDestruct", new HandleNamedMessageDelegate(HandleTriggerSelfDestructMsg)); customMessagingManager.RegisterNamedMessageHandler("LethalOtis.StartFlashing", new HandleNamedMessageDelegate(HandleStartFlashingMsg)); customMessagingManager.RegisterNamedMessageHandler("LethalOtis.Explode", new HandleNamedMessageDelegate(HandleExplodeMsg)); customMessagingManager.RegisterNamedMessageHandler("LethalOtis.ShrinkPlayer", new HandleNamedMessageDelegate(HandleShrinkPlayerMsg)); Plugin.logger.LogInfo((object)"[OtisRoam] CustomMessagingManager handlers registered."); } private static void UnregisterHandlers() { NetworkManager singleton = NetworkManager.Singleton; CustomMessagingManager val = ((singleton != null) ? singleton.CustomMessagingManager : null); if (val != null) { val.UnregisterNamedMessageHandler("LethalOtis.CursePlayer"); val.UnregisterNamedMessageHandler("LethalOtis.MilkCollected"); val.UnregisterNamedMessageHandler("LethalOtis.TriggerSelfDestruct"); val.UnregisterNamedMessageHandler("LethalOtis.StartFlashing"); val.UnregisterNamedMessageHandler("LethalOtis.Explode"); val.UnregisterNamedMessageHandler("LethalOtis.ShrinkPlayer"); } } private static bool TryFindInstance(ulong networkObjectId, out OtisRoam otis) { otis = null; if (!NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var value)) { return false; } otis = ((Component)value).GetComponent(); return (Object)(object)otis != (Object)null; } private static void SendToAllClients(string messageName, FastBufferWriter writer) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != 0) { customMessagingManager.SendNamedMessage(messageName, connectedClientsId, writer, (NetworkDelivery)3); } } } public unsafe void CursePlayerSend(ulong playerId) { //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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref playerId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalOtis.CursePlayer", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleCursePlayerMsg(ulong senderClientId, FastBufferReader reader) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); ulong playerId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerId, default(ForPrimitives)); if (TryFindInstance(networkObjectId, out var otis)) { otis.ServerHandleCursePlayer(playerId); } } } private void ServerHandleCursePlayer(ulong playerId) { if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving) { return; } if ((Object)(object)curse == (Object)null) { curse = ((Component)this).GetComponent(); } if (!((Object)(object)curse == (Object)null)) { int num = 1 << (int)playerId; if ((cursedBitmask.Value & num) == 0) { NetworkVariable obj = cursedBitmask; obj.Value |= num; Plugin.logger.LogInfo((object)$"[OtisCurse] Server cursed player {playerId}. Bitmask={cursedBitmask.Value}"); BroadcastShrinkPlayer(playerId); } } } private unsafe void BroadcastShrinkPlayer(ulong playerId) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0045: 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) curse?.ApplyShrinkEffect(playerId); FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(16, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref playerId, default(ForPrimitives)); SendToAllClients("LethalOtis.ShrinkPlayer", writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleShrinkPlayerMsg(ulong senderClientId, FastBufferReader reader) { //IL_0007: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); ulong playerId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerId, default(ForPrimitives)); if (TryFindInstance(networkObjectId, out var otis)) { if ((Object)(object)otis.curse == (Object)null) { otis.curse = ((Component)otis).GetComponent(); } otis.curse?.ApplyShrinkEffect(playerId); } } public unsafe void MilkCollectedSend(Vector3 milkSpawnPosition, ulong thiefClientId, ulong bucketNetworkId) { //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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(40, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref milkSpawnPosition); ((FastBufferWriter)(ref val)).WriteValueSafe(ref thiefClientId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref bucketNetworkId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalOtis.MilkCollected", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleMilkCollectedMsg(ulong senderClientId, FastBufferReader reader) { //IL_001c: 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_003a: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); Vector3 milkSpawnPosition = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref milkSpawnPosition); ulong thiefClientId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref thiefClientId, default(ForPrimitives)); ulong bucketNetworkId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref bucketNetworkId, default(ForPrimitives)); if (TryFindInstance(networkObjectId, out var otis)) { otis.ServerHandleMilkCollected(milkSpawnPosition, thiefClientId, bucketNetworkId); } } } private void ServerHandleMilkCollected(Vector3 milkSpawnPosition, ulong thiefClientId, ulong bucketNetworkId) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(bucketNetworkId, out var value)) { value.Despawn(true); } Item fullBucketItemData = SetupMilkBucket.fullBucketItemData; if ((Object)(object)fullBucketItemData == (Object)null || (Object)(object)fullBucketItemData.spawnPrefab == (Object)null) { Plugin.logger.LogError((object)"MilkCollectedSend: fullBucketItemData is null — cannot spawn milk bottle."); } else { GameObject val = Object.Instantiate(fullBucketItemData.spawnPrefab, milkSpawnPosition, Quaternion.identity); NetworkObject component = val.GetComponent(); component.Spawn(false); GrabbableObject component2 = val.GetComponent(); if ((Object)(object)component2 != (Object)null) { int num = Random.Range(60, 101); component2.SetScrapValue(num); RoundManager.Instance.SyncScrapValuesClientRpc((NetworkObjectReference[])(object)new NetworkObjectReference[1] { NetworkObjectReference.op_Implicit(component) }, new int[1] { num }); } Plugin.logger.LogInfo((object)"Full milk bottle spawned!"); } BeginSelfDestruct(); } public unsafe void TriggerSelfDestructSend() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(8, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalOtis.TriggerSelfDestruct", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleTriggerSelfDestructMsg(ulong senderClientId, FastBufferReader reader) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer) { ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); if (TryFindInstance(networkObjectId, out var otis)) { otis.BeginSelfDestruct(); } } } private void BeginSelfDestruct() { if (!isSelfDestructing) { isSelfDestructing = true; if ((Object)(object)base.agent != (Object)null) { base.agent.speed = 0f; base.agent.isStopped = true; } Plugin.logger.LogInfo((object)"Otis self-destruct sequence started!"); BroadcastStartFlashing(); ((MonoBehaviour)this).StartCoroutine(SelfDestructCountdown()); } } private unsafe void BroadcastStartFlashing() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) ((MonoBehaviour)this).StartCoroutine(FlashRedRoutine()); FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(8, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); SendToAllClients("LethalOtis.StartFlashing", writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleStartFlashingMsg(ulong senderClientId, FastBufferReader reader) { //IL_0007: 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) ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); if (TryFindInstance(networkObjectId, out var otis)) { ((MonoBehaviour)otis).StartCoroutine(otis.FlashRedRoutine()); } } private unsafe void BroadcastExplode(Vector3 explosionPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_003d: Unknown result type (might be due to invalid IL or missing references) ApplyExplode(explosionPos); FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(20, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)this).NetworkObjectId; ((FastBufferWriter)(ref writer)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe(ref explosionPos); SendToAllClients("LethalOtis.Explode", writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private static void HandleExplodeMsg(ulong senderClientId, FastBufferReader reader) { //IL_0007: 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_001e: 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) ulong networkObjectId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref networkObjectId, default(ForPrimitives)); Vector3 val = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val); Landmine.SpawnExplosion(val, true, 0f, 0f, 0, 0f, (GameObject)null, false); if (TryFindInstance(networkObjectId, out var otis)) { otis.ApplyExplode(val); } } private IEnumerator SelfDestructCountdown() { yield return (object)new WaitForSeconds(selfDestructDelay); Vector3 pos = ((Component)this).transform.position; BroadcastExplode(pos); yield return (object)new WaitForSeconds(0.15f); Landmine.SpawnExplosion(pos, true, explosionKillRadius, explosionDamageRadius, explosionNonLethalDamage, 0f, (GameObject)null, false); Plugin.logger.LogInfo((object)"Otis exploded!"); base.isEnemyDead = true; ((Component)this).GetComponent().Despawn(true); } private IEnumerator FlashRedRoutine() { Renderer[] renderers = ((Component)this).GetComponentsInChildren(); Color[] originalColors = (Color[])(object)new Color[renderers.Length]; for (int i = 0; i < renderers.Length; i++) { originalColors[i] = renderers[i].material.color; } GameObject lightObj = new GameObject("SelfDestructWarningLight"); lightObj.transform.SetParent(((Component)this).transform); lightObj.transform.localPosition = Vector3.up * 0.5f; Light warningLight = lightObj.AddComponent(); warningLight.color = Color.red; warningLight.range = 12f; warningLight.intensity = 0f; float elapsed = 0f; bool isRed = false; for (; elapsed < selfDestructDelay; elapsed += 0.3f) { isRed = !isRed; for (int j = 0; j < renderers.Length; j++) { renderers[j].material.color = (isRed ? Color.red : originalColors[j]); } warningLight.intensity = (isRed ? 3f : 0f); yield return (object)new WaitForSeconds(0.3f); } Object.Destroy((Object)(object)lightObj); } private void ApplyExplode(Vector3 explosionPos) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (explodePieces == null || explodePieces.Length == 0) { Plugin.logger.LogWarning((object)"OtisRoam: explodePieces not assigned — skipping body piece launch."); return; } SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(); foreach (SkinnedMeshRenderer val in componentsInChildren) { ((Renderer)val).enabled = false; } Transform[] array = explodePieces; foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null)) { val2.SetParent((Transform)null, true); Rigidbody val3 = ((Component)val2).GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val2).gameObject.AddComponent(); } val3.isKinematic = false; Vector3 val4 = new Vector3(Random.Range(-1f, 1f), Random.Range(0.3f, 1f), Random.Range(-1f, 1f)); Vector3 normalized = ((Vector3)(ref val4)).normalized; val3.AddForce(normalized * Random.Range(otisExplosionForceMin, otisExplosionForceMax), (ForceMode)1); val3.AddTorque(Random.insideUnitSphere * 10f, (ForceMode)1); Object.Destroy((Object)(object)((Component)val2).gameObject, otisTimeToDespawn); } } } } namespace LethalOtisMod { [BepInPlugin("com.bazookaben.LethalOtis", "LethalOtis", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static class PluginInfo { public const string PLUGIN_GUID = "com.bazookaben.LethalOtis"; public const string PLUGIN_NAME = "LethalOtis"; public const string PLUGIN_VERSION = "1.2.1"; } public static ManualLogSource logger; private readonly Harmony harmony = new Harmony("com.BazookaB3n.LethalOtis"); public static AssetBundle ModAssets; public static EnemyType OtisEnemyType; private void Awake() { logger = ((BaseUnityPlugin)this).Logger; logger.LogInfo((object)"Plugin com.bazookaben.LethalOtis is loading..."); logger.LogInfo((object)"OTIS WAS HERE! BOOM BEACH TOO!"); string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "modassets"); ModAssets = AssetBundle.LoadFromFile(text); if ((Object)(object)ModAssets == (Object)null) { logger.LogError((object)"Failed to load Mod Assets!"); return; } harmony.PatchAll(); logger.LogInfo((object)"[Harmony] PatchAll() completed."); IEnumerable patchedMethods = harmony.GetPatchedMethods(); foreach (MethodBase item in patchedMethods) { logger.LogInfo((object)("[Harmony] Patched: " + item.DeclaringType?.Name + "." + item.Name)); } MethodInfo method = typeof(StartOfRound).GetMethod("ReviveDeadPlayers", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { logger.LogInfo((object)"[Harmony] ReviveDeadPlayers found in StartOfRound — patches should fire."); } else { logger.LogError((object)"[Harmony] ReviveDeadPlayers NOT found in StartOfRound! Patches will never fire. Method was likely renamed in this LC version."); } GameObject val = ModAssets.LoadAsset("Otis"); if ((Object)(object)val == (Object)null) { logger.LogError((object)"Failed to load the prefab 'Otis' from the bundle!"); return; } NetworkPrefabs.RegisterNetworkPrefab(val); OtisEnemyType = ScriptableObject.CreateInstance(); OtisEnemyType.enemyName = "Otis"; OtisEnemyType.enemyPrefab = val; OtisEnemyType.isDaytimeEnemy = false; OtisEnemyType.isOutsideEnemy = false; OtisEnemyType.canDie = true; OtisEnemyType.PowerLevel = 1f; OtisEnemyType.MaxCount = 2; Enemies.RegisterEnemy(OtisEnemyType, 30, (LevelTypes)(-1), (TerminalNode)null, (TerminalKeyword)null); logger.LogInfo((object)"Otis successfully registered as an enemy!"); Item val2 = ModAssets.LoadAsset("Assets/EmptyMilkItemData.asset"); Item val3 = ModAssets.LoadAsset("Assets/FullMilkItemData.asset"); TerminalNode val4 = ModAssets.LoadAsset("Assets/EmptyMilkBottleTerminal.asset"); SetupMilkBucket.SetupMilkBuckets(); } public static GameObject GetModAssetItem(string name) { return ModAssets.LoadAsset(name); } } [HarmonyPatch(typeof(StartOfRound), "EndGameClientRpc")] internal class CurseResetPatch { [HarmonyPostfix] private static void ResetAllCurses() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) Plugin.logger.LogInfo((object)"[CurseResetPatch] Postfix fired — EndGameClientRpc was called."); if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)SoundManager.Instance == (Object)null) { return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (((NetworkBehaviour)val).IsOwner) { val.movementSpeed = 4.6f; val.jumpForce = 13f; } ((Component)val).transform.localScale = Vector3.one; SoundManager.Instance.playerVoicePitchTargets[(uint)val.playerClientId] = 1f; SoundManager.Instance.SetPlayerPitch(1f, (int)val.playerClientId); } Plugin.logger.LogInfo((object)"The Otis effects have been cleared!"); } } } namespace LethalOtis { public class EmptyMilkBucketItem : PhysicsProp { public Item fullMilkItemData; [Header("Collection Settings")] public float collectionRange = 3f; public float aimForgiveness = 0.75f; private ScanNodeProperties _scanNode; private bool _lastHeld; public override void ItemActivate(bool used, bool buttonDown = true) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) ((GrabbableObject)this).ItemActivate(used, buttonDown); if (!buttonDown || (Object)(object)((GrabbableObject)this).playerHeldBy == (Object)null) { return; } Plugin.logger.LogInfo((object)"Empty Bucket Left-Click Activated!"); Ray val = default(Ray); ((Ray)(ref val))..ctor(((Component)((GrabbableObject)this).playerHeldBy.gameplayCamera).transform.position, ((Component)((GrabbableObject)this).playerHeldBy.gameplayCamera).transform.forward); RaycastHit[] array = Physics.SphereCastAll(val, aimForgiveness, collectionRange); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val2 = array2[i]; OtisRoam componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { Plugin.logger.LogInfo((object)"Successfully scooped the Milk!"); Vector3 milkSpawnPosition = ((Component)((GrabbableObject)this).playerHeldBy).transform.position + ((Component)((GrabbableObject)this).playerHeldBy).transform.forward * 0.5f + Vector3.up * 0.5f; ulong playerClientId = ((GrabbableObject)this).playerHeldBy.playerClientId; ulong networkObjectId = ((Component)this).GetComponent().NetworkObjectId; ((GrabbableObject)this).playerHeldBy.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true); componentInParent.MilkCollectedSend(milkSpawnPosition, playerClientId, networkObjectId); break; } } } public override void Start() { ((GrabbableObject)this).itemProperties = Object.Instantiate(((GrabbableObject)this).itemProperties); ((GrabbableObject)this).itemProperties.floorYOffset = 0; ((GrabbableObject)this).Start(); ((Component)this).gameObject.layer = 6; ((Component)this).gameObject.tag = "PhysicsProp"; ((GrabbableObject)this).propColliders = ((Component)this).GetComponents(); ((GrabbableObject)this).mainObjectRenderer = ((Component)this).GetComponentInChildren(); _scanNode = ((Component)this).GetComponentInChildren(); _lastHeld = false; AudioSource[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { val.spatialBlend = 1f; } } public override void Update() { ((GrabbableObject)this).Update(); if ((Object)(object)_scanNode != (Object)null && ((GrabbableObject)this).isHeld != _lastHeld) { _lastHeld = ((GrabbableObject)this).isHeld; ((Component)_scanNode).gameObject.SetActive(!((GrabbableObject)this).isHeld); } } } public class SetupMilkBucket { public static Item emptyBucketItemData; public static Item fullBucketItemData; public static void SetupMilkBuckets() { emptyBucketItemData = Plugin.ModAssets.LoadAsset("Assets/EmptyMilkItemData.asset"); fullBucketItemData = Plugin.ModAssets.LoadAsset("Assets/FullMilkItemData.asset"); if ((Object)(object)emptyBucketItemData == (Object)null) { Plugin.logger.LogError((object)"Could not load Item assets from bundle! \nCheck file names."); return; } if ((Object)(object)fullBucketItemData == (Object)null) { Plugin.logger.LogError((object)"Could not load Item assets from bundle! \nCheck file names!"); return; } GameObject spawnPrefab = emptyBucketItemData.spawnPrefab; GameObject spawnPrefab2 = fullBucketItemData.spawnPrefab; if ((Object)(object)spawnPrefab == (Object)null) { Plugin.logger.LogError((object)"CRASH PREVENTED: Empty Milk Bucket Prefab is NULL!"); return; } if ((Object)(object)spawnPrefab2 == (Object)null) { Plugin.logger.LogError((object)"CRASH PREVENTED: Full Milk Bucket Prefab is NULL!"); return; } EmptyMilkBucketItem component = spawnPrefab.GetComponent(); if ((Object)(object)component != (Object)null) { component.fullMilkItemData = fullBucketItemData; } TerminalNode val = ScriptableObject.CreateInstance(); ((Object)val).name = "Empty Milk Bucket"; val.displayText = "Allows you to milk Otis.\n\n"; val.clearPreviousText = true; val.maxCharactersToType = 15; NetworkPrefabs.RegisterNetworkPrefab(spawnPrefab); NetworkPrefabs.RegisterNetworkPrefab(spawnPrefab2); ScanNodeProperties componentInChildren = spawnPrefab.GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.subText = "Store item"; } ScanNodeProperties componentInChildren2 = spawnPrefab2.GetComponentInChildren(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.subText = "Full Milk Bottle"; } Plugin.logger.LogInfo((object)("[CHECK] Empty Milk Bucket Name: " + emptyBucketItemData.itemName)); Plugin.logger.LogInfo((object)("[CHECK] Full Milk Bucket Name: " + fullBucketItemData.itemName)); Items.RegisterShopItem(emptyBucketItemData, (TerminalNode)null, (TerminalNode)null, val, 10); Items.RegisterItem(fullBucketItemData); Utilities.FixMixerGroups(spawnPrefab); Utilities.FixMixerGroups(spawnPrefab2); Plugin.logger.LogInfo((object)"Milk Buckets successfully loaded and registered!"); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }