using 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);
}
}
}
}
}
}