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 ReviveHeadInTruckOrExtractionPointToxinFork v1.3.0
ReviveHeadInTruckOrExtractionPoint.dll
Decompiled 5 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Autodesk.Fbx")] [assembly: IgnoresAccessChecksTo("Discord.Sdk")] [assembly: IgnoresAccessChecksTo("Domain_Reload")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")] [assembly: IgnoresAccessChecksTo("Klattersynth")] [assembly: IgnoresAccessChecksTo("Photon3Unity3D")] [assembly: IgnoresAccessChecksTo("PhotonChat")] [assembly: IgnoresAccessChecksTo("PhotonRealtime")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")] [assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")] [assembly: IgnoresAccessChecksTo("PhotonVoice.API")] [assembly: IgnoresAccessChecksTo("PhotonVoice")] [assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")] [assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")] [assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")] [assembly: IgnoresAccessChecksTo("Sirenix.Serialization")] [assembly: IgnoresAccessChecksTo("Sirenix.Utilities")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.MemoryProfiler")] [assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Splines")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")] [assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: IgnoresAccessChecksTo("websocket-sharp")] [assembly: AssemblyCompany("Hypn,Toxin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.3.0.0")] [assembly: AssemblyInformationalVersion("1.3.0+fabf6491c804bd6ec3995a3208ef8aaaeb5ebe44")] [assembly: AssemblyProduct("ReviveHeadInTruckOrExtractionPoint")] [assembly: AssemblyTitle("ReviveHeadInTruckOrExtractionPoint")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.3.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 Hypn { [BepInPlugin("HT.ReviveHeadInTruckOrExtractionPoint", "ReviveHeadInTruckOrExtractionPoint (Toxin fork, original: Hypn)", "1.2.1")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "HT.ReviveHeadInTruckOrExtractionPoint"; public const string ModName = "ReviveHeadInTruckOrExtractionPoint (Toxin fork, original: Hypn)"; public const string ModAuthors = "Hypn, Toxin"; public const string ModVersion = "1.2.1"; private readonly Harmony harmony = new Harmony("HT.ReviveHeadInTruckOrExtractionPoint"); internal static Plugin Instance { get; private set; } public static ManualLogSource Logger { get; private set; } private void Awake() { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Plugin ReviveHeadInTruckOrExtractionPoint (Toxin fork, original: Hypn) v1.2.1 is loaded! Authors: Hypn, Toxin"); harmony.PatchAll(); } internal void Unpatch() { harmony.UnpatchSelf(); } } } namespace Hypn.Patches { [HarmonyPatch(typeof(PlayerDeathHead), "Update")] internal class HypnReviveInTruckAndExtractionPatch { private class ReviveInfo { private PlayerAvatar Player; private int Count = 0; private DateTime LastReviveTime = DateTime.UtcNow; private float OutsideLevelTimer = 0f; private bool Reviving = false; private Queue<string> Messages = new Queue<string>(); private DateTime lastMessageTime = DateTime.MinValue; public PlayerAvatar GetPlayer() { return Player; } public int GetCount() { return Count; } public ReviveInfo SetCount(int value) { Count = value; return this; } public ReviveInfo IncCount() { Count++; return this; } public DateTime GetLastReviveTime() { return LastReviveTime; } public ReviveInfo SetLastReviveTime(DateTime time) { LastReviveTime = time; return this; } public float GetOutsideLevelTimer() { return OutsideLevelTimer; } public ReviveInfo SetOutsideLevelTimer(float value) { OutsideLevelTimer = value; return this; } public bool IsReviving() { return Reviving; } public ReviveInfo SetReviving(bool value) { Reviving = value; return this; } public ReviveInfo AddMessage(string message) { Messages.Enqueue(message); return this; } public string GetMessage() { return Messages.Dequeue(); } public ReviveInfo ClearMessages() { Messages.Clear(); return this; } public ReviveInfo DropReviving() { return ClearMessages().SetReviving(value: false); } public bool AnyMessages() { return Messages.Count > 0; } public ReviveInfo SetPlayer(PlayerAvatar player) { Player = player; return this; } public ReviveInfo TryAddMessageWithCooldown(string message) { DateTime utcNow = DateTime.UtcNow; if ((utcNow - lastMessageTime).TotalSeconds >= (double)MessageCooldownSeconds) { AddMessage(message); lastMessageTime = utcNow; } return this; } } private static readonly Dictionary<string, ReviveInfo> _reviveTracker = new Dictionary<string, ReviveInfo>(); private static readonly object _reviveLock = new object(); private static readonly int ReviveCooldownSeconds = 300; private static readonly float MessageCooldownSeconds = 30f; private static int Level = 0; private static int Currency = 0; private static float updateThrottle = 0f; private static readonly string[] Countdown = new string[6] { "Five", "Four", "Three", "Two", "One", "Zero" }; private static void TryTeleportPlayer(ReviveInfo info) { //IL_018f: 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_0143: 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) PlayerAvatar player = info.GetPlayer(); PlayerDeathHead playerDeathHead = player.playerDeathHead; int num = playerDeathHead.roomVolumeCheck?.CurrentRooms?.Count ?? 1; if (num > 0) { info.SetOutsideLevelTimer(0f); return; } info.SetOutsideLevelTimer(info.GetOutsideLevelTimer() + Time.deltaTime); if ((Object)(object)playerDeathHead.physGrabObject == (Object)null) { LogInfo("Player \"" + player.playerName + "\" could not be teleported — no physGrabObject."); } else if (!(info.GetOutsideLevelTimer() < 5f)) { if ((player.playerDeathHead?.roomVolumeCheck?.inTruck).GetValueOrDefault()) { LogInfo("Teleporting player \"" + player.playerName + "\" to truck"); playerDeathHead.physGrabObject.Teleport(((Component)TruckSafetySpawnPoint.instance).transform.position, ((Component)TruckSafetySpawnPoint.instance).transform.rotation); } else { LogInfo("Teleporting player \"" + player.playerName + "\" to extraction point"); playerDeathHead.physGrabObject.Teleport(RoundDirector.instance.extractionPointCurrent.safetySpawn.position, RoundDirector.instance.extractionPointCurrent.safetySpawn.rotation); } } } private static void Revive(ReviveInfo info) { if (!info.AnyMessages() && !PlayerIsTalking(info)) { PlayerAvatar player = info.GetPlayer(); int num = CalculateReviveCost(info); Currency = Math.Max(Currency - num, 0); SemiFunc.StatSetRunCurrency(Currency); int num2 = (int)((float)player.playerHealth.maxHealth * 0.2f); info.IncCount().SetLastReviveTime(DateTime.UtcNow).SetReviving(value: false); LogInfo($"Reviving player \"{player.playerName}\" with {num2}/{player.playerHealth.maxHealth} health (revives: {info.GetCount()}). Revive cost: {num}. Currency left: {Currency}."); player.Revive((player.playerDeathHead?.roomVolumeCheck?.inTruck).GetValueOrDefault()); player.playerHealth.HealOther(num2 - 1, true); TryTeleportPlayer(info); } } private static void Speak(ReviveInfo info) { if (info.AnyMessages() && !PlayerIsTalking(info)) { string message = info.GetMessage(); LogInfo("Player \"" + info.GetPlayer().playerName + "\" talk " + message); info.GetPlayer().ChatMessageSend(message); } } private static void LogInfo(string message) { Plugin.Logger.LogInfo((object)$"[{DateTime.Now:HH:mm:ss.fff}] {message}"); } private static bool PlayerIsTalking(ReviveInfo info) { if (info.GetPlayer().voiceChat.ttsVoice.isSpeaking) { LogInfo("Player \"" + info.GetPlayer().playerName + "\" is talking"); return true; } return false; } private static void CheckCurrentLevel(int currentlevel) { if (Level == currentlevel) { return; } LogInfo("New level. Reset count revive"); Level = currentlevel; foreach (ReviveInfo value in _reviveTracker.Values) { LogInfo(((Object)value.GetPlayer()).name + " revive reset"); value.SetCount(0); } } private static bool CooldownPassed(ReviveInfo info) { int num = ((info.GetCount() == 0) ? ReviveCooldownSeconds : ((int)(DateTime.UtcNow - info.GetLastReviveTime()).TotalSeconds)); if (num >= ReviveCooldownSeconds) { return true; } LogInfo($"Player \"{info.GetPlayer().playerName}\" cannot be revived, cooldown: {num} ."); return false; } private static int CalculateReviveCost(ReviveInfo info) { return (info.GetCount() > 0) ? (Math.Min(Level, 20) + info.GetCount() - 1) : 0; } private static bool IsCostPayable(ReviveInfo info) { int num = CalculateReviveCost(info); if (Currency >= num) { return true; } LogInfo($"Player \"{info.GetPlayer().playerName}\" cannot be revived, not enough money. Revive cost: ${num}k. Current currency: ${Currency}k"); return false; } private static bool IsCanRevive(ReviveInfo info) { PlayerDeathHead playerDeathHead = info.GetPlayer().playerDeathHead; if (((Object)(object)playerDeathHead.physGrabObject?.impactDetector?.currentCart != (Object)null) ? true : false) { LogInfo("Player \"" + info.GetPlayer().playerName + "\" inCart"); info.DropReviving(); return false; } bool flag = playerDeathHead.roomVolumeCheck?.inTruck ?? false; bool flag2 = playerDeathHead.roomVolumeCheck?.inExtractionPoint ?? false; if (!flag && !flag2) { LogInfo("Player \"" + info.GetPlayer().playerName + "\" is not in the truck or at the extraction point"); info.DropReviving(); return false; } if (!CooldownPassed(info)) { info.DropReviving(); info.TryAddMessageWithCooldown("I can't revive yet, still on cooldown"); return false; } if (!IsCostPayable(info)) { info.DropReviving(); info.TryAddMessageWithCooldown("We are don't have enough currency to revive"); return false; } return true; } private static void StartReviving(ReviveInfo info) { info.AddMessage($"My revival will cost ${CalculateReviveCost(info)}k"); info.AddMessage("Reviving"); string[] countdown = Countdown; foreach (string message in countdown) { info.AddMessage(message); } info.SetReviving(value: true); } private static void Postfix(PlayerDeathHead __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } updateThrottle += Time.deltaTime; if (updateThrottle < 1f) { return; } updateThrottle = 0f; PlayerAvatar val = __instance?.playerAvatar; if ((Object)(object)val == (Object)null) { return; } string steamID = val.steamID; if (string.IsNullOrEmpty(steamID) || (Object)(object)__instance == (Object)null || !__instance.triggered) { return; } lock (_reviveLock) { _reviveTracker.TryGetValue(steamID, out ReviveInfo value); if (value == null) { value = new ReviveInfo(); _reviveTracker[steamID] = value; } value.SetPlayer(val); CheckCurrentLevel(StatsManager.instance.GetRunStatLevel() + 1); Currency = SemiFunc.StatGetRunCurrency(); Speak(value); if (IsCanRevive(value)) { if (value.IsReviving()) { Revive(value); } else { StartReviving(value); } } } } } }