Decompiled source of Desfibrilator v1.0.0

BepInEx/plugins/Desfibrilator/Desfibrilator.dll

Decompiled 6 hours ago
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 ago
using 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;
		}
	}
}