Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Industrial Defibrillator v0.1.5
BepInEx/plugins/IndustrialDefibrillator/Defibrillator.Core.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; 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("Defibrillator.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.5.0")] [assembly: AssemblyInformationalVersion("0.1.5+9d197fcbfb4d444b476161ad58b79e319e14f80f")] [assembly: AssemblyProduct("Defibrillator.Core")] [assembly: AssemblyTitle("Defibrillator.Core")] [assembly: AssemblyVersion("0.1.5.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 Defibrillator.Core { public static class AftershockImpact { public static bool RollTumble(double sample, double chance) { if (!Settings.Finite(sample) || sample < 0.0 || sample >= 1.0) { throw new ArgumentOutOfRangeException("sample"); } if (!Settings.Finite(chance) || chance < 0.0 || chance > 1.0) { throw new ArgumentOutOfRangeException("chance"); } return sample < chance; } public static float YawAt(float degrees, double progress) { if (!Settings.Finite(degrees) || Math.Abs(degrees) > 180f) { throw new ArgumentOutOfRangeException("degrees"); } if (!Settings.Finite(progress)) { throw new ArgumentOutOfRangeException("progress"); } double num = Math.Max(0.0, Math.Min(1.0, progress)); return (float)((double)degrees * num * num * (3.0 - 2.0 * num)); } public static (float Strength, float Seconds) UpgradeLegacy(int revision, float strength, float seconds) { if (revision < 1) { return (Strength: (strength == 3.5f) ? 7f : strength, Seconds: (seconds == 0.8f) ? 1.2f : seconds); } return (Strength: strength, Seconds: seconds); } } public static class BalanceMigration { public const int Revision = 1; public const int Price = 2; public const int BatteryCost = 50; public static (int Price, int BatteryCost) Apply(int revision, int price, int batteryCost) { if (revision >= 1) { return (Price: price, BatteryCost: batteryCost); } return (Price: (price == 0) ? 2 : price, BatteryCost: (batteryCost == 25) ? 50 : batteryCost); } } public static class DeviceGeometry { public const float ModelScale = 0.5f; public const float MassKg = 3f; public const float FloorY = -0.07875f; public static IReadOnlyList<CollisionBox> CollisionBoxes { get; } = Array.AsReadOnly(new CollisionBox[6] { new CollisionBox("Casing", 0f, 0f, 0f, 0.51f, 0.315f, 0.24f), new CollisionBox("Left paddle", -0.3f, 0f, -0.025f, 0.1f, 0.16f, 0.12f), new CollisionBox("Right paddle", 0.3f, 0f, -0.025f, 0.1f, 0.16f, 0.12f), new CollisionBox("Handle", 0f, 0.23f, 0f, 0.22f, 0.032f, 0.05f), new CollisionBox("Left handle mount", -0.11f, 0.19f, 0f, 0.025f, 0.08f, 0.05f), new CollisionBox("Right handle mount", 0.11f, 0.19f, 0f, 0.025f, 0.08f, 0.05f) }); } public readonly struct CollisionBox { public string Name { get; } public float X { get; } public float Y { get; } public float Z { get; } public float Width { get; } public float Height { get; } public float Depth { get; } internal CollisionBox(string name, float x, float y, float z, float width, float height, float depth) { Name = name; X = x; Y = y; Z = z; Width = width; Height = height; Depth = depth; } } [Flags] public enum DonorParts { None = 0, Tracker = 1, Attributes = 2, Battery = 4, Equippable = 8, Physics = 0x10, Rigidbody = 0x20, NetworkView = 0x40, ColorPreset = 0x80, BatteryDisplay = 0x100, NativeReviver = 0x200 } public static class DonorRequirements { public const DonorParts Required = DonorParts.Tracker | DonorParts.Attributes | DonorParts.Battery | DonorParts.Equippable | DonorParts.Physics | DonorParts.Rigidbody | DonorParts.NetworkView | DonorParts.ColorPreset; public static DonorParts Missing(DonorParts available) { return (DonorParts.Tracker | DonorParts.Attributes | DonorParts.Battery | DonorParts.Equippable | DonorParts.Physics | DonorParts.Rigidbody | DonorParts.NetworkView | DonorParts.ColorPreset) & ~available; } public static bool IsCompatible(DonorParts available) { if (Missing(available) == DonorParts.None) { return (available & DonorParts.NativeReviver) == 0; } return false; } } public sealed class PcmWave { public int SampleRate { get; } public float[] Samples { get; } public double Seconds => (double)Samples.Length / (double)SampleRate; private PcmWave(int rate, float[] samples) { SampleRate = rate; Samples = samples; } public static PcmWave Read(Stream input) { using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[4096]; int count; while ((count = input.Read(array, 0, array.Length)) > 0) { memoryStream.Write(array, 0, count); if (memoryStream.Length > 400000) { throw new InvalidDataException("Animal WAV exceeds size limit."); } } memoryStream.Position = 0L; BinaryReader reader = new BinaryReader(memoryStream, Encoding.ASCII, leaveOpen: true); try { if (memoryStream.Length < 44 || Four() != "RIFF") { throw new InvalidDataException("Expected RIFF WAV."); } if ((long)reader.ReadUInt32() + 8L != memoryStream.Length || Four() != "WAVE") { throw new InvalidDataException("Invalid WAV container."); } int num = 0; bool flag = false; byte[] array2 = null; while (memoryStream.Position + 8 <= memoryStream.Length) { string text = Four(); uint num2 = reader.ReadUInt32(); long num3 = memoryStream.Position + num2; if (num3 > memoryStream.Length) { throw new InvalidDataException("Truncated WAV chunk."); } if (text == "fmt ") { if (flag || num2 < 16 || reader.ReadUInt16() != 1 || reader.ReadUInt16() != 1) { throw new InvalidDataException("Expected mono PCM."); } num = reader.ReadInt32(); int num4 = reader.ReadInt32(); int num5 = reader.ReadUInt16(); int num6 = reader.ReadUInt16(); if ((num != 44100 && num != 48000) || num6 != 16 || num5 != 2 || num4 != num * 2) { throw new InvalidDataException("Expected PCM16 at 44100/48000 Hz."); } flag = true; } else if (text == "data") { if (array2 != null || num2 == 0 || num2 % 2 != 0) { throw new InvalidDataException("Invalid PCM data."); } array2 = reader.ReadBytes((int)num2); } memoryStream.Position = num3 + num2 % 2; if (memoryStream.Position > memoryStream.Length) { throw new InvalidDataException("Missing WAV padding."); } } if (!flag || array2 == null || array2.Length / 2 > num * 3) { throw new InvalidDataException("Missing audio or clip exceeds three seconds."); } float[] array3 = new float[array2.Length / 2]; for (int i = 0; i < array3.Length; i++) { array3[i] = (float)(short)(array2[2 * i] | (array2[2 * i + 1] << 8)) / 32768f; } return new PcmWave(num, array3); } finally { if (reader != null) { ((IDisposable)reader).Dispose(); } } string Four() { return Encoding.ASCII.GetString(reader.ReadBytes(4)); } } } public enum Outcome { Charging, Revived, Cancelled, InvalidRequest, InvalidTarget, ItemUnavailable, Busy, EmptyBattery, Interrupted, TimedOut, RevivalFailed } public readonly struct Result { public Outcome Outcome { get; } public double Progress { get; } public int Charge { get; } internal Result(Outcome outcome, double progress, int charge) { Outcome = outcome; Progress = progress; Charge = charge; } } public sealed class RevivalService { private sealed class ItemState { public int Charge; public Session? Session; public ItemState(int charge) { Charge = charge; } } private sealed class Session { public int Actor; public int Target; public string Life = ""; public long Damage; public double Started; public double LastHeartbeat; } private readonly Settings settings; private readonly IRevivalWorld world; private readonly Func<double> clock; private readonly Dictionary<string, ItemState> items = new Dictionary<string, ItemState>(); private readonly HashSet<string> completedLives = new HashSet<string>(); private double lastTime = double.NegativeInfinity; private bool inCommit; public RevivalService(Settings settings, IRevivalWorld world, Func<double> monotonicClock) { this.settings = settings ?? throw new ArgumentNullException("settings"); this.world = world ?? throw new ArgumentNullException("world"); clock = monotonicClock ?? throw new ArgumentNullException("monotonicClock"); } public void RegisterItem(string itemId, int charge = 100) { EnsureNotCommitting(); ValidateItemId(itemId); ValidateCharge(charge); if (items.ContainsKey(itemId)) { throw new InvalidOperationException("Item already registered."); } items.Add(itemId, new ItemState(charge)); } public void RemoveItem(string itemId) { EnsureNotCommitting(); items.Remove(itemId); } public int GetCharge(string itemId) { if (!items.TryGetValue(itemId, out ItemState value)) { throw new ArgumentException("Unknown item.", "itemId"); } return value.Charge; } public void UpdateChargeFromCharger(string itemId, int charge) { EnsureNotCommitting(); ValidateCharge(charge); if (!items.TryGetValue(itemId, out ItemState value)) { throw new ArgumentException("Unknown item."); } value.Session = null; value.Charge = charge; } public Result Hold(int authenticatedActor, string itemId, int targetActor) { EnsureNotCommitting(); double num = ReadTime(); Expire(num); if (authenticatedActor <= 0 || targetActor <= 0 || authenticatedActor == targetActor || string.IsNullOrWhiteSpace(itemId)) { return new Result(Outcome.InvalidRequest, 0.0, 0); } if (!items.TryGetValue(itemId, out ItemState value)) { return new Result(Outcome.ItemUnavailable, 0.0, 0); } Session session = value.Session; if (session != null && session.Actor != authenticatedActor) { return Respond(Outcome.Busy, value); } if (session != null && session.Target != targetActor) { value.Session = null; session = null; } Observation observation = world.Observe(authenticatedActor, itemId, targetActor); if (!Eligible(observation) || completedLives.Contains(LifeKey(targetActor, observation.TargetLifeId))) { value.Session = null; return Respond(Outcome.InvalidTarget, value); } if (value.Charge < settings.BatteryCost) { value.Session = null; return Respond(Outcome.EmptyBattery, value); } if (session != null && (session.Damage != observation.DamageRevision || session.Life != observation.TargetLifeId)) { value.Session = null; return Respond(Outcome.Interrupted, value); } if (session == null) { foreach (ItemState value2 in items.Values) { if (value2.Session != null && (value2.Session.Target == targetActor || value2.Session.Actor == authenticatedActor)) { return Respond(Outcome.Busy, value); } } value.Session = new Session { Actor = authenticatedActor, Target = targetActor, Life = observation.TargetLifeId, Damage = observation.DamageRevision, Started = num, LastHeartbeat = num }; return Respond(Outcome.Charging, value); } session.LastHeartbeat = num; double num2 = Math.Min(1.0, (num - session.Started) / settings.HoldSeconds); if (num2 < 1.0) { return new Result(Outcome.Charging, num2, value.Charge); } value.Session = null; inCommit = true; bool flag; try { flag = world.TryRevive(authenticatedActor, targetActor, session.Life, settings.RevivalHealth); } finally { inCommit = false; } if (!flag) { return Respond(Outcome.RevivalFailed, value); } completedLives.Add(LifeKey(targetActor, session.Life)); value.Charge -= settings.BatteryCost; return new Result(Outcome.Revived, 1.0, value.Charge); } public Result Release(int authenticatedActor, string itemId) { EnsureNotCommitting(); if (!items.TryGetValue(itemId, out ItemState value)) { return new Result(Outcome.ItemUnavailable, 0.0, 0); } if (value.Session != null && value.Session.Actor != authenticatedActor) { return Respond(Outcome.Busy, value); } value.Session = null; return Respond(Outcome.Cancelled, value); } public void Tick() { EnsureNotCommitting(); Expire(ReadTime()); foreach (KeyValuePair<string, ItemState> item in items) { Session session = item.Value.Session; if (session != null) { Observation observation = world.Observe(session.Actor, item.Key, session.Target); if (!Eligible(observation) || observation.DamageRevision != session.Damage || observation.TargetLifeId != session.Life) { item.Value.Session = null; } } } } public void CancelActor(int actorId) { EnsureNotCommitting(); foreach (ItemState value in items.Values) { if (value.Session != null && (value.Session.Actor == actorId || value.Session.Target == actorId)) { value.Session = null; } } } public void CancelAll() { EnsureNotCommitting(); foreach (ItemState value in items.Values) { value.Session = null; } } private void Expire(double now) { foreach (ItemState value in items.Values) { if (value.Session != null && now - value.Session.LastHeartbeat > settings.HeartbeatTimeoutSeconds) { value.Session = null; } } } private bool Eligible(Observation observation) { if (observation != null && observation.RoundAllowsRevival && observation.OperatorAlive && observation.OperatorHoldsItem && observation.TargetDead && observation.HasLineOfSight && Settings.Finite(observation.DistanceMeters) && observation.DistanceMeters >= 0.0 && observation.DistanceMeters <= settings.RangeMeters) { return !string.IsNullOrWhiteSpace(observation.TargetLifeId); } return false; } private double ReadTime() { double num = clock(); if (!Settings.Finite(num) || num < lastTime) { throw new InvalidOperationException("Clock must be finite and monotonic."); } lastTime = num; return num; } private void EnsureNotCommitting() { if (inCommit) { throw new InvalidOperationException("Revival callbacks must not reenter the service."); } } private static void ValidateCharge(int charge) { if (charge < 0 || charge > 100) { throw new ArgumentOutOfRangeException("charge"); } } private static void ValidateItemId(string itemId) { if (string.IsNullOrWhiteSpace(itemId)) { throw new ArgumentException("An item ID is required.", "itemId"); } } private static string LifeKey(int target, string life) { return target + ":" + life; } private static Result Respond(Outcome outcome, ItemState item) { return new Result(outcome, 0.0, item.Charge); } } public sealed class Settings { public double HoldSeconds { get; } public double RangeMeters { get; } public int RevivalHealth { get; } public int BatteryCost { get; } public int Price { get; } public double HeartbeatTimeoutSeconds { get; } public Settings(double holdSeconds = 3.0, double rangeMeters = 2.0, int revivalHealth = 1, int batteryCost = 50, int price = 2, double heartbeatTimeoutSeconds = 0.75) { if (!Finite(holdSeconds) || holdSeconds < 0.25 || holdSeconds > 30.0) { throw new ArgumentOutOfRangeException("holdSeconds"); } if (!Finite(rangeMeters) || rangeMeters <= 0.0 || rangeMeters > 10.0) { throw new ArgumentOutOfRangeException("rangeMeters"); } if (revivalHealth < 1 || revivalHealth > 100) { throw new ArgumentOutOfRangeException("revivalHealth"); } if (batteryCost < 1 || batteryCost > 100) { throw new ArgumentOutOfRangeException("batteryCost"); } if (price < 0) { throw new ArgumentOutOfRangeException("price"); } if (!Finite(heartbeatTimeoutSeconds) || heartbeatTimeoutSeconds <= 0.0 || heartbeatTimeoutSeconds > 2.0) { throw new ArgumentOutOfRangeException("heartbeatTimeoutSeconds"); } HoldSeconds = holdSeconds; RangeMeters = rangeMeters; RevivalHealth = revivalHealth; BatteryCost = batteryCost; Price = price; HeartbeatTimeoutSeconds = heartbeatTimeoutSeconds; } internal static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public sealed class VoiceEffect { public float Pitch { get; } public double VoiceExpiresAt { get; } public double NextShockAt { get; private set; } public double ShockInterval { get; } public int Sequence { get; private set; } public double NextAnimalAt { get; private set; } public double AnimalInterval { get; } public int AnimalSequence { get; private set; } public string Round { get; } public string Token { get; } public VoiceEffect(float pitch, double voiceExpiresAt, double nextShockAt, double shockInterval, string round, string token, int sequence = 0, double? nextAnimalAt = null, double animalInterval = 30.0, int animalSequence = 0) { if (!Settings.Finite(pitch) || pitch < 0.5f || pitch > 2f) { throw new ArgumentOutOfRangeException("pitch"); } if (!Settings.Finite(voiceExpiresAt) || voiceExpiresAt < 0.0) { throw new ArgumentOutOfRangeException("voiceExpiresAt"); } if (!Settings.Finite(nextShockAt) || nextShockAt < 0.0) { throw new ArgumentOutOfRangeException("nextShockAt"); } if (!Settings.Finite(shockInterval) || shockInterval < 5.0 || shockInterval > 300.0) { throw new ArgumentOutOfRangeException("shockInterval"); } if (string.IsNullOrWhiteSpace(round)) { throw new ArgumentException("A round identity is required.", "round"); } if (string.IsNullOrWhiteSpace(token)) { throw new ArgumentException("An effect identity is required.", "token"); } if (sequence < 0) { throw new ArgumentOutOfRangeException("sequence"); } if (!Settings.Finite(animalInterval) || animalInterval < 5.0 || animalInterval > 300.0 || !Settings.Finite(nextAnimalAt ?? nextShockAt) || (nextAnimalAt ?? nextShockAt) < 0.0 || animalSequence < 0) { throw new ArgumentOutOfRangeException("animalInterval"); } Pitch = pitch; VoiceExpiresAt = voiceExpiresAt; NextShockAt = nextShockAt; ShockInterval = shockInterval; Round = round; Token = token; Sequence = sequence; NextAnimalAt = nextAnimalAt ?? nextShockAt; AnimalInterval = animalInterval; AnimalSequence = animalSequence; } public bool IsActive(double now, string round, bool playerAlive) { return Settings.Finite(now) && Round == round && playerAlive; } public bool HasVoice(double now, string round, bool playerAlive) { if (IsActive(now, round, playerAlive)) { return now < VoiceExpiresAt; } return false; } public bool TryShock(double now, string round, bool playerAlive) { if (!IsActive(now, round, playerAlive) || now < NextShockAt) { return false; } NextShockAt = now + ShockInterval; checked { Sequence++; return true; } } public bool TryAnimal(double now, string round, bool playerAlive) { if (!IsActive(now, round, playerAlive) || now < NextAnimalAt) { return false; } NextAnimalAt = now + AnimalInterval; checked { AnimalSequence++; return true; } } public static float ChoosePitch(int coin, float high = 1.8f, float low = 0.55f) { if (coin != 0 && coin != 1) { throw new ArgumentOutOfRangeException("coin"); } if (!Settings.Finite(high) || high <= 1f || high > 2f || !Settings.Finite(low) || low < 0.5f || low >= 1f) { throw new ArgumentOutOfRangeException("high", "High must be in (1,2]; low must be in [0.5,1)."); } if (coin != 0) { return low; } return high; } } public sealed class Observation { public bool RoundAllowsRevival { get; } public bool OperatorAlive { get; } public bool OperatorHoldsItem { get; } public bool TargetDead { get; } public bool HasLineOfSight { get; } public double DistanceMeters { get; } public long DamageRevision { get; } public string TargetLifeId { get; } public Observation(bool roundAllowsRevival, bool operatorAlive, bool operatorHoldsItem, bool targetDead, bool hasLineOfSight, double distanceMeters, long damageRevision, string targetLifeId) { RoundAllowsRevival = roundAllowsRevival; OperatorAlive = operatorAlive; OperatorHoldsItem = operatorHoldsItem; TargetDead = targetDead; HasLineOfSight = hasLineOfSight; DistanceMeters = distanceMeters; DamageRevision = damageRevision; TargetLifeId = targetLifeId; } } public interface IRevivalWorld { Observation Observe(int actorId, string itemId, int targetActorId); bool TryRevive(int actorId, int targetActorId, string targetLifeId, int health); } }
BepInEx/plugins/IndustrialDefibrillator/Defibrillator.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Defibrillator.Core; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using REPOLib.Modules; using TMPro; using UnityEngine; using UnityEngine.Events; [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("Defibrillator")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.5.0")] [assembly: AssemblyInformationalVersion("0.1.5+9d197fcbfb4d444b476161ad58b79e319e14f80f")] [assembly: AssemblyProduct("Defibrillator")] [assembly: AssemblyTitle("Defibrillator")] [assembly: AssemblyVersion("0.1.5.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 Defibrillator.Mod { public sealed class AftershockCamera : MonoBehaviour { private PlayerAvatar target; private float started; private float duration; private float yaw; private float delivered; internal static void Spawn(PlayerAvatar player, float degrees, float seconds) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (GameAccess.IsLocal(player) && degrees != 0f) { AftershockCamera aftershockCamera = new GameObject("Defibrillator camera jolt").AddComponent<AftershockCamera>(); aftershockCamera.target = player; aftershockCamera.started = Time.unscaledTime; aftershockCamera.duration = Mathf.Min(0.65f, seconds); aftershockCamera.yaw = degrees; } } private void Update() { if (!Object.op_Implicit((Object)(object)target) || !GameAccess.IsLocal(target) || !GameAccess.IsAlive(target) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.RunIsLevel() || !Object.op_Implicit((Object)(object)CameraAim.Instance) || !Object.op_Implicit((Object)(object)GameDirector.instance) || GameDirector.instance.DisableInput || !GameAccess.InputAllowed()) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } float num = (Time.unscaledTime - started) / duration; float num2 = AftershockImpact.YawAt(yaw, (double)num); CameraAim.Instance.AdditiveAimX(num2 - delivered); delivered = num2; if (num >= 1f) { Object.Destroy((Object)(object)((Component)this).gameObject); } } } public sealed class AftershockVisual : MonoBehaviour { private PlayerAvatar target; private readonly LineRenderer[] arcs = (LineRenderer[])(object)new LineRenderer[7]; private float ends; private int seed; private Material material; internal static void Spawn(PlayerAvatar player, int sequence, float strength, float seconds) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if (GameAccess.IsLocal(player) && Object.op_Implicit((Object)(object)GameDirector.instance) && Object.op_Implicit((Object)(object)GameDirector.instance.CameraShake)) { GameDirector.instance.CameraShake.Shake(strength, seconds, 0f); } GameObject val = new GameObject("Defibrillator harmless aftershock"); AftershockVisual aftershockVisual = val.AddComponent<AftershockVisual>(); aftershockVisual.target = player; aftershockVisual.ends = Time.unscaledTime + seconds; aftershockVisual.seed = sequence; Shader val2 = Shader.Find("Sprites/Default") ?? Shader.Find("Standard"); if (!Object.op_Implicit((Object)(object)val2)) { Plugin.Error("No aftershock shader found; camera shake applied but visible arcs unavailable."); Object.Destroy((Object)(object)val); return; } aftershockVisual.material = new Material(val2); aftershockVisual.material.color = new Color(0.3f, 0.8f, 1f, 1f); for (int i = 0; i < aftershockVisual.arcs.Length; i++) { GameObject val3 = new GameObject("Electrical arc"); val3.transform.SetParent(val.transform, false); LineRenderer val4 = val3.AddComponent<LineRenderer>(); val4.useWorldSpace = false; ((Renderer)val4).sharedMaterial = aftershockVisual.material; val4.positionCount = 9; val4.startWidth = 0.035f; val4.endWidth = 0.018f; aftershockVisual.arcs[i] = val4; } AudioSource obj = val.AddComponent<AudioSource>(); obj.spatialBlend = 1f; obj.rolloffMode = (AudioRolloffMode)1; obj.minDistance = 1f; obj.maxDistance = 14f; obj.volume = 0.45f; obj.PlayOneShot(OriginalAssets.Shock); } private void Update() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)target) || !GameAccess.IsAlive(target) || !Object.op_Implicit((Object)(object)RunManager.instance) || !SemiFunc.RunIsLevel() || Time.unscaledTime >= ends) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } ((Component)this).transform.position = ((Component)target).transform.position + Vector3.up * 0.3f; for (int i = 0; i < arcs.Length; i++) { if (Object.op_Implicit((Object)(object)arcs[i])) { for (int j = 0; j < 9; j++) { float num = (float)j / 8f; float num2 = (float)i * MathF.PI * 2f / (float)arcs.Length + num * 2f + (float)seed; float num3 = Mathf.Sin(Time.unscaledTime * 83f + (float)(j * 5) + (float)(i * 11)) * 0.12f; arcs[i].SetPosition(j, new Vector3(Mathf.Cos(num2) * (0.4f + num3), Mathf.Lerp(-0.35f, 0.65f, num), Mathf.Sin(num2) * (0.4f + num3))); } } } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)material)) { Object.Destroy((Object)(object)material); } } } internal static class AnimalClips { internal static readonly string[] Names = new string[4] { "sheep", "cat", "dog", "horse" }; private static readonly AudioClip[] clips = (AudioClip[])(object)new AudioClip[4]; private static readonly PcmWave[] data = (PcmWave[])(object)new PcmWave[4]; internal static bool Ready { get; private set; } internal static void Load() { try { for (int i = 0; i < Names.Length; i++) { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Defibrillator.Animals." + Names[i] + ".wav") ?? throw new InvalidDataException("Missing embedded animal clip: " + Names[i]); data[i] = PcmWave.Read(stream); clips[i] = AudioClip.Create("Defibrillator " + Names[i], data[i].Samples.Length, 1, data[i].SampleRate, false); if (!clips[i].SetData(data[i].Samples, 0)) { throw new InvalidDataException("Could not load animal PCM data."); } } Ready = true; Plugin.LogInfo("Loaded four embedded animal recordings, each at most three seconds."); } catch (Exception ex) { Ready = false; AudioClip[] array = clips; foreach (AudioClip val in array) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } Plugin.Error("Animal audio disabled; normal voice is preserved. " + ex); } } internal static AudioClip Get(int index) { return clips[index]; } internal static float Level(int index, int sample) { float[] samples = data[index].Samples; double num = 0.0; int num2 = Math.Max(0, Math.Min(sample, samples.Length - 1)); int num3 = Math.Min(512, samples.Length - num2); for (int i = num2; i < num2 + num3; i++) { num += (double)(samples[i] * samples[i]); } return Mathf.Clamp((float)Math.Sqrt(num / (double)num3) * 2f, 0f, 0.25f); } } public sealed class AnimalVoicePlayback : MonoBehaviour { private static readonly Dictionary<int, AnimalVoicePlayback> active = new Dictionary<int, AnimalVoicePlayback>(); private static readonly FieldInfo talking = AccessTools.Field(typeof(PlayerVoiceChat), "isTalking"); private static readonly FieldInfo loudness = AccessTools.Field(typeof(PlayerVoiceChat), "clipLoudness"); private static readonly FieldInfo talkStart = AccessTools.Field(typeof(PlayerVoiceChat), "isTalkingStartTime"); private static readonly FieldInfo voiceGain = AccessTools.Field(typeof(PlayerVoiceChat), "voiceGain"); private PlayerAvatar target; private PlayerVoiceChat voice; private AudioSource source; private string token = ""; private int id; private int animal; private double ends; private float started; private bool overridden; private bool nativeTalking; private float nativeLoudness; private float nativeStart; private bool Playing { get { if (Object.op_Implicit((Object)(object)target) && Object.op_Implicit((Object)(object)voice) && Object.op_Implicit((Object)(object)source) && source.isPlaying && VoiceDebuffs.Now < ends && GameAccess.IsAlive(target) && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && VoiceDebuffs.Effects.TryGetValue(id, out VoiceEffect value)) { return value.Token == token; } return false; } } internal static void Play(int targetId, string effectToken, int index, double at) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Invalid comparison between Unknown and I4 if (!AnimalClips.Ready || index < 0 || index >= 4) { return; } PlayerAvatar val = GameAccess.FindPlayer(targetId); PlayerVoiceChat val2 = (Object.op_Implicit((Object)(object)val) ? GameAccess.Voice(val) : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2)) { return; } AudioClip val3 = AnimalClips.Get(index); double num = VoiceDebuffs.Now - at; if (!(num < -1.0) && !(num >= (double)val3.length)) { Stop(targetId); GameObject val4 = new GameObject("Defibrillator animal voice - " + AnimalClips.Names[index]); AnimalVoicePlayback animalVoicePlayback = val4.AddComponent<AnimalVoicePlayback>(); animalVoicePlayback.id = targetId; animalVoicePlayback.target = val; animalVoicePlayback.voice = val2; animalVoicePlayback.token = effectToken; animalVoicePlayback.animal = index; animalVoicePlayback.ends = at + (double)val3.length; animalVoicePlayback.started = Time.time; val4.transform.position = ((Component)val2).transform.position; animalVoicePlayback.source = val4.AddComponent<AudioSource>(); AudioSource component = ((Component)val2).GetComponent<AudioSource>(); animalVoicePlayback.source.clip = val3; animalVoicePlayback.source.pitch = 1f; animalVoicePlayback.source.dopplerLevel = 0f; animalVoicePlayback.source.playOnAwake = false; animalVoicePlayback.source.loop = false; animalVoicePlayback.source.spatialBlend = (GameAccess.IsLocal(val) ? 0f : component.spatialBlend); animalVoicePlayback.source.rolloffMode = component.rolloffMode; animalVoicePlayback.source.minDistance = component.minDistance; animalVoicePlayback.source.maxDistance = component.maxDistance; if ((int)component.rolloffMode == 2) { animalVoicePlayback.source.SetCustomCurve((AudioSourceCurveType)0, component.GetCustomCurve((AudioSourceCurveType)0)); } animalVoicePlayback.source.outputAudioMixerGroup = val2.mixerMicrophoneSound; animalVoicePlayback.source.volume = VoiceDebuffs.AnimalVolume * (GameAccess.IsLocal(val) ? 1f : Mathf.Clamp01((float)voiceGain.GetValue(val2) * 2f)); active[targetId] = animalVoicePlayback; animalVoicePlayback.source.Play(); animalVoicePlayback.source.time = Mathf.Max(0f, (float)num); } } private void Update() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (!Playing) { Stop(id); return; } ((Component)this).transform.position = ((Component)voice).transform.position; source.outputAudioMixerGroup = voice.mixerMicrophoneSound; source.volume = VoiceDebuffs.AnimalVolume * (GameAccess.IsLocal(target) ? 1f : Mathf.Clamp01((float)voiceGain.GetValue(voice) * 2f)); } internal static void BeforeVoice(PlayerVoiceChat instance) { foreach (AnimalVoicePlayback value in active.Values) { if ((Object)(object)value.voice == (Object)(object)instance) { value.Restore(); if (value.Playing) { instance.OverrideVolumeMute(0.05f); } } } } internal static void AfterVoice(PlayerVoiceChat instance) { foreach (AnimalVoicePlayback value in active.Values) { if ((Object)(object)value.voice == (Object)(object)instance && value.Playing) { value.nativeTalking = (bool)talking.GetValue(instance); value.nativeLoudness = (float)loudness.GetValue(instance); value.nativeStart = (float)talkStart.GetValue(instance); float num = AnimalClips.Level(value.animal, value.source.timeSamples); talking.SetValue(instance, num > 0.005f); loudness.SetValue(instance, num); talkStart.SetValue(instance, value.started); value.overridden = true; } } } private void Restore() { if (overridden && Object.op_Implicit((Object)(object)voice)) { talking.SetValue(voice, nativeTalking); loudness.SetValue(voice, nativeLoudness); talkStart.SetValue(voice, nativeStart); overridden = false; } } internal static void Stop(int targetId) { if (active.TryGetValue(targetId, out AnimalVoicePlayback value)) { active.Remove(targetId); value.Restore(); if (Object.op_Implicit((Object)(object)value.source)) { value.source.Stop(); } Object.Destroy((Object)(object)((Component)value).gameObject); } } internal static void StopAll() { foreach (int item in new List<int>(active.Keys)) { Stop(item); } } private void OnDestroy() { Restore(); if (active.TryGetValue(id, out AnimalVoicePlayback value) && (Object)(object)value == (Object)(object)this) { active.Remove(id); } } } [HarmonyPatch(typeof(PlayerVoiceChat), "IsTalkingRPC")] internal static class AnimalTalkingRpcPatch { [HarmonyPrefix] private static void Prefix(PlayerVoiceChat __instance) { AnimalVoicePlayback.BeforeVoice(__instance); } [HarmonyPostfix] private static void Postfix(PlayerVoiceChat __instance) { AnimalVoicePlayback.AfterVoice(__instance); } } internal static class BatteryDisplayFallback { internal static BatteryVisualLogic? FindTemplate() { if (Object.op_Implicit((Object)(object)BatteryUI.instance) && SelfContained(BatteryUI.instance.batteryVisualLogic)) { return BatteryUI.instance.batteryVisualLogic; } BatteryVisualLogic[] array = Resources.FindObjectsOfTypeAll<BatteryVisualLogic>(); foreach (BatteryVisualLogic val in array) { if (SelfContained(val)) { return val; } } return null; } private static bool SelfContained(BatteryVisualLogic visual) { if (!Object.op_Implicit((Object)(object)visual) || !Object.op_Implicit((Object)(object)visual.batteryBarPrefab) || !Object.op_Implicit((Object)(object)visual.barLossEffectPrefab)) { return false; } if (Owns(visual, (Component)(object)visual.batteryBarContainerGroup) && Owns(visual, (Component)(object)visual.batteryBarContainer) && Owns(visual, (Component)(object)visual.batteryBarCharge) && Owns(visual, (Component)(object)visual.batteryBarDrain) && Owns(visual, (Component)(object)visual.batteryBorderShadow) && Owns(visual, (Component)(object)visual.batteryBorderMain) && Owns(visual, (Component)(object)visual.batteryBackground) && Owns(visual, (Component)(object)visual.batteryCharge) && Owns(visual, (Component)(object)visual.batteryDrain) && Object.op_Implicit((Object)(object)visual.batteryOutVisual) && Object.op_Implicit((Object)(object)visual.batteryChargeNeededVisual) && visual.batteryOutVisual.transform.IsChildOf(((Component)visual).transform)) { return visual.batteryChargeNeededVisual.transform.IsChildOf(((Component)visual).transform); } return false; } private static bool Owns(BatteryVisualLogic root, Component component) { if (Object.op_Implicit((Object)(object)component)) { if (!((Object)(object)component.transform == (Object)(object)((Component)root).transform)) { return component.transform.IsChildOf(((Component)root).transform); } return true; } return false; } internal static void Attach(GameObject prefab, BatteryVisualLogic template) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown GameObject val = new GameObject("Defibrillator native battery bookkeeping", new Type[2] { typeof(RectTransform), typeof(Canvas) }); val.transform.SetParent(prefab.transform, false); ((Behaviour)val.GetComponent<Canvas>()).enabled = false; GameObject val2 = Object.Instantiate<GameObject>(((Component)template).gameObject, val.transform); ((Object)val2).name = "Private battery display"; BatteryVisualLogic component = val2.GetComponent<BatteryVisualLogic>(); component.inUI = true; component.cameraTurn = false; component.itemBattery = prefab.GetComponent<ItemBattery>(); Canvas[] componentsInChildren = val2.GetComponentsInChildren<Canvas>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } val2.SetActive(true); prefab.GetComponent<ItemBattery>().hasBatteryVisuals = false; Plugin.LogInfo("Attached a private native battery-display fallback; the shared HUD is unchanged."); } } public sealed class Device : MonoBehaviour { internal static readonly HashSet<Device> Active = new HashSet<Device>(); internal ItemAttributes Attributes; internal ItemBattery Battery; internal PhotonView View; private PhysGrabObject physical; private RevivalService? registeredWith; private string registeredId = ""; private bool started; private float nextInput; private bool holding; private int lastOperator; private float progress; private string message = "Aim at a dead player's head and hold Interact"; private float lastFeedback; private AudioSource audioSource; private Renderer[] indicators = Array.Empty<Renderer>(); private readonly MaterialPropertyBlock indicatorColor = new MaterialPropertyBlock(); internal string Id { get { if (!SemiFunc.IsMultiplayer()) { return "local:" + ((Object)this).GetInstanceID(); } return "net:" + View.ViewID; } } internal bool Ready { get { if (started) { if (SemiFunc.IsMultiplayer()) { return View.ViewID > 0; } return true; } return false; } } internal int NetworkId => View.ViewID; private void OnEnable() { Active.Add(this); } private IEnumerator Start() { Attributes = ((Component)this).GetComponent<ItemAttributes>(); Battery = ((Component)this).GetComponent<ItemBattery>(); physical = ((Component)this).GetComponent<PhysGrabObject>(); View = ((Component)this).GetComponent<PhotonView>(); audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); audioSource.spatialBlend = 1f; audioSource.rolloffMode = (AudioRolloffMode)1; audioSource.minDistance = 1f; audioSource.maxDistance = 12f; audioSource.volume = 0.45f; audioSource.playOnAwake = false; indicators = (from renderer in ((Component)this).GetComponentsInChildren<Renderer>(true) where ((Object)renderer).name.StartsWith("Cell ") select renderer).ToArray(); yield return null; ((Component)this).GetComponent<Rigidbody>().ResetInertiaTensor(); started = true; } internal bool IsHeldBy(PlayerAvatar player) { if (Object.op_Implicit((Object)(object)physical)) { return physical.playerGrabbing.Any((PhysGrabber grabber) => Object.op_Implicit((Object)(object)grabber) && (Object)(object)grabber.playerAvatar == (Object)(object)player); } return false; } internal void SyncHostBattery() { RevivalService service = Plugin.Service; if (!Ready || service == null) { return; } int num = Mathf.FloorToInt(Mathf.Clamp(Battery.batteryLife, 0f, 100f)); if (registeredWith != service || registeredId != Id) { RevivalService? obj = registeredWith; if (obj != null) { obj.RemoveItem(registeredId); } service.RegisterItem(Id, num); registeredWith = service; registeredId = Id; } else if (service.GetCharge(Id) != num) { service.UpdateChargeFromCharger(Id, num); } } private void Update() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.Operational || !Ready || !Object.op_Implicit((Object)(object)PlayerAvatar.instance) || !Object.op_Implicit((Object)(object)RunManager.instance)) { return; } for (int i = 0; i < indicators.Length; i++) { Color val = ((Battery.batteryLife >= (float)((i + 1) * 25)) ? new Color(0.15f, 0.95f, 0.3f) : new Color(0.04f, 0.06f, 0.04f)); indicatorColor.SetColor("_Color", val); indicatorColor.SetColor("_BaseColor", val); indicators[i].SetPropertyBlock(indicatorColor); } PlayerAvatar instance = PlayerAvatar.instance; if (!IsHeldBy(instance) || !GameAccess.IsLocal(instance) || !SemiFunc.RunIsLevel() || !GameAccess.InputAllowed() || !GameAccess.IsAlive(instance) || !SemiFunc.InputHold((InputKey)2)) { if (holding) { Plugin.Instance.Network.Send(this, lastOperator, 0, release: true); } holding = false; progress = 0f; return; } int actor = GameAccess.PlayerId(instance); int num = FindAimedTarget(instance); if (num == 0) { if (holding) { Plugin.Instance.Network.Send(this, actor, 0, release: true); } holding = false; progress = 0f; message = "Aim at a dead player's head within range"; } else if (!(Time.unscaledTime < nextInput)) { nextInput = Time.unscaledTime + 0.15f; holding = true; lastOperator = actor; Plugin.Instance.Network.Send(this, actor, num, release: false); } } private int FindAimedTarget(PlayerAvatar player) { if (!Object.op_Implicit((Object)(object)GameDirector.instance)) { return 0; } int result = 0; double num = double.PositiveInfinity; foreach (PlayerAvatar player2 in GameDirector.instance.PlayerList) { if (Object.op_Implicit((Object)(object)player2) && !((Object)(object)player2 == (Object)(object)player)) { Observation val = Plugin.World.Observe(GameAccess.PlayerId(player), Id, GameAccess.PlayerId(player2)); if (val.TargetDead && val.HasLineOfSight && val.DistanceMeters < num) { num = val.DistanceMeters; result = GameAccess.PlayerId(player2); } } } return result; } internal void Feedback(int operatorId, Outcome outcome, float value, int charge) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected I4, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if ((int)outcome == 1) { audioSource.PlayOneShot(OriginalAssets.Shock); } if (Object.op_Implicit((Object)(object)PlayerAvatar.instance) && GameAccess.PlayerId(PlayerAvatar.instance) == operatorId) { progress = Mathf.Clamp01(value); lastFeedback = Time.unscaledTime; message = (int)outcome switch { 0 => "Charging — keep holding Interact", 1 => "Revived • battery " + charge + "%", 7 => "Recharge the defibrillator", 6 => "Another revival is in progress", 8 => "Revival interrupted", 4 => "Target unavailable or out of range", 10 => "Revival failed — no battery consumed", _ => "Aim at a dead player's head and hold Interact", }; if ((int)outcome == 0 && value == 0f) { audioSource.PlayOneShot(OriginalAssets.StartCharge); } } } private void OnGUI() { //IL_008f: 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) if (Ready && Object.op_Implicit((Object)(object)PlayerAvatar.instance) && IsHeldBy(PlayerAvatar.instance) && SemiFunc.RunIsLevel()) { if (holding && Time.unscaledTime - lastFeedback > 1.5f) { progress = 0f; message = "Waiting for host"; } Rect val = default(Rect); ((Rect)(ref val))..ctor((float)Screen.width / 2f - 190f, (float)Screen.height / 2f + 70f, 380f, 65f); GUI.Box(val, "DEFIBRILLATOR • " + Mathf.FloorToInt(Battery.batteryLife) + "%\n" + message); GUI.Box(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 48f, 360f * progress, 8f), ""); } } private void OnDisable() { Active.Remove(this); if (holding && Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Network != null && Object.op_Implicit((Object)(object)GameManager.instance) && Ready) { Plugin.Instance.Network.Send(this, lastOperator, 0, release: true); } RevivalService? obj = registeredWith; if (obj != null) { obj.RemoveItem(registeredId); } registeredWith = null; holding = false; } internal void ResetInput() { holding = false; progress = 0f; nextInput = 0f; message = "Aim at a dead player's head and hold Interact"; } } internal static class DevicePhysics { internal static void ConfigurePrefab(GameObject prefab) { //IL_0006: 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_00c7: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_0251: 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_0283: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: 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_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: 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_0329: Unknown result type (might be due to invalid IL or missing references) prefab.transform.localScale = Vector3.one; prefab.transform.localPosition = Vector3.zero; prefab.transform.localRotation = Quaternion.identity; PhysGrabObject component = prefab.GetComponent<PhysGrabObject>(); PhysGrabObjectCollider[] componentsInChildren = prefab.GetComponentsInChildren<PhysGrabObjectCollider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } PhysGrabObjectBoxCollider[] componentsInChildren2 = prefab.GetComponentsInChildren<PhysGrabObjectBoxCollider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Collider[] componentsInChildren3 = prefab.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } component.colliders.Clear(); foreach (CollisionBox collisionBox in DeviceGeometry.CollisionBoxes) { CollisionBox current = collisionBox; GameObject val = new GameObject("Defibrillator collision - " + ((CollisionBox)(ref current)).Name) { layer = prefab.layer }; val.transform.SetParent(prefab.transform, false); val.transform.localPosition = new Vector3(((CollisionBox)(ref current)).X, ((CollisionBox)(ref current)).Y, ((CollisionBox)(ref current)).Z) * 0.5f; val.AddComponent<BoxCollider>().size = new Vector3(((CollisionBox)(ref current)).Width, ((CollisionBox)(ref current)).Height, ((CollisionBox)(ref current)).Depth) * 0.5f; val.AddComponent<PhysGrabObjectCollider>(); val.AddComponent<PhysGrabObjectBoxCollider>().drawGizmos = false; } Rigidbody component2 = prefab.GetComponent<Rigidbody>(); component2.mass = 3f; component2.useGravity = true; component2.linearDamping = 0.35f; component2.angularDamping = 1f; component2.centerOfMass = new Vector3(0f, -0.015f, 0f); component.massOriginal = 3f; NotValuableObject component3 = prefab.GetComponent<NotValuableObject>(); if (Object.op_Implicit((Object)(object)component3)) { PhysAttribute val2 = (Object.op_Implicit((Object)(object)component3.physAttributePreset) ? Object.Instantiate<PhysAttribute>(component3.physAttributePreset) : ScriptableObject.CreateInstance<PhysAttribute>()); ((Object)val2).name = "Industrial Defibrillator physics"; val2.mass = 3f; component3.physAttributePreset = val2; } Transform val3 = prefab.transform.Find("Center of Mass"); if (Object.op_Implicit((Object)(object)val3)) { val3.position = prefab.transform.TransformPoint(component2.centerOfMass); } Transform val4 = prefab.transform.Find("Force Grab Point"); if (Object.op_Implicit((Object)(object)val4)) { val4.position = prefab.transform.position; } RoomVolumeCheck component4 = prefab.GetComponent<RoomVolumeCheck>(); if (Object.op_Implicit((Object)(object)component4)) { component4.CheckPosition = Vector3.zero; component4.currentSize = new Vector3(0.35f, 0.24f, 0.13f); } ItemVolume[] componentsInChildren4 = prefab.GetComponentsInChildren<ItemVolume>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { ((Component)componentsInChildren4[i]).transform.position = prefab.transform.TransformPoint(new Vector3(0f, -0.07875f, 0f)); } prefab.GetComponent<ItemAttributes>().costOffset = new Vector3(0f, 0.2f, 0f); } } [HarmonyPatch(typeof(PhysGrabObject), "Awake")] internal static class CompactScalePatch { [HarmonyPrefix] private static void Prefix(PhysGrabObject __instance) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Device>())) { PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); object[] array = (Object.op_Implicit((Object)(object)component) ? component.InstantiationData : null); if (array != null && array.Length >= 3) { object[] array2 = (object[])array.Clone(); array2[0] = (array2[1] = (array2[2] = 1f)); (AccessTools.PropertySetter(typeof(PhotonView), "InstantiationData") ?? throw new MissingMethodException("PhotonView.InstantiationData setter")).Invoke(component, new object[1] { array2 }); } ((Component)__instance).transform.localScale = Vector3.one; } } } internal static class GameAccess { private static readonly FieldInfo Disabled = Require(typeof(PlayerAvatar), "isDisabled"); private static readonly FieldInfo DeadSet = Require(typeof(PlayerAvatar), "deadSet"); private static readonly FieldInfo TumbleField = Require(typeof(PlayerAvatar), "tumble"); private static readonly FieldInfo Tumbling = Require(typeof(PlayerAvatar), "isTumbling"); private static readonly FieldInfo VoiceField = Require(typeof(PlayerAvatar), "voiceChat"); private static readonly FieldInfo DeathHead = Require(typeof(PlayerAvatar), "playerDeathHead"); private static readonly FieldInfo Health = Require(typeof(PlayerHealth), "health"); private static readonly FieldInfo ShopItem = Require(typeof(ItemAttributes), "shopItem"); private static readonly FieldInfo ItemValue = Require(typeof(ItemAttributes), "value"); private static readonly FieldInfo CameraPosition = Require(typeof(PlayerAvatar), "clientCameraPosition"); private static readonly FieldInfo CameraRotation = Require(typeof(PlayerAvatar), "clientCameraRotation"); private static readonly FieldInfo InputDisabled = Require(typeof(PlayerController), "InputDisableTimer"); private static FieldInfo Require(Type type, string field) { return AccessTools.Field(type, field) ?? throw new MissingFieldException(type.FullName, field); } internal static void Validate() { _ = Disabled; _ = DeathHead; _ = Health; _ = ShopItem; _ = ItemValue; if (AccessTools.Method(typeof(PunManager), "SpawnShopItem", (Type[])null, (Type[])null) == null) { throw new MissingMethodException("PunManager.SpawnShopItem"); } } internal static bool IsDead(PlayerAvatar avatar) { return (bool)Disabled.GetValue(avatar); } internal static PlayerTumble? Tumble(PlayerAvatar avatar) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return (PlayerTumble)TumbleField.GetValue(avatar); } internal static PlayerVoiceChat? Voice(PlayerAvatar avatar) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return (PlayerVoiceChat)VoiceField.GetValue(avatar); } internal static bool IsTumbling(PlayerAvatar avatar) { return (bool)Tumbling.GetValue(avatar); } internal static bool IsAlive(PlayerAvatar avatar) { if (!IsDead(avatar)) { return !(bool)DeadSet.GetValue(avatar); } return false; } internal static PlayerDeathHead? Head(PlayerAvatar avatar) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return (PlayerDeathHead)DeathHead.GetValue(avatar); } internal static int GetHealth(PlayerHealth health) { return (int)Health.GetValue(health); } internal static bool IsShopItem(ItemAttributes attributes) { return (bool)ShopItem.GetValue(attributes); } internal static void SetPrice(ItemAttributes attributes, int price) { ItemValue.SetValue(attributes, price); } internal static int PlayerId(PlayerAvatar avatar) { if (!SemiFunc.IsMultiplayer()) { return 1; } return avatar.photonView.ViewID; } internal static PlayerAvatar? FindPlayer(int id) { if (!SemiFunc.IsMultiplayer()) { if (id != 1) { return null; } return PlayerAvatar.instance; } PhotonView val = PhotonView.Find(id); if (!Object.op_Implicit((Object)(object)val)) { return null; } return ((Component)val).GetComponent<PlayerAvatar>(); } internal static bool IsLocal(PlayerAvatar avatar) { if (SemiFunc.IsMultiplayer()) { return avatar.photonView.IsMine; } return true; } internal static bool InputAllowed() { if (Object.op_Implicit((Object)(object)PlayerController.instance)) { return (float)InputDisabled.GetValue(PlayerController.instance) <= 0f; } return false; } internal static (Vector3 Position, Vector3 Forward) Aim(PlayerAvatar avatar) { //IL_0043: 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_0058: 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_005a: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (IsLocal(avatar) && Object.op_Implicit((Object)(object)Camera.main)) { return (Position: ((Component)Camera.main).transform.position, Forward: ((Component)Camera.main).transform.forward); } Vector3 item = (Vector3)CameraPosition.GetValue(avatar); Quaternion val = (Quaternion)CameraRotation.GetValue(avatar); return (Position: item, Forward: val * Vector3.forward); } } internal sealed class GameWorld : IRevivalWorld { private readonly Dictionary<int, long> damage = new Dictionary<int, long>(); private readonly Dictionary<int, long> lives = new Dictionary<int, long>(); internal void Damaged(PlayerAvatar player) { int key = GameAccess.PlayerId(player); damage[key] = (damage.TryGetValue(key, out var value) ? (value + 1) : 1); } internal void Died(PlayerAvatar player) { int key = GameAccess.PlayerId(player); lives[key] = (lives.TryGetValue(key, out var value) ? (value + 1) : 1); } internal string Life(PlayerAvatar player) { int key = GameAccess.PlayerId(player); long value; return ((Object)player).GetInstanceID() + "/" + (lives.TryGetValue(key, out value) ? value : 0); } public Observation Observe(int actorId, string itemId, int targetActorId) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_0098: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Invalid comparison between Unknown and I4 //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown PlayerAvatar val = GameAccess.FindPlayer(actorId); PlayerAvatar val2 = GameAccess.FindPlayer(targetActorId); Device device = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Id == itemId); PlayerDeathHead val3 = (Object.op_Implicit((Object)(object)val2) ? GameAccess.Head(val2) : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)device) || !device.Ready) { return new Observation(false, false, false, false, false, 999.0, 0L, ""); } (Vector3, Vector3) tuple = GameAccess.Aim(val); Vector3 val4 = ((Component)val3).transform.position - tuple.Item1; float num = Vector3.Dot(val4, tuple.Item2); int num2; if (num >= 0f) { Vector3 val5 = val4 - tuple.Item2 * num; if (((Vector3)(ref val5)).magnitude <= 0.35f) { num2 = (ClearRay(tuple.Item1, ((Component)val3).transform.position, val, val3, device) ? 1 : 0); goto IL_0110; } } num2 = 0; goto IL_0110; IL_0110: bool flag = (byte)num2 != 0; long value; return new Observation(Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && Object.op_Implicit((Object)(object)GameDirector.instance) && (int)GameDirector.instance.currentState == 2 && !GameAccess.IsShopItem(device.Attributes), GameAccess.IsAlive(val), device.IsHeldBy(val), GameAccess.IsDead(val2) && ((Component)val3).gameObject.activeInHierarchy, flag, (double)((Vector3)(ref val4)).magnitude, damage.TryGetValue(actorId, out value) ? value : 0, Life(val2)); } private static bool ClearRay(Vector3 origin, Vector3 destination, PlayerAvatar player, PlayerDeathHead head, Device device) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) Vector3 val = destination - origin; RaycastHit[] array = Physics.RaycastAll(origin, ((Vector3)(ref val)).normalized, ((Vector3)(ref val)).magnitude, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; Transform transform = ((Component)((RaycastHit)(ref val2)).collider).transform; if (!transform.IsChildOf(((Component)player).transform) && !transform.IsChildOf(((Component)device).transform) && !transform.IsChildOf(((Component)head).transform)) { return false; } } return true; } public bool TryRevive(int actorId, int targetActorId, string targetLifeId, int health) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return false; } PlayerAvatar val = GameAccess.FindPlayer(targetActorId); if (!Object.op_Implicit((Object)(object)val) || !GameAccess.IsDead(val) || Life(val) != targetLifeId) { return false; } PlayerDeathHead val2 = GameAccess.Head(val); if (!Object.op_Implicit((Object)(object)val2) || !((Component)val2).gameObject.activeInHierarchy) { return false; } val.Revive(false); if (GameAccess.IsDead(val)) { return false; } if (health > 1) { try { val.playerHealth.HealOther(health - 1, true); } catch (Exception ex) { Plugin.Error("Revival completed, but the additional configured healing failed. " + ex); } } return true; } } internal static class ItemFactory { internal static Item? Item; private static bool failed; private static float nextDiscovery; private static string lastDiscoveryReport = ""; internal unsafe static void EnsureRegistered() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)Item) || failed || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)StatsManager.instance) || Time.realtimeSinceStartup < nextDiscovery) { return; } nextDiscovery = Time.realtimeSinceStartup + 2f; GameObject val = null; try { (Item, GameObject, DonorParts)? tuple = FindDonor(); if (!tuple.HasValue) { return; } (Item, GameObject, DonorParts) value = tuple.Value; BatteryVisualLogic val2 = null; if ((value.Item3 & 0x100) == 0) { val2 = BatteryDisplayFallback.FindTemplate(); if (!Object.op_Implicit((Object)(object)val2)) { ReportDiscovery("Compatible tracker found: " + ((Object)value.Item1).name + "; waiting for a self-contained native battery-display template. Enter a lobby/level so the HUD can initialize."); return; } } Plugin.LogInfo("Native donor selected: " + ((Object)value.Item1).name + "; components=" + ((object)(*(DonorParts*)(&value.Item3))/*cast due to .constrained prefix*/).ToString()); val = new GameObject("Defibrillator Prefab Storage"); val.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val); GameObject val3 = Object.Instantiate<GameObject>(value.Item2, val.transform); ((Object)val3).name = "Item Industrial Defibrillator"; ItemAttributes component = val3.GetComponent<ItemAttributes>(); Item val4 = Object.Instantiate<Item>(value.Item1); ((Object)val4).name = ((Object)val3).name; val4.itemName = "Industrial Defibrillator"; val4.itemNameLocalized = null; val4.description = "Hold Interact while aiming at a dead player's head. Recharge at a charging station."; val4.status = (Status)1; val4.disabled = false; val4.maxAmount = 100; val4.maxAmountInShop = 1; val4.maxPurchase = false; val4.minPlayerCount = 1; val4.spawnRotationOffset = Quaternion.identity; val4.itemSecretShopType = (itemSecretShopType)0; val4.value = ScriptableObject.CreateInstance<Value>(); val4.value.valueMin = (val4.value.valueMax = (float)Plugin.Instance.Settings.Price * 1000f); component.item = val4; component.icon = null; ItemTracker[] componentsInChildren = val3.GetComponentsInChildren<ItemTracker>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } ItemToggle component2 = val3.GetComponent<ItemToggle>(); if (Object.op_Implicit((Object)(object)component2)) { ((Behaviour)component2).enabled = false; component2.toggleState = false; component2.playSound = false; component2.onToggle = new UnityEvent(); } ItemBattery component3 = val3.GetComponent<ItemBattery>(); component3.autoDrain = false; component3.batteryActive = false; component3.isUnchargable = false; if (Object.op_Implicit((Object)(object)val2)) { BatteryDisplayFallback.Attach(val3, val2); } Light[] componentsInChildren2 = val3.GetComponentsInChildren<Light>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } TMP_Text[] componentsInChildren3 = val3.GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { ((Behaviour)componentsInChildren3[i]).enabled = false; } DevicePhysics.ConfigurePrefab(val3); OriginalAssets.BuildModel(val3); val3.AddComponent<Device>(); val3.SetActive(true); if (Items.RegisterItem(component) == null) { throw new InvalidOperationException("REPOLib rejected the item prefab."); } Item = val4; Plugin.LogInfo("Registered Industrial Defibrillator using native shell: " + ((Object)value.Item1).name); } catch (Exception ex) { failed = true; if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } Plugin.Error("Item registration failed; no replacement of vanilla items was attempted. " + ex); } } private unsafe static (Item Item, GameObject Prefab, DonorParts Parts)? FindDonor() { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: 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) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: 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_01b2: 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_014c: Unknown result type (might be due to invalid IL or missing references) string folderPath = StatsManager.instance.folderPath; IOrderedEnumerable<Item> orderedEnumerable = (from item in (from item in Resources.LoadAll<Item>(folderPath).Concat(Resources.FindObjectsOfTypeAll<Item>()).Concat(StatsManager.instance.itemDictionary.Values) where Object.op_Implicit((Object)(object)item) && item.prefab != null && ((PrefabRef<GameObject>)(object)item.prefab).IsValid() && ((Object)item).name != "Item Industrial Defibrillator" select item).Distinct() orderby (((Object)item).name.IndexOf("Tracker", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0 select item).ThenBy<Item, string>((Item item) => ((Object)item).name, StringComparer.Ordinal); List<string> list = new List<string>(); (Item, GameObject, DonorParts)? result = null; int num = 0; foreach (Item item in orderedEnumerable) { num++; try { GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab; if (!Object.op_Implicit((Object)(object)prefab)) { list.Add(((Object)item).name + ": prefab unavailable"); continue; } DonorParts val = Parts(item, prefab); if (DonorRequirements.IsCompatible(val)) { if ((val & 0x100) != 0) { return (item, prefab, val); } (Item, GameObject, DonorParts) valueOrDefault = result.GetValueOrDefault(); if (!result.HasValue) { valueOrDefault = (item, prefab, val); result = valueOrDefault; } } if ((val & 1) != 0 || ((Object)item).name.IndexOf("Tracker", StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(((Object)item).name + ": present=" + ((object)(*(DonorParts*)(&val))/*cast due to .constrained prefix*/).ToString() + "; missing=" + ((object)DonorRequirements.Missing(val)/*cast due to .constrained prefix*/).ToString()); } } catch (Exception ex) { list.Add(((Object)item).name + ": load failed: " + ex.GetBaseException().Message); } } if (result.HasValue) { return result; } ReportDiscovery("No compatible tracker prefab is available yet. Folder=" + folderPath + "; definitions examined=" + num + ". Candidate report: " + ((list.Count == 0) ? "no tracker components found" : string.Join(" | ", list))); return null; } private static DonorParts Parts(Item definition, GameObject prefab) { //IL_0001: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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) //IL_0032: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0046: 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_0057: 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_0066: 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_006a: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) DonorParts val = (DonorParts)0; if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ItemTracker>(true))) { val = (DonorParts)(val | 1); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemAttributes>())) { val = (DonorParts)(val | 2); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemBattery>())) { val = (DonorParts)(val | 4); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<ItemEquippable>())) { val = (DonorParts)(val | 8); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<PhysGrabObject>())) { val = (DonorParts)(val | 0x10); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<Rigidbody>())) { val = (DonorParts)(val | 0x20); } if (Object.op_Implicit((Object)(object)prefab.GetComponent<PhotonView>())) { val = (DonorParts)(val | 0x40); } if (Object.op_Implicit((Object)(object)definition.colorPreset)) { val = (DonorParts)(val | 0x80); } if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<BatteryVisualLogic>(true))) { val = (DonorParts)(val | 0x100); } if (Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<ItemReviveItem>(true))) { val = (DonorParts)(val | 0x200); } return val; } private static void ReportDiscovery(string report) { if (!(report == lastDiscoveryReport)) { lastDiscoveryReport = report; Plugin.LogInfo("Donor discovery pending: " + report); } } } internal sealed class NetworkBridge { private const string Protocol = "ciriolopipado.defibrillator/3"; private readonly NetworkedEvent channel; internal NetworkBridge() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown channel = new NetworkedEvent("ciriolopipado.defibrillator/3", (Action<EventData>)Receive); } internal void ResetLocalInput() { foreach (Device item in Device.Active) { if (Object.op_Implicit((Object)(object)item) && item.Ready) { item.ResetInput(); } } } internal void Send(Device device, int actor, int target, bool release) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { Handle(device, actor, target, release); return; } channel.RaiseEvent((object)new object[5] { "ciriolopipado.defibrillator/3", release ? 1 : 0, device.NetworkId, actor, target }, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable); } private void Receive(EventData packet) { //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.Operational || !(packet.CustomData is object[] array) || array.Length < 2 || !(array[0] is string text) || text != "ciriolopipado.defibrillator/3" || !(array[1] is int num)) { return; } try { switch (num) { case 3: if (array.Length == 13 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num8 && num8 > 0 && array[3] is float num9 && array[4] is double num10 && array[5] is double num11 && array[6] is double num12 && array[7] is string { Length: <=256 } text3 && array[8] is string { Length: <=64 } text4 && array[9] is int num13 && array[10] is double value && array[11] is double num14 && array[12] is int num15) { VoiceDebuffs.Receive(num8, new VoiceEffect(num9, num10, num11, num12, text3, text4, num13, (double?)value, num14, num15)); } break; case 6: if (array.Length == 7 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num19 && num19 > 0 && array[3] is string { Length: <=64 } text5 && array[4] is int num20 && num20 > 0 && array[5] is int num21 && num21 >= 0 && num21 < 4 && array[6] is double num22 && !double.IsNaN(num22) && !double.IsInfinity(num22)) { VoiceDebuffs.Animal(num19, text5, num20, num21, num22); } break; case 5: if (array.Length == 9 && PhotonNetwork.MasterClient != null && packet.Sender == PhotonNetwork.MasterClient.ActorNumber && array[2] is int num3 && num3 > 0 && array[3] is string { Length: <=64 } text2 && array[4] is int num4 && num4 > 0 && array[5] is float num5 && array[6] is float num6 && !float.IsNaN(num5) && !(num5 < 0f) && !(num5 > 10f) && !float.IsNaN(num6) && !(num6 < 0.1f) && !(num6 > 2f) && array[7] is float num7 && !float.IsNaN(num7) && !(Math.Abs(num7) > 180f) && array[8] is bool tumble) { VoiceDebuffs.Shock(num3, text2, num4, num5, num6, num7, tumble); } break; case 4: { if (array.Length != 2 || !SemiFunc.IsMasterClientOrSingleplayer()) { break; } Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? currentRoom.GetPlayer(packet.Sender, false) : null) == null) { break; } RaiseEventOptions val2 = new RaiseEventOptions(); val2.TargetActors = new int[1] { packet.Sender }; RaiseEventOptions options = val2; { foreach (KeyValuePair<int, VoiceEffect> effect in VoiceDebuffs.Effects) { SendVoice(effect.Key, effect.Value, options); } break; } } case 2: { if (array.Length != 7 || PhotonNetwork.MasterClient == null || packet.Sender != PhotonNetwork.MasterClient.ActorNumber) { break; } object obj = array[2]; if (!(obj is int)) { break; } int id = (int)obj; if (array[3] is int operatorId && array[4] is int num16 && array[5] is float num17 && array[6] is int num18 && Enum.IsDefined(typeof(Outcome), num16) && !float.IsNaN(num17) && !float.IsInfinity(num17) && num18 >= 0 && num18 <= 100) { Device device2 = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Ready && item.NetworkId == id); if (Object.op_Implicit((Object)(object)device2)) { device2.Feedback(operatorId, (Outcome)num16, num17, num18); } } break; } case 0: case 1: { if (array.Length != 5 || !SemiFunc.IsMasterClientOrSingleplayer()) { break; } object obj = array[2]; if (!(obj is int)) { break; } int itemId = (int)obj; if (!(array[3] is int num2) || !(array[4] is int target)) { break; } PlayerAvatar val = GameAccess.FindPlayer(num2); if (Object.op_Implicit((Object)(object)val) && val.photonView.OwnerActorNr == packet.Sender) { Device device = Device.Active.FirstOrDefault((Device item) => Object.op_Implicit((Object)(object)item) && item.Ready && item.NetworkId == itemId); if (Object.op_Implicit((Object)(object)device)) { Handle(device, num2, target, num == 1); } } break; } } } catch (Exception ex) { RevivalService? service = Plugin.Service; if (service != null) { service.CancelAll(); } Plugin.Error("Defibrillator request failed; active revivals cancelled. " + ex); } } private void Handle(Device device, int actor, int target, bool release) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0048: Invalid comparison between Unknown and I4 //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected I4, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Service == null || !device.Ready) { return; } device.SyncHostBattery(); Result val = (release ? Plugin.Service.Release(actor, device.Id) : Plugin.Service.Hold(actor, device.Id, target)); if ((int)((Result)(ref val)).Outcome == 1) { device.Battery.SetBatteryLife(((Result)(ref val)).Charge); try { VoiceDebuffs.Revived(target); } catch (Exception ex) { Plugin.Error("Revival succeeded, but aftereffects could not be applied. " + ex); } Plugin.LogInfo("Revival completed: operator=" + actor + ", target=" + target + ", battery=" + ((Result)(ref val)).Charge); } device.Feedback(actor, ((Result)(ref val)).Outcome, (float)((Result)(ref val)).Progress, ((Result)(ref val)).Charge); if (SemiFunc.IsMultiplayer()) { channel.RaiseEvent((object)new object[7] { "ciriolopipado.defibrillator/3", 2, device.NetworkId, actor, (int)((Result)(ref val)).Outcome, (float)((Result)(ref val)).Progress, ((Result)(ref val)).Charge }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } internal void SendVoice(int target, VoiceEffect effect, RaiseEventOptions? options = null) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer()) { channel.RaiseEvent((object)new object[13] { "ciriolopipado.defibrillator/3", 3, target, effect.Pitch, effect.VoiceExpiresAt, effect.NextShockAt, effect.ShockInterval, effect.Round, effect.Token, effect.Sequence, effect.NextAnimalAt, effect.AnimalInterval, effect.AnimalSequence }, options ?? NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } internal void RequestVoiceSnapshot() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) channel.RaiseEvent((object)new object[2] { "ciriolopipado.defibrillator/3", 4 }, NetworkingEvents.RaiseMasterClient, SendOptions.SendReliable); } internal void SendShock(int target, string token, int sequence, float strength, float seconds, float yaw, bool tumble) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer()) { channel.RaiseEvent((object)new object[9] { "ciriolopipado.defibrillator/3", 5, target, token, sequence, strength, seconds, yaw, tumble }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } internal void SendAnimal(int target, string token, int sequence, int animal, double at) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMultiplayer()) { channel.RaiseEvent((object)new object[7] { "ciriolopipado.defibrillator/3", 6, target, token, sequence, animal, at }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable); } } } internal static class OriginalAssets { private static AudioClip? startCharge; private static AudioClip? shock; internal static AudioClip StartCharge { get { if (!Object.op_Implicit((Object)(object)startCharge)) { return startCharge = Tone("Defibrillator charge", 0.28f, discharge: false); } return startCharge; } } internal static AudioClip Shock { get { if (!Object.op_Implicit((Object)(object)shock)) { return shock = Tone("Defibrillator discharge", 0.45f, discharge: true); } return shock; } } internal static void BuildModel(GameObject prefab) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0229: 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_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_0326: 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_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Unknown result type (might be due to invalid IL or missing references) Material val = null; Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent<BatteryVisualLogic>())) { MeshFilter component = ((Component)val2).GetComponent<MeshFilter>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && val == null) { val = val2.sharedMaterial; } val2.enabled = false; } } GameObject val3 = new GameObject("Original Industrial Defibrillator Model"); val3.layer = prefab.layer; val3.transform.SetParent(prefab.transform, false); val3.transform.localPosition = Vector3.zero; val3.transform.localScale = Vector3.one * 0.5f; Material material = Material(new Color(0.83f, 0.3f, 0.055f), val); Material val4 = Material(new Color(0.055f, 0.063f, 0.067f), val); Material material2 = Material(new Color(0.58f, 0.63f, 0.65f), val); Material material3 = Material(new Color(0.02f, 0.16f, 0.15f), val); Material material4 = Material(new Color(0.85f, 0.87f, 0.76f), val); Material material5 = Material(new Color(0.15f, 0.95f, 0.3f), val); Box(val3.transform, "Casing", Vector3.zero, new Vector3(0.48f, 0.28f, 0.21f), material); Box(val3.transform, "Lower bumper", new Vector3(0f, -0.14f, 0f), new Vector3(0.51f, 0.035f, 0.24f), val4); Box(val3.transform, "Upper bumper", new Vector3(0f, 0.14f, 0f), new Vector3(0.51f, 0.035f, 0.24f), val4); Box(val3.transform, "Display", new Vector3(-0.065f, 0.035f, -0.113f), new Vector3(0.24f, 0.12f, 0.012f), material3); Box(val3.transform, "Cross horizontal", new Vector3(0.15f, 0.035f, -0.117f), new Vector3(0.085f, 0.023f, 0.012f), material4); Box(val3.transform, "Cross vertical", new Vector3(0.15f, 0.035f, -0.119f), new Vector3(0.023f, 0.085f, 0.012f), material4); Box(val3.transform, "Handle", new Vector3(0f, 0.23f, 0f), new Vector3(0.22f, 0.032f, 0.05f), val4); float[] array = new float[2] { -1f, 1f }; foreach (float num in array) { Box(val3.transform, "Handle mount", new Vector3(num * 0.11f, 0.19f, 0f), new Vector3(0.025f, 0.08f, 0.05f), val4); Box(val3.transform, "Paddle plate", new Vector3(num * 0.3f, 0f, 0f), new Vector3(0.1f, 0.16f, 0.06f), material2); Box(val3.transform, "Paddle grip", new Vector3(num * 0.3f, 0f, -0.055f), new Vector3(0.045f, 0.11f, 0.055f), val4); GameObject val5 = new GameObject("Paddle cable") { layer = prefab.layer }; val5.transform.SetParent(val3.transform, false); LineRenderer val6 = val5.AddComponent<LineRenderer>(); val6.useWorldSpace = false; ((Renderer)val6).sharedMaterial = val4; float startWidth = (val6.endWidth = 0.012f); val6.startWidth = startWidth; val6.positionCount = 12; for (int j = 0; j < 12; j++) { float num3 = (float)j / 11f; val6.SetPosition(j, new Vector3(num * Mathf.Lerp(0.2f, 0.3f, num3), -0.08f - Mathf.Sin(num3 * MathF.PI) * 0.15f, 0.07f)); } } for (int k = 0; k < 4; k++) { Box(val3.transform, "Cell " + k, new Vector3(-0.16f + (float)k * 0.055f, -0.08f, -0.12f), new Vector3(0.037f, 0.025f, 0.012f), material5); } } private static Material Material(Color color, Material? template) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"); Material val2; if (!Object.op_Implicit((Object)(object)val)) { if (!Object.op_Implicit((Object)(object)template)) { throw new InvalidOperationException("No supported model shader available."); } val2 = new Material(template); } else { val2 = new Material(val); } Material val3 = val2; ((Object)val3).name = "Defibrillator original material"; if (val3.HasProperty("_Color")) { val3.SetColor("_Color", color); } if (val3.HasProperty("_BaseColor")) { val3.SetColor("_BaseColor", color); } return val3; } private static void Box(Transform parent, string name, Vector3 position, Vector3 scale, Material material) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = name; Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>()); obj.transform.SetParent(parent, false); obj.transform.localPosition = position; obj.transform.localScale = scale; obj.GetComponent<Renderer>().sharedMaterial = material; obj.layer = ((Component)parent).gameObject.layer; } private static AudioClip Tone(string name, float duration, bool discharge) { float[] array = new float[(int)(44100f * duration)]; uint num = 173u; double num2 = 0.0; for (int i = 0; i < array.Length; i++) { double num3 = (double)i / 44100.0; double num4 = num3 / (double)duration; double num5 = (discharge ? (180.0 * Math.Exp(-5.0 * num4) + 65.0) : (600.0 + num4 * 1500.0)); num2 += Math.PI * 2.0 * num5 / 44100.0; num = num * 1664525 + 1013904223; double num6 = (double)num / 4294967295.0 * 2.0 - 1.0; double num7 = Math.Min(1.0, num3 / 0.008) * Math.Pow(1.0 - num4, discharge ? 3.0 : 0.7); array[i] = (float)(num7 * (Math.Sin(num2) * 0.45 + (discharge ? (num6 * 0.3) : 0.0))); } AudioClip obj = AudioClip.Create(name, array.Length, 1, 44100, false); obj.SetData(array, 0); return obj; } } [HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")] internal static class RegisterPatch { [HarmonyPrefix] private static void Prefix() { ItemFactory.EnsureRegistered(); } } [HarmonyPatch(typeof(ItemAttributes), "GetValue")] internal static class PricePatch { [HarmonyPrefix] private static bool Prefix(ItemAttributes __instance) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Device>())) { return true; } if (SemiFunc.IsMasterClientOrSingleplayer()) { int price = Plugin.Instance.Settings.Price; GameAccess.SetPrice(__instance, price); PhotonView component = ((Component)__instance).GetComponent<PhotonView>(); if (SemiFunc.IsMultiplayer() && component.ViewID != 0) { component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { price }); } } return false; } } [HarmonyPatch] internal static class ShopPatch { private static MethodBase TargetMethod() { return AccessTools.GetDeclaredMethods(typeof(PunManager)).Single((MethodInfo method) => method.Name == "ShopPopulateItemVolumes" && method.GetParameters().Length == 1); } [HarmonyPrefix] [HarmonyPriority(0)] private static void Prefix(PunManager __instance, object[] __args) { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_010a: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || !Object.op_Implicit((Object)(object)ShopManager.instance)) { return; } ItemFactory.EnsureRegistered(); Item item = ItemFactory.Item; if (!Object.op_Implicit((Object)(object)item)) { return; } ShopManager instance = ShopManager.instance; instance.potentialItems.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item); instance.potentialItemConsumables.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item); instance.potentialItemUpgrades.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item); instance.potentialItemHealthPacks.RemoveAll((Item candidate) => (Object)(object)candidate == (Object)(object)item); ItemVolume val = ((IEnumerable<ItemVolume>)instance.itemVolumes).FirstOrDefault((Func<ItemVolume, bool>)((ItemVolume candidate) => Object.op_Implicit((Object)(object)candidate) && candidate.itemVolume == item.itemVolume)) ?? ((IEnumerable<ItemVolume>)instance.itemVolumes).FirstOrDefault((Func<ItemVolume, bool>)((ItemVolume candidate) => Object.op_Implicit((Object)(object)candidate))); if (!Object.op_Implicit((Object)(object)val)) { Plugin.Error("No shop slot available for the guaranteed defibrillator."); return; } itemVolume itemVolume = val.itemVolume; try { val.itemVolume = item.itemVolume; object[] parameters = new object[5] { val, new List<Item> { item }, 0, false, __args[0] }; if (!(bool)AccessTools.Method(typeof(PunManager), "SpawnShopItem", (Type[])null, (Type[])null).Invoke(__instance, parameters)) { Plugin.Error("Failed to reserve the defibrillator shop slot."); return; } instance.itemVolumes.Remove(val); Object.Destroy((Object)(object)((Component)val).gameObject); Plugin.LogInfo("Reserved one defibrillator shop slot at price " + Plugin.Instance.Settings.Price + "."); } catch (Exception ex) { Plugin.Error("Defibrillator shop injection failed. " + ex); } finally { val.itemVolume = itemVolume; } } } [HarmonyPatch(typeof(PlayerHealth), "Hurt")] internal static class LocalDamagePatch { [HarmonyPrefix] private static void Prefix(PlayerHealth __instance, out int __state) { __state = GameAccess.GetHealth(__instance); } [HarmonyPostfix] private static void Postfix(PlayerHealth __instance, int __state) { if (GameAccess.GetHealth(__instance) < __state) { PlayerAvatar componentInParent = ((Component)__instance).GetComponentInParent<PlayerAvatar>(); if (Object.op_Implicit((Object)(object)componentInParent)) { Plugin.World.Damaged(componentInParent); } } } } [HarmonyPatch(typeof(PlayerHealth), "UpdateHealthRPC")] internal static class RemoteDamagePatch { [HarmonyPrefix] private static void Prefix(PlayerHealth __instance, out int __state) { __state = GameAccess.GetHealth(__instance); } [HarmonyPostfix] private static void Postfix(PlayerHealth __instance, int __state) { if (GameAccess.GetHealth(__instance) < __state) { PlayerAvatar componentInParent = ((Component)__instance).GetComponentInParent<PlayerAvatar>(); if (Object.op_Implicit((Object)(object)componentInParent)) { Plugin.World.Damaged(componentInParent); } } } } [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathDone")] internal static class DeathPatch { [HarmonyPrefix] private static void Prefix(PlayerAvatar __instance, out bool __state) { __state = GameAccess.IsDead(__instance); } [HarmonyPostfix] private static void Postfix(PlayerAvatar __instance, bool __state) { if (!__state && GameAccess.IsDead(__instance)) { Plugin.World.Died(__instance); VoiceDebuffs.ClearPlayer(GameAccess.PlayerId(__instance)); } } } [BepInPlugin("ciriolopipado.defibrillator", "Industrial Defibrillator", "0.1.5")] [BepInDependency("REPOLib", "4.3.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "ciriolopipado.defibrillator"; public const string Version = "0.1.5"; internal static Plugin Instance = null; internal Settings Settings; internal NetworkBridge Network; private Harmony? harmony; private bool failed; private bool wasHost; internal static RevivalService? Service; internal static readonly GameWorld World = new GameWorld(); internal bool Operational => !failed; private void Awake() { //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Expected O, but got Unknown Instance = this; try { ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "Price", 2, "Host setting: price in displayed shop currency units; 2 means 2k."); ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Battery", "CostPercent", 50, "Host setting: percent spent per successful revival, 1–100. Default 50 gives two uses per charge."); ConfigEntry<int> val3 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "BalanceRevision", 0, "One-time migration of legacy free-price / four-use test defaults. Keep this value after upgrading."); if (val3.Value < 1) { (int, int) tuple = BalanceMigration.Apply(val3.Value, val.Value, val2.Value); val.Value = tuple.Item1; val2.Value = tuple.Item2; val3.Value = 1; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Balance defaults migrated: Price=" + val.Value + ", CostPercent=" + val2.Value + ". Custom values were preserved.")); } Settings = new Settings(((BaseUnityPlugin)this).Config.Bind<double>("Revival", "HoldSeconds", 3.0, "Host setting: hold duration, 0.25–30 seconds.").Value, ((BaseUnityPlugin)this).Config.Bind<double>("Revival", "RangeMeters", 2.0, "Host setting: maximum eye-to-head distance, up to 10 meters.").Value, ((BaseUnityPlugin)this).Config.Bind<int>("Revival", "Health", 1, "Host setting: health after revival, 1–100.").Value, val2.Value, val.Value, 0.75); GameAccess.Validate(); VoiceDebuffs.Seconds = ((BaseUnityPlugin)this).Config.Bind<double>("VoiceDebuff", "Seconds", 180.0, "Maximum duration, 1–3600 seconds; also ends at death or level end.").Value; VoiceDebuffs.HighPitch = ((BaseUnityPlugin)this).Config.Bind<float>("VoiceDebuff", "HighPitch", 1.8f, "Comically high voice multiplier, above 1 and up to 2.").Value; VoiceDebuffs.LowPitch = ((BaseUnityPlugin)this).Config.Bind<float>("VoiceDebuff", "LowPitch", 0.55f, "Comically low voice multiplier, at least 0.5 and below 1.").Value; VoiceDebuffs.ShockInterval = ((BaseUnityPlugin)this).Config.Bind<double>("Aftershock", "IntervalSeconds", 30.0, "Harmless shock interval, 5–300 seconds; ends at death or level end.").Value; ConfigEntry<float> val4 = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "CameraShakeStrength", 7f, "Camera shake strength, 0–10; respects native camera-shake settings."); ConfigEntry<float> val5 = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "CameraShakeSeconds", 1.2f, "Camera shake duration, 0.1–2 seconds."); ConfigEntry<int> val6 = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "AftershockRevision", 0, "Once-only upgrade of old weak shake defaults."); if (val6.Value < 1) { (float, float) tuple2 = AftershockImpact.UpgradeLegacy(val6.Value, val4.Value, val5.Value); val4.Value = tuple2.Item1; val5.Value = tuple2.Item2; val6.Value = 1; ((BaseUnityPlugin)this).Config.Save(); } VoiceDebuffs.ShakeStrength = val4.Value; VoiceDebuffs.ShakeSeconds = val5.Value; VoiceDebuffs.YawDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("Aftershock", "YawDegrees", 180f, "Horizontal turn per shock, 0–180 degrees; random left/right. Set 0 to disable turning.").Value; VoiceDebuffs.TumbleChance = ((BaseUnityPlugin)this).Config.Bind<double>("Aftershock", "TumbleChance", 0.25, "Probability of native Q/tumble per shock, 0–1; 0 disables, 1 always triggers.").Value; AftershockImpact.YawAt(VoiceDebuffs.YawDegrees, 0.0); AftershockImpact.RollTumble(0.0, VoiceDebuffs.TumbleChance); VoiceDebuffs.AnimalEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AnimalVoice", "Enabled", true, "Host setting: emit a random animal sound automatically after revival.").Value; VoiceDebuffs.AnimalInterval = ((BaseUnityPlugin)this).Config.Bind<double>("AnimalVoice", "IntervalSeconds", 30.0, "Host setting: animal interval, 5–300 seconds; independent of electrical shocks.").Value; VoiceDebuffs.AnimalVolume = ((BaseUnityPlugin)this).Config.Bind<float>("AnimalVoice", "Volume", 0.7f, "Local playback volume, 0–1. Per-player voice gain and the voice mixer also apply.").Value; if (double.IsNaN(VoiceDebuffs.AnimalInterval) || double.IsInfinity(VoiceDebuffs.AnimalInterval) || VoiceDebuffs.AnimalInterval < 5.0 || VoiceDebuffs.AnimalInterval > 300.0 || float.IsNaN(VoiceDebuffs.AnimalVolume) || VoiceDebuffs.AnimalVolume < 0f || VoiceDebuffs.AnimalVolume > 1f) { throw new ArgumentException("Invalid animal voice settings."); } VoiceEffect.ChoosePitch(0, VoiceDebuffs.HighPitch, VoiceDebuffs.LowPitch); if (double.IsNaN(VoiceDebuffs.Seconds) || double.IsInfinity(VoiceDebuffs.Seconds) || VoiceDebuffs.Seconds < 1.0 || VoiceDebuffs.Seconds > 3600.0 || double.IsNaN(VoiceDebuffs.ShockInterval) || double.IsInfinity(VoiceDebuffs.ShockInterval) || VoiceDebuffs.ShockInterval < 5.0 || VoiceDebuffs.ShockInterval > 300.0 || float.IsNaN(VoiceDebuffs.ShakeStrength) || VoiceDebuffs.ShakeStrength < 0f || VoiceDebuffs.ShakeStrength > 10f || float.IsNaN(VoiceDebuffs.ShakeSeconds) || VoiceDebuffs.ShakeSeconds < 0.1f || VoiceDebuffs.ShakeSeconds > 2f) { throw new ArgumentException("Invalid voice debuff duration settings."); } AnimalClips.Load(); Network = new NetworkBridge(); harmony = new Harmony("ciriolopipado.defibrillator"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Industrial Defibrillator 0.1.5 loaded. Target: R.E.P.O. 0.5.1 / REPOLib 4.3.0. In-game validation required."); } catch (Exception ex) { failed = true; Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("Defibrillator initialization failed; features disabled. " + ex)); } } private void Update() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (failed || !Object.op_Implicit((Object)(object)RunManager.instance) || !Object.op_Implicit((Object)(object)GameManager.instance)) { return; } try { ItemFactory.EnsureRegistered(); VoiceDebuffs.Tick(); bool flag = SemiFunc.IsMasterClientOrSingleplayer(); if (flag != wasHost || (flag && Service == null)) { RevivalService? service = Service; if (service != null) { service.CancelAll(); } Service = ((!flag) ? ((RevivalService)null) : new RevivalService(Settings, (IRevivalWorld)(object)World, (Func<double>)(() => Time.realtimeSinceStartupAsDouble))); wasHost = flag; Network.ResetLocalInput(); } if (!flag) { return; } foreach (Device item in Device.Active) { if (Object.op_Implicit((Object)(object)item) && item.Ready) { item.SyncHostBattery(); } } RevivalService? service2 = Service; if (service2 != null) { service2.Tick(); } } catch (Exception ex) { failed = true; RevivalService? service3 = Service; if (service3 != null) { service3.CancelAll(); } Service = null; ((BaseUnityPlugin)this).Logger.LogError((object)("Defibrillator stopped after an unexpected runtime error. Restart the lobby and report this log. " + ex)); } } private void OnDestroy() { failed = true; AnimalVoicePlayback.StopAll(); RevivalService? service = Service; if (service != null) { service.CancelAll(); } Service = null; Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal static void LogInfo(string message) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } internal static void Error(string message) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } } internal static class VoiceDebuffs { internal static readonly Dictionary<int, VoiceEffect> Effects = new Dictionary<int, VoiceEffect>(); private static readonly Dictionary<string, int> seenPulses = new Dictionary<string, int>(); private static readonly HashSet<string> endedTokens = new HashSet<string>(); private static readonly Dictionary<string, int> seenAnimals = new Dictionary<string, int>(); internal static bool AnimalEnabled; internal static double AnimalInterval; internal static float AnimalVolume; internal static double Seconds; internal static float HighPitch; internal static float LowPitch; internal static double ShockInterval; internal static float ShakeStrength; internal static float ShakeSeconds; internal static float YawDegrees; internal static double TumbleChance; private static float nextSnapshotRequest; private static object? previousRoom; private static readonly FieldInfo VoicePlayer = AccessTools.Field(typeof(PlayerVoiceChat), "playerAvatar") ?? throw new MissingFieldException("PlayerVoiceChat.playerAvatar"); internal static double Now { get { if (!SemiFunc.IsMultiplayer()) { return Time.realtimeSinceStartupAsDouble; } return PhotonNetwork.Time; } } internal static string Round => ((Object)RunManager.instance.levelCurrent).name + "/" + RunManager.instance.levelsCompleted; internal static void Revived(int target) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown if (SemiFunc.IsMasterClientOrSingleplayer()) { EnsureRoom(); VoiceEffect val = new VoiceEffect(VoiceEffect.ChoosePitch(Random.Range(0, 2), HighPitch, LowPitch), Now + Seconds, Now + ShockInterval, ShockInterval, Round, Guid.NewGuid().ToString("N"), 0, (double?)(Now + AnimalInterval), AnimalInterval, 0); Effects[target] = val; seenPulses[val.Token] = 0; seenAnimals[val.Token] = 0; Plugin.Instance.Network.SendVoice(target, val); Plugin.LogInfo("Revival aftereffects applied: target=" + target + ", pitch=" + val.Pitch + ", voiceSeconds=" + Seconds); } } internal static void Tick() { EnsureRoom(); if (!SemiFunc.RunIsLevel()) { AnimalVoicePlayback.StopAll(); Effects.Clear(); seenPulses.Clear(); seenAnimals.Clear(); endedTokens.Clear(); return; } KeyValuePair<int, VoiceEffect>[] array = Effects.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<int, VoiceEffect> keyValuePair = array[i]; PlayerAvatar val = GameAccess.FindPlayer(keyValuePair.Key); if (!Object.op_Implicit((Object)(object)val)) { Effects.Remove(keyValuePair.Key); seenPulses.Remove(keyValuePair.Value.Token); continue; } if (!keyValuePair.Value.IsActive(Now, Round, GameAccess.IsAlive(val))) { ClearPlayer(keyValuePair.Key); continue; } if (SemiFunc.IsMasterClientOrSingleplayer() && keyValuePair.Value.TryShock(Now, Round, true)) { float yaw = YawDegrees * (float)((Random.Range(0, 2) != 0) ? 1 : (-1)); bool tumble = AftershockImpact.RollTumble((double)Random.Range(0, 1000000) / 1000000.0, TumbleChance); Shock(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.Sequence, ShakeStrength, ShakeSeconds, yaw, tumble); Plugin.Instance.Network.SendShock(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.Sequence, ShakeStrength, ShakeSeconds, yaw, tumble); } if (SemiFunc.IsMasterClientOrSingleplayer() && AnimalEnabled && AnimalClips.Ready && keyValuePair.Value.TryAnimal(Now, Round, true)) { int animal = Random.Range(0, 4); double now = Now; Animal(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.AnimalSequence, animal, now); Plugin.Instance.Network.SendAnimal(keyValuePair.Key, keyValuePair.Value.Token, keyValuePair.Value.AnimalSequence, animal, now); } } if (SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient && Time.unscaledTime >= nextSnapshotRequest) { nextSnapshotRequest = Time.unscaledTime + 3f; Plugin.Instance.Network.RequestVoiceSnapshot(); } } private static void EnsureRoom() { object currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != previousRoom) { AnimalVoicePlayback.StopAll(); Effects.Clear(); seenPulses.Clear(); seenAnimals.Clear(); endedTokens.Clear(); previousRoom = currentRoom; nextSnapshotRequest = 0f; } } internal static void ClearPlayer(int target) { if (Effects.TryGetValue(target, out VoiceEffect value)) { Effects.Remove(target); AnimalVoicePlayback.Stop(target); seenPulses.Remove(value.Token); seenAnimals.Remove(value.Token); endedTokens.Add(value.Token); } } internal static void Receive(int target, VoiceEffect effect) { EnsureRoom(); if (Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel() && !(effect.Round != Round) && !endedTokens.Contains(effect.Token)) { if (Effects.TryGetValue(target, out VoiceEffect value) && value.Token != effect.Token) { seenPulses.Remove(value.Token); } Effects[target] = effect; seenPulses[effect.Token] = Math.Max(effect.Sequence, seenPulses.TryGetValue(effect.Token, out var value2) ? value2 : 0); seenAnimals[effect.Token] = Math.Max(effect.AnimalSequence, seenAnimals.TryGetValue(effect.Token, out var value3) ? value3 : 0); } } internal static void Animal(int target, string token, int sequence, int animal, double at) { if (AnimalClips.Ready && animal >= 0 && animal < 4 && sequence > 0 && Effects.TryGetValue(target, out VoiceEffect value) && !(value.Token != token) && (!seenAnimals.TryGetValue(token, out var value2) || sequence > value2)) { PlayerAvatar val = GameAccess.FindPlayer(target); if (Object.op_Implicit((Object)(object)val) && value.IsActive(Now, Round, GameAccess.IsAlive(val))) { seenAnimals[token] = sequence; AnimalVoicePlayback.Play(target, token, animal, at); } } } internal static void Shock(int target, string token, int sequence, float strength, float seconds, float yaw, bool tumble) { if (!Effects.TryGetValue(target, out VoiceEffect value) || value.Token != token || (seenPulses.TryGetValue(token, out var value2) && sequence <= value2)) { return; } PlayerAvatar val = GameAccess.FindPlayer(target); if (!Object.op_Implicit((Object)(object)val) || !value.IsActive(Now, Round, GameAccess.IsAlive(val))) { return; } seenPulses[token] = sequence; AftershockVisual.Spawn(val, sequence, strength, seconds); AftershockCamera.Spawn(val, yaw, seconds); if (tumble && SemiFunc.IsMasterClientOrSingleplayer() && !GameAccess.IsTumbling(val)) { PlayerTumble val2 = GameAccess.Tumble(val); if (Object.op_Implicit((Object)(object)val2)) { val2.TumbleSet(true, false, false); } } } internal static void Apply(PlayerVoiceChat voice) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Operational && Object.op_Implicit((Object)(object)RunManager.instance) && SemiFunc.RunIsLevel()) { PlayerAvatar val = (PlayerAvatar)VoicePlayer.GetValue(voice); if (Object.op_Implicit((Object)(object)val) && Effects.TryGetValue(GameAccess.PlayerId(val), out VoiceEffect value) && value.HasVoice(Now, Round, GameAccess.IsAlive(val))) { voice.OverridePitch(value.Pitch, 0.12f, 0.2f, 0.3f, 0f, 0f); } } } } [HarmonyPatch(typeof(PlayerVoiceChat), "Update")] internal static class VoicePatch { [HarmonyPrefix] private static void Prefix(PlayerVoiceChat __instance) { AnimalVoicePlayback.BeforeVoice(__instance); VoiceDebuffs.Apply(__instance); } [HarmonyPostfix] private static void Postfix(PlayerVoiceChat __instance) { AnimalVoicePlayback.AfterVoice(__instance); } } }