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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Extensions;
using CSync.Lib;
using GameNetcodeStuff;
using HarmonyLib;
using LCVR;
using LCVR.Patches.Spectating;
using LCVR.Player;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("LCVR")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("slenered.LC_Lives")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Adds lives to Lethal Company for parties less than for.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("slenered.LC_Lives")]
[assembly: AssemblyTitle("slenered.LC_Lives")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.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 LC_Lives
{
public class Configs : SyncedConfig2<Configs>
{
[field: SyncedEntryField]
public SyncedEntry<int> PartySize { get; private set; }
[field: SyncedEntryField]
public SyncedEntry<int> GlobalLives { get; private set; }
[field: SyncedEntryField]
public SyncedEntry<int> PlayerLives { get; private set; }
[field: SyncedEntryField]
public SyncedEntry<float> RespawnTimeSeconds { get; private set; }
[field: SyncedEntryField]
public SyncedEntry<bool> ReviveOnBodyCollectedBool { get; private set; }
[field: SyncedEntryField]
public SyncedEntry<bool> PreventShipFromLeaving { get; private set; }
public Configs(ConfigFile configFile)
: base("slenered.LC_Lives")
{
PartySize = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, "General", "Party Size", 4, "The number lives that the team shares. (Each player consumes a life by landing)");
GlobalLives = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, "General", "Global Lives", 0, "Additional lives that the team shares.");
PlayerLives = SyncedBindingExtensions.BindSyncedEntry<int>(configFile, "General", "Player Lives", 0, "The number lives that each player has.");
ReviveOnBodyCollectedBool = SyncedBindingExtensions.BindSyncedEntry<bool>(configFile, "General", "Revive on body collection", true, "Force revive a player when their body is returned to the ship.");
RespawnTimeSeconds = SyncedBindingExtensions.BindSyncedEntry<float>(configFile, "General", "Respawn Timer (Seconds)", 30f, "The amount of time before respawning a player.");
PreventShipFromLeaving = SyncedBindingExtensions.BindSyncedEntry<bool>(configFile, "General", "Prevent Ship From Leaving", false, "Stop the ship from leaving if there are lives left.");
ConfigManager.Register<Configs>((SyncedConfig2<Configs>)(object)this);
PartySize.Changed += delegate(object _, SyncedSettingChangedEventArgs<int> args)
{
Logger.LogInfo((object)$"(NOW) PartySize: {args.OldValue} -> {args.NewValue}");
};
GlobalLives.Changed += delegate(object _, SyncedSettingChangedEventArgs<int> args)
{
Logger.LogInfo((object)$"(NOW) GlobalLives: {args.OldValue} -> {args.NewValue}");
};
PlayerLives.Changed += delegate(object _, SyncedSettingChangedEventArgs<int> args)
{
Logger.LogInfo((object)$"(NOW) PlayerLives: {args.OldValue} -> {args.NewValue}");
};
PreventShipFromLeaving.Changed += delegate(object _, SyncedSettingChangedEventArgs<bool> args)
{
Logger.LogInfo((object)$"(NOW) PreventShipFromLeaving: {args.OldValue} -> {args.NewValue}");
};
RespawnTimeSeconds.Changed += delegate(object _, SyncedSettingChangedEventArgs<float> args)
{
if (args.NewValue > 0f)
{
Logger.LogInfo((object)"(NOW) On Timer!");
LC_Lives.RevivePlayerMetric.RevivePlayerSystem.AddReviveCondition(new LC_Lives.RevivePlayerMetric.ReviveOnTimer());
}
else
{
Logger.LogInfo((object)"(NOW) Off on Timer!");
LC_Lives.RevivePlayerMetric.RevivePlayerSystem.RemoveReviveCondition(new LC_Lives.RevivePlayerMetric.ReviveOnTimer());
}
};
ReviveOnBodyCollectedBool.Changed += delegate(object _, SyncedSettingChangedEventArgs<bool> args)
{
if (args.NewValue)
{
Logger.LogInfo((object)"(NOW) On Body Collect!");
LC_Lives.RevivePlayerMetric.RevivePlayerSystem.AddReviveCondition(new LC_Lives.RevivePlayerMetric.ReviveOnBodyCollected());
}
else
{
Logger.LogInfo((object)"(NOW) Off on Body Collect!");
LC_Lives.RevivePlayerMetric.RevivePlayerSystem.RemoveReviveCondition(new LC_Lives.RevivePlayerMetric.ReviveOnBodyCollected());
}
};
}
}
[BepInPlugin("slenered.LC_Lives", "slenered.LC_Lives", "1.0.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency("com.sigurd.csync", "5.0.1")]
public class LC_Lives : BaseUnityPlugin
{
internal class RevivePlayerMetric
{
internal static class RevivePlayerSystem
{
private static readonly List<IReviveCondition> SReviveActions = new List<IReviveCondition>();
private static readonly Dictionary<ulong, RevivePlayerMetric> SPlayerMetrics = new Dictionary<ulong, RevivePlayerMetric>();
public static void AddReviveCondition(IReviveCondition condition)
{
SReviveActions.Add(condition);
}
public static void RemoveReviveCondition(IReviveCondition condition)
{
SReviveActions.Remove(condition);
}
public static void ClearReviveActions()
{
SReviveActions.Clear();
}
[HarmonyPatch(typeof(StartOfRound), "ShipLeaveAutomatically")]
[HarmonyPrefix]
private static bool ShipLeaveAutomaticallyPatch(StartOfRound __instance)
{
bool flag = false;
foreach (RevivePlayerMetric value in SPlayerMetrics.Values)
{
if (value.CanRevive())
{
flag = true;
break;
}
}
Logger.LogInfo((object)TimeOfDay.Instance.shipLeavingOnMidnight);
if (_config.PreventShipFromLeaving.Value && flag && !TimeOfDay.Instance.shipLeavingOnMidnight)
{
__instance.allPlayersDead = false;
return false;
}
return true;
}
[HarmonyPatch(typeof(RoundManager), "FinishGeneratingNewLevelClientRpc")]
[HarmonyPrefix]
private static void ResetMetricsOnRoundStart()
{
Logger.LogError((object)"Round Manager Finished Level Generation!");
StartOfRound instance = StartOfRound.Instance;
SPlayerMetrics.Clear();
if (instance == null)
{
Logger.LogError((object)"Start of Round is null at 'FinishGeneratingNewLevelClientRpc'");
return;
}
SReviveActions.ForEach(delegate(IReviveCondition x)
{
x.Reset();
});
int value = _config.PlayerLives.Value;
PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
PlayerControllerB[] array = allPlayerScripts;
foreach (PlayerControllerB val in array)
{
ulong actualClientId = val.actualClientId;
string playerUsername = val.playerUsername;
if (actualClientId == 0L && !val.isHostPlayerObject)
{
break;
}
Logger.LogInfo((object)$"Starting Revive Tracking for: '{actualClientId}' => '{playerUsername}'");
SPlayerMetrics.Add(val.actualClientId, new RevivePlayerMetric(val, value));
}
Instance.GlobalLivesLeft = _config.GlobalLives.Value + Math.Max(_config.PartySize.Value - instance.livingPlayers, 0);
if (Object.op_Implicit((Object)(object)HUDManager.Instance))
{
HUDManager.Instance.DisplayTip("Lives", $"{Instance.GlobalLivesLeft} Global lives,\n{value} Personal lives.", false, false, "LC_Tip1");
}
}
[HarmonyPatch(typeof(StartOfRound), "Update")]
[HarmonyPrefix]
private static void TryRevivePlayers(ref StartOfRound __instance)
{
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
if (!__instance.shipHasLanded || __instance.inShipPhase)
{
return;
}
if (SPlayerMetrics.Count <= 0 || SReviveActions.Count <= 0)
{
Logger.LogInfo((object)"No revive actions or players available to revive");
return;
}
foreach (KeyValuePair<ulong, RevivePlayerMetric> sPlayerMetric in SPlayerMetrics)
{
sPlayerMetric.Deconstruct(out var key, out var value);
ulong num = key;
RevivePlayerMetric revivePlayerMetric = value;
PlayerControllerB player = revivePlayerMetric.Player;
if (!player.isPlayerDead || (player != null && player.actualClientId == 0L && !player.isHostPlayerObject))
{
continue;
}
foreach (IReviveCondition sReviveAction in SReviveActions)
{
if (revivePlayerMetric.CanRevive() && sReviveAction.ShouldRevivePlayer(revivePlayerMetric))
{
SReviveActions.ForEach(delegate(IReviveCondition x)
{
x.SoftReset(revivePlayerMetric);
});
Logger.LogInfo((object)$"Reviving Player '{num}' => '{player.playerUsername}'");
revivePlayerMetric.Revive(sReviveAction.GetRevivePosition(revivePlayerMetric));
}
}
}
}
}
internal class ReviveOnBodyCollected : IReviveCondition
{
private readonly Dictionary<ulong, float> _mTimers = new Dictionary<ulong, float>();
public void Reset()
{
_mTimers.Clear();
}
public void SoftReset(RevivePlayerMetric metric)
{
ulong actualClientId = metric.Player.actualClientId;
_mTimers[actualClientId] = 0f;
}
public bool ShouldRevivePlayer(RevivePlayerMetric metric)
{
if (_config.ReviveOnBodyCollectedBool.Value && metric.Player.isPlayerDead)
{
ulong actualClientId = metric.Player.actualClientId;
float num = 5f;
if (!_mTimers.TryGetValue(actualClientId, out var value))
{
_mTimers.Add(actualClientId, 0f);
return false;
}
_mTimers[actualClientId] = value + Time.deltaTime;
value = _mTimers[actualClientId];
if (value > num)
{
_mTimers[actualClientId] = 0f;
return metric.Player.deadBody.isInShip;
}
}
return false;
}
}
internal class ReviveOnTimer : IReviveCondition
{
private readonly Dictionary<ulong, float> _mTimers = new Dictionary<ulong, float>();
public void Reset()
{
_mTimers.Clear();
}
public void SoftReset(RevivePlayerMetric metric)
{
ulong actualClientId = metric.Player.actualClientId;
_mTimers[actualClientId] = 0f;
}
public bool ShouldRevivePlayer(RevivePlayerMetric metric)
{
if (!metric.Player.isPlayerDead)
{
return false;
}
ulong actualClientId = metric.Player.actualClientId;
float value = _config.RespawnTimeSeconds.Value;
if (!_mTimers.TryGetValue(actualClientId, out var value2))
{
_mTimers.Add(actualClientId, 0f);
return false;
}
_mTimers[actualClientId] = value2 + Time.deltaTime;
value2 = _mTimers[actualClientId];
if (value2 > value)
{
_mTimers[actualClientId] = 0f;
return true;
}
return false;
}
}
private PlayerControllerB Player { get; }
private int LivesLeft { get; set; }
private RevivePlayerMetric(PlayerControllerB player, int revives)
{
Player = player;
LivesLeft = revives;
}
private bool CanRevive()
{
return LivesLeft + Instance.GlobalLivesLeft > 0;
}
private int GetPlayerIndex()
{
StartOfRound instance = StartOfRound.Instance;
if (instance == null)
{
throw new NullReferenceException("Start of round is null");
}
for (int i = 0; i < instance.allPlayerScripts.Length; i++)
{
PlayerControllerB val = instance.allPlayerScripts[i];
if (val.actualClientId == Player.actualClientId && (val.actualClientId != 0L || val.isHostPlayerObject))
{
return i;
}
}
throw new ArgumentException("Unknown Player Index: " + (object)Player);
}
private void Revive(Vector3 revivePos)
{
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_026c: Unknown result type (might be due to invalid IL or missing references)
//IL_0271: Unknown result type (might be due to invalid IL or missing references)
if (!CanRevive())
{
return;
}
StartOfRound instance = StartOfRound.Instance;
if (Instance.inVR)
{
ReviveVRPlayer();
}
int playerIndex = GetPlayerIndex();
instance.livingPlayers++;
Player.isClimbingLadder = false;
Player.clampLooking = false;
Player.inVehicleAnimation = false;
Player.disableMoveInput = false;
Player.ResetZAndXRotation();
((Collider)Player.thisController).enabled = true;
Player.health = 100;
Player.hasBeenCriticallyInjured = false;
Player.disableLookInput = false;
Player.disableInteract = false;
Player.isPlayerDead = false;
Player.isPlayerControlled = true;
Player.isInElevator = true;
Player.isInHangarShipRoom = true;
Player.isInsideFactory = false;
Player.parentedToElevatorLastFrame = false;
Player.overrideGameOverSpectatePivot = null;
instance.SetPlayerObjectExtrapolate(false);
Player.TeleportPlayer(revivePos, false, 0f, false, true);
Player.setPositionOfDeadPlayer = false;
Player.DisablePlayerModel(instance.allPlayerObjects[playerIndex], true, true);
((Behaviour)Player.helmetLight).enabled = false;
Player.Crouch(false);
Player.criticallyInjured = false;
if ((Object)(object)Player.playerBodyAnimator != (Object)null)
{
Player.playerBodyAnimator.SetBool(LimpAnimator, false);
}
Player.bleedingHeavily = false;
Player.activatingItem = false;
Player.twoHanded = false;
Player.inShockingMinigame = false;
Player.inSpecialInteractAnimation = false;
Player.freeRotationInInteractAnimation = false;
Player.disableSyncInAnimation = false;
Player.inAnimationWithEnemy = null;
Player.holdingWalkieTalkie = false;
Player.speakingToWalkieTalkie = false;
Player.isSinking = false;
Player.isUnderwater = false;
Player.sinkingValue = 0f;
Player.statusEffectAudio.Stop();
Player.DisableJetpackControlsLocally();
Player.mapRadarDotAnimator.SetBool(DeadAnimator, false);
Player.externalForceAutoFade = Vector3.zero;
if (((NetworkBehaviour)Player).IsOwner)
{
HUDManager.Instance.gasHelmetAnimator.SetBool(GasEmittingAnimator, false);
Player.hasBegunSpectating = false;
HUDManager.Instance.RemoveSpectateUI();
HUDManager.Instance.gameOverAnimator.SetTrigger(ReviveAnimator);
Player.hinderedMultiplier = 1f;
Player.isMovementHindered = 0;
Player.sourcesCausingSinking = 0;
Player.reverbPreset = instance.shipReverb;
HUDManager.Instance.UpdateHealthUI(100, false);
((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false;
HUDManager.Instance.HideHUD(false);
}
SoundManager.Instance.earsRingingTimer = 0f;
Player.voiceMuffledByEnemy = false;
SoundManager.Instance.playerVoicePitchTargets[playerIndex] = 1f;
SoundManager.Instance.SetPlayerPitch(1f, playerIndex);
if ((Object)(object)Player.currentVoiceChatIngameSettings == (Object)null)
{
instance.RefreshPlayerVoicePlaybackObjects();
}
if ((Object)(object)Player.currentVoiceChatIngameSettings != (Object)null)
{
if ((Object)(object)Player.currentVoiceChatIngameSettings.voiceAudio == (Object)null)
{
Player.currentVoiceChatIngameSettings.InitializeComponents();
}
if ((Object)(object)Player.currentVoiceChatIngameSettings.voiceAudio == (Object)null)
{
return;
}
((Component)Player.currentVoiceChatIngameSettings.voiceAudio).GetComponent<OccludeAudio>().overridingLowPass = false;
}
Player.spectatedPlayerScript = null;
instance.SetSpectateCameraToGameOverMode(false, Player);
instance.UpdatePlayerVoiceEffects();
Logger.LogInfo((object)$"LivesLeft: {LivesLeft} | GlobalLivesLeft: {Instance.GlobalLivesLeft}");
if (LivesLeft > 0)
{
int livesLeft = LivesLeft - 1;
LivesLeft = livesLeft;
if (Object.op_Implicit((Object)(object)HUDManager.Instance) && ((NetworkBehaviour)Player).IsOwner)
{
HUDManager.Instance.DisplayTip("Lives", $"You have {LivesLeft} live(s) left.", LivesLeft <= 1, false, "LC_Tip1");
}
}
else
{
int globalLivesLeft = Instance.GlobalLivesLeft - 1;
Instance.GlobalLivesLeft = globalLivesLeft;
if (Object.op_Implicit((Object)(object)HUDManager.Instance))
{
HUDManager.Instance.DisplayTip("Lives", $"There are {Instance.GlobalLivesLeft} team live(s) left.", Instance.GlobalLivesLeft <= 1, false, "LC_Tip1");
}
}
}
private void ReviveVRPlayer()
{
SpectatorPlayerPatches.OnPlayerRevived();
}
}
internal interface IReviveCondition
{
void Reset();
void SoftReset(RevivePlayerMetric metric);
bool ShouldRevivePlayer(RevivePlayerMetric metric);
Vector3 GetRevivePosition(RevivePlayerMetric _)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return StartOfRound.Instance.middleOfShipNode.position;
}
}
public bool inVR;
private static Configs _config = null;
private static readonly int LimpAnimator = Animator.StringToHash("Limp");
private static readonly int DeadAnimator = Animator.StringToHash("dead");
private static readonly int GasEmittingAnimator = Animator.StringToHash("gasEmitting");
private static readonly int ReviveAnimator = Animator.StringToHash("revive");
private static LC_Lives Instance { get; set; } = null;
private static ManualLogSource Logger { get; set; } = null;
private static Harmony? Harmony { get; set; }
private int GlobalLivesLeft { get; set; }
private void Awake()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
Instance = this;
Harmony = new Harmony("slenered.LC_Lives");
if (Chainloader.PluginInfos.ContainsKey("io.daxcess.lcvr"))
{
LCVRCompatibility();
}
else
{
Logger.LogInfo((object)"LCVR was not found. Skipping...");
}
_config = new Configs(((BaseUnityPlugin)this).Config);
((SyncedConfig2<Configs>)(object)_config).InitialSyncCompleted += delegate
{
Logger.LogInfo((object)"Initial sync complete!");
if (_config.ReviveOnBodyCollectedBool.Value)
{
Logger.LogInfo((object)"On Body Collect!");
RevivePlayerMetric.RevivePlayerSystem.AddReviveCondition(new RevivePlayerMetric.ReviveOnBodyCollected());
}
if (_config.RespawnTimeSeconds.Value > 0f)
{
Logger.LogInfo((object)"On Timer!");
RevivePlayerMetric.RevivePlayerSystem.AddReviveCondition(new RevivePlayerMetric.ReviveOnTimer());
}
};
try
{
Harmony.PatchAll(typeof(RevivePlayerMetric.RevivePlayerSystem));
}
catch (Exception ex)
{
Logger.LogError((object)("Failed to patch Revive System; '" + ex.Message + "'\n" + ex.StackTrace));
}
Logger.LogInfo((object)$"PartySize: {_config.PartySize.Value}");
Logger.LogInfo((object)$"GlobalLives: {_config.GlobalLives.Value}");
Logger.LogInfo((object)$"PlayerLives: {_config.PlayerLives.Value}");
Logger.LogInfo((object)$"ReviveOnBodyCollectedBool: {_config.ReviveOnBodyCollectedBool.Value}");
Logger.LogInfo((object)$"RespawnTimeSeconds: {_config.RespawnTimeSeconds.Value}");
Logger.LogInfo((object)$"PreventShipFromLeaving: {_config.PreventShipFromLeaving.Value}");
Logger.LogInfo((object)"------------------------------------------");
Logger.LogInfo((object)"slenered.LC_Lives v1.0.3 has loaded!");
}
private void LCVRCompatibility()
{
Logger.LogInfo((object)"LCVR Found!");
inVR = VRSession.InVR;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "slenered.LC_Lives";
public const string PLUGIN_NAME = "slenered.LC_Lives";
public const string PLUGIN_VERSION = "1.0.3";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}