using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Start With Backpacks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Start With Backpacks")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("15dcd9e4-16a0-4a1e-a65b-574db31f5eb5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace StartWithBackpacks;
[BepInPlugin("tony4twentys.Start_With_Backpacks", "Start With Backpacks", "1.0.0")]
[BepInProcess("PEAK.exe")]
public class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(PlayerHandler), "RegisterPlayer")]
private static class Patch_RegisterPlayer
{
private static void Postfix(Player player)
{
if (!((Object)(object)((player != null) ? player.character : null) == (Object)null) && (!TryGetActorNumber(player.character, out var actorNumber) || !_lateOrReconnect.Contains(actorNumber)))
{
TryGrantStarter(player.character);
}
}
}
[HarmonyPatch(typeof(Character), "UnPassOutDone")]
private static class Patch_UnPassOutDone
{
private static void Postfix(Character __instance)
{
TryGrantStarter(__instance);
}
}
[HarmonyPatch(typeof(Character), "RPCA_Revive")]
private static class Patch_Revive
{
private static void Postfix(Character __instance)
{
if (_reviveAtPositionDepth <= 0)
{
TryGrantOnRevive(__instance);
}
}
}
[HarmonyPatch(typeof(Character), "RPCA_ReviveAtPosition")]
private static class Patch_ReviveAtPosition
{
private static void Prefix()
{
_reviveAtPositionDepth++;
}
private static void Postfix(Character __instance)
{
try
{
TryGrantOnRevive(__instance);
}
finally
{
_reviveAtPositionDepth--;
}
}
}
public const string PluginGuid = "tony4twentys.Start_With_Backpacks";
public const string PluginName = "Start With Backpacks";
public const string PluginVersion = "1.0.0";
private const ushort BackpackItemId = 6;
private static readonly HashSet<int> _needsStarter = new HashSet<int>();
private static readonly HashSet<int> _lateOrReconnect = new HashSet<int>();
private static readonly HashSet<string> _disconnectedUserIds = new HashSet<string>();
private static readonly HashSet<int> _waitingForWarp = new HashSet<int>();
private static int _reviveAtPositionDepth;
private static ConfigEntry<bool> _giveBackpackOnAnyRevive;
private Harmony _harmony;
private void Awake()
{
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
_giveBackpackOnAnyRevive = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GiveBackpackOnAnyRevive", false, "If true, any revived player without a backpack gets one (campfire/effigy/statue). If false, only pending starters (run start / late join / reconnect) get backpacks.");
SceneManager.sceneLoaded += OnSceneLoaded;
SubscribeEvents();
_harmony = new Harmony("tony4twentys.Start_With_Backpacks");
_harmony.PatchAll(typeof(Plugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Start With Backpacks v1.0.0 loaded (host-only).");
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
UnsubscribeEvents();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
_needsStarter.Clear();
_lateOrReconnect.Clear();
_disconnectedUserIds.Clear();
_waitingForWarp.Clear();
_reviveAtPositionDepth = 0;
SubscribeEvents();
}
private void SubscribeEvents()
{
UnsubscribeEvents();
PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Combine(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
GlobalEvents.OnPlayerConnected = (Action<Player>)Delegate.Combine(GlobalEvents.OnPlayerConnected, new Action<Player>(OnPlayerConnected));
GlobalEvents.OnPlayerDisconnected = (Action<Player>)Delegate.Combine(GlobalEvents.OnPlayerDisconnected, new Action<Player>(OnPlayerDisconnected));
GlobalEvents.OnCharacterDied = (Action<Character>)Delegate.Combine(GlobalEvents.OnCharacterDied, new Action<Character>(OnCharacterDied));
}
private void UnsubscribeEvents()
{
PlayerHandler.CharacterRegistered = (Action<Character>)Delegate.Remove(PlayerHandler.CharacterRegistered, new Action<Character>(OnCharacterRegistered));
GlobalEvents.OnPlayerConnected = (Action<Player>)Delegate.Remove(GlobalEvents.OnPlayerConnected, new Action<Player>(OnPlayerConnected));
GlobalEvents.OnPlayerDisconnected = (Action<Player>)Delegate.Remove(GlobalEvents.OnPlayerDisconnected, new Action<Player>(OnPlayerDisconnected));
GlobalEvents.OnCharacterDied = (Action<Character>)Delegate.Remove(GlobalEvents.OnCharacterDied, new Action<Character>(OnCharacterDied));
}
private static void OnPlayerConnected(Player player)
{
if (player != null && PhotonNetwork.IsMasterClient && IsGameplayLevel() && (Object)(object)Character.localCharacter != (Object)null)
{
_lateOrReconnect.Add(player.ActorNumber);
}
}
private static void OnPlayerDisconnected(Player player)
{
if (player != null)
{
if (!string.IsNullOrEmpty(player.UserId))
{
_disconnectedUserIds.Add(player.UserId);
}
ClearActor(player.ActorNumber);
}
}
private static void OnCharacterDied(Character character)
{
try
{
if (TryGetActorNumber(character, out var actorNumber) && _lateOrReconnect.Contains(actorNumber))
{
_needsStarter.Add(actorNumber);
}
}
catch (Exception arg)
{
Debug.LogError((object)$"[Start With Backpacks] OnCharacterDied failed: {arg}");
}
}
private static void OnCharacterRegistered(Character character)
{
try
{
if (PhotonNetwork.IsMasterClient && IsGameplayLevel() && TryGetActorNumber(character, out var actorNumber))
{
Player owner = ((MonoBehaviourPun)character).photonView.Owner;
if (owner != null && !string.IsNullOrEmpty(owner.UserId) && _disconnectedUserIds.Remove(owner.UserId))
{
_lateOrReconnect.Add(actorNumber);
}
_needsStarter.Add(actorNumber);
}
}
catch (Exception arg)
{
Debug.LogError((object)$"[Start With Backpacks] OnCharacterRegistered failed: {arg}");
}
}
private static void TryGrantStarter(Character character)
{
try
{
if (PhotonNetwork.IsMasterClient && IsGameplayLevel() && TryGetActorNumber(character, out var actorNumber) && _needsStarter.Contains(actorNumber) && !((Object)(object)character.data == (Object)null) && !character.data.dead)
{
bool clearLate = _lateOrReconnect.Contains(actorNumber);
TryGiveBackpack(character, actorNumber, clearLate);
}
}
catch (Exception arg)
{
Debug.LogError((object)$"[Start With Backpacks] TryGrantStarter failed: {arg}");
}
}
private static void TryGrantOnRevive(Character character)
{
try
{
if (PhotonNetwork.IsMasterClient && IsGameplayLevel() && TryGetActorNumber(character, out var actorNumber))
{
bool flag = _needsStarter.Contains(actorNumber);
bool flag2 = _giveBackpackOnAnyRevive != null && _giveBackpackOnAnyRevive.Value;
if ((flag || flag2) && !((Object)(object)character.data == (Object)null) && !character.data.dead)
{
TryGiveBackpack(character, actorNumber, flag);
}
}
}
catch (Exception arg)
{
Debug.LogError((object)$"[Start With Backpacks] TryGrantOnRevive failed: {arg}");
}
}
private static void TryGiveBackpack(Character character, int actorNumber, bool clearLate)
{
if (character.warping)
{
ScheduleAfterWarp(character, actorNumber);
return;
}
Player player = character.player;
if (player?.backpackSlot != null)
{
ItemSlot val = default(ItemSlot);
if (player.backpackSlot.hasBackpack)
{
FinishStarter(actorNumber, clearLate);
}
else if (player.AddItem((ushort)6, (ItemInstanceData)null, ref val) && player.backpackSlot.hasBackpack)
{
FinishStarter(actorNumber, clearLate);
}
}
}
private static void FinishStarter(int actorNumber, bool clearLate)
{
_needsStarter.Remove(actorNumber);
_waitingForWarp.Remove(actorNumber);
if (clearLate)
{
_lateOrReconnect.Remove(actorNumber);
}
}
private static void ScheduleAfterWarp(Character character, int actorNumber)
{
if (_waitingForWarp.Add(actorNumber))
{
character.WarpCompleted += OnWarpDone;
}
void OnWarpDone(Character c)
{
try
{
c.WarpCompleted -= OnWarpDone;
_waitingForWarp.Remove(actorNumber);
if (_needsStarter.Contains(actorNumber) || (_giveBackpackOnAnyRevive != null && _giveBackpackOnAnyRevive.Value))
{
TryGrantOnRevive(c);
}
}
catch (Exception arg)
{
_waitingForWarp.Remove(actorNumber);
Debug.LogError((object)$"[Start With Backpacks] WarpCompleted grant failed: {arg}");
}
}
}
private static void ClearActor(int actorNumber)
{
_needsStarter.Remove(actorNumber);
_lateOrReconnect.Remove(actorNumber);
_waitingForWarp.Remove(actorNumber);
}
private static bool TryGetActorNumber(Character character, out int actorNumber)
{
actorNumber = 0;
if ((Object)(object)character == (Object)null || character.isBot)
{
return false;
}
PhotonView photonView = ((MonoBehaviourPun)character).photonView;
if (((photonView != null) ? photonView.Owner : null) == null)
{
return false;
}
actorNumber = photonView.Owner.ActorNumber;
return true;
}
private static bool IsGameplayLevel()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
return ((Scene)(ref activeScene)).name != null && ((Scene)(ref activeScene)).name.Contains("Level_");
}
}