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 Desfibrilator v1.0.0
BepInEx/plugins/Desfibrilator/Desfibrilator.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; using BepInEx; using BepInEx.Configuration; using Desfibrilator.Core; using Dissonance; using Dissonance.Audio.Capture; using GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using NAudio.Wave; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Audio; using UnityEngine.InputSystem; 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("Desfibrilator")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d34b1e8655b95f46dddd55b5047a7305cee42f6b")] [assembly: AssemblyProduct("Desfibrilator")] [assembly: AssemblyTitle("Desfibrilator")] [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.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 Desfibrilator { [HarmonyPatch(typeof(PlayerControllerB), "Update")] internal static class ConvulsionInputPatch { internal static bool Installed; private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = -1; FieldInfo objB = AccessTools.Field(typeof(PlayerControllerB), "moveInputVector"); for (int i = 0; i + 1 < list.Count; i++) { if ((list[i].opcode == OpCodes.Call || list[i].opcode == OpCodes.Callvirt) && list[i].operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(InputAction) && methodInfo.Name == "ReadValue" && methodInfo.ReturnType == typeof(Vector2) && list[i + 1].opcode == OpCodes.Stfld && object.Equals(list[i + 1].operand, objB)) { if (num >= 0) { num = -1; break; } num = i; } } Installed = num >= 0; if (Installed) { list.InsertRange(num + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ConvulsionInputPatch), "Filter", (Type[])null, (Type[])null)) }); Plugin.Log("Ciriolator convulsion input hook installed."); } else { Plugin.Error("Ciriolator convulsion input hook unavailable: native Move read changed. Involuntary walking disabled; other effects remain enabled."); } return list; } private static Vector2 Filter(Vector2 input, PlayerControllerB player) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) if (!((Object)(object)RevivalSideEffects.Instance != (Object)null)) { return input; } return RevivalSideEffects.Instance.FilterMovement(input, player); } } public sealed class DefibrillatorItem : GrabbableObject { public Transform Visual; public Transform LeftPaddle; public Transform RightPaddle; public AudioSource Sound; private bool charging; private double nextPulse; private ulong? requestedBody; public override void Update() { ((GrabbableObject)this).Update(); ReviveNetwork instance = ReviveNetwork.Instance; if ((Object)(object)instance == (Object)null || !((NetworkBehaviour)this).IsSpawned) { return; } PlayerControllerB playerHeldBy = base.playerHeldBy; int num; object obj; if ((Object)(object)playerHeldBy != (Object)null && ((NetworkBehaviour)playerHeldBy).IsOwner && Interaction.HasActiveTool(playerHeldBy)) { num = (((Object)(object)playerHeldBy.currentlyHeldObjectServer == (Object)(object)this) ? 1 : 0); if (num != 0) { obj = Interaction.FindAimedBody(playerHeldBy); goto IL_0059; } } else { num = 0; } obj = null; goto IL_0059; IL_0059: DeadBodyInfo val = (DeadBodyInfo)obj; if (num != 0 && (Object)(object)val != (Object)null && Interaction.IsRecoverable(val) && Interaction.RoundActive && !playerHeldBy.isTypingChat && !playerHeldBy.inTerminalMenu && !playerHeldBy.inSpecialInteractAnimation && Plugin.Use.IsPressed() && instance.Cooldown <= 0.0) { ulong networkObjectId = ((NetworkBehaviour)val.grabBodyObject).NetworkObjectId; if (requestedBody != networkObjectId) { CancelRequest(); requestedBody = networkObjectId; nextPulse = 0.0; } if (Time.realtimeSinceStartupAsDouble >= nextPulse) { instance.Request(1, ((NetworkBehaviour)this).NetworkObjectId, networkObjectId); nextPulse = Time.realtimeSinceStartupAsDouble + 0.1; } } else { CancelRequest(); } bool flag = instance.ActiveTool == ((NetworkBehaviour)this).NetworkObjectId; if (flag && !charging) { Sound.clip = ItemFactory.Charge; Sound.loop = false; Sound.Play(); } if (!flag && charging) { Sound.Stop(); } charging = flag; } public override void LateUpdate() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) ((GrabbableObject)this).LateUpdate(); float num = (((Object)(object)ReviveNetwork.Instance != (Object)null && ReviveNetwork.Instance.ActiveTool == ((NetworkBehaviour)this).NetworkObjectId) ? Mathf.Clamp01((float)(5.0 - ReviveNetwork.Instance.ChargeRemaining) / 0.6f) : 0f); LeftPaddle.localPosition = Vector3.Lerp(new Vector3(-0.21f, 0f, 0f), new Vector3(-0.13f, 0.04f, 0.2f), num); RightPaddle.localPosition = Vector3.Lerp(new Vector3(0.21f, 0f, 0f), new Vector3(0.13f, 0.04f, 0.2f), num); Visual.localRotation = Quaternion.Euler(num * 20f, 0f, 0f); } internal void PlayDischarge() { charging = false; Sound.Stop(); Sound.PlayOneShot(ItemFactory.Discharge); } private void CancelRequest() { if (requestedBody.HasValue) { ReviveNetwork.Instance?.Request(2, ((NetworkBehaviour)this).NetworkObjectId, requestedBody.Value); requestedBody = null; } } public override void PocketItem() { CancelRequest(); ((GrabbableObject)this).PocketItem(); } public override void DiscardItem() { CancelRequest(); ((GrabbableObject)this).DiscardItem(); } private void OnDisable() { CancelRequest(); if ((Object)(object)Sound != (Object)null) { Sound.Stop(); } charging = false; } private void OnGUI() { //IL_013a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)base.playerHeldBy == (Object)null || !((NetworkBehaviour)base.playerHeldBy).IsOwner || !Interaction.HasActiveTool(base.playerHeldBy) || (Object)(object)base.playerHeldBy.currentlyHeldObjectServer != (Object)(object)this) { return; } ReviveNetwork instance = ReviveNetwork.Instance; if (!((Object)(object)instance == (Object)null)) { string text; if (!instance.Connected) { text = "Ciriolator: conectando con el anfitrión…"; } else if (!(instance.Cooldown > 0.0)) { text = ((instance.ActiveTool == ((NetworkBehaviour)this).NetworkObjectId) ? $"Desfibrilando… {Mathf.Clamp01((float)(5.0 - instance.ChargeRemaining) / 5f) * 100f:0}%" : ((!instance.ActiveTool.HasValue) ? "Ciriolator listo · Mantén E sobre un cadáver recuperable (5 s)" : "Ciriolator ocupado: reanimación en curso")); } else { int num = Mathf.CeilToInt((float)instance.Cooldown); text = $"Ciriolator no disponible: {num / 60:00}:{num % 60:00}"; } GUI.Box(new Rect((float)Screen.width / 2f - 260f, (float)Screen.height * 0.78f, 520f, 40f), text); } } } internal static class Interaction { internal const float Range = 2.5f; internal static bool RoundActive { get { if ((Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase) { return !StartOfRound.Instance.firingPlayersCutsceneRunning; } return false; } } internal static bool HasActiveTool(PlayerControllerB? player) { if ((Object)(object)player != (Object)null && !player.isPlayerDead && player.currentlyHeldObjectServer is DefibrillatorItem { isHeld: not false, isPocketed: false } defibrillatorItem) { return (Object)(object)((GrabbableObject)defibrillatorItem).playerHeldBy == (Object)(object)player; } return false; } internal static DeadBodyInfo? FindAimedBody(PlayerControllerB player) { //IL_001b: 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_0030: 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) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player.gameplayCamera == (Object)null) { return null; } foreach (RaycastHit item in from h in Physics.RaycastAll(new Ray(((Component)player.gameplayCamera).transform.position, ((Component)player.gameplayCamera).transform.forward), 2.5f, -1, (QueryTriggerInteraction)2) orderby ((RaycastHit)(ref h)).distance select h) { RaycastHit current = item; if (((Component)((RaycastHit)(ref current)).collider).transform.IsChildOf(((Component)player).transform)) { continue; } DefibrillatorItem componentInParent = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<DefibrillatorItem>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)((GrabbableObject)componentInParent).playerHeldBy == (Object)(object)player) { continue; } DeadBodyInfo val = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<DeadBodyInfo>(); if ((Object)(object)val == (Object)null) { RagdollGrabbableObject componentInParent2 = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<RagdollGrabbableObject>(); if ((Object)(object)componentInParent2 != (Object)null) { val = componentInParent2.ragdoll; } } if ((Object)(object)val != (Object)null) { return val; } if (!((RaycastHit)(ref current)).collider.isTrigger) { return null; } } return null; } internal static Vector3 BodyPosition(DeadBodyInfo body) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (body.bodyParts == null || body.bodyParts.Length == 0 || !((Object)(object)body.bodyParts[0] != (Object)null)) { return ((Component)body).transform.position; } return body.bodyParts[0].position; } internal static bool IsRecoverable(DeadBodyInfo? body) { if ((Object)(object)body == (Object)null || !((Component)body).gameObject.activeInHierarchy || body.deactivated || body.detachedHead || (Object)(object)body.attachedTo != (Object)null || (Object)(object)body.secondaryAttachedTo != (Object)null) { return false; } PlayerControllerB playerScript = body.playerScript; GrabbableObject grabBodyObject = body.grabBodyObject; if ((Object)(object)playerScript != (Object)null && playerScript.isPlayerDead && (Object)(object)playerScript.deadBody == (Object)(object)body && (Object)(object)grabBodyObject != (Object)null && ((NetworkBehaviour)grabBodyObject).IsSpawned && grabBodyObject.grabbable && !grabBodyObject.isHeld && !grabBodyObject.isHeldByEnemy && body.bodyParts != null && body.bodyParts.Length != 0 && body.bodyParts.All((Rigidbody p) => (Object)(object)p != (Object)null && ((Component)p).gameObject.activeInHierarchy) && playerScript.ItemSlots != null && playerScript.ItemSlots.All((GrabbableObject i) => (Object)(object)i == (Object)null)) { return (Object)(object)playerScript.ItemOnlySlot == (Object)null; } return false; } } internal static class ItemFactory { internal const int ShopPrice = 50; internal static AudioClip Charge; internal static AudioClip Discharge; internal static void Register() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) Charge = MakeSound("DesfibrilatorCharge", 5f, discharge: false); Discharge = MakeSound("DesfibrilatorDischarge", 0.28f, discharge: true); GameObject val = NetworkPrefabs.CreateNetworkPrefab("DesfibrilatorPrefab"); val.tag = "PhysicsProp"; val.layer = 6; BoxCollider val2 = val.AddComponent<BoxCollider>(); val2.size = new Vector3(0.34f, 0.22f, 0.25f); Item val3 = ScriptableObject.CreateInstance<Item>(); ((Object)val3).name = "DesfibrilatorItem"; val3.itemName = "Ciriolator"; val3.itemId = 198481; val3.creditsWorth = 50; val3.weight = 1.15f; val3.isScrap = false; val3.requiresBattery = false; val3.canBeGrabbedBeforeGameStart = true; val3.canBeInspected = true; val3.twoHanded = false; val3.twoHandedAnimation = true; val3.isConductiveMetal = true; val3.spawnPositionTypes = new List<ItemGroup>(); val3.toolTips = new string[1] { "Desfibrilar: mantener E durante 5 s" }; val3.grabAnim = "HoldClipboard"; val3.pocketAnim = ""; val3.useAnim = ""; val3.throwAnim = ""; val3.grabAnimationTime = 0.3f; val3.rotationOffset = new Vector3(0f, 0f, 0f); val3.positionOffset = new Vector3(0.08f, 0.02f, -0.12f); val3.restingRotation = Vector3.zero; val3.verticalOffset = 0.12f; val3.highestSalePercentage = 0; val3.itemIcon = MakeIcon(); val3.spawnPrefab = val; DefibrillatorItem defibrillatorItem = val.AddComponent<DefibrillatorItem>(); ((GrabbableObject)defibrillatorItem).itemProperties = val3; ((GrabbableObject)defibrillatorItem).grabbable = true; ((GrabbableObject)defibrillatorItem).grabbableToEnemies = false; ((GrabbableObject)defibrillatorItem).propColliders = (Collider[])(object)new Collider[1] { (Collider)val2 }; defibrillatorItem.Visual = new GameObject("DesfibrilatorModel").transform; defibrillatorItem.Visual.SetParent(val.transform, false); Color color = default(Color); ((Color)(ref color))..ctor(0.9f, 0.34f, 0.04f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.07f, 0.08f, 0.08f); Color val5 = default(Color); ((Color)(ref val5))..ctor(0.78f, 0.76f, 0.64f); ((GrabbableObject)defibrillatorItem).mainObjectRenderer = Part(defibrillatorItem.Visual, "Carcasa", Vector3.zero, new Vector3(0.34f, 0.2f, 0.24f), color); Part(defibrillatorItem.Visual, "Panel", new Vector3(0f, 0.105f, 0f), new Vector3(0.29f, 0.015f, 0.2f), val5); Part(defibrillatorItem.Visual, "Pantalla", new Vector3(-0.055f, 0.12f, 0f), new Vector3(0.12f, 0.015f, 0.09f), val4); Part(defibrillatorItem.Visual, "Indicador", new Vector3(-0.055f, 0.13f, 0f), new Vector3(0.085f, 0.006f, 0.009f), Color.green); Part(defibrillatorItem.Visual, "CruzHorizontal", new Vector3(0.08f, 0.12f, 0f), new Vector3(0.065f, 0.012f, 0.02f), Color.red); Part(defibrillatorItem.Visual, "CruzVertical", new Vector3(0.08f, 0.12f, 0f), new Vector3(0.02f, 0.012f, 0.065f), Color.red); Part(defibrillatorItem.Visual, "Asa", new Vector3(0f, 0.04f, -0.155f), new Vector3(0.18f, 0.04f, 0.03f), val4); defibrillatorItem.LeftPaddle = Paddle(defibrillatorItem.Visual, "PalaIzquierda", new Vector3(-0.21f, 0f, 0f), val5, val4); defibrillatorItem.RightPaddle = Paddle(defibrillatorItem.Visual, "PalaDerecha", new Vector3(0.21f, 0f, 0f), val5, val4); Cable(defibrillatorItem.Visual, -0.17f, -0.21f, val4); Cable(defibrillatorItem.Visual, 0.17f, 0.21f, val4); AudioSource val6 = val.AddComponent<AudioSource>(); val6.spatialBlend = 1f; val6.minDistance = 1f; val6.maxDistance = 15f; val6.rolloffMode = (AudioRolloffMode)1; val6.playOnAwake = false; defibrillatorItem.Sound = val6; Utilities.FixMixerGroups(val); Items.RegisterShopItem(val3, 50); } private static Transform Paddle(Transform parent, string name, Vector3 position, Color pale, Color dark) { //IL_0001: 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_0020: 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) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //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) Transform transform = new GameObject(name).transform; transform.SetParent(parent, false); transform.localPosition = position; Part(transform, "Electrodo", Vector3.zero, new Vector3(0.065f, 0.018f, 0.1f), pale); Part(transform, "Empunadura", new Vector3(0f, 0.035f, 0f), new Vector3(0.035f, 0.05f, 0.07f), dark); return transform; } private static void Cable(Transform root, float from, float to, Color color) { //IL_0019: 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_0053: 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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) Part(root, "Cable", new Vector3((from + to) / 2f, -0.025f, -0.07f), new Vector3(Math.Abs(to - from) + 0.01f, 0.012f, 0.012f), color); Part(root, "CableRetorno", new Vector3(to, -0.01f, -0.04f), new Vector3(0.012f, 0.012f, 0.07f), color); } private static MeshRenderer Part(Transform parent, string name, Vector3 position, Vector3 scale, Color color) { //IL_0027: 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_004a: 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) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = name; obj.layer = 6; obj.transform.SetParent(parent, false); obj.transform.localPosition = position; obj.transform.localScale = scale; Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>()); obj.AddComponent<PartTint>().Tint = color; return obj.GetComponent<MeshRenderer>(); } private static Sprite MakeIcon() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { Color val2 = Color.clear; if (j >= 8 && j < 56 && i >= 12 && i < 50) { ((Color)(ref val2))..ctor(0.95f, 0.4f, 0.05f); } if (j >= 14 && j < 32 && i >= 24 && i < 40) { ((Color)(ref val2))..ctor(0.1f, 0.2f, 0.15f); } if ((j >= 39 && j < 44 && i >= 25 && i < 42) || (j >= 34 && j < 49 && i >= 31 && i < 36)) { val2 = Color.white; } array[i * 64 + j] = val2; } } val.SetPixels(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f); } private static AudioClip MakeSound(string name, float seconds, bool discharge) { float[] array = new float[(int)(seconds * 22050f)]; Random random = new Random(81); double num = 0.0; for (int i = 0; i < array.Length; i++) { double num2 = (double)i / 22050.0; double num3 = num2 / (double)seconds; num += Math.PI * 2.0 * (discharge ? 110.0 : (180.0 + 1100.0 * num3)) / 22050.0; double num4 = (discharge ? Math.Exp((0.0 - num3) * 8.0) : (Math.Min(1.0, num2 * 12.0) * Math.Min(1.0, ((double)seconds - num2) * 15.0))); array[i] = (float)(num4 * (discharge ? ((random.NextDouble() * 2.0 - 1.0) * 0.55 + Math.Sin(num) * 0.15) : (Math.Sin(num) * 0.16))); } AudioClip obj = AudioClip.Create(name, array.Length, 1, 22050, false); obj.SetData(array, 0); return obj; } } public sealed class PartTint : MonoBehaviour { public Color Tint; private Material? material; private void Start() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) MeshRenderer component = ((Component)this).GetComponent<MeshRenderer>(); Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard") ?? ((Renderer)component).sharedMaterial.shader; material = new Material(val); if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", Tint); } if (material.HasProperty("_Color")) { material.SetColor("_Color", Tint); } ((Renderer)component).sharedMaterial = material; } private void OnDestroy() { if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } } } internal sealed class LastWordsCapture : IMicrophoneSubscriber, IDisposable { private readonly object gate = new object(); private readonly LastWordsBuffer buffer = new LastWordsBuffer(); private DissonanceComms? comms; private volatile bool allowed; private volatile bool transmitting; private double phase; private int previousRate; private bool previouslyTransmitting; private VoiceBroadcastTrigger[] triggers = Array.Empty<VoiceBroadcastTrigger>(); private double refreshTriggersAt; private volatile bool failed; private string? captureError; internal short[] Frozen { get; private set; } = Array.Empty<short>(); internal void Update(bool enabled, bool aliveInMission, bool replaying) { if (!enabled) { Dispose(); return; } string text = Interlocked.Exchange(ref captureError, null); if (text != null) { Plugin.Error("Ciriolator voice capture disabled for this expedition; live voice was left untouched: " + text); Unsubscribe(); } if (failed) { return; } if ((Object)(object)comms == (Object)null) { comms = Object.FindObjectOfType<DissonanceComms>(); if ((Object)(object)comms != (Object)null) { comms.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)this); Plugin.Log("Ciriolator: local last-words capture enabled (memory only)."); } } allowed = aliveInMission && !replaying; if (Time.realtimeSinceStartupAsDouble >= refreshTriggersAt) { triggers = Object.FindObjectsOfType<VoiceBroadcastTrigger>(); refreshTriggersAt = Time.realtimeSinceStartupAsDouble + 2.0; } bool flag = (Object)(object)comms != (Object)null && (((Channels<RoomChannel, string>)(object)comms.RoomChannels).Count > 0 || ((Channels<PlayerChannel, string>)(object)comms.PlayerChannels).Count > 0); bool flag2 = ((triggers.Length == 0) ? flag : triggers.Any((VoiceBroadcastTrigger t) => (Object)(object)t != (Object)null && ((Behaviour)t).isActiveAndEnabled && !t.IsMuted && t.IsTransmitting)); transmitting = allowed && (Object)(object)comms != (Object)null && !comms.IsMuted && flag && flag2; if (previouslyTransmitting && !transmitting) { lock (gate) { buffer.EndPhrase(); } } previouslyTransmitting = transmitting; } internal void FreezeAtDeath() { allowed = (transmitting = false); lock (gate) { Array.Clear(Frozen, 0, Frozen.Length); Frozen = buffer.Snapshot(); buffer.Clear(); } Plugin.Log($"Ciriolator last words frozen: {Frozen.Length} samples ({(double)Frozen.Length / 8000.0:0.00}s)."); } public void ReceiveMicrophoneData(ArraySegment<float> input, WaveFormat format) { try { Receive(input, format); } catch (Exception ex) { failed = true; allowed = (transmitting = false); Interlocked.CompareExchange(ref captureError, ex.ToString(), null); } } private void Receive(ArraySegment<float> input, WaveFormat format) { if (!allowed || input.Array == null || format.Channels <= 0 || format.Channels > 8 || format.SampleRate < 8000 || format.SampleRate > 192000) { return; } lock (gate) { if (!allowed) { return; } if (previousRate != format.SampleRate) { phase = 0.0; previousRate = format.SampleRate; } int num = input.Count / format.Channels; if (num <= 0 || num > format.SampleRate) { return; } short[] array = new short[(int)Math.Ceiling((double)num * 8000.0 / (double)format.SampleRate) + 1]; double num2 = 0.0; int num3 = 0; bool flag = transmitting; for (int i = 0; i < num; i++) { float num4 = 0f; if (flag) { for (int j = 0; j < format.Channels; j++) { num4 += input.Array[input.Offset + i * format.Channels + j]; } num4 /= (float)format.Channels; if (float.IsNaN(num4) || float.IsInfinity(num4)) { num4 = 0f; } num4 = Math.Max(-1f, Math.Min(1f, num4)); } num2 += (double)(num4 * num4); phase += 8000.0; if (phase >= (double)format.SampleRate) { phase -= format.SampleRate; array[num3++] = (short)(num4 * 32767f); } } buffer.Append(array, num3, flag && Math.Sqrt(num2 / (double)num) >= 0.008); } } public void Reset() { try { lock (gate) { buffer.EndPhrase(); phase = 0.0; previousRate = 0; } } catch (Exception ex) { failed = true; allowed = (transmitting = false); Interlocked.CompareExchange(ref captureError, ex.ToString(), null); } } internal void ClearRound() { allowed = (transmitting = false); lock (gate) { buffer.Clear(); Array.Clear(Frozen, 0, Frozen.Length); Frozen = Array.Empty<short>(); phase = 0.0; } previouslyTransmitting = false; failed = false; } private void Unsubscribe() { allowed = (transmitting = false); if ((Object)(object)comms != (Object)null) { comms.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)this); comms = null; } triggers = Array.Empty<VoiceBroadcastTrigger>(); refreshTriggersAt = 0.0; } public void Dispose() { Unsubscribe(); ClearRound(); } } [BepInPlugin("ciriolopipado.desfibrilator", "Ciriolator", "1.0.0")] [BepInDependency("evaisa.lethallib", "1.2.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "ciriolopipado.desfibrilator"; internal static Plugin Instance; internal static InputAction Use; private Harmony? harmony; private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown Instance = this; ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Controls", "Defibrillate", "<Keyboard>/e", "Input System binding path. Restart the game after changing it."); Use = new InputAction("Ciriolator", (InputActionType)1, val.Value, (string)null, (string)null, (string)null); Use.Enable(); ItemFactory.Register(); ((Component)this).gameObject.AddComponent<ReviveNetwork>(); ((Component)this).gameObject.AddComponent<RevivalSideEffects>(); harmony = new Harmony("ciriolopipado.desfibrilator"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Ciriolator 1.0.0 loaded. Target: Lethal Company v81. All peers need the mod."); } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } InputAction use = Use; if (use != null) { use.Dispose(); } } internal static void Error(object message) { ((BaseUnityPlugin)Instance).Logger.LogError(message); } internal static void Log(object message) { ((BaseUnityPlugin)Instance).Logger.LogInfo(message); } } [HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")] internal static class CorpseInteractionPatch { private static bool Prefix(PlayerControllerB __instance) { if (Interaction.HasActiveTool(__instance)) { return (Object)(object)Interaction.FindAimedBody(__instance) == (Object)null; } return true; } } [HarmonyPatch(typeof(PlayerControllerB), "SetHoverTipAndCurrentInteractTrigger")] internal static class CorpseTooltipPatch { private static void Postfix(PlayerControllerB __instance) { if (!((NetworkBehaviour)__instance).IsOwner || !Interaction.HasActiveTool(__instance)) { return; } DeadBodyInfo val = Interaction.FindAimedBody(__instance); if (!((Object)(object)val == (Object)null)) { object value = AccessTools.Field(typeof(PlayerControllerB), "cursorTip").GetValue(__instance); if (value != null) { string value2 = (Interaction.IsRecoverable(val) ? "Desfibrilar: mantener la tecla configurada (E por defecto)" : "Cadáver no recuperable"); AccessTools.Property(value.GetType(), "text").SetValue(value, value2); } } } } internal static class Revival { internal static bool TryFindPosition(DeadBodyInfo body, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_001b: 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) //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_0047: 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_005d: 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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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) //IL_008d: 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) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: 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_0139: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Interaction.BodyPosition(body); Vector3[] obj = new Vector3[5] { Vector3.zero, Vector3.right * 0.6f, Vector3.left * 0.6f, Vector3.forward * 0.6f, Vector3.back * 0.6f }; int collidersAndRoomMask = StartOfRound.Instance.collidersAndRoomMask; Vector3[] array = (Vector3[])(object)obj; RaycastHit val3 = default(RaycastHit); foreach (Vector3 val2 in array) { if (Physics.Raycast(val + val2 + Vector3.up * 0.7f, Vector3.down, ref val3, 2.5f, collidersAndRoomMask, (QueryTriggerInteraction)1)) { Vector3 val4 = ((RaycastHit)(ref val3)).point + Vector3.up * 0.08f; if (!Physics.CheckCapsule(val4 + Vector3.up * 0.35f, val4 + Vector3.up * 1.5f, 0.28f, collidersAndRoomMask, (QueryTriggerInteraction)1) && !Physics.Linecast(val + Vector3.up * 0.25f, val4 + Vector3.up * 0.5f, collidersAndRoomMask, (QueryTriggerInteraction)1)) { position = val4; return true; } } } position = default(Vector3); return false; } internal static void Apply(PlayerControllerB player, Vector3 position, bool inside, bool ship) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!player.isPlayerDead) { return; } StartOfRound round = StartOfRound.Instance; DeadBodyInfo deadBody = player.deadBody; player.TeleportPlayer(position, false, 0f, false, true); player.isPlayerDead = false; ((Behaviour)player).enabled = true; player.isPlayerControlled = true; player.health = 30; player.criticallyInjured = false; player.hasBeenCriticallyInjured = false; player.bleedingHeavily = false; player.isClimbingLadder = false; player.inSpecialInteractAnimation = false; player.disableSyncInAnimation = false; player.inVehicleAnimation = false; player.freeRotationInInteractAnimation = false; player.clampLooking = false; player.inShockingMinigame = false; player.currentTriggerInAnimationWith = null; player.inAnimationWithEnemy = null; player.activatingItem = false; player.disableLookInput = false; player.disableMoveInput = false; player.disableInteract = false; player.isSinking = false; player.sinkingValue = 0f; player.sourcesCausingSinking = 0; player.isMovementHindered = 0; player.hinderedMultiplier = 1f; player.isUnderwater = false; SetInternal(player, "isFaceUnderwaterOnServer", value: false); SetInternal(player, "wasUnderwaterLastFrame", value: false); player.isExhausted = false; player.sprintMeter = 1f; player.setPositionOfDeadPlayer = false; player.isInsideFactory = inside; player.isInHangarShipRoom = ship; player.isInElevator = ship; player.parentedToElevatorLastFrame = false; player.isInGameOverAnimation = 0f; player.overrideGameOverSpectatePivot = null; player.holdingWalkieTalkie = (player.speakingToWalkieTalkie = false); player.voiceMuffledByEnemy = false; player.isHoldingObject = false; player.twoHanded = (player.twoHandedAnimation = false); player.currentlyHeldObjectServer = null; player.carryWeight = 1f; ((Collider)player.thisController).enabled = true; if ((Object)(object)player.movementAudio != (Object)null) { ((Behaviour)player.movementAudio).enabled = true; } player.deadBody = null; if ((Object)(object)deadBody != (Object)null) { ((Component)deadBody).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)deadBody).gameObject); } round.livingPlayers = round.allPlayerScripts.Count((PlayerControllerB p) => (Object)(object)p != (Object)null && p.isPlayerControlled && !p.isPlayerDead); round.allPlayersDead = round.livingPlayers == 0; Present(delegate { AccessTools.Method(typeof(PlayerControllerB), "ResetFallGravity", (Type[])null, (Type[])null).Invoke(player, Array.Empty<object>()); player.ResetZAndXRotation(); player.DisableJetpackControlsLocally(); player.Crouch(false); player.ResetPlayerBloodObjects(true); }); Present(delegate { RestoreAnimator(player, round); player.DisablePlayerModel(((Component)player).gameObject, true, true); SkinnedMeshRenderer[] array = (SkinnedMeshRenderer[])(object)new SkinnedMeshRenderer[3] { player.thisPlayerModel, player.thisPlayerModelLOD1, player.thisPlayerModelLOD2 }; foreach (SkinnedMeshRenderer val in array) { if ((Object)(object)val != (Object)null) { ((Renderer)val).enabled = true; ((Renderer)val).shadowCastingMode = (ShadowCastingMode)((!((NetworkBehaviour)player).IsOwner) ? 1 : 3); } } }); if (((NetworkBehaviour)player).IsOwner) { Present(delegate { SetInternal(player, "hasBegunSpectating", value: false); player.spectatedPlayerScript = null; SetInternal(player, "isCameraDisabled", value: true); ((Behaviour)player.gameplayCamera).enabled = true; ((Renderer)player.thisPlayerModelArms).enabled = true; AccessTools.Method(typeof(PlayerControllerB), "ChangeAudioListenerToObject", (Type[])null, (Type[])null).Invoke(player, new object[1] { ((Component)player.gameplayCamera).gameObject }); round.SetSpectateCameraToGameOverMode(false, player); round.SwitchCamera(player.gameplayCamera); HUDManager.Instance.HideHUD(false); HUDManager.Instance.RemoveSpectateUI(); if ((Object)(object)HUDManager.Instance.audioListenerLowPass != (Object)null) { ((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false; } HUDManager.Instance.UpdateHealthUI(30, false); HUDManager.Instance.gameOverAnimator.SetTrigger("revive"); player.statusEffectAudio.Stop(); if ((Object)(object)SoundManager.Instance != (Object)null) { SoundManager.Instance.SetDiageticMixerSnapshot(0, 0.1f); } }); } Present(delegate { RepairVoice(player); }); ((MonoBehaviour)Plugin.Instance).StartCoroutine(DeferredVoiceRepair(player)); Plugin.Log($"Ciriolator revive applied: client={player.actualClientId}, owner={((NetworkBehaviour)player).IsOwner}, alive={!player.isPlayerDead}, controlled={player.isPlayerControlled}."); } private static void RestoreAnimator(PlayerControllerB player, StartOfRound round) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Invalid comparison between Unknown and I4 //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Invalid comparison between Unknown and I4 Animator playerBodyAnimator = player.playerBodyAnimator; RuntimeAnimatorController runtimeAnimatorController = (((NetworkBehaviour)player).IsOwner ? round.localClientAnimatorController : round.otherClientsAnimatorController); if ((Object)(object)playerBodyAnimator.runtimeAnimatorController == (Object)null || (Object)(object)playerBodyAnimator.runtimeAnimatorController == (Object)(object)round.localClientAnimatorController || (Object)(object)playerBodyAnimator.runtimeAnimatorController == (Object)(object)round.otherClientsAnimatorController) { playerBodyAnimator.runtimeAnimatorController = runtimeAnimatorController; } ((Behaviour)playerBodyAnimator).enabled = true; playerBodyAnimator.speed = 1f; if (((NetworkBehaviour)player).IsOwner) { playerBodyAnimator.cullingMode = (AnimatorCullingMode)0; } playerBodyAnimator.Rebind(); playerBodyAnimator.Update(0f); AnimatorControllerParameter[] parameters = playerBodyAnimator.parameters; foreach (AnimatorControllerParameter val in parameters) { if ((int)val.type == 4 && new string[8] { "Limp", "Walking", "Sprinting", "Sideways", "crouching", "Jumping", "FallNoJump", "HoldLung" }.Contains(val.name)) { playerBodyAnimator.SetBool(val.nameHash, false); } if ((int)val.type == 9 && val.name == "SA_stopAnimation") { playerBodyAnimator.SetTrigger(val.nameHash); } } SetField(player, "currentAnimationStateHash", Enumerable.Repeat(0, playerBodyAnimator.layerCount).ToList()); SetField(player, "previousAnimationStateHash", Enumerable.Repeat(int.MinValue, playerBodyAnimator.layerCount).ToList()); SetField(player, "updatePlayerAnimationsInterval", 1f); } private static IEnumerator DeferredVoiceRepair(PlayerControllerB player) { yield return null; if ((Object)(object)player == (Object)null || player.isPlayerDead) { yield break; } Present(delegate { RepairVoice(player); }); yield return (object)new WaitForSeconds(1f); if ((Object)(object)player != (Object)null && !player.isPlayerDead) { Present(delegate { RepairVoice(player); }); object[] obj = new object[4] { player.actualClientId, ((NetworkBehaviour)player).IsOwner, null, null }; object obj2; if (!((Object)(object)player.playerBodyAnimator != (Object)null)) { obj2 = "missing"; } else { RuntimeAnimatorController runtimeAnimatorController = player.playerBodyAnimator.runtimeAnimatorController; obj2 = ((runtimeAnimatorController != null) ? ((Object)runtimeAnimatorController).name : null); } obj[2] = obj2; obj[3] = (Object)(object)player.activeAudioListener != (Object)null && ((Component)player.activeAudioListener).transform.IsChildOf(((Component)player).transform); Plugin.Log(string.Format("Ciriolator post-revive check: client={0}, owner={1}, animator={2}, listenerOnPlayer={3}.", obj)); } } private static void RepairVoice(PlayerControllerB player) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)player == (Object)null || player.isPlayerDead) { return; } player.voiceMuffledByEnemy = false; instance.RefreshPlayerVoicePlaybackObjects(); if ((Object)(object)player.currentVoiceChatIngameSettings != (Object)null) { if ((Object)(object)player.currentVoiceChatIngameSettings.voiceAudio == (Object)null) { player.currentVoiceChatIngameSettings.InitializeComponents(); } player.currentVoiceChatIngameSettings.set2D = false; } if ((Object)(object)player.currentVoiceChatAudioSource != (Object)null) { ((Behaviour)player.currentVoiceChatAudioSource).enabled = true; OccludeAudio component = ((Component)player.currentVoiceChatAudioSource).GetComponent<OccludeAudio>(); if ((Object)(object)component != (Object)null) { component.overridingLowPass = false; } } if (!((NetworkBehaviour)player).IsOwner && player.voicePlayerState != null) { player.voicePlayerState.Volume = 1f; } int num = Array.IndexOf(instance.allPlayerScripts, player); SoundManager instance2 = SoundManager.Instance; if ((Object)(object)instance2 != (Object)null && num >= 0 && num < instance2.playerVoicePitchTargets.Length) { instance2.playerVoicePitchTargets[num] = 1f; instance2.SetPlayerPitch(1f, num); } instance.UpdatePlayerVoiceEffects(); } private static void Present(Action action) { try { action(); } catch (Exception arg) { Plugin.Error($"Player revived, but a presentation/voice integration failed: {arg}"); } } private static void SetInternal(PlayerControllerB player, string name, bool value) { SetField(player, name, value); } private static void SetField(PlayerControllerB player, string name, object value) { FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerControllerB), name); if (fieldInfo != null) { fieldInfo.SetValue(player, value); } else { Plugin.Error("Game API mismatch: PlayerControllerB." + name + " was not found."); } } } public sealed class RevivalSideEffects : MonoBehaviour { private sealed class PlayerState { internal bool Dead; internal VoiceUploadPermit? Permit; internal VoiceTransferBuffer? Incoming; internal double RetryAt; internal double NoiseUntil; internal double NextNoise; internal short[] Samples = Array.Empty<short>(); internal readonly SideEffectSchedule Schedule = new SideEffectSchedule(); } private sealed class Playback { internal AudioClip Clip; internal AudioSource? Source; } private sealed class Outbound { internal ulong Peer; internal ulong Owner; internal uint Epoch; internal uint Ticket; internal bool Upload; internal int Position; internal short[] Samples = Array.Empty<short>(); } internal static RevivalSideEffects? Instance; private const string RequestName = "ciriolopipado.desfibrilator.effects.request.v2"; private const string EventName = "ciriolopipado.desfibrilator.effects.event.v2"; private readonly LastWordsCapture capture = new LastWordsCapture(); private readonly Dictionary<ulong, PlayerState> states = new Dictionary<ulong, PlayerState>(); private readonly Dictionary<ulong, Playback> voices = new Dictionary<ulong, Playback>(); private readonly HashSet<ulong> affected = new HashSet<ulong>(); private readonly HashSet<ulong> peers = new HashSet<ulong>(); private readonly List<Outbound> outgoing = new List<Outbound>(); private readonly Dictionary<ulong, VoiceTransferBuffer> incoming = new Dictionary<ulong, VoiceTransferBuffer>(); private readonly Dictionary<ulong, uint> incomingTickets = new Dictionary<ulong, uint>(); private readonly Random random = new Random(); private readonly Dictionary<string, double> nextFaultLog = new Dictionary<string, double>(); private readonly Dictionary<ulong, AudioSource> shockSources = new Dictionary<ulong, AudioSource>(); private readonly Dictionary<ulong, ShockSparkBurst> sparks = new Dictionary<ulong, ShockSparkBurst>(); private readonly ForcedWalkWindow forcedWalk = new ForcedWalkWindow(); private NetworkManager? manager; private ConfigEntry<bool> automaticCapture; private ConfigEntry<float> cameraStrength; private bool registered; private bool listening; private bool ready; private bool missionSeen; private bool lastCaptureEnabled; private bool localWasDead; private bool welcomed; private uint epoch = 1u; private uint nextTicket; private uint localTicket; private double nextHello; private double localTicketExpires; private double noticeUntil; private string notice = ""; private static double Now => Time.realtimeSinceStartupAsDouble; private static bool AtOrbit { get { if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.inShipPhase) { return !StartOfRound.Instance.shipIsLeaving; } return false; } } private static PlayerControllerB? Local => StartOfRound.Instance?.localPlayerController; private static PlayerControllerB? Player(ulong id) { return StartOfRound.Instance?.allPlayerScripts?.FirstOrDefault((Func<PlayerControllerB, bool>)((PlayerControllerB p) => (Object)(object)p != (Object)null && p.actualClientId == id && (p.isPlayerControlled || p.isPlayerDead))); } private void Awake() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown Instance = this; automaticCapture = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("LastWords", "AutomaticVoiceCapture", true, "Automatically keep up to 5 seconds of YOUR transmitted game voice in memory during an expedition. Shared with current teammates for replay after revival, then cleared at orbit/disconnect. Set false to disable locally. The legacy RecordOwnVoice/F8 settings are no longer used."); cameraStrength = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<float>("SideEffects", "CameraStrength", 1f, new ConfigDescription("Camera impulse multiplier. 0 disables camera movement locally; no damage. Defaults: random yaw 90–180°, pitch 2–6°. Only scales camera rotation, not involuntary walking/jumping or sparks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); lastCaptureEnabled = automaticCapture.Value; } private void Update() { //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) BindManager(); if (!registered || (Object)(object)manager == (Object)null || !manager.IsListening) { capture.Update(enabled: false, aliveInMission: false, replaying: false); return; } if (!manager.IsServer && !manager.IsConnectedClient) { capture.Update(enabled: false, aliveInMission: false, replaying: false); return; } PlayerControllerB local = Local; if ((Object)(object)local != (Object)null && !welcomed) { Show(automaticCapture.Value ? "Ciriolator: captura automática de tu voz de partida (solo memoria hasta órbita)." : "Ciriolator: captura automática desactivada en la configuración local."); welcomed = true; } if (automaticCapture.Value != lastCaptureEnabled) { lastCaptureEnabled = automaticCapture.Value; Show(lastCaptureEnabled ? "Ciriolator: captura automática de tu voz activada (memoria hasta órbita)." : "Ciriolator: captura desactivada; se elimina tu frase."); if (!lastCaptureEnabled) { capture.Dispose(); if ((Object)(object)local != (Object)null) { CancelTransfers(local.actualClientId); ClearVoice(local.actualClientId); } SendRevoke(); } } if (Interaction.RoundActive) { missionSeen = true; } if (missionSeen && AtOrbit) { missionSeen = false; if (manager.IsServer) { epoch++; ClearRound(); SendAll(0, 0uL); } else { ClearLocal(); } } Guard("voice capture", delegate { bool flag = (Object)(object)local != (Object)null && local.isPlayerControlled && !local.isPlayerDead; Playback value; bool replaying = (Object)(object)local != (Object)null && voices.TryGetValue(local.actualClientId, out value) && (Object)(object)value.Source != (Object)null && value.Source.isPlaying; capture.Update(automaticCapture.Value, flag && Interaction.RoundActive, replaying); if ((Object)(object)local != (Object)null && local.isPlayerDead && !localWasDead) { capture.FreezeAtDeath(); } localWasDead = (Object)(object)local != (Object)null && local.isPlayerDead; }); if (manager.IsServer) { ready = true; peers.Add(manager.LocalClientId); Guard("effect scheduler", ServerTick); } else if (!ready && (Object)(object)local != (Object)null && Now >= nextHello) { SendHello(); nextHello = Now + 1.0; } if (localTicket != 0 && (Object)(object)local != (Object)null && local.isPlayerDead && Now <= localTicketExpires) { uint ticket = localTicket; localTicket = 0u; Upload(ticket, automaticCapture.Value ? capture.Frozen : Array.Empty<short>()); } if (Now > localTicketExpires) { localTicket = 0u; } Guard("voice transfer", PumpTransfers); if ((Object)(object)local == (Object)null || !CanConvulse(local)) { forcedWalk.Clear(); } ulong[] array = sparks.Keys.ToArray(); foreach (ulong num2 in array) { PlayerControllerB val = Player(num2); if ((Object)(object)val == (Object)null || val.isPlayerDead || !Interaction.RoundActive) { ClearShock(num2); } } foreach (KeyValuePair<ulong, Playback> voice in voices) { PlayerControllerB val2 = Player(voice.Key); if ((Object)(object)voice.Value.Source != (Object)null && ((Object)(object)val2 == (Object)null || val2.isPlayerDead || !Interaction.RoundActive)) { voice.Value.Source.Stop(); } } } private void BindManager() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)manager != (Object)(object)singleton) { Detach(); manager = singleton; } if ((Object)(object)manager == (Object)null || !manager.IsListening) { if (listening) { Detach(); } return; } listening = true; if (!registered && manager.CustomMessagingManager != null) { manager.CustomMessagingManager.RegisterNamedMessageHandler("ciriolopipado.desfibrilator.effects.request.v2", new HandleNamedMessageDelegate(OnRequest)); manager.CustomMessagingManager.RegisterNamedMessageHandler("ciriolopipado.desfibrilator.effects.event.v2", new HandleNamedMessageDelegate(OnEvent)); manager.OnClientDisconnectCallback += OnDisconnect; registered = true; } } internal void ActivateOnServer(ulong client) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)manager == (Object)null) && manager.IsServer && Interaction.RoundActive) { if (!states.TryGetValue(client, out PlayerState value)) { value = (states[client] = new PlayerState()); } value.Dead = false; value.Schedule.Activate(Now, (Func<double>)random.NextDouble); Plugin.Log($"Ciriolator effects activated: client={client}, voiceIn={value.Schedule.NextVoice - Now:0.0}s, shockIn={value.Schedule.NextShock - Now:0.0}s, samples={value.Samples.Length}."); affected.Add(client); SendAll(3, client); if (value.Samples.Length != 0) { RelayClip(client, value.Samples); } } } private void ServerTick() { if ((Object)(object)manager == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return; } ulong[] array = manager.ConnectedClientsIds.ToArray(); foreach (ulong client in array) { Guard($"effects for client {client}", delegate { TickPlayer(client); }); } } private void TickPlayer(ulong client) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager == (Object)null) { return; } PlayerControllerB val = Player(client); if ((Object)(object)val == (Object)null) { return; } if (!states.TryGetValue(client, out PlayerState value)) { Dictionary<ulong, PlayerState> dictionary = states; ulong key = client; PlayerState obj = new PlayerState { Dead = false }; value = obj; dictionary[key] = obj; } if (Interaction.RoundActive && val.isPlayerDead && !value.Dead) { value.Dead = true; value.NoiseUntil = 0.0; CancelTransfers(client); ClearSamples(value); ClearVoice(client); SendAll(6, client); value.Permit = new VoiceUploadPermit(client, epoch, ++nextTicket, Now + 10.0); value.RetryAt = 0.0; } if (!val.isPlayerDead) { value.Dead = false; } VoiceUploadPermit? permit = value.Permit; if (permit != null && permit.Pending(Now) && Now >= value.RetryAt) { if (client == manager.LocalClientId) { QueueTicket(value.Permit.Ticket); } else if (peers.Contains(client)) { SendTicket(client, value.Permit.Ticket); } value.RetryAt = Now + 1.0; } VoiceUploadPermit? permit2 = value.Permit; if (permit2 != null && !permit2.Pending(Now) && value.Incoming != null) { value.Incoming.Clear(); value.Incoming = null; Plugin.Log($"Ciriolator: incomplete voice transfer discarded for client {client}."); } if (!Interaction.RoundActive) { return; } SideEffectEvent val2 = value.Schedule.Tick(Now, !val.isPlayerDead, value.Samples.Length != 0, (Func<double>)random.NextDouble); if ((val2 & 1) != 0) { SendAll(4, client); value.NoiseUntil = Now + (double)value.Samples.Length / 8000.0; value.NextNoise = Now; Guard("echo playback", delegate { PlayEcho(client); }); } if ((val2 & 2) != 0) { ShockImpulse impulse = ShockImpulse.Create((Func<double>)random.NextDouble); SendAll(5, client, impulse); Guard("shock playback", delegate { //IL_0017: Unknown result type (might be due to invalid IL or missing references) Shock(client, impulse); }); } if (val.isPlayerDead || !(Now < value.NoiseUntil) || !(Now >= value.NextNoise)) { return; } try { RoundManager instance = RoundManager.Instance; if (instance != null) { instance.PlayAudibleNoise(((Component)val).transform.position, 12f, 0.7f, 0, val.isInHangarShipRoom && StartOfRound.Instance.hangarDoorsClosed, 0); } } catch (Exception arg) { Plugin.Error($"An enemy-noise integration failed: {arg}"); } value.NextNoise = Now + 1.0; } private unsafe void SendHello() { //IL_0012: 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) //IL_0028: 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_0035: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(8, (Allocator)2, -1); try { byte b = 0; ((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<uint>(ref epoch, default(ForPrimitives)); SendRequest(writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe void SendRevoke() { //IL_0048: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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) if ((Object)(object)manager == (Object)null || !registered) { return; } if (manager.IsServer) { Revoke(manager.LocalClientId); return; } FastBufferWriter writer = default(FastBufferWriter); ((FastBufferWriter)(ref writer))..ctor(8, (Allocator)2, -1); try { byte b = 2; ((FastBufferWriter)(ref writer)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<uint>(ref epoch, default(ForPrimitives)); SendRequest(writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private void SendRequest(FastBufferWriter writer) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) manager.CustomMessagingManager.SendNamedMessage("ciriolopipado.desfibrilator.effects.request.v2", 0uL, writer, (NetworkDelivery)3); } private void OnRequest(ulong sender, FastBufferReader reader) { //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_0052: 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) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown if ((Object)(object)manager == (Object)null || !manager.IsServer || !manager.ConnectedClients.ContainsKey(sender) || !((FastBufferReader)(ref reader)).TryBeginRead(5)) { return; } byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives)); uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num, default(ForPrimitives)); if (b == 0) { bool num2 = peers.Add(sender); SendOne(sender, 0, 0uL); if (!num2) { return; } KeyValuePair<ulong, PlayerState>[] array = states.Where<KeyValuePair<ulong, PlayerState>>((KeyValuePair<ulong, PlayerState> p) => p.Value.Schedule.Active).ToArray(); for (int num3 = 0; num3 < array.Length; num3++) { KeyValuePair<ulong, PlayerState> keyValuePair = array[num3]; SendOne(sender, 3, keyValuePair.Key); if (keyValuePair.Value.Samples.Length != 0) { ulong key = keyValuePair.Key; short[] samples = keyValuePair.Value.Samples; VoiceUploadPermit? permit = keyValuePair.Value.Permit; SendClip(sender, key, samples, (permit != null) ? permit.Ticket : 0u); } } } else { if (num != epoch || !peers.Contains(sender)) { return; } switch (b) { case 2: Revoke(sender); break; case 1: { if (!((FastBufferReader)(ref reader)).TryBeginRead(16)) { break; } uint num4 = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num4, default(ForPrimitives)); int num5 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num5, default(ForPrimitives)); int num6 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num6, default(ForPrimitives)); int num7 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num7, default(ForPrimitives)); if (!states.TryGetValue(sender, out PlayerState value)) { break; } VoiceUploadPermit? permit2 = value.Permit; if (permit2 == null || !permit2.Allows(sender, epoch, num4, num5, (num5 <= 40000 && num5 >= 0) ? (num5 * 2) : (-1), Now) || num7 < 0 || num7 > 384 || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position != num7 * 2) { break; } if (num5 == 0) { if (num6 == 0 && num7 == 0) { AcceptUpload(sender, num4, Array.Empty<short>()); } } else { if (num7 == 0) { break; } if (value.Incoming == null) { if (num6 != 0) { break; } value.Incoming = new VoiceTransferBuffer(num5); } if (value.Incoming.Count == num5) { byte[] array2 = new byte[num7 * 2]; ((FastBufferReader)(ref reader)).ReadBytesSafe(ref array2, array2.Length, 0); short[] array3 = new short[num7]; Buffer.BlockCopy(array2, 0, array3, 0, array2.Length); if (value.Incoming.Append(num6, array3) && value.Incoming.Complete) { short[] array4 = value.Incoming.Snapshot(); AcceptUpload(sender, num4, array4); Array.Clear(array4, 0, array4.Length); } Array.Clear(array2, 0, array2.Length); Array.Clear(array3, 0, array3.Length); } } break; } } } } private void AcceptUpload(ulong sender, uint ticket, short[] samples) { if (!states.TryGetValue(sender, out PlayerState value)) { return; } VoiceUploadPermit? permit = value.Permit; if (permit != null && permit.TryConsume(sender, epoch, ticket, samples.Length, samples.Length * 2, Now)) { VoiceTransferBuffer? obj = value.Incoming; if (obj != null) { obj.Clear(); } value.Incoming = null; ClearSamples(value); value.Samples = (short[])samples.Clone(); Plugin.Log($"Ciriolator last words received: client={sender}, samples={samples.Length}, ticket={ticket}."); if (value.Schedule.Active && samples.Length != 0 && !value.Dead) { RelayClip(sender, samples); } } } private void Upload(uint ticket, short[] samples) { if ((Object)(object)manager == (Object)null) { return; } if (manager.IsServer) { AcceptUpload(manager.LocalClientId, ticket, samples); return; } foreach (Outbound item in outgoing.Where((Outbound t) => t.Upload)) { Array.Clear(item.Samples, 0, item.Samples.Length); } outgoing.RemoveAll((Outbound t) => t.Upload); outgoing.Add(new Outbound { Peer = 0uL, Owner = manager.LocalClientId, Epoch = epoch, Ticket = ticket, Upload = true, Samples = (short[])samples.Clone() }); } private void QueueTicket(uint ticket) { localTicket = ticket; localTicketExpires = Now + 10.0; } private unsafe void SendTicket(ulong peer, uint ticket) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) FastBufferWriter writer = Header(1); try { ((FastBufferWriter)(ref writer)).WriteValueSafe<uint>(ref ticket, default(ForPrimitives)); SendEvent(peer, writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private void Revoke(ulong client) { //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) CancelTransfers(client); if (states.TryGetValue(client, out PlayerState value)) { ClearSamples(value); VoiceUploadPermit? permit = value.Permit; if (permit != null) { permit.Cancel(); } value.NoiseUntil = 0.0; } ClearVoice(client); SendAll(6, client); } private FastBufferWriter Header(byte kind, int capacity = 32) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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) FastBufferWriter result = default(FastBufferWriter); ((FastBufferWriter)(ref result))..ctor(capacity, (Allocator)2, -1); ((FastBufferWriter)(ref result)).WriteValueSafe<byte>(ref kind, default(ForPrimitives)); ((FastBufferWriter)(ref result)).WriteValueSafe<uint>(ref epoch, default(ForPrimitives)); return result; } private void SendEvent(ulong peer, FastBufferWriter writer) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager != (Object)null && peer != manager.LocalClientId && manager.ConnectedClients.ContainsKey(peer)) { manager.CustomMessagingManager.SendNamedMessage("ciriolopipado.desfibrilator.effects.event.v2", peer, writer, (NetworkDelivery)3); } } private unsafe void SendOne(ulong peer, byte kind, ulong client = 0uL, ShockImpulse impulse = default(ShockImpulse)) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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_0065: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter writer = Header(kind); try { if (kind != 0) { ((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref client, default(ForPrimitives)); } if (kind == 5) { float yaw = ((ShockImpulse)(ref impulse)).Yaw; ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref yaw, default(ForPrimitives)); yaw = ((ShockImpulse)(ref impulse)).Pitch; ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref yaw, default(ForPrimitives)); bool convulse = ((ShockImpulse)(ref impulse)).Convulse; ((FastBufferWriter)(ref writer)).WriteValueSafe<bool>(ref convulse, default(ForPrimitives)); yaw = ((ShockImpulse)(ref impulse)).DirectionDegrees; ((FastBufferWriter)(ref writer)).WriteValueSafe<float>(ref yaw, default(ForPrimitives)); } SendEvent(peer, writer); } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } private void SendAll(byte kind, ulong client = 0uL, ShockImpulse impulse = default(ShockImpulse)) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) ulong[] array = peers.ToArray(); foreach (ulong peer in array) { SendOne(peer, kind, client, impulse); } } private void SendClip(ulong peer, ulong client, short[] samples, uint ticket) { if (!((Object)(object)manager == (Object)null) && peer != manager.LocalClientId) { outgoing.RemoveAll((Outbound t) => !t.Upload && t.Peer == peer && t.Owner == client); outgoing.Add(new Outbound { Peer = peer, Owner = client, Epoch = epoch, Ticket = ticket, Samples = samples }); } } private void RelayClip(ulong client, short[] samples) { InstallClip(client, samples); if (states.TryGetValue(client, out PlayerState value)) { ulong[] array = peers.ToArray(); foreach (ulong peer in array) { short[] samples2 = value.Samples; VoiceUploadPermit? permit = value.Permit; SendClip(peer, client, samples2, (permit != null) ? permit.Ticket : 0u); } } } private unsafe void PumpTransfers() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_011c: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 4; i++) { if (outgoing.Count <= 0) { break; } Outbound outbound = outgoing[0]; outgoing.RemoveAt(0); if ((Object)(object)manager == (Object)null || outbound.Epoch != epoch || (!outbound.Upload && !manager.ConnectedClients.ContainsKey(outbound.Peer))) { continue; } int num = Math.Min(384, outbound.Samples.Length - outbound.Position); byte[] array = new byte[num * 2]; Buffer.BlockCopy(outbound.Samples, outbound.Position * 2, array, 0, array.Length); FastBufferWriter writer = Header((byte)(outbound.Upload ? 1 : 2), 1024); try { if (!outbound.Upload) { ((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref outbound.Owner, default(ForPrimitives)); } ((FastBufferWriter)(ref writer)).WriteValueSafe<uint>(ref outbound.Ticket, default(ForPrimitives)); int num2 = outbound.Samples.Length; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num2, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref outbound.Position, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref writer)).WriteBytesSafe(array, -1, 0); if (outbound.Upload) { SendRequest(writer); } else { SendEvent(outbound.Peer, writer); } outbound.Position += num; Array.Clear(array, 0, array.Length); if (outbound.Position < outbound.Samples.Length) { outgoing.Add(outbound); } else if (outbound.Upload) { Array.Clear(outbound.Samples, 0, outbound.Samples.Length); } } finally { ((IDisposable)(*(FastBufferWriter*)(&writer))/*cast due to .constrained prefix*/).Dispose(); } } } private void CancelTransfers(ulong owner) { foreach (Outbound item in outgoing.Where((Outbound t) => t.Owner == owner && t.Upload)) { Array.Clear(item.Samples, 0, item.Samples.Length); } outgoing.RemoveAll((Outbound t) => t.Owner == owner); } private void OnEvent(ulong sender, FastBufferReader reader) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Expected O, but got Unknown //IL_01b1: Expected O, but got Unknown if ((Object)(object)manager == (Object)null || manager.IsServer || sender != 0L || !((FastBufferReader)(ref reader)).TryBeginRead(5)) { return; } byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives)); uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num, default(ForPrimitives)); if (b == 0) { if (epoch != num) { ClearLocal(); epoch = num; } ready = true; } else { if (!ready || num != epoch) { return; } if (b == 1 && ((FastBufferReader)(ref reader)).TryBeginRead(4)) { uint ticket = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref ticket, default(ForPrimitives)); QueueTicket(ticket); } else { if (!((FastBufferReader)(ref reader)).TryBeginRead(8)) { return; } ulong client = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref client, default(ForPrimitives)); if (b == 2 && ((FastBufferReader)(ref reader)).TryBeginRead(16) && affected.Contains(client)) { uint num2 = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe<uint>(ref num2, default(ForPrimitives)); int num3 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num3, default(ForPrimitives)); int num4 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num4, default(ForPrimitives)); int num5 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num5, default(ForPrimitives)); if (num3 <= 0 || num3 > 40000 || num5 <= 0 || num5 > 384 || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position != num5 * 2) { return; } if (!incoming.TryGetValue(client, out VoiceTransferBuffer value)) { if (num4 != 0) { return; } Dictionary<ulong, VoiceTransferBuffer> dictionary = incoming; ulong key = client; VoiceTransferBuffer val = new VoiceTransferBuffer(num3); value = val; dictionary[key] = val; incomingTickets[client] = num2; } if (value.Count == num3 && incomingTickets[client] == num2) { byte[] array = new byte[num5 * 2]; ((FastBufferReader)(ref reader)).ReadBytesSafe(ref array, array.Length, 0); short[] array2 = new short[num5]; Buffer.BlockCopy(array, 0, array2, 0, array.Length); if (value.Append(num4, array2) && value.Complete) { short[] array3 = value.Snapshot(); InstallClip(client, array3); Array.Clear(array3, 0, array3.Length); } Array.Clear(array, 0, array.Length); Array.Clear(array2, 0, array2.Length); } return; } switch (b) { case 3: affected.Add(client); return; case 4: if (affected.Contains(client)) { Guard("received echo", delegate { PlayEcho(client); }); return; } break; } if (b == 5 && affected.Contains(client) && ((FastBufferReader)(ref reader)).TryBeginRead(13)) { float num6 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num6, default(ForPrimitives)); float num7 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num7, default(ForPrimitives)); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); float num8 = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num8, default(ForPrimitives)); ShockImpulse impulse = new ShockImpulse(num6, num7, flag, num8); if (((ShockImpulse)(ref impulse)).IsValid) { Guard("received shock", delegate { //IL_0017: Unknown result type (might be due to invalid IL or missing references) Shock(client, impulse); }); } } else { switch (b) { case 6: ClearVoice(client); break; case 7: affected.Remove(client); ClearVoice(client); ClearShock(client); break; } } } } } private void InstallClip(ulong client, short[] samples) { ClearVoice(client); if (samples.Length != 0) { float[] array = new float[samples.Length]; for (int i = 0; i < samples.Length; i++) { array[i] = (float)samples[i] / 32768f; } AudioClip val = AudioClip.Create("CiriolatorLastWords", array.Length, 1, 8000, false); val.SetData(array, 0); Array.Clear(array, 0, array.Length); voices[client] = new Playback { Clip = val }; } } private void PlayEcho(ulong client) { PlayerControllerB val = Player(client); if ((Object)(object)val == (Object)null || val.isPlayerDead || !Interaction.RoundActive || !voices.TryGetValue(client, out Playback value)) { return; } if (!((NetworkBehaviour)val).IsOwner) { VoicePlayerState voicePlayerState = val.voicePlayerState; if (voicePlayerState != null && voicePlayerState.IsLocallyMuted) { return; } } if ((Object)(object)value.Source == (Object)null) { value.Source = CreateEffectSource(val, "CiriolatorProximityEcho"); value.Source.volume = 0.7f; value.Source.pitch = 0.98f; ((Component)value.Source).gameObject.AddComponent<AudioLowPassFilter>().cutoffFrequency = 2800f; } value.Source.clip = value.Clip; value.Source.Play(); Plugin.Log($"Ciriolator echo playing: client={client}, seconds={value.Clip.length:0.00}."); } private void Shock(ulong client, ShockImpulse impulse) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB player = Player(client); if ((Object)(object)player == (Object)null || player.isPlayerDead || !Interaction.RoundActive) { return; } Guard("shock sound", delegate { if (!shockSources.TryGetValue(client, out AudioSource value) || (Object)(object)value == (Object)null) { value = (shockSources[client] = CreateEffectSource(player, "CiriolatorShock")); } value.PlayOneShot(ItemFactory.Discharge, 0.5f); }); Guard("shock sparks", delegate { if (sparks.TryGetValue(client, out ShockSparkBurst value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } ShockSparkBurst shockSparkBurst = ShockSparkBurst.Spawn(player); if ((Object)(object)shockSparkBurst != (Object)null) { sparks[client] = shockSparkBurst; Plugin.Log($"Ciriolator sparks attached to revived body: client={client}, anchor={((Object)((Component)shockSparkBurst).transform.parent).name}."); } }); Plugin.Log($"Ciriolator shock received: client={client}, owner={((NetworkBehaviour)player).IsOwner}, yaw={((ShockImpulse)(ref impulse)).Yaw:0.0}, pitch={((ShockImpulse)(ref impulse)).Pitch:0.0}, convulse={((ShockImpulse)(ref impulse)).Convulse}."); if (!((NetworkBehaviour)player).IsOwner) { return; } Guard("shock camera", delegate { //IL_000d: Unknown result type (might be due to invalid IL or missing references) RotateCamera(player, impulse); }); if (((ShockImpulse)(ref impulse)).Convulse) { Guard("shock convulsion", delegate { BeginConvulsion(player, ((ShockImpulse)(ref impulse)).DirectionDegrees); }); } } private void RotateCamera(PlayerControllerB player, ShockImpulse impulse) { //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (!player.disableLookInput && !player.inTerminalMenu && !player.inSpecialInteractAnimation && !player.isTypingChat) { QuickMenuManager quickMenuManager = player.quickMenuManager; if (quickMenuManager == null || !quickMenuManager.isMenuOpen) { float value = cameraStrength.Value; if (value <= 0f) { Plugin.Log("Ciriolator camera impulse disabled by CameraStrength=0."); return; } ((Component)player).transform.Rotate(0f, ((ShockImpulse)(ref impulse)).Yaw * value, 0f, (Space)0); FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerControllerB), "cameraUp"); if (fieldInfo != null && (Object)(object)player.gameplayCamera != (Object)null) { float num = Mathf.Clamp((float)fieldInfo.GetValue(player) + ((ShockImpulse)(ref impulse)).Pitch * value, -80f, 80f); fieldInfo.SetValue(player, num); Vector3 localEulerAngles = ((Component)player.gameplayCamera).transform.localEulerAngles; ((Component)player.gameplayCamera).transform.localEulerAngles = new Vector3(num, localEulerAngles.y, localEulerAngles.z); } Plugin.Log($"Ciriolator camera impulse applied to local client {player.actualClientId}."); return; } } Plugin.Log($"Ciriolator camera impulse skipped during a locked interaction for client {player.actualClientId}."); } private static bool CanConvulse(PlayerControllerB player) { if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).IsOwner && player.isPlayerControlled && !player.isPlayerDead && Interaction.RoundActive && !player.disableMoveInput && !player.inTerminalMenu && !player.inSpecialInteractAnimation && !player.isTypingChat) { QuickMenuManager quickMenuManager = player.quickMenuManager; if ((quickMenuManager == null || !quickMenuManager.isMenuOpen) && !player.isClimbingLadder && !player.jetpackControls && !player.inVehicleAnimation) { return !player.isFreeCamera; } } return false; } private void BeginConvulsion(PlayerControllerB player, float direction) { //IL_0067: 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) if (!CanConvulse(player)) { Plugin.Log($"Ciriolator convulsion skipped during locked movement for client {player.actualClientId}."); return; } if (ConvulsionInputPatch.Installed) { forcedWalk.Begin(Now, direction); } MethodInfo methodInfo = AccessTools.Method(typeof(PlayerControllerB), "Jump_performed", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(player, new object[1] { (object)default(CallbackContext) }); } else { Plugin.Error("Ciriolator native jump request unavailable; walking and other effects remain enabled."); } Plugin.Log($"Ciriolator convulsion requested: client={player.actualClientId}, walk={ConvulsionInputPatch.Installed}, seconds={0.75}, direction={direction:0.0}, jumping={player.isJumping}."); } internal Vector2 FilterMovement(Vector2 input, PlayerControllerB player) { //IL_0008: 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_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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0024: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)player).IsOwner) { return input; } float num = default(float); if (!forcedWalk.TryGet(Now, CanConvulse(player), ref num)) { return input; } float num2 = num * (MathF.PI / 180f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Sin(num2), 0f, Mathf.Cos(num2)); Vector3 val2 = ((Component)player).transform.InverseTransformDirection(val); Vector2 val3 = new Vector2(val2.x, val2.z); return ((Vector2)(ref val3)).normalized; } private static AudioSource CreateEffectSource(PlayerControllerB player, string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(((Component)player).transform, false); val.transform.localPosition = Vector3.up * 1.5f; AudioSource val2 = val.AddComponent<AudioSource>(); val2.playOnAwake = false; val2.loop = false; val2.spatialBlend = 1f; val2.minDistance = 1f; val2.maxDistance = 12f; val2.rolloffMode = (AudioRolloffMode)1; if ((Object)(object)SoundManager.Instance != (Object)null && (Object)(object)SoundManager.Instance.diageticMixer != (Object)null) { AudioMixerGroup[] array = SoundManager.Instance.diageticMixer.FindMatchingGroups("SFX"); if (array.Length != 0) { val2.outputAudioMixerGroup = array[0]; } } return val2; } private void ClearShock(ulong client) { if ((Object)(object)Local != (Object)null && Local.actualClientId == client) { forcedWalk.Clear(); } if (sparks.TryGetValue(client, out ShockSparkBurst value)) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } sparks.Remove(client); } if (shockSources.TryGetValue(client, out AudioSource value2)) { if ((Object)(object)value2 != (Object)null) { value2.Stop(); Object.Destroy((Object)(object)((Component)value2).gameObject); } shockSources.Remove(client); } } private void Guard(string stage, Action action) { try { action(); } catch (Exception arg) { if (!nextFaultLog.TryGetValue(stage, out var value) || Now >= value) { nextFaultLog[stage] = Now + 5.0; Plugin.Error($"Ciriolator {stage} failed; other effects remain active: {arg}"); } } } private void ClearVoice(ulong client) { if (incoming.TryGetValue(client, out VoiceTransferBuffer value)) { value.Clear(); incoming.Remove(client); } incomingTickets.Remove(client); if (voices.TryGetValue(client, out Playback value2)) { if ((Object)(object)value2.Source != (Object)null) { value2.Source.Stop(); Object.Destroy((Object)(object)((Component)value2.Source).gameObject); } if ((Object)(object)value2.Clip != (Object)null) { Object.Destroy((Object)(object)value2.Clip); } voices.Remove(client); } } private static void ClearSamples(PlayerState state) { VoiceTransferBuffer? obj = state.Incoming; if (obj != null) { obj.Clear(); } state.Incoming = null; Array.Clear(state.Samples, 0,
BepInEx/plugins/Desfibrilator/Desfibrilator.Core.dll
Decompiled 6 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [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("Desfibrilator.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d34b1e8655b95f46dddd55b5047a7305cee42f6b")] [assembly: AssemblyProduct("Desfibrilator.Core")] [assembly: AssemblyTitle("Desfibrilator.Core")] [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.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 Desfibrilator.Core { public sealed class LastWordsBuffer { public const int SampleRate = 8000; public const int MaxSamples = 40000; private const int SilenceLimit = 6400; private const int MinimumSpeech = 2000; private readonly short[] ring = new short[46400]; private short[] lastPhrase = Array.Empty<short>(); private long written; private long lastSpeechEnd; private int silence; private int speechSamples; private bool active; public void Append(short[] samples, int count, bool speech) { if (count < 0 || count > samples.Length) { throw new ArgumentOutOfRangeException("count"); } if (speech && !active) { active = true; written = (lastSpeechEnd = 0L); silence = (speechSamples = 0); } if (!active) { return; } for (int i = 0; i < count; i++) { ring[written++ % ring.Length] = (short)(speech ? samples[i] : 0); if (speech) { lastSpeechEnd = written; speechSamples++; silence = 0; } else if (++silence >= 6400) { EndPhrase(); break; } } } public void EndPhrase() { if (active) { if (speechSamples >= 2000) { short[] array = Extract(); Array.Clear(lastPhrase, 0, lastPhrase.Length); lastPhrase = array; } active = false; written = (lastSpeechEnd = 0L); silence = (speechSamples = 0); Array.Clear(ring, 0, ring.Length); } } public short[] Snapshot() { if (!active || speechSamples < 2000) { return (short[])lastPhrase.Clone(); } return Extract(); } private short[] Extract() { int num = (int)Math.Min(lastSpeechEnd, 40000L); short[] array = new short[num]; long num2 = lastSpeechEnd - num; for (int i = 0; i < num; i++) { array[i] = ring[(num2 + i) % ring.Length]; } return array; } public void Clear() { Array.Clear(ring, 0, ring.Length); Array.Clear(lastPhrase, 0, lastPhrase.Length); lastPhrase = Array.Empty<short>(); active = false; written = (lastSpeechEnd = 0L); silence = (speechSamples = 0); } } public enum RevivalDecision { Apply, AlreadyAlive, Duplicate, WrongPlayer, DifferentDeath } public sealed class RevivalReceipts { private readonly Dictionary<ulong, ulong> received = new Dictionary<ulong, ulong>(); public RevivalDecision Decide(ulong sequence, ulong expectedPlayer, ulong actualPlayer, bool dead, ulong expectedCorpse, ulong? actualCorpse) { if (expectedPlayer != actualPlayer) { return RevivalDecision.WrongPlayer; } if (received.TryGetValue(actualPlayer, out var value) && sequence <= value) { return RevivalDecision.Duplicate; } if (!dead) { return RevivalDecision.AlreadyAlive; } if (actualCorpse.HasValue && expectedCorpse != actualCorpse.Value) { return RevivalDecision.DifferentDeath; } return RevivalDecision.Apply; } public void Commit(ulong sequence, ulong player) { if (!received.TryGetValue(player, out var value) || sequence > value) { received[player] = sequence; } } public void Clear() { received.Clear(); } } public readonly struct Attempt : IEquatable<Attempt> { public readonly ulong Actor; public readonly ulong Tool; public readonly ulong Corpse; public Attempt(ulong actor, ulong tool, ulong corpse) { Actor = actor; Tool = tool; Corpse = corpse; } public bool Equals(Attempt other) { if (Actor == other.Actor && Tool == other.Tool) { return Corpse == other.Corpse; } return false; } public override bool Equals(object? other) { if (other is Attempt other2) { return Equals(other2); } return false; } public override int GetHashCode() { return Actor.GetHashCode() ^ Tool.GetHashCode() ^ Corpse.GetHashCode(); } } public sealed class ReviveCoordinator { public const double ChargeSeconds = 5.0; public const double CooldownSeconds = 90.0; public const double HeartbeatTimeout = 0.45; private double startedAt; private double lastPulse; private double availableAt; public Attempt? Active { get; private set; } public double CooldownRemaining(double now) { return Math.Max(0.0, availableAt - now); } public double ChargeRemaining(double now) { if (!Active.HasValue) { return 5.0; } return Math.Max(0.0, 5.0 - (now - startedAt)); } public bool Pulse(Attempt attempt, double now) { if (CooldownRemaining(now) > 0.0) { return false; } if (Active.HasValue && now - lastPulse > 0.45) { Active = null; } if (Active.HasValue && !Active.Value.Equals(attempt)) { return false; } if (!Active.HasValue) { Active = attempt; startedAt = now; } lastPulse = now; return true; } public Attempt? Tick(double now, Func<Attempt, bool> validate) { if (!Active.HasValue) { return null; } if (now - lastPulse > 0.45 || !validate(Active.Value)) { Active = null; return null; } if (!(ChargeRemaining(now) <= 0.0)) { return null; } return Active; } public void Cancel(ulong actor) { Attempt? active = Active; if (active.HasValue && active.GetValueOrDefault().Actor == actor) { Active = null; } } public void Complete(double now) { if (!Active.HasValue || ChargeRemaining(now) > 0.0 || now - lastPulse > 0.45) { throw new InvalidOperationException("Cannot complete an interrupted or unfinished reanimation."); } Active = null; availableAt = now + 90.0; } public void ResetSession() { Active = null; availableAt = 0.0; } } public readonly struct ShockImpulse { public const double WalkSeconds = 0.75; public float Yaw { get; } public float Pitch { get; } public bool Convulse { get; } public float DirectionDegrees { get; } public bool IsValid { get { if (Finite(Yaw) && Math.Abs(Yaw) >= 90f && Math.Abs(Yaw) <= 180f && Finite(Pitch) && Math.Abs(Pitch) >= 2f && Math.Abs(Pitch) <= 6f && Finite(DirectionDegrees) && DirectionDegrees >= 0f) { return DirectionDegrees <= 360f; } return false; } } public ShockImpulse(float yaw, float pitch, bool convulse, float directionDegrees) { Yaw = yaw; Pitch = pitch; Convulse = convulse; DirectionDegrees = directionDegrees; } public static ShockImpulse Create(Func<double> random) { return new ShockImpulse(Signed(90f, 180f, random), Signed(2f, 6f, random), Unit(random()) < 0.5, (float)(360.0 * Unit(random()))); } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static double Unit(double value) { if (!double.IsNaN(value)) { return Math.Max(0.0, Math.Min(1.0, value)); } return 0.0; } private static float Signed(float min, float max, Func<double> random) { return (float)((double)min + (double)(max - min) * Unit(random())) * (float)((!(Unit(random()) < 0.5)) ? 1 : (-1)); } } public sealed class ForcedWalkWindow { private bool active; private double until; private float direction; public void Begin(double now, float directionDegrees) { active = true; until = now + 0.75; direction = directionDegrees; } public bool TryGet(double now, bool eligible, out float directionDegrees) { directionDegrees = direction; if (!active) { return false; } if (!eligible || now >= until) { Clear(); return false; } return true; } public void Clear() { active = false; until = 0.0; direction = 0f; } } [Flags] public enum SideEffectEvent { None = 0, Voice = 1, Shock = 2 } public sealed class SideEffectSchedule { public bool Active { get; private set; } public double NextVoice { get; private set; } public double NextShock { get; private set; } public void Activate(double now, Func<double> random) { Active = true; NextVoice = now + Interval(15.0, 30.0, random()); NextShock = now + Interval(15.0, 30.0, random()); } public SideEffectEvent Tick(double now, bool alive, bool hasVoice, Func<double> random) { if (!Active || !alive) { return SideEffectEvent.None; } SideEffectEvent sideEffectEvent = SideEffectEvent.None; if (now >= NextVoice) { if (hasVoice) { sideEffectEvent |= SideEffectEvent.Voice; } NextVoice = now + Interval(15.0, 30.0, random()); } if (now >= NextShock) { sideEffectEvent |= SideEffectEvent.Shock; NextShock = now + Interval(15.0, 30.0, random()); } return sideEffectEvent; } public void Clear() { Active = false; double nextVoice = (NextShock = 0.0); NextVoice = nextVoice; } private static double Interval(double min, double max, double value) { return min + (max - min) * Math.Max(0.0, Math.Min(1.0, value)); } } public sealed class VoiceTransferBuffer { public const int ChunkSamples = 384; private readonly short[] samples; public int Count => samples.Length; public int Position { get; private set; } public bool Complete => Position == Count; public VoiceTransferBuffer(int count) { if (count <= 0 || count > 40000) { throw new ArgumentOutOfRangeException("count"); } samples = new short[count]; } public bool Append(int offset, short[] chunk) { if (offset != Position || chunk.Length == 0 || chunk.Length > 384 || chunk.Length > Count - Position) { return false; } Array.Copy(chunk, 0, samples, Position, chunk.Length); Position += chunk.Length; return true; } public short[] Snapshot() { if (!Complete) { throw new InvalidOperationException("Incomplete voice transfer."); } return (short[])samples.Clone(); } public void Clear() { Array.Clear(samples, 0, samples.Length); Position = 0; } } public sealed class VoiceUploadPermit { private readonly double expires; private bool consumed; public ulong Owner { get; } public uint Epoch { get; } public uint Ticket { get; } public VoiceUploadPermit(ulong owner, uint epoch, uint ticket, double expires) { Owner = owner; Epoch = epoch; Ticket = ticket; this.expires = expires; } public bool Pending(double now) { if (!consumed) { return now <= expires; } return false; } public bool Allows(ulong owner, uint epoch, uint ticket, int count, int bytes, double now) { if (Pending(now) && Owner == owner && Epoch == epoch && Ticket == ticket && count >= 0 && count <= 40000) { return bytes == count * 2; } return false; } public bool TryConsume(ulong owner, uint epoch, uint ticket, int count, int bytes, double now) { if (!Allows(owner, epoch, ticket, count, bytes, now)) { return false; } consumed = true; return true; } public void Cancel() { consumed = true; } } }