Decompiled source of Start With Backpacks v1.1.0

tony4twentys-Start With Backpacks.dll

Decompiled a month 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.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace StartWithBackpacks;

[BepInPlugin("tony4twentys.Start_With_Backpacks", "Start With Backpacks", "1.1.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_ReviveAtPosition")]
	private static class Patch_ReviveAtPosition
	{
		private static void Postfix(Character __instance)
		{
			TryGrantOnRevive(__instance);
		}
	}

	public const string PluginGuid = "tony4twentys.Start_With_Backpacks";

	public const string PluginName = "Start With Backpacks";

	public const string PluginVersion = "1.1.0";

	private const ushort BackpackItemId = 6;

	private const ushort FannypackItemId = 166;

	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 readonly Dictionary<int, ushort> _packIdForActor = new Dictionary<int, ushort>();

	private static ConfigEntry<bool> _givePackOnAnyRevive;

	private static ConfigEntry<bool> _useFannypack;

	private static ConfigEntry<bool> _randomPack;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Expected O, but got Unknown
		_givePackOnAnyRevive = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "GiveBackpackOnAnyRevive", false, "If true, any revived player without a pack gets one (campfire/effigy/statue). If false, only pending starters (run start / late join / reconnect) get packs.");
		_useFannypack = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseFannypack", false, "If true, grant a Fannypack (id 166) instead of a Backpack (id 6). Ignored when RandomPack is true.");
		_randomPack = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RandomPack", false, "If true, each player randomly gets either a Backpack or a Fannypack (host picks; overrides UseFannypack).");
		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.1.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();
		_packIdForActor.Clear();
		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);
				TryGivePack(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 = _givePackOnAnyRevive != null && _givePackOnAnyRevive.Value;
				if ((flag || flag2) && !((Object)(object)character.data == (Object)null) && !character.data.dead)
				{
					TryGivePack(character, actorNumber, flag);
				}
			}
		}
		catch (Exception arg)
		{
			Debug.LogError((object)$"[Start With Backpacks] TryGrantOnRevive failed: {arg}");
		}
	}

	private static void TryGivePack(Character character, int actorNumber, bool clearLate)
	{
		if (character.warping)
		{
			ScheduleAfterWarp(character, actorNumber);
			return;
		}
		Player player = character.player;
		if (player?.backpackSlot == null)
		{
			return;
		}
		if (HasPackEquipped(player))
		{
			FinishStarter(actorNumber, clearLate);
			return;
		}
		ushort itemIdForActor = GetItemIdForActor(actorNumber);
		ItemSlot val = default(ItemSlot);
		if (player.AddItem(itemIdForActor, (ItemInstanceData)null, ref val) && HasPackEquipped(player))
		{
			FinishStarter(actorNumber, clearLate);
		}
	}

	private static bool HasPackEquipped(Player player)
	{
		return player?.backpackSlot != null && !((ItemSlot)player.backpackSlot).IsEmpty();
	}

	private static ushort GetItemIdForActor(int actorNumber)
	{
		if (_packIdForActor.TryGetValue(actorNumber, out var value))
		{
			return value;
		}
		value = ResolveConfiguredItemId();
		_packIdForActor[actorNumber] = value;
		return value;
	}

	private static ushort ResolveConfiguredItemId()
	{
		if (_randomPack != null && _randomPack.Value)
		{
			return (ushort)((Random.value < 0.5f) ? 6 : 166);
		}
		if (_useFannypack != null && _useFannypack.Value)
		{
			return 166;
		}
		return 6;
	}

	private static void FinishStarter(int actorNumber, bool clearLate)
	{
		_needsStarter.Remove(actorNumber);
		_waitingForWarp.Remove(actorNumber);
		_packIdForActor.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) || (_givePackOnAnyRevive != null && _givePackOnAnyRevive.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);
		_packIdForActor.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_");
	}
}