Decompiled source of Start With Backpacks v1.0.0

tony4twentys-Start With Backpacks.dll

Decompiled 12 hours ago
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_");
	}
}