using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BunkbedRevive.Configuration;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using Microsoft.CodeAnalysis;
using StaticNetcodeLib;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
[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")]
[assembly: AssemblyCompany("BunkbedRevive")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Revive dead players at the bunkbeds")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("BunkbedRevive")]
[assembly: AssemblyTitle("BunkbedRevive")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.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 BunkbedRevive
{
public class BunkbedController : MonoBehaviour
{
private static InteractTrigger interactTrigger;
private static Sprite defaultIcon;
private static Sprite disabledIcon;
public static BunkbedController Instance;
public static int remainingOverallRevives = 0;
public static List<int> teleportedBodies = new List<int>();
public static Dictionary<int, int> remainingPlayerRevives = new Dictionary<int, int>();
public static int GetReviveCost()
{
CostMethods reviveCostMethod = NetworkSync.Config.ReviveCostMethod;
int reviveCostPercent = NetworkSync.Config.ReviveCostPercent;
int reviveCostAmount = NetworkSync.Config.ReviveCostAmount;
BunkbedRevive.Logger.LogDebug((object)$"GetReviveCost called - Method: {reviveCostMethod}, Percent: {reviveCostPercent}%, Amount: {reviveCostAmount}");
if (reviveCostMethod == CostMethods.SetAmount)
{
int num = ((reviveCostAmount > 0) ? reviveCostAmount : 0);
BunkbedRevive.Logger.LogDebug((object)$"Using SetAmount method - Cost: {num}");
return num;
}
if (reviveCostPercent <= 0)
{
BunkbedRevive.Logger.LogDebug((object)"Using Percentage method but percent is 0 - Cost: 0");
return 0;
}
int num2 = (int)Math.Floor((float)TimeOfDay.Instance.profitQuota * ((float)reviveCostPercent / 100f));
BunkbedRevive.Logger.LogDebug((object)$"Using Percentage method - Quota: {TimeOfDay.Instance.profitQuota}, Calculated Cost: {num2}");
return num2;
}
public static bool CanRevive(int id, bool logStuff = false)
{
ReviveLimits reviveLimitMethod = NetworkSync.Config.ReviveLimitMethod;
bool reviveTeleported = NetworkSync.Config.ReviveTeleported;
BunkbedRevive.Logger.LogDebug((object)$"CanRevive called - PlayerID: {id}, ReviveLimit: {reviveLimitMethod}, CanReviveTeleported: {reviveTeleported}");
if (!reviveTeleported && teleportedBodies.Contains(id))
{
BunkbedRevive.Logger.LogDebug((object)$"Player {id} cannot be revived - body was teleported");
return false;
}
switch (reviveLimitMethod)
{
case ReviveLimits.None:
BunkbedRevive.Logger.LogDebug((object)$"Player {id} can be revived - no revive limits");
return true;
case ReviveLimits.Overall:
{
bool flag2 = remainingOverallRevives > 0;
BunkbedRevive.Logger.LogDebug((object)$"Overall revive limit - Remaining: {remainingOverallRevives}, Can Revive: {flag2}");
return flag2;
}
case ReviveLimits.PerPlayer:
if (remainingPlayerRevives.ContainsKey(id))
{
bool flag = remainingPlayerRevives[id] > 0;
BunkbedRevive.Logger.LogDebug((object)$"Per-player revive limit for {id} - Remaining: {remainingPlayerRevives[id]}, Can Revive: {flag}");
return flag;
}
BunkbedRevive.Logger.LogDebug((object)$"Player {id} not in revive dictionary - adding with limit {NetworkSync.Config.ReviveLimitPer}");
remainingPlayerRevives.Add(id, NetworkSync.Config.ReviveLimitPer);
return true;
default:
BunkbedRevive.Logger.LogDebug((object)$"Player {id} can be revived - default true");
return true;
}
}
public static void UpdateReviveCount(int id)
{
ReviveLimits reviveLimitMethod = NetworkSync.Config.ReviveLimitMethod;
BunkbedRevive.Logger.LogDebug((object)$"UpdateReviveCount called - PlayerID: {id}, ReviveLimit: {reviveLimitMethod}");
switch (reviveLimitMethod)
{
case ReviveLimits.None:
BunkbedRevive.Logger.LogDebug((object)"No revive limits - not updating count");
return;
case ReviveLimits.Overall:
{
int num = remainingOverallRevives;
remainingOverallRevives--;
BunkbedRevive.Logger.LogDebug((object)$"Overall revive count updated - Before: {num}, After: {remainingOverallRevives}");
break;
}
}
if (reviveLimitMethod == ReviveLimits.PerPlayer)
{
if (!remainingPlayerRevives.ContainsKey(id))
{
BunkbedRevive.Logger.LogDebug((object)$"Player {id} not in revive dictionary - adding with limit {NetworkSync.Config.ReviveLimitPer}");
remainingPlayerRevives.Add(id, NetworkSync.Config.ReviveLimitPer);
}
int num2 = remainingPlayerRevives[id];
remainingPlayerRevives[id]--;
BunkbedRevive.Logger.LogDebug((object)$"Per-player revive count updated for {id} - Before: {num2}, After: {remainingPlayerRevives[id]}");
}
}
private static void CreateTrigger()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_004a: 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)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Expected O, but got Unknown
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_0196: Expected O, but got Unknown
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01b4: Expected O, but got Unknown
GameObject val = new GameObject("Bed", new Type[2]
{
typeof(BoxCollider),
typeof(InteractTrigger)
});
Transform transform = ((Component)Instance).transform;
val.transform.SetParent(transform);
val.transform.localPosition = Vector3.zero;
val.layer = LayerMask.NameToLayer("InteractableObject");
val.tag = "InteractTrigger";
BoxCollider component = val.GetComponent<BoxCollider>();
component.center = Vector3.zero;
component.size = new Vector3(2.5f, 3f, 1f);
((Collider)component).enabled = true;
int reviveCost = GetReviveCost();
interactTrigger = val.GetComponent<InteractTrigger>();
interactTrigger.twoHandedItemAllowed = true;
interactTrigger.interactable = true;
interactTrigger.holdInteraction = false;
interactTrigger.timeToHold = 0.4f;
interactTrigger.cooldownTime = 0.25f;
interactTrigger.timeToHoldSpeedMultiplier = 1f;
interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]";
interactTrigger.hoverIcon = defaultIcon;
interactTrigger.disabledHoverIcon = disabledIcon;
interactTrigger.disabledHoverTip = "No dead players";
interactTrigger.onCancelAnimation = new InteractEvent();
interactTrigger.holdingInteractEvent = new InteractEventFloat();
interactTrigger.onInteractEarly = new InteractEvent();
interactTrigger.onInteract = new InteractEvent();
interactTrigger.onStopInteract = new InteractEvent();
((UnityEvent<PlayerControllerB>)(object)interactTrigger.onInteract).AddListener((UnityAction<PlayerControllerB>)delegate
{
OnInteract();
});
((UnityEvent<PlayerControllerB>)(object)interactTrigger.onStopInteract).AddListener((UnityAction<PlayerControllerB>)delegate
{
OnStopInteract();
});
}
public static void ResetValues()
{
BunkbedRevive.Logger.LogDebug((object)$"ResetValues called - Setting overall revives to {NetworkSync.Config.ReviveLimitOverall}");
remainingOverallRevives = NetworkSync.Config.ReviveLimitOverall;
remainingPlayerRevives.Clear();
teleportedBodies.Clear();
BunkbedRevive.Logger.LogDebug((object)"Player revive counters and teleported bodies cleared");
}
private void Awake()
{
BunkbedRevive.Logger.LogDebug((object)"BunkbedController Awake called");
Instance = this;
GetIcons();
CreateTrigger();
ResetValues();
BunkbedRevive.Logger.LogInfo((object)"BunkbedController initialized successfully");
}
private void Update()
{
if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)
{
return;
}
bool flag = StartOfRound.Instance.connectedPlayersAmount + 1 - StartOfRound.Instance.livingPlayers > 0;
RagdollGrabbableObject heldBody = GetHeldBody();
interactTrigger.interactable = flag && Object.op_Implicit((Object)(object)heldBody);
if (!Object.op_Implicit((Object)(object)heldBody))
{
return;
}
string text = (Object.op_Implicit((Object)(object)heldBody.ragdoll) ? heldBody.ragdoll.playerScript.playerUsername : "Player");
int num = heldBody.bodyID.Value;
if ((Object)(object)heldBody.ragdoll != (Object)null && (Object)(object)heldBody.ragdoll.playerScript != (Object)null)
{
int num2 = (int)heldBody.ragdoll.playerScript.playerClientId;
if (num != num2)
{
num = num2;
}
}
if (!CanRevive(num))
{
interactTrigger.hoverTip = "Can't revive " + text;
return;
}
int reviveCost = GetReviveCost();
interactTrigger.hoverTip = "Revive " + text + " for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]";
}
private static void GetIcons()
{
StartMatchLever val = Object.FindObjectOfType<StartMatchLever>();
defaultIcon = val.triggerScript.hoverIcon;
disabledIcon = val.triggerScript.disabledHoverIcon;
}
private static RagdollGrabbableObject? GetHeldBody()
{
PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
GrabbableObject currentlyHeldObjectServer = GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer;
if (!localPlayerController.isHoldingObject || (Object)(object)currentlyHeldObjectServer == (Object)null || !Object.op_Implicit((Object)(object)currentlyHeldObjectServer) || !(currentlyHeldObjectServer is RagdollGrabbableObject))
{
return null;
}
return (RagdollGrabbableObject?)(object)((currentlyHeldObjectServer is RagdollGrabbableObject) ? currentlyHeldObjectServer : null);
}
private static PlayerControllerB GetLocalPlayer()
{
return GameNetworkManager.Instance.localPlayerController;
}
public static void RevivePlayer(int playerId)
{
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
BunkbedRevive.Logger.LogDebug((object)$"RevivePlayer called for PlayerID: {playerId}");
PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerId];
if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)null)
{
BunkbedRevive.Logger.LogError((object)$"Cannot revive player {playerId} - player script is null or invalid");
return;
}
string playerUsername = val.playerUsername;
bool isPlayerDead = val.isPlayerDead;
BunkbedRevive.Logger.LogDebug((object)$"Reviving {playerUsername} (ID: {playerId}) - Was Dead: {isPlayerDead}, Is Controlled: {val.isPlayerControlled}");
UpdateReviveCount(playerId);
if (val.isPlayerDead || val.isPlayerControlled)
{
BunkbedRevive.Logger.LogDebug((object)("Resetting player state for " + playerUsername));
val.ResetPlayerBloodObjects(val.isPlayerDead);
val.isClimbingLadder = false;
val.clampLooking = false;
val.inVehicleAnimation = false;
val.disableMoveInput = false;
val.ResetZAndXRotation();
((Collider)val.thisController).enabled = true;
val.health = 100;
val.disableLookInput = false;
val.disableInteract = false;
if (val.isPlayerDead)
{
BunkbedRevive.Logger.LogDebug((object)("Player " + playerUsername + " was dead - performing full revival"));
val.isPlayerDead = false;
val.isPlayerControlled = true;
val.isInElevator = true;
val.isInHangarShipRoom = true;
val.isInsideFactory = false;
val.parentedToElevatorLastFrame = false;
val.overrideGameOverSpectatePivot = null;
StartOfRound.Instance.SetPlayerObjectExtrapolate(false);
val.TeleportPlayer(StartOfRound.Instance.GetPlayerSpawnPosition(playerId, false), false, 0f, false, true);
BunkbedRevive.Logger.LogDebug((object)("Teleported " + playerUsername + " to spawn position"));
val.setPositionOfDeadPlayer = false;
val.DisablePlayerModel(StartOfRound.Instance.allPlayerObjects[playerId], true, true);
((Behaviour)val.helmetLight).enabled = false;
val.Crouch(false);
val.criticallyInjured = false;
if ((Object)(object)val.playerBodyAnimator != (Object)null)
{
val.playerBodyAnimator.SetBool("Limp", false);
}
val.bleedingHeavily = false;
val.activatingItem = false;
val.twoHanded = false;
val.inShockingMinigame = false;
val.inSpecialInteractAnimation = false;
val.freeRotationInInteractAnimation = false;
val.disableSyncInAnimation = false;
val.inAnimationWithEnemy = null;
val.holdingWalkieTalkie = false;
val.speakingToWalkieTalkie = false;
val.isSinking = false;
val.isUnderwater = false;
val.sinkingValue = 0f;
val.statusEffectAudio.Stop();
val.DisableJetpackControlsLocally();
val.health = 100;
val.mapRadarDotAnimator.SetBool("dead", false);
val.deadBody = null;
val.externalForceAutoFade = Vector3.zero;
if ((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController)
{
BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is local player - updating local UI"));
HUDManager.Instance.gasHelmetAnimator.SetBool("gasEmitting", false);
val.hasBegunSpectating = false;
HUDManager.Instance.RemoveSpectateUI();
HUDManager.Instance.gameOverAnimator.SetTrigger("revive");
val.hinderedMultiplier = 1f;
val.isMovementHindered = 0;
val.sourcesCausingSinking = 0;
val.reverbPreset = StartOfRound.Instance.shipReverb;
}
}
BunkbedRevive.Logger.LogDebug((object)("Resetting audio and voice settings for " + playerUsername));
SoundManager.Instance.earsRingingTimer = 0f;
val.voiceMuffledByEnemy = false;
SoundManager.Instance.playerVoicePitchTargets[playerId] = 1f;
SoundManager.Instance.SetPlayerPitch(1f, playerId);
if ((Object)(object)val.currentVoiceChatIngameSettings == (Object)null)
{
StartOfRound.Instance.RefreshPlayerVoicePlaybackObjects();
}
if ((Object)(object)val.currentVoiceChatIngameSettings != (Object)null)
{
if ((Object)(object)val.currentVoiceChatIngameSettings.voiceAudio == (Object)null)
{
val.currentVoiceChatIngameSettings.InitializeComponents();
}
if ((Object)(object)val.currentVoiceChatIngameSettings.voiceAudio == (Object)null)
{
return;
}
((Component)val.currentVoiceChatIngameSettings.voiceAudio).GetComponent<OccludeAudio>().overridingLowPass = false;
}
}
BunkbedRevive.Logger.LogDebug((object)$"Updating game state - Living players before: {StartOfRound.Instance.livingPlayers}");
StartOfRound instance = StartOfRound.Instance;
instance.livingPlayers++;
StartOfRound.Instance.allPlayersDead = false;
BunkbedRevive.Logger.LogDebug((object)$"Living players after: {StartOfRound.Instance.livingPlayers}, All players dead: {StartOfRound.Instance.allPlayersDead}");
if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)(object)val)
{
BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is local player - updating local player state"));
val.bleedingHeavily = false;
val.criticallyInjured = false;
val.playerBodyAnimator.SetBool("Limp", false);
val.health = 100;
HUDManager.Instance.UpdateHealthUI(100, false);
val.spectatedPlayerScript = null;
((Behaviour)HUDManager.Instance.audioListenerLowPass).enabled = false;
StartOfRound.Instance.SetSpectateCameraToGameOverMode(false, val);
TimeOfDay.Instance.DisableAllWeather(false);
StartOfRound.Instance.UpdatePlayerVoiceEffects();
((Renderer)val.thisPlayerModel).enabled = true;
HUDManager.Instance.HideHUD(false);
}
else
{
BunkbedRevive.Logger.LogDebug((object)(playerUsername + " is remote player - enabling player models"));
((Renderer)val.thisPlayerModel).enabled = true;
((Renderer)val.thisPlayerModelLOD1).enabled = true;
((Renderer)val.thisPlayerModelLOD2).enabled = true;
}
BunkbedRevive.Logger.LogInfo((object)$"Successfully revived {playerUsername} (ID: {playerId})");
}
public static void OnInteract()
{
BunkbedRevive.Logger.LogDebug((object)"OnInteract called - bunkbed interaction started");
PlayerControllerB localPlayer = GetLocalPlayer();
RagdollGrabbableObject heldBody = GetHeldBody();
if (!Object.op_Implicit((Object)(object)heldBody))
{
BunkbedRevive.Logger.LogWarning((object)"OnInteract called but player is not holding a body");
return;
}
int num = heldBody.bodyID.Value;
string text = "Unknown";
if ((Object)(object)heldBody.ragdoll != (Object)null && (Object)(object)heldBody.ragdoll.playerScript != (Object)null)
{
text = heldBody.ragdoll.playerScript.playerUsername;
int num2 = (int)heldBody.ragdoll.playerScript.playerClientId;
BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Body Info - BodyID from NetworkVar: {num}, Actual PlayerClientId from ragdoll: {num2}, Player Name: {text}");
if (num != num2)
{
BunkbedRevive.Logger.LogWarning((object)$"[CLIENT] BODY ID MISMATCH! BodyID ({num}) != PlayerClientId ({num2}) for player {text}");
BunkbedRevive.Logger.LogWarning((object)"[CLIENT] This is likely a desync issue. Using actual PlayerClientId instead.");
num = num2;
}
}
else
{
BunkbedRevive.Logger.LogWarning((object)$"[CLIENT] Could not get ragdoll player info! Using bodyID: {num}");
}
int reviveCost = GetReviveCost();
BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Attempting revive - PlayerID: {num}, Player Name: {text}, Cost: {reviveCost}, Current Credits: {HUDManager.Instance.terminalScript.groupCredits}");
if (HUDManager.Instance.terminalScript.groupCredits < reviveCost)
{
BunkbedRevive.Logger.LogDebug((object)$"Not enough credits - Need: {reviveCost}, Have: {HUDManager.Instance.terminalScript.groupCredits}");
HUDManager.Instance.DisplayGlobalNotification("Not enough credits");
interactTrigger.StopInteraction();
return;
}
if (!CanRevive(num, logStuff: true))
{
BunkbedRevive.Logger.LogDebug((object)$"Cannot revive player {num} ({text}) - revive limit or teleportation rule");
HUDManager.Instance.DisplayGlobalNotification("Can't Revive");
interactTrigger.StopInteraction();
return;
}
BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] Sending RevivePlayerServerRpc for player {num} ({text})");
BunkbedNetworking.RevivePlayerServerRpc(num, reviveCost);
if (Object.op_Implicit((Object)(object)localPlayer))
{
BunkbedRevive.Logger.LogDebug((object)"Despawning held body object");
localPlayer.DespawnHeldObject();
}
}
private static void OnStopInteract()
{
int reviveCost = GetReviveCost();
interactTrigger.hoverTip = "Revive for " + ((reviveCost <= 0) ? "free" : (reviveCost + " scrap")) + " : [E]";
}
}
[StaticNetcode]
internal class BunkbedNetworking
{
[ServerRpc(RequireOwnership = false)]
public static void RevivePlayerServerRpc(int id, int reviveCost)
{
BunkbedRevive.Logger.LogDebug((object)$"[SERVER] RevivePlayerServerRpc called - PlayerID: {id}, Cost: {reviveCost}");
if ((Object)(object)StartOfRound.Instance == (Object)null || id < 0 || id >= StartOfRound.Instance.allPlayerScripts.Length)
{
ManualLogSource logger = BunkbedRevive.Logger;
object arg = id;
StartOfRound instance = StartOfRound.Instance;
logger.LogError((object)$"[SERVER] Invalid player ID: {arg}. Valid range: 0-{((instance != null) ? (instance.allPlayerScripts.Length - 1) : (-1))}");
NotifyClientRpc("Invalid player ID", success: false);
return;
}
PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[id];
if ((Object)(object)val == (Object)null)
{
BunkbedRevive.Logger.LogError((object)$"[SERVER] Player script is null for ID: {id}");
NotifyClientRpc("Player not found", success: false);
return;
}
if (!val.isPlayerDead)
{
BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Attempted to revive player {val.playerUsername} (ID: {id}) who is not dead!");
NotifyClientRpc(val.playerUsername + " is not dead", success: false);
return;
}
BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Validated player {val.playerUsername} (ID: {id}) is dead and ready for revival");
Terminal val2 = Object.FindObjectOfType<Terminal>();
if ((Object)(object)val2 == (Object)null)
{
BunkbedRevive.Logger.LogError((object)"[SERVER] Terminal not found! Cannot process revive.");
return;
}
BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Current credits before revive: {val2.groupCredits}");
if (val2.groupCredits < reviveCost)
{
BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Not enough credits to revive player {id}. Required: {reviveCost}, Available: {val2.groupCredits}");
NotifyClientRpc("Not enough credits", success: false);
return;
}
if (!BunkbedController.CanRevive(id))
{
BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Cannot revive player {id} due to revive limits or teleportation rules");
NotifyClientRpc("Can't Revive", success: false);
return;
}
val2.groupCredits -= reviveCost;
BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Credits after deduction: {val2.groupCredits}");
BunkbedRevive.Logger.LogDebug((object)"[SERVER] Syncing credits to all clients...");
val2.SyncGroupCreditsServerRpc(val2.groupCredits, val2.numberOfItemsInDropship);
string text = "Player";
if ((Object)(object)StartOfRound.Instance != (Object)null && id >= 0 && id < StartOfRound.Instance.allPlayerScripts.Length)
{
PlayerControllerB val3 = StartOfRound.Instance.allPlayerScripts[id];
if ((Object)(object)val3 != (Object)null)
{
text = val3.playerUsername;
BunkbedRevive.Logger.LogDebug((object)$"[SERVER] Reviving player: {text} (ID: {id})");
}
else
{
BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Player script is null for ID: {id}");
}
}
else
{
BunkbedRevive.Logger.LogWarning((object)$"[SERVER] Invalid player ID: {id} or StartOfRound instance not found");
}
BunkbedRevive.Logger.LogInfo((object)$"[SERVER] Broadcasting revive for {text} (ID: {id})");
RevivePlayerClientRpc(id, text);
}
[ClientRpc]
public static void RevivePlayerClientRpc(int id, string playerName)
{
BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] RevivePlayerClientRpc received - PlayerID: {id}, PlayerName: {playerName}");
try
{
BunkbedController.RevivePlayer(id);
HUDManager.Instance.DisplayGlobalNotification(playerName + " has been revived");
BunkbedRevive.Logger.LogDebug((object)("[CLIENT] Successfully revived " + playerName));
}
catch (Exception ex)
{
BunkbedRevive.Logger.LogError((object)$"[CLIENT] Error reviving player {playerName} (ID: {id}): {ex.Message}");
BunkbedRevive.Logger.LogError((object)("[CLIENT] Stack trace: " + ex.StackTrace));
}
}
[ClientRpc]
public static void NotifyClientRpc(string message, bool success)
{
BunkbedRevive.Logger.LogDebug((object)$"[CLIENT] NotifyClientRpc received - Message: '{message}', Success: {success}");
HUDManager.Instance.DisplayGlobalNotification(message);
}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("viviko.BunkbedRevive", "BunkbedRevive", "2.0.0")]
public sealed class BunkbedRevive : BaseUnityPlugin
{
[CompilerGenerated]
private static class <>O
{
public static CanModifyDelegate <0>__CanModifyCallback;
}
private readonly Harmony harmony = new Harmony("viviko.BunkbedRevive");
public static BunkbedRevive Instance;
internal static ManualLogSource Logger { get; private set; }
private void Awake()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_003d: 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: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Expected O, but got Unknown
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Expected O, but got Unknown
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Expected O, but got Unknown
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Expected O, but got Unknown
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Expected O, but got Unknown
//IL_00bf: 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_00ca: Expected O, but got Unknown
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Expected O, but got Unknown
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Expected O, but got Unknown
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Expected O, but got Unknown
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Expected O, but got Unknown
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Expected O, but got Unknown
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Expected O, but got Unknown
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Expected O, but got Unknown
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Expected O, but got Unknown
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01eb: Expected O, but got Unknown
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Expected O, but got Unknown
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
//IL_0220: Expected O, but got Unknown
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Expected O, but got Unknown
Instance = this;
Logger = ((BaseUnityPlugin)this).Logger;
CustomConfig.Init();
ConfigEntry<CostMethods> reviveCostMethod = CustomConfig.ReviveCostMethod;
EnumDropDownOptions val = new EnumDropDownOptions();
((BaseOptions)val).RequiresRestart = false;
EnumDropDownOptions obj = val;
object obj2 = <>O.<0>__CanModifyCallback;
if (obj2 == null)
{
CanModifyDelegate val2 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val2;
obj2 = (object)val2;
}
((BaseOptions)obj).CanModifyCallback = (CanModifyDelegate)obj2;
LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<CostMethods>(reviveCostMethod, val));
ConfigEntry<int> reviveCostPercent = CustomConfig.ReviveCostPercent;
IntSliderOptions val3 = new IntSliderOptions();
((BaseOptions)val3).RequiresRestart = false;
IntSliderOptions obj3 = val3;
object obj4 = <>O.<0>__CanModifyCallback;
if (obj4 == null)
{
CanModifyDelegate val4 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val4;
obj4 = (object)val4;
}
((BaseOptions)obj3).CanModifyCallback = (CanModifyDelegate)obj4;
LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveCostPercent, val3));
ConfigEntry<int> reviveCostAmount = CustomConfig.ReviveCostAmount;
val3 = new IntSliderOptions();
((BaseOptions)val3).RequiresRestart = false;
IntSliderOptions obj5 = val3;
object obj6 = <>O.<0>__CanModifyCallback;
if (obj6 == null)
{
CanModifyDelegate val5 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val5;
obj6 = (object)val5;
}
((BaseOptions)obj5).CanModifyCallback = (CanModifyDelegate)obj6;
LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveCostAmount, val3));
ConfigEntry<ReviveLimits> reviveLimitMethod = CustomConfig.ReviveLimitMethod;
val = new EnumDropDownOptions();
((BaseOptions)val).RequiresRestart = false;
EnumDropDownOptions obj7 = val;
object obj8 = <>O.<0>__CanModifyCallback;
if (obj8 == null)
{
CanModifyDelegate val6 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val6;
obj8 = (object)val6;
}
((BaseOptions)obj7).CanModifyCallback = (CanModifyDelegate)obj8;
LethalConfigManager.AddConfigItem((BaseConfigItem)(object)new EnumDropDownConfigItem<ReviveLimits>(reviveLimitMethod, val));
ConfigEntry<int> reviveLimitPer = CustomConfig.ReviveLimitPer;
val3 = new IntSliderOptions();
((BaseOptions)val3).RequiresRestart = false;
IntSliderOptions obj9 = val3;
object obj10 = <>O.<0>__CanModifyCallback;
if (obj10 == null)
{
CanModifyDelegate val7 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val7;
obj10 = (object)val7;
}
((BaseOptions)obj9).CanModifyCallback = (CanModifyDelegate)obj10;
LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveLimitPer, val3));
ConfigEntry<int> reviveLimitOverall = CustomConfig.ReviveLimitOverall;
val3 = new IntSliderOptions();
((BaseOptions)val3).RequiresRestart = false;
IntSliderOptions obj11 = val3;
object obj12 = <>O.<0>__CanModifyCallback;
if (obj12 == null)
{
CanModifyDelegate val8 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val8;
obj12 = (object)val8;
}
((BaseOptions)obj11).CanModifyCallback = (CanModifyDelegate)obj12;
LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(reviveLimitOverall, val3));
ConfigEntry<bool> reviveTeleported = CustomConfig.ReviveTeleported;
BoolCheckBoxOptions val9 = new BoolCheckBoxOptions();
((BaseOptions)val9).RequiresRestart = false;
object obj13 = <>O.<0>__CanModifyCallback;
if (obj13 == null)
{
CanModifyDelegate val10 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val10;
obj13 = (object)val10;
}
((BaseOptions)val9).CanModifyCallback = (CanModifyDelegate)obj13;
LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(reviveTeleported, val9));
ConfigEntry<float> reviveBodyWeight = CustomConfig.ReviveBodyWeight;
FloatSliderOptions val11 = new FloatSliderOptions();
((BaseOptions)val11).RequiresRestart = false;
object obj14 = <>O.<0>__CanModifyCallback;
if (obj14 == null)
{
CanModifyDelegate val12 = CanModifyCallback;
<>O.<0>__CanModifyCallback = val12;
obj14 = (object)val12;
}
((BaseOptions)val11).CanModifyCallback = (CanModifyDelegate)obj14;
LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(reviveBodyWeight, val11));
harmony.PatchAll();
Logger.LogInfo((object)"Plugin BunkbedRevive v2.0.0 is loaded!");
}
private static CanModifyResult CanModifyCallback()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)GameNetworkManager.Instance) && GameNetworkManager.Instance.gameHasStarted)
{
return CanModifyResult.op_Implicit((false, "This setting cant be changed while in a game"));
}
return CanModifyResult.True();
}
}
internal static class GeneratedPluginInfo
{
public const string Identifier = "viviko.BunkbedRevive";
public const string Name = "BunkbedRevive";
public const string Version = "2.0.0";
}
}
namespace BunkbedRevive.Patches
{
[HarmonyPatch(typeof(RagdollGrabbableObject))]
public class RagdollGrabbableObjectPatch
{
[HarmonyPatch("Start")]
[HarmonyPrefix]
private static void StartPatch(RagdollGrabbableObject __instance)
{
((GrabbableObject)__instance).itemProperties.weight = NetworkSync.Config.ReviveBodyWeight;
}
}
[HarmonyPatch(typeof(RoundManager))]
public class RoundManagerPatch
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
private static void AwakePatch()
{
NetworkSync.Init();
}
[HarmonyPatch("OnDestroy")]
[HarmonyPostfix]
private static void DestroyPatch()
{
NetworkSync.Cleanup();
}
[HarmonyPatch("FinishGeneratingNewLevelClientRpc")]
[HarmonyPostfix]
private static void FinishGeneratingNewLevelClientRpcPatch()
{
NetworkSync.FinishSync(hostSynced: false);
}
}
[HarmonyPatch(typeof(ShipTeleporter))]
public class ShipTeleporterPatch
{
[HarmonyPatch("SetPlayerTeleporterId")]
[HarmonyPrefix]
private static void SetPlayerTeleporterIdPatch(PlayerControllerB playerScript, int teleporterId)
{
if (teleporterId == 1)
{
int num = (int)playerScript.playerClientId;
BunkbedRevive.Logger.LogDebug((object)$"Player {playerScript.playerUsername} (ID: {num}) was teleported (inverse teleporter)");
if (!BunkbedController.teleportedBodies.Contains(num))
{
BunkbedController.teleportedBodies.Add(num);
BunkbedRevive.Logger.LogDebug((object)$"Added player {num} to teleported bodies list");
}
else
{
BunkbedRevive.Logger.LogDebug((object)$"Player {num} already in teleported bodies list");
}
}
}
}
[HarmonyPatch(typeof(StartOfRound))]
public class StartOfRoundPatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void StartPatch(StartOfRound __instance)
{
BunkbedRevive.Logger.LogDebug((object)"StartOfRound.Start called - attaching BunkbedController to bunkbeds");
int bunkBedId = __instance.unlockablesList.unlockables.FindIndex((UnlockableItem un) => un.unlockableName.Contains("bunkbeds", StringComparison.CurrentCultureIgnoreCase));
if (bunkBedId == -1)
{
BunkbedRevive.Logger.LogError((object)"Could not find bunkbeds in unlockables list!");
return;
}
BunkbedRevive.Logger.LogDebug((object)$"Found bunkbeds at index {bunkBedId}");
PlaceableShipObject val = Object.FindObjectsOfType<PlaceableShipObject>().First((PlaceableShipObject pc) => pc.unlockableID == bunkBedId);
if ((Object)(object)val == (Object)null)
{
BunkbedRevive.Logger.LogError((object)"Could not find bunkbeds PlaceableShipObject!");
return;
}
((Component)val).gameObject.AddComponent<BunkbedController>();
BunkbedRevive.Logger.LogInfo((object)"BunkbedController component attached to bunkbeds successfully");
}
[HarmonyPatch("EndOfGame")]
[HarmonyPrefix]
private static void EndOfGamePatch()
{
BunkbedRevive.Logger.LogDebug((object)"EndOfGame called - resetting revive values");
BunkbedController.ResetValues();
}
[HarmonyPatch("openingDoorsSequence")]
[HarmonyPrefix]
private static void openingDoorsSequencePatch()
{
BunkbedRevive.Logger.LogDebug((object)"openingDoorsSequence called - resetting revive values");
BunkbedController.ResetValues();
}
}
}
namespace BunkbedRevive.Configuration
{
internal class CustomConfig
{
internal static ConfigEntry<CostMethods> ReviveCostMethod;
internal static ConfigEntry<int> ReviveCostPercent;
internal static ConfigEntry<int> ReviveCostAmount;
internal static ConfigEntry<ReviveLimits> ReviveLimitMethod;
internal static ConfigEntry<int> ReviveLimitPer;
internal static ConfigEntry<int> ReviveLimitOverall;
internal static ConfigEntry<bool> ReviveTeleported;
internal static ConfigEntry<float> ReviveBodyWeight;
internal static void Init()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Expected O, but got Unknown
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Expected O, but got Unknown
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Expected O, but got Unknown
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Expected O, but got Unknown
ConfigFile config = ((BaseUnityPlugin)BunkbedRevive.Instance).Config;
config.SaveOnConfigSet = false;
ReviveCostMethod = config.Bind<CostMethods>("Cost", "Cost Method", CostMethods.PercentOfQuota, "Which method to use for revive cost");
ReviveCostPercent = config.Bind<int>("Cost", "Percent Of Quota", 30, new ConfigDescription("Adjust the percent of quota a revive will cost", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
ReviveCostAmount = config.Bind<int>("Cost", "Set Amount", 50, new ConfigDescription("Adjust the amount a revive will cost", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
ReviveLimitMethod = config.Bind<ReviveLimits>("Limits", "Revive Limit Method", ReviveLimits.None, "Which method to use for revive limits");
ReviveLimitPer = config.Bind<int>("Limits", "Revives per Player", 2, new ConfigDescription("Adjust the amount of revives per player", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
ReviveLimitOverall = config.Bind<int>("Limits", "Overall Revives", 4, new ConfigDescription("Adjust the amount of overall revives", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
ReviveTeleported = config.Bind<bool>("Limits", "Can Revive Teleported bodies", true, (ConfigDescription)null);
ReviveBodyWeight = config.Bind<float>("Other", "Dead Body Weight", 1.1f, new ConfigDescription("Adjust the weight of dead bodies\n Default is 1.1 as of v56", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null);
dictionary.Clear();
config.Save();
config.SaveOnConfigSet = true;
}
}
public enum CostMethods
{
PercentOfQuota,
SetAmount
}
public enum ReviveLimits
{
None,
PerPlayer,
Overall
}
internal class NetworkConfig : INetworkSerializable
{
public CostMethods ReviveCostMethod = CostMethods.PercentOfQuota;
public int ReviveCostPercent = 30;
public int ReviveCostAmount = 50;
public ReviveLimits ReviveLimitMethod = ReviveLimits.None;
public int ReviveLimitPer = 2;
public int ReviveLimitOverall = 4;
public bool ReviveTeleported = false;
public float ReviveBodyWeight = 1.1f;
public void CopyLocalConfig()
{
ReviveCostMethod = CustomConfig.ReviveCostMethod.Value;
ReviveCostPercent = CustomConfig.ReviveCostPercent.Value;
ReviveCostAmount = CustomConfig.ReviveCostAmount.Value;
ReviveLimitMethod = CustomConfig.ReviveLimitMethod.Value;
ReviveLimitPer = CustomConfig.ReviveLimitPer.Value;
ReviveLimitOverall = CustomConfig.ReviveLimitOverall.Value;
ReviveTeleported = CustomConfig.ReviveTeleported.Value;
ReviveBodyWeight = CustomConfig.ReviveBodyWeight.Value;
}
public unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: 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_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
((BufferSerializer<CostMethods>*)(&serializer))->SerializeValue<CostMethods>(ref ReviveCostMethod, default(ForEnums));
((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveCostPercent, default(ForPrimitives));
((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveCostAmount, default(ForPrimitives));
((BufferSerializer<ReviveLimits>*)(&serializer))->SerializeValue<ReviveLimits>(ref ReviveLimitMethod, default(ForEnums));
((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveLimitPer, default(ForPrimitives));
((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref ReviveLimitOverall, default(ForPrimitives));
((BufferSerializer<bool>*)(&serializer))->SerializeValue<bool>(ref ReviveTeleported, default(ForPrimitives));
((BufferSerializer<float>*)(&serializer))->SerializeValue<float>(ref ReviveBodyWeight, default(ForPrimitives));
}
}
internal static class NetworkSync
{
[CompilerGenerated]
private static class <>O
{
public static HandleNamedMessageDelegate <0>__ContactServerRpc;
public static Action<ulong> <1>__OnClientDisconnect;
public static HandleNamedMessageDelegate <2>__SendConfigClientRpc;
}
public static NetworkConfig Config;
public static bool SyncedWithHost;
public static bool FinishedSync;
public static List<ulong> HostSyncedList;
public static void Init()
{
//IL_0076: 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_0081: Expected O, but got Unknown
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Expected O, but got Unknown
BunkbedRevive.Logger.LogDebug((object)"NetworkSync.Init called");
Config = new NetworkConfig();
Config.CopyLocalConfig();
SyncedWithHost = false;
FinishedSync = false;
if (NetworkManager.Singleton.IsHost)
{
BunkbedRevive.Logger.LogInfo((object)"Setup as host - initializing host-specific handlers");
HostSyncedList = new List<ulong>();
SyncedWithHost = true;
object obj = <>O.<0>__ContactServerRpc;
if (obj == null)
{
HandleNamedMessageDelegate val = ContactServerRpc;
<>O.<0>__ContactServerRpc = val;
obj = (object)val;
}
SetupMessageHandler("ContactServerRpc", (HandleNamedMessageDelegate)obj);
FinishSync(hostSynced: true);
NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnect;
}
else if (NetworkManager.Singleton.IsClient)
{
BunkbedRevive.Logger.LogInfo((object)"Setup as client - registering with host");
object obj2 = <>O.<2>__SendConfigClientRpc;
if (obj2 == null)
{
HandleNamedMessageDelegate val2 = SendConfigClientRpc;
<>O.<2>__SendConfigClientRpc = val2;
obj2 = (object)val2;
}
SetupMessageHandler("SendConfigClientRpc", (HandleNamedMessageDelegate)obj2);
string text = "2.0.0".ToString();
BunkbedRevive.Logger.LogDebug((object)("Sending version " + text + " to host"));
FastBufferWriter buffer = default(FastBufferWriter);
((FastBufferWriter)(ref buffer))..ctor(text.Length * 2, (Allocator)2, -1);
((FastBufferWriter)(ref buffer)).WriteValue(text, false);
SendToHost("ContactServerRpc", buffer, forceSend: true);
}
}
public static void Cleanup()
{
Config = null;
SyncedWithHost = false;
HostSyncedList = null;
FinishedSync = false;
NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnect;
}
public static void OnClientDisconnect(ulong clientId)
{
if (HostSyncedList.Remove(clientId))
{
BunkbedRevive.Logger.LogInfo((object)("BunkbedRevive client " + clientId + " disconnected."));
}
}
public static void SetupMessageHandler(string name, HandleNamedMessageDelegate del)
{
NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("BunkbedRevive." + name, del);
}
public static void DeleteMessageHandler(string name)
{
NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("BunkbedRevive." + name);
}
public static void SendToClients(string name, IReadOnlyList<ulong> clients, ref FastBufferWriter buffer)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
if (!NetworkManager.Singleton.IsHost)
{
BunkbedRevive.Logger.LogError((object)"SendToClients called from client!");
}
else
{
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive." + name, clients, buffer, (NetworkDelivery)3);
}
}
public static void SendToClients(string name, ref FastBufferWriter buffer)
{
SendToClients(name, HostSyncedList, ref buffer);
}
public static void SendToHost(string name, FastBufferWriter buffer, bool forceSend = false)
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
if (forceSend || SyncedWithHost)
{
NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("BunkbedRevive." + name, 0uL, buffer, (NetworkDelivery)3);
}
}
public static void ContactServerRpc(ulong clientId, FastBufferReader reader)
{
string text = default(string);
((FastBufferReader)(ref reader)).ReadValue(ref text, false);
BunkbedRevive.Logger.LogInfo((object)("Client " + clientId + " connected with BunkbedRevive version " + text));
BunkbedRevive.Logger.LogDebug((object)$"Sending config to client {clientId}");
HostSyncedList.Add(clientId);
FastBufferWriter buffer = default(FastBufferWriter);
((FastBufferWriter)(ref buffer))..ctor(128, (Allocator)2, 1024);
((FastBufferWriter)(ref buffer)).WriteNetworkSerializable<NetworkConfig>(ref Config);
SendToClients("SendConfigClientRpc", new <>z__ReadOnlySingleElementList<ulong>(clientId), ref buffer);
}
public static void SendConfigClientRpc(ulong clientId, FastBufferReader reader)
{
((FastBufferReader)(ref reader)).ReadNetworkSerializableInPlace<NetworkConfig>(ref Config);
BunkbedRevive.Logger.LogInfo((object)"Successfully synced config with host");
BunkbedRevive.Logger.LogDebug((object)$"Config values - CostMethod: {Config.ReviveCostMethod}, CostPercent: {Config.ReviveCostPercent}, CostAmount: {Config.ReviveCostAmount}");
BunkbedRevive.Logger.LogDebug((object)$"Config values - LimitMethod: {Config.ReviveLimitMethod}, LimitPer: {Config.ReviveLimitPer}, LimitOverall: {Config.ReviveLimitOverall}");
FinishSync(hostSynced: true);
}
public static void FinishSync(bool hostSynced)
{
if (FinishedSync)
{
BunkbedRevive.Logger.LogDebug((object)"FinishSync called but already finished");
return;
}
SyncedWithHost = hostSynced;
FinishedSync = true;
if (!SyncedWithHost)
{
BunkbedRevive.Logger.LogWarning((object)"Could not sync with host BunkbedRevive instance. Only client-side effects will apply.");
}
else
{
BunkbedRevive.Logger.LogInfo((object)"Successfully finished sync with host");
}
}
}
}
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class ExperimentalAttribute : Attribute
{
public string DiagnosticId { get; }
public string? UrlFormat { get; set; }
public ExperimentalAttribute(string diagnosticId)
{
DiagnosticId = diagnosticId;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullAttribute : Attribute
{
public string[] Members { get; }
public MemberNotNullAttribute(string member)
{
Members = new string[1] { member };
}
public MemberNotNullAttribute(params string[] members)
{
Members = members;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[ExcludeFromCodeCoverage]
internal sealed class MemberNotNullWhenAttribute : Attribute
{
public bool ReturnValue { get; }
public string[] Members { get; }
public MemberNotNullWhenAttribute(bool returnValue, string member)
{
ReturnValue = returnValue;
Members = new string[1] { member };
}
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
{
ReturnValue = returnValue;
Members = members;
}
}
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class SetsRequiredMembersAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class StringSyntaxAttribute : Attribute
{
public const string CompositeFormat = "CompositeFormat";
public const string DateOnlyFormat = "DateOnlyFormat";
public const string DateTimeFormat = "DateTimeFormat";
public const string EnumFormat = "EnumFormat";
public const string GuidFormat = "GuidFormat";
public const string Json = "Json";
public const string NumericFormat = "NumericFormat";
public const string Regex = "Regex";
public const string TimeOnlyFormat = "TimeOnlyFormat";
public const string TimeSpanFormat = "TimeSpanFormat";
public const string Uri = "Uri";
public const string Xml = "Xml";
public string Syntax { get; }
public object?[] Arguments { get; }
public StringSyntaxAttribute(string syntax)
{
Syntax = syntax;
Arguments = new object[0];
}
public StringSyntaxAttribute(string syntax, params object?[] arguments)
{
Syntax = syntax;
Arguments = arguments;
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class UnscopedRefAttribute : Attribute
{
}
}
namespace System.Runtime.Versioning
{
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresPreviewFeaturesAttribute : Attribute
{
public string? Message { get; }
public string? Url { get; set; }
public RequiresPreviewFeaturesAttribute()
{
}
public RequiresPreviewFeaturesAttribute(string? message)
{
Message = message;
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CallerArgumentExpressionAttribute : Attribute
{
public string ParameterName { get; }
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CollectionBuilderAttribute : Attribute
{
public Type BuilderType { get; }
public string MethodName { get; }
public CollectionBuilderAttribute(Type builderType, string methodName)
{
BuilderType = builderType;
MethodName = methodName;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public const string RefStructs = "RefStructs";
public const string RequiredMembers = "RequiredMembers";
public string FeatureName { get; }
public bool IsOptional { get; set; }
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
{
public string[] Arguments { get; }
public InterpolatedStringHandlerArgumentAttribute(string argument)
{
Arguments = new string[1] { argument };
}
public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
{
Arguments = arguments;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class InterpolatedStringHandlerAttribute : Attribute
{
}
[EditorBrowsable(EditorBrowsableState.Never)]
[ExcludeFromCodeCoverage]
internal static class IsExternalInit
{
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class ModuleInitializerAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class RequiredMemberAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[ExcludeFromCodeCoverage]
internal sealed class RequiresLocationAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
[ExcludeFromCodeCoverage]
internal sealed class SkipLocalsInitAttribute : Attribute
{
}
}
[CompilerGenerated]
internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T>
{
private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T>
{
object IEnumerator.Current => _item;
T IEnumerator<T>.Current => _item;
public Enumerator(T item)
{
_item = item;
}
bool IEnumerator.MoveNext()
{
return !_moveNextCalled && (_moveNextCalled = true);
}
void IEnumerator.Reset()
{
_moveNextCalled = false;
}
void IDisposable.Dispose()
{
}
}
int ICollection.Count => 1;
bool ICollection.IsSynchronized => false;
object ICollection.SyncRoot => this;
object IList.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
bool IList.IsFixedSize => true;
bool IList.IsReadOnly => true;
int IReadOnlyCollection<T>.Count => 1;
T IReadOnlyList<T>.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
}
int ICollection<T>.Count => 1;
bool ICollection<T>.IsReadOnly => true;
T IList<T>.this[int index]
{
get
{
if (index != 0)
{
throw new IndexOutOfRangeException();
}
return _item;
}
set
{
throw new NotSupportedException();
}
}
public <>z__ReadOnlySingleElementList(T item)
{
_item = item;
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(_item);
}
void ICollection.CopyTo(Array array, int index)
{
array.SetValue(_item, index);
}
int IList.Add(object value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object value)
{
return EqualityComparer<T>.Default.Equals(_item, (T)value);
}
int IList.IndexOf(object value)
{
return (!EqualityComparer<T>.Default.Equals(_item, (T)value)) ? (-1) : 0;
}
void IList.Insert(int index, object value)
{
throw new NotSupportedException();
}
void IList.Remove(object value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator(_item);
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return EqualityComparer<T>.Default.Equals(_item, item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
array[arrayIndex] = _item;
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
return (!EqualityComparer<T>.Default.Equals(_item, item)) ? (-1) : 0;
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}