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 _needsStarter = new HashSet(); private static readonly HashSet _lateOrReconnect = new HashSet(); private static readonly HashSet _disconnectedUserIds = new HashSet(); private static readonly HashSet _waitingForWarp = new HashSet(); private static int _reviveAtPositionDepth; private static ConfigEntry _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("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)Delegate.Combine(PlayerHandler.CharacterRegistered, new Action(OnCharacterRegistered)); GlobalEvents.OnPlayerConnected = (Action)Delegate.Combine(GlobalEvents.OnPlayerConnected, new Action(OnPlayerConnected)); GlobalEvents.OnPlayerDisconnected = (Action)Delegate.Combine(GlobalEvents.OnPlayerDisconnected, new Action(OnPlayerDisconnected)); GlobalEvents.OnCharacterDied = (Action)Delegate.Combine(GlobalEvents.OnCharacterDied, new Action(OnCharacterDied)); } private void UnsubscribeEvents() { PlayerHandler.CharacterRegistered = (Action)Delegate.Remove(PlayerHandler.CharacterRegistered, new Action(OnCharacterRegistered)); GlobalEvents.OnPlayerConnected = (Action)Delegate.Remove(GlobalEvents.OnPlayerConnected, new Action(OnPlayerConnected)); GlobalEvents.OnPlayerDisconnected = (Action)Delegate.Remove(GlobalEvents.OnPlayerDisconnected, new Action(OnPlayerDisconnected)); GlobalEvents.OnCharacterDied = (Action)Delegate.Remove(GlobalEvents.OnCharacterDied, new Action(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_"); } }