Decompiled source of Healing Campfires v4.5.0

tony4twentys-Healing Campfires.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PEAKLib.Core;
using Photon.Pun;
using Photon.Realtime;
using PhotonCustomPropsUtils;
using UnityEngine;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Healing Campfires")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Healing Campfires")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("56f9024b-9ced-4a82-bd45-483d74b8ea2e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
}
namespace Healing_Campfires
{
	internal sealed class CampfireConfigSnapshot
	{
		public float HealPerSecond = 0.025f;

		public float MoraleBoostRadius;

		public bool HealAfflictionsEnabled = true;

		public bool HealAllStatuses = true;

		public bool RespawnEnabled = true;

		public bool BlockNegativeStatus = true;

		public bool BlockAllStatuses = true;

		public bool RemoveRestriction = true;

		public bool RevivePassedOut;

		public bool EnforceRevivePenalty;

		public bool DynamicMallows = true;

		public bool MallowDecrease = true;

		public bool MallowMultiplierEnabled;

		public int MallowMultiplier = 2;

		public float GlizzyChance = 0.25f;

		public bool DynamicBackpacks = true;

		public bool BackpackDecrease = true;

		public bool EnableSoloMoraleBoost = true;

		public float MoraleBoostStamina = 0.25f;

		public bool HealInjury;

		public bool HealDrowsy;

		public bool HealPoison;

		public bool HealCold;

		public bool HealCurse;

		public bool HealHunger;

		public bool HealHot;

		public bool HealThorns;

		public bool HealSpores;

		public bool HealWeb;

		public bool HealCrab;

		public bool BlockInjury;

		public bool BlockCold;

		public bool BlockPoison;

		public bool BlockCrab;

		public bool BlockCurse;

		public bool BlockDrowsy;

		public bool BlockHot;

		public bool BlockThorns;

		public bool BlockSpores;

		public bool BlockWeb;
	}
	internal static class CampfireConfigSyncService
	{
		public const int SchemaVersion = 9;

		public const char PairSeparator = ';';

		public const char KeyValueSeparator = '=';

		public static bool HasRemoteHostConfig { get; private set; }

		public static void ClearRemoteHostConfig()
		{
			HasRemoteHostConfig = false;
		}

		public static void ApplyLocalAuthoritativeConfig()
		{
			if (!((Object)(object)CampfireHealingMod.Instance == (Object)null))
			{
				ClearRemoteHostConfig();
				CampfireHealingMod.Instance.ApplySnapshot(CampfireHealingMod.Instance.BuildSnapshot());
			}
		}

		public static void ApplyRemoteSnapshot(string payload)
		{
			if (PhotonNetwork.IsMasterClient || string.IsNullOrEmpty(payload))
			{
				return;
			}
			if (!TryDeserialize(payload, out var snapshot))
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogError((object)"[Healing Campfires] Failed to apply host config snapshot.");
				}
			}
			else
			{
				HasRemoteHostConfig = true;
				CampfireHealingMod.Instance.ApplySnapshot(snapshot);
			}
		}

		public static string Serialize(CampfireConfigSnapshot snapshot)
		{
			if (snapshot == null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(520);
			AppendPair(stringBuilder, "v", 9.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "healRate", snapshot.HealPerSecond.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "moraleRadius", snapshot.MoraleBoostRadius.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "healEnabled", snapshot.HealAfflictionsEnabled ? "1" : "0");
			AppendPair(stringBuilder, "healAll", snapshot.HealAllStatuses ? "1" : "0");
			AppendPair(stringBuilder, "respawn", snapshot.RespawnEnabled ? "1" : "0");
			AppendPair(stringBuilder, "blockStatus", snapshot.BlockNegativeStatus ? "1" : "0");
			AppendPair(stringBuilder, "blockAll", snapshot.BlockAllStatuses ? "1" : "0");
			AppendPair(stringBuilder, "removeRestriction", snapshot.RemoveRestriction ? "1" : "0");
			AppendPair(stringBuilder, "revivePassedOut", snapshot.RevivePassedOut ? "1" : "0");
			AppendPair(stringBuilder, "enforceRevivePenalty", snapshot.EnforceRevivePenalty ? "1" : "0");
			AppendPair(stringBuilder, "dynMallows", snapshot.DynamicMallows ? "1" : "0");
			AppendPair(stringBuilder, "mallowDecrease", snapshot.MallowDecrease ? "1" : "0");
			AppendPair(stringBuilder, "mallowMultOn", snapshot.MallowMultiplierEnabled ? "1" : "0");
			AppendPair(stringBuilder, "mallowMult", snapshot.MallowMultiplier.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "glizzyChance", snapshot.GlizzyChance.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "dynBackpacks", snapshot.DynamicBackpacks ? "1" : "0");
			AppendPair(stringBuilder, "backpackDecrease", snapshot.BackpackDecrease ? "1" : "0");
			AppendPair(stringBuilder, "soloMorale", snapshot.EnableSoloMoraleBoost ? "1" : "0");
			AppendPair(stringBuilder, "moraleStamina", snapshot.MoraleBoostStamina.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "healInjury", snapshot.HealInjury ? "1" : "0");
			AppendPair(stringBuilder, "healDrowsy", snapshot.HealDrowsy ? "1" : "0");
			AppendPair(stringBuilder, "healPoison", snapshot.HealPoison ? "1" : "0");
			AppendPair(stringBuilder, "healCold", snapshot.HealCold ? "1" : "0");
			AppendPair(stringBuilder, "healCurse", snapshot.HealCurse ? "1" : "0");
			AppendPair(stringBuilder, "healHunger", snapshot.HealHunger ? "1" : "0");
			AppendPair(stringBuilder, "healHot", snapshot.HealHot ? "1" : "0");
			AppendPair(stringBuilder, "healThorns", snapshot.HealThorns ? "1" : "0");
			AppendPair(stringBuilder, "healSpores", snapshot.HealSpores ? "1" : "0");
			AppendPair(stringBuilder, "healWeb", snapshot.HealWeb ? "1" : "0");
			AppendPair(stringBuilder, "healCrab", snapshot.HealCrab ? "1" : "0");
			AppendPair(stringBuilder, "blockInjury", snapshot.BlockInjury ? "1" : "0");
			AppendPair(stringBuilder, "blockCold", snapshot.BlockCold ? "1" : "0");
			AppendPair(stringBuilder, "blockPoison", snapshot.BlockPoison ? "1" : "0");
			AppendPair(stringBuilder, "blockCrab", snapshot.BlockCrab ? "1" : "0");
			AppendPair(stringBuilder, "blockCurse", snapshot.BlockCurse ? "1" : "0");
			AppendPair(stringBuilder, "blockDrowsy", snapshot.BlockDrowsy ? "1" : "0");
			AppendPair(stringBuilder, "blockHot", snapshot.BlockHot ? "1" : "0");
			AppendPair(stringBuilder, "blockThorns", snapshot.BlockThorns ? "1" : "0");
			AppendPair(stringBuilder, "blockSpores", snapshot.BlockSpores ? "1" : "0");
			AppendPair(stringBuilder, "blockWeb", snapshot.BlockWeb ? "1" : "0");
			return stringBuilder.ToString();
		}

		public static bool TryDeserialize(string payload, out CampfireConfigSnapshot snapshot)
		{
			snapshot = new CampfireConfigSnapshot();
			if (string.IsNullOrEmpty(payload))
			{
				return false;
			}
			string[] array = payload.Split(new char[1] { ';' });
			int result = 0;
			bool flag = false;
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num <= 0)
				{
					continue;
				}
				string text2 = text.Substring(0, num);
				string text3 = text.Substring(num + 1);
				switch (text2)
				{
				case "v":
					flag = int.TryParse(text3, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
					break;
				case "healRate":
					float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out snapshot.HealPerSecond);
					break;
				case "moraleRadius":
					float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out snapshot.MoraleBoostRadius);
					break;
				case "radius":
					if (snapshot.MoraleBoostRadius <= 0f)
					{
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out snapshot.MoraleBoostRadius);
					}
					break;
				case "healEnabled":
					snapshot.HealAfflictionsEnabled = text3 == "1";
					break;
				case "healAll":
					snapshot.HealAllStatuses = text3 == "1";
					break;
				case "respawn":
					snapshot.RespawnEnabled = text3 == "1";
					break;
				case "blockStatus":
					snapshot.BlockNegativeStatus = text3 == "1";
					break;
				case "blockAll":
					snapshot.BlockAllStatuses = text3 == "1";
					break;
				case "removeRestriction":
					snapshot.RemoveRestriction = text3 == "1";
					break;
				case "revivePassedOut":
					snapshot.RevivePassedOut = text3 == "1";
					break;
				case "enforceRevivePenalty":
					snapshot.EnforceRevivePenalty = text3 == "1";
					break;
				case "dynMallows":
					snapshot.DynamicMallows = text3 == "1";
					break;
				case "mallowDecrease":
					snapshot.MallowDecrease = text3 == "1";
					break;
				case "mallowMultOn":
					snapshot.MallowMultiplierEnabled = text3 == "1";
					break;
				case "mallowMult":
				{
					if (int.TryParse(text3, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4))
					{
						snapshot.MallowMultiplier = Math.Max(1, result4);
					}
					break;
				}
				case "glizzyChance":
				{
					if (float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
					{
						snapshot.GlizzyChance = Math.Max(0f, Math.Min(1f, result3));
					}
					break;
				}
				case "dynBackpacks":
					snapshot.DynamicBackpacks = text3 == "1";
					break;
				case "backpackDecrease":
					snapshot.BackpackDecrease = text3 == "1";
					break;
				case "soloMorale":
					snapshot.EnableSoloMoraleBoost = text3 == "1";
					break;
				case "moraleStamina":
				{
					if (float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
					{
						snapshot.MoraleBoostStamina = Math.Max(0f, Math.Min(1f, result2));
					}
					break;
				}
				case "healInjury":
					snapshot.HealInjury = text3 == "1";
					break;
				case "healDrowsy":
					snapshot.HealDrowsy = text3 == "1";
					break;
				case "healPoison":
					snapshot.HealPoison = text3 == "1";
					break;
				case "healCold":
					snapshot.HealCold = text3 == "1";
					break;
				case "healCurse":
					snapshot.HealCurse = text3 == "1";
					break;
				case "healHunger":
					snapshot.HealHunger = text3 == "1";
					break;
				case "healHot":
					snapshot.HealHot = text3 == "1";
					break;
				case "healThorns":
					snapshot.HealThorns = text3 == "1";
					break;
				case "healSpores":
					snapshot.HealSpores = text3 == "1";
					break;
				case "healWeb":
					snapshot.HealWeb = text3 == "1";
					break;
				case "healCrab":
					snapshot.HealCrab = text3 == "1";
					break;
				case "blockInjury":
					snapshot.BlockInjury = text3 == "1";
					break;
				case "blockCold":
					snapshot.BlockCold = text3 == "1";
					break;
				case "blockPoison":
					snapshot.BlockPoison = text3 == "1";
					break;
				case "blockCrab":
					snapshot.BlockCrab = text3 == "1";
					break;
				case "blockCurse":
					snapshot.BlockCurse = text3 == "1";
					break;
				case "blockDrowsy":
					snapshot.BlockDrowsy = text3 == "1";
					break;
				case "blockHot":
					snapshot.BlockHot = text3 == "1";
					break;
				case "blockThorns":
					snapshot.BlockThorns = text3 == "1";
					break;
				case "blockSpores":
					snapshot.BlockSpores = text3 == "1";
					break;
				case "blockWeb":
					snapshot.BlockWeb = text3 == "1";
					break;
				}
			}
			return flag && result >= 1 && result <= 9;
		}

		private static void AppendPair(StringBuilder builder, string key, string value)
		{
			if (builder.Length > 0)
			{
				builder.Append(';');
			}
			builder.Append(key);
			builder.Append('=');
			builder.Append(value ?? string.Empty);
		}
	}
	internal static class CampfireDynamicBackpackService
	{
		private sealed class CampfireBackpackState
		{
			public GameObject Root;

			public string PrefabName = "Backpack";

			public readonly List<Transform> SpawnPoints = new List<Transform>();

			public readonly List<PhotonView> TrackedViews = new List<PhotonView>();

			public float RegisteredAt;
		}

		private const string FallbackPrefabName = "Backpack";

		private const float NearbyPlayerSyncDistance = 80f;

		private const float RecentRegisterWindowSeconds = 120f;

		private const float ScatterMin = 0.45f;

		private const float ScatterMax = 1.15f;

		private const float CountDistance = 14f;

		private static readonly Dictionary<int, CampfireBackpackState> StatesByRootId = new Dictionary<int, CampfireBackpackState>();

		private static int _lastPlayerCount = -1;

		private static float _deferredSyncAt = -1f;

		private static string _deferredSyncReason = string.Empty;

		private static int _deferredSyncRootId;

		public static void OnCampfireItemsSpawned(GameObject campfireRoot)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient || (Object)(object)campfireRoot == (Object)null)
			{
				return;
			}
			CampfireBackpackState campfireBackpackState = RegisterOrUpdate(campfireRoot);
			AttachNearbyBackpackSpawners(campfireBackpackState, campfireRoot.transform.position, 40f);
			if (campfireBackpackState.SpawnPoints.Count != 0)
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Backpacks] Registered '{((Object)campfireRoot).name}' with {campfireBackpackState.SpawnPoints.Count} backpack spawn point(s), prefab='{campfireBackpackState.PrefabName}'.");
				}
				RequestDeferredSync("campfire-items-spawned", ((Object)campfireRoot).GetInstanceID());
			}
		}

		private static void AttachNearbyBackpackSpawners(CampfireBackpackState state, Vector3 center, float maxDistance)
		{
			//IL_003a: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (state == null)
			{
				return;
			}
			float num = maxDistance * maxDistance;
			SingleItemSpawner[] array = Object.FindObjectsByType<SingleItemSpawner>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (SingleItemSpawner val in array)
			{
				if (IsBackpackSpawner(val))
				{
					Vector3 val2 = ((Component)val).transform.position - center;
					if (!(((Vector3)(ref val2)).sqrMagnitude > num))
					{
						EnsureSpawnPoint(state, ((Component)val).transform);
						TryReadPrefabName(((Component)val).transform, state);
					}
				}
			}
		}

		public static void TrackVanillaSpawnedViews(SingleItemSpawner spawner, List<PhotonView> views)
		{
			if (!PhotonNetwork.IsMasterClient || (Object)(object)spawner == (Object)null || views == null || views.Count == 0 || !IsBackpackSpawner(spawner))
			{
				return;
			}
			GameObject val = FindNearestCampfireRoot(((Component)spawner).transform, 40f);
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)spawner).gameObject;
			}
			CampfireBackpackState campfireBackpackState = RegisterOrUpdate(val);
			EnsureSpawnPoint(campfireBackpackState, ((Component)spawner).transform);
			if ((Object)(object)spawner.prefab != (Object)null && !string.IsNullOrEmpty(((Object)spawner.prefab).name))
			{
				campfireBackpackState.PrefabName = ((Object)spawner.prefab).name;
			}
			for (int i = 0; i < views.Count; i++)
			{
				PhotonView val2 = views[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				bool flag = false;
				for (int j = 0; j < campfireBackpackState.TrackedViews.Count; j++)
				{
					if ((Object)(object)campfireBackpackState.TrackedViews[j] != (Object)null && campfireBackpackState.TrackedViews[j].ViewID == val2.ViewID)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					campfireBackpackState.TrackedViews.Add(val2);
				}
			}
			RequestDeferredSync("backpack-spawned", ((Object)val).GetInstanceID());
		}

		public static void RequestDeferredSync(string reason, int rootId = 0)
		{
			_deferredSyncReason = reason ?? "sync";
			_deferredSyncAt = Time.time + 0.75f;
			_deferredSyncRootId = rootId;
		}

		public static void Tick()
		{
			if (!PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom || !CampfireHealingMod.syncedDynamicBackpacks)
			{
				return;
			}
			int roomPlayerCount = CampfireDynamicMallowService.GetRoomPlayerCount();
			if (roomPlayerCount != _lastPlayerCount)
			{
				int lastPlayerCount = _lastPlayerCount;
				_lastPlayerCount = roomPlayerCount;
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Backpacks] Player count {lastPlayerCount} -> {roomPlayerCount}. Target={roomPlayerCount}.");
				}
				RequestDeferredSync("player-count-changed");
			}
			if (!(_deferredSyncAt < 0f) && !(Time.time < _deferredSyncAt))
			{
				_deferredSyncAt = -1f;
				string deferredSyncReason = _deferredSyncReason;
				int deferredSyncRootId = _deferredSyncRootId;
				_deferredSyncReason = string.Empty;
				_deferredSyncRootId = 0;
				if (deferredSyncRootId != 0)
				{
					SyncOneCampfire(deferredSyncRootId, deferredSyncReason);
				}
				else
				{
					SyncRelevantCampfires(deferredSyncReason);
				}
			}
		}

		public static void SyncAllCampfiresNow(string reason)
		{
			if (PhotonNetwork.IsMasterClient && CampfireHealingMod.syncedDynamicBackpacks)
			{
				SyncRelevantCampfires(reason ?? "manual");
			}
		}

		private static void SyncOneCampfire(int rootId, string reason)
		{
			if (CampfireHealingMod.IsModActive && CampfireHealingMod.syncedDynamicBackpacks && StatesByRootId.ContainsKey(rootId))
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Backpacks] Syncing 1 campfire ({reason}). players={CampfireDynamicMallowService.GetRoomPlayerCount()}.");
				}
				SyncCampfire(rootId);
			}
		}

		private static void SyncRelevantCampfires(string reason)
		{
			if (!CampfireHealingMod.IsModActive || !CampfireHealingMod.syncedDynamicBackpacks)
			{
				return;
			}
			if (StatesByRootId.Count == 0)
			{
				DiscoverCampfires();
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, CampfireBackpackState> item in StatesByRootId)
			{
				if (IsRelevantForPlayerCountSync(item.Value))
				{
					list.Add(item.Key);
				}
			}
			ManualLogSource log = CampfireHealingMod.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[Dynamic Backpacks] Syncing {list.Count}/{StatesByRootId.Count} relevant campfire(s) ({reason}). players={CampfireDynamicMallowService.GetRoomPlayerCount()}, decrease={CampfireHealingMod.syncedBackpackDecrease}.");
			}
			for (int i = 0; i < list.Count; i++)
			{
				SyncCampfire(list[i]);
			}
		}

		private static bool IsRelevantForPlayerCountSync(CampfireBackpackState state)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			if (state == null || (Object)(object)state.Root == (Object)null || !state.Root.activeInHierarchy)
			{
				return false;
			}
			if (Time.time - state.RegisteredAt <= 120f)
			{
				return true;
			}
			Campfire componentInChildren = state.Root.GetComponentInChildren<Campfire>(true);
			if ((Object)(object)componentInChildren != (Object)null && componentInChildren.Lit && !CampfireHealingMod.CampfireHelper.IsPortableStove(componentInChildren))
			{
				return true;
			}
			Vector3 spawnCenter = GetSpawnCenter(state);
			float num = 6400f;
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null))
				{
					Vector3 val = allPlayerCharacter.Center - spawnCenter;
					if (((Vector3)(ref val)).sqrMagnitude <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void DiscoverCampfires()
		{
			SingleItemSpawner[] array = Object.FindObjectsByType<SingleItemSpawner>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (SingleItemSpawner val in array)
			{
				if (IsBackpackSpawner(val))
				{
					GameObject campfireRoot = FindNearestCampfireRoot(((Component)val).transform, 40f) ?? ((Component)val).gameObject;
					CampfireBackpackState state = RegisterOrUpdate(campfireRoot);
					EnsureSpawnPoint(state, ((Component)val).transform);
					TryReadPrefabName(((Component)val).transform, state);
				}
			}
		}

		private static bool IsBackpackSpawner(SingleItemSpawner spawner)
		{
			return (Object)(object)spawner != (Object)null && IsBackpackObjectName(((Object)((Component)spawner).gameObject).name);
		}

		private static bool IsBackpackObjectName(string name)
		{
			return !string.IsNullOrEmpty(name) && name.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static GameObject FindNearestCampfireRoot(Transform start, float maxDistance)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)start == (Object)null)
			{
				return null;
			}
			Transform val = start;
			while ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)((Component)val).GetComponent<Campfire>() != (Object)null)
				{
					return ((Component)val).gameObject;
				}
				val = val.parent;
			}
			Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			Vector3 position = start.position;
			float num = maxDistance * maxDistance;
			Campfire val2 = null;
			float num2 = num;
			foreach (Campfire val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && !CampfireHealingMod.CampfireHelper.IsPortableStove(val3))
				{
					Vector3 val4 = ((Component)val3).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (sqrMagnitude <= num2)
					{
						num2 = sqrMagnitude;
						val2 = val3;
					}
				}
			}
			return ((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null;
		}

		private static void EnsureSpawnPoint(CampfireBackpackState state, Transform point)
		{
			if (state == null || (Object)(object)point == (Object)null)
			{
				return;
			}
			for (int i = 0; i < state.SpawnPoints.Count; i++)
			{
				if ((Object)(object)state.SpawnPoints[i] == (Object)(object)point)
				{
					return;
				}
			}
			state.SpawnPoints.Add(point);
		}

		private static CampfireBackpackState RegisterOrUpdate(GameObject campfireRoot)
		{
			int instanceID = ((Object)campfireRoot).GetInstanceID();
			if (!StatesByRootId.TryGetValue(instanceID, out var value))
			{
				value = new CampfireBackpackState
				{
					Root = campfireRoot,
					RegisteredAt = Time.time
				};
				StatesByRootId[instanceID] = value;
			}
			else
			{
				value.Root = campfireRoot;
				value.RegisteredAt = Time.time;
			}
			if (string.IsNullOrEmpty(value.PrefabName))
			{
				value.PrefabName = "Backpack";
			}
			SingleItemSpawner[] componentsInChildren = campfireRoot.GetComponentsInChildren<SingleItemSpawner>(true);
			foreach (SingleItemSpawner val in componentsInChildren)
			{
				if (IsBackpackSpawner(val))
				{
					EnsureSpawnPoint(value, ((Component)val).transform);
					TryReadPrefabName(((Component)val).transform, value);
				}
			}
			return value;
		}

		private static void TryReadPrefabName(Transform t, CampfireBackpackState state)
		{
			if ((Object)(object)t == (Object)null || state == null)
			{
				return;
			}
			SingleItemSpawner component = ((Component)t).GetComponent<SingleItemSpawner>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.prefab != (Object)null && !string.IsNullOrEmpty(((Object)component.prefab).name))
			{
				state.PrefabName = ((Object)component.prefab).name;
				return;
			}
			Component[] components = ((Component)t).GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				FieldInfo field = ((object)val).GetType().GetField("prefab");
				if (!(field == null) && !(field.FieldType != typeof(GameObject)))
				{
					object? value = field.GetValue(val);
					GameObject val2 = (GameObject)((value is GameObject) ? value : null);
					if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name))
					{
						state.PrefabName = ((Object)val2).name;
						break;
					}
				}
			}
		}

		private static void SyncCampfire(int rootId)
		{
			if (!StatesByRootId.TryGetValue(rootId, out var value))
			{
				return;
			}
			if ((Object)(object)value.Root == (Object)null)
			{
				StatesByRootId.Remove(rootId);
				return;
			}
			if (value.SpawnPoints.Count == 0)
			{
				RegisterOrUpdate(value.Root);
			}
			if (value.SpawnPoints.Count == 0)
			{
				return;
			}
			PruneTracked(value);
			int num = CountPresentBackpacks(value);
			int roomPlayerCount = CampfireDynamicMallowService.GetRoomPlayerCount();
			int num2 = 0;
			int num3 = 0;
			while (num < roomPlayerCount && TrySpawnOne(value))
			{
				num2++;
				num = CountPresentBackpacks(value);
			}
			num = CountPresentBackpacks(value);
			if (CampfireHealingMod.syncedBackpackDecrease)
			{
				while (num > roomPlayerCount && TryDestroyOneExtra(value))
				{
					num3++;
					num = CountPresentBackpacks(value);
				}
			}
			ManualLogSource log = CampfireHealingMod.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[Dynamic Backpacks] '{((Object)value.Root).name}': present~{num}, target={roomPlayerCount}, spawned+{num2}, destroyed-{num3}, tracked={value.TrackedViews.Count}, prefab='{value.PrefabName}'.");
			}
		}

		private static void PruneTracked(CampfireBackpackState state)
		{
			for (int num = state.TrackedViews.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)state.TrackedViews[num] == (Object)null)
				{
					state.TrackedViews.RemoveAt(num);
				}
			}
		}

		private static bool MatchesBackpack(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			if (item is Backpack)
			{
				return true;
			}
			string text = (((Object)(object)((Component)item).gameObject != (Object)null) ? ((Object)((Component)item).gameObject).name : string.Empty);
			string text2 = ((Object)item).name ?? string.Empty;
			return text.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static int CountPresentBackpacks(CampfireBackpackState state)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			PruneTracked(state);
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			Vector3 spawnCenter = GetSpawnCenter(state);
			for (int i = 0; i < state.TrackedViews.Count; i++)
			{
				PhotonView val = state.TrackedViews[i];
				if (!((Object)(object)val == (Object)null) && hashSet.Add(val.ViewID) && !IsClaimedOrGone(val))
				{
					num++;
				}
			}
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Item val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null) && MatchesBackpack(val2) && hashSet.Add(((MonoBehaviourPun)val2).photonView.ViewID) && !IsClaimedOrGone(((MonoBehaviourPun)val2).photonView) && !(Vector3.Distance(((Component)val2).transform.position, spawnCenter) > 14f))
				{
					state.TrackedViews.Add(((MonoBehaviourPun)val2).photonView);
					num++;
				}
			}
			return num;
		}

		private static bool IsClaimedOrGone(PhotonView view)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			if ((Object)(object)view == (Object)null)
			{
				return true;
			}
			Item component = ((Component)view).GetComponent<Item>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if ((Object)(object)component.holderCharacter != (Object)null)
			{
				return true;
			}
			return (int)component.itemState == 1 || (int)component.itemState == 2;
		}

		private static Vector3 GetSpawnCenter(CampfireBackpackState state)
		{
			//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)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			int num = 0;
			for (int i = 0; i < state.SpawnPoints.Count; i++)
			{
				if (!((Object)(object)state.SpawnPoints[i] == (Object)null))
				{
					val += state.SpawnPoints[i].position;
					num++;
				}
			}
			if (num > 0)
			{
				return val / (float)num;
			}
			Campfire val2 = (((Object)(object)state.Root != (Object)null) ? state.Root.GetComponentInChildren<Campfire>(true) : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.Center();
			}
			return ((Object)(object)state.Root != (Object)null) ? state.Root.transform.position : Vector3.zero;
		}

		private static bool TrySpawnOne(CampfireBackpackState state)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if (state.SpawnPoints.Count == 0)
			{
				return false;
			}
			int index = state.TrackedViews.Count % state.SpawnPoints.Count;
			Transform val = state.SpawnPoints[index] ?? state.SpawnPoints[0];
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			string text = (string.IsNullOrEmpty(state.PrefabName) ? "Backpack" : state.PrefabName);
			Vector3 scatteredPosition = GetScatteredPosition(val.position);
			Quaternion val2 = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			try
			{
				GameObject val3 = PhotonNetwork.InstantiateItemRoom(text, scatteredPosition, val2);
				if ((Object)(object)val3 == (Object)null)
				{
					ManualLogSource log = CampfireHealingMod.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Dynamic Backpacks] InstantiateItemRoom returned null for '" + text + "'."));
					}
					return false;
				}
				PhotonView component = val3.GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					return false;
				}
				Item component2 = val3.GetComponent<Item>();
				if ((Object)(object)component2 != (Object)null)
				{
					component.RPC("SetKinematicRPC", (RpcTarget)3, new object[3]
					{
						true,
						val3.transform.position,
						val3.transform.rotation
					});
				}
				state.TrackedViews.Add(component);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = CampfireHealingMod.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Dynamic Backpacks] Spawn failed for '" + text + "': " + ex.Message));
				}
				return false;
			}
		}

		private static Vector3 GetScatteredPosition(Vector3 basePosition)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_004b: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			float num = Random.Range(0f, (float)Math.PI * 2f);
			float num2 = Random.Range(0.45f, 1.15f);
			return new Vector3(basePosition.x + Mathf.Cos(num) * num2, basePosition.y + 0.05f, basePosition.z + Mathf.Sin(num) * num2);
		}

		private static bool TryDestroyOneExtra(CampfireBackpackState state)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			for (int num = state.TrackedViews.Count - 1; num >= 0; num--)
			{
				PhotonView val = state.TrackedViews[num];
				state.TrackedViews.RemoveAt(num);
				if (!((Object)(object)val == (Object)null) && !IsClaimedOrGone(val))
				{
					PhotonNetwork.Destroy(val);
					return true;
				}
			}
			Vector3 spawnCenter = GetSpawnCenter(state);
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsSortMode)0);
			for (int num2 = array.Length - 1; num2 >= 0; num2--)
			{
				Item val2 = array[num2];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null) && MatchesBackpack(val2) && !IsClaimedOrGone(((MonoBehaviourPun)val2).photonView) && !(Vector3.Distance(((Component)val2).transform.position, spawnCenter) > 14f))
				{
					PhotonNetwork.Destroy(((MonoBehaviourPun)val2).photonView);
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(MapHandler), "SpawnCampfireItems")]
	internal static class MapHandlerSpawnCampfireItemsBackpackPatch
	{
		private static void Postfix(GameObject campfireRoot)
		{
			CampfireDynamicBackpackService.OnCampfireItemsSpawned(campfireRoot);
		}
	}
	[HarmonyPatch(typeof(SingleItemSpawner), "TrySpawnItems")]
	internal static class SingleItemSpawnerTrySpawnItemsBackpackPatch
	{
		private static void Postfix(SingleItemSpawner __instance, List<PhotonView> __result)
		{
			CampfireDynamicBackpackService.TrackVanillaSpawnedViews(__instance, __result);
		}
	}
	internal static class CampfireDynamicMallowService
	{
		private sealed class CampfireMallowState
		{
			public GameObject Root;

			public string PrefabName = "Marshmallow";

			public readonly List<Transform> SpawnPoints = new List<Transform>();

			public readonly List<PhotonView> TrackedViews = new List<PhotonView>();

			public float RegisteredAt;

			public float LastSyncedAt = -1f;
		}

		private const string MarshmallowPrefabName = "Marshmallow";

		private const string GlizzyPrefabName = "Glizzy";

		private const string FallbackPrefabName = "Marshmallow";

		private const float NearbyPlayerSyncDistance = 80f;

		private const float RecentRegisterWindowSeconds = 120f;

		private const float CircleInnerRadius = 1.2f;

		private const float CircleRingGap = 0.75f;

		private const float CircleMinSpacing = 0.7f;

		private static readonly Dictionary<int, CampfireMallowState> StatesByRootId = new Dictionary<int, CampfireMallowState>();

		private static int _lastPlayerCount = -1;

		private static float _deferredSyncAt = -1f;

		private static string _deferredSyncReason = string.Empty;

		private static int _deferredSyncRootId;

		public static int GetRoomPlayerCount()
		{
			if (PhotonNetwork.CurrentRoom != null)
			{
				return Mathf.Max(1, PhotonNetwork.CurrentRoom.PlayerCount);
			}
			if (PhotonNetwork.PlayerList != null && PhotonNetwork.PlayerList.Length != 0)
			{
				return PhotonNetwork.PlayerList.Length;
			}
			return 1;
		}

		public static int GetTargetMallowCount()
		{
			int roomPlayerCount = GetRoomPlayerCount();
			int num = 1;
			if (CampfireHealingMod.syncedMallowMultiplierEnabled)
			{
				num = Mathf.Max(1, CampfireHealingMod.syncedMallowMultiplier);
			}
			return roomPlayerCount * num;
		}

		public static void OnCampfireItemsSpawned(GameObject campfireRoot)
		{
			if (PhotonNetwork.IsMasterClient && !((Object)(object)campfireRoot == (Object)null))
			{
				CampfireMallowState campfireMallowState = RegisterOrUpdate(campfireRoot);
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Mallows] Registered '{((Object)campfireRoot).name}' with {campfireMallowState.SpawnPoints.Count} food spawn point(s), prefab='{campfireMallowState.PrefabName}'.");
				}
				RequestDeferredSync("campfire-items-spawned", ((Object)campfireRoot).GetInstanceID());
			}
		}

		public static bool TrySpawnCampfireFoodWithGlizzyChance(SingleItemSpawner spawner, out List<PhotonView> result)
		{
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			result = null;
			if (!PhotonNetwork.IsMasterClient || !CampfireHealingMod.IsModActive || !CampfireHealingMod.syncedDynamicMallows || (Object)(object)spawner == (Object)null)
			{
				return false;
			}
			if (!IsCampfireFoodSpawner(spawner))
			{
				return false;
			}
			Component component = ((Component)spawner).GetComponent("SpawnedItemTracker");
			if ((Object)(object)component != (Object)null)
			{
				PropertyInfo property = ((object)component).GetType().GetProperty("HasSpawnHistory");
				bool flag = default(bool);
				int num;
				if (property != null)
				{
					object value = property.GetValue(component);
					if (value is bool)
					{
						flag = (bool)value;
						num = 1;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					num = 0;
				}
				if (((uint)num & (flag ? 1u : 0u)) != 0)
				{
					return false;
				}
			}
			if (spawner.belowAscentRequirement != -1 && Ascents.currentAscent >= spawner.belowAscentRequirement)
			{
				result = new List<PhotonView>();
				return true;
			}
			if (spawner.playersInRoomRequirement > PhotonNetwork.PlayerList.Length)
			{
				result = new List<PhotonView>();
				return true;
			}
			GameObject val = FindCampfireRoot(((Component)spawner).transform);
			CampfireMallowState campfireMallowState = (((Object)(object)val != (Object)null) ? RegisterOrUpdate(val) : null);
			int slotIndex = ((campfireMallowState != null) ? CountPresentMallows(campfireMallowState) : 0);
			int targetMallowCount = GetTargetMallowCount();
			string text = PickFoodPrefabName();
			Vector3 val2 = ((campfireMallowState != null) ? GetCircleSpawnPosition(campfireMallowState, slotIndex, targetMallowCount) : (((Component)spawner).transform.position + Vector3.up * 0.1f));
			Quaternion val3 = ((campfireMallowState != null) ? GetOutwardSpawnRotation(campfireMallowState, val2) : ((Component)spawner).transform.rotation);
			PhotonView val4 = null;
			try
			{
				GameObject val5 = PhotonNetwork.InstantiateItemRoom(text, val2, val3);
				if ((Object)(object)val5 != (Object)null)
				{
					val4 = val5.GetComponent<PhotonView>();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Dynamic Mallows] Vanilla-override spawn failed for '" + text + "': " + ex.Message));
				}
			}
			if ((Object)(object)val4 == (Object)null && !string.Equals(text, "Marshmallow", StringComparison.OrdinalIgnoreCase))
			{
				try
				{
					GameObject val6 = PhotonNetwork.InstantiateItemRoom("Marshmallow", val2, val3);
					if ((Object)(object)val6 != (Object)null)
					{
						val4 = val6.GetComponent<PhotonView>();
					}
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = CampfireHealingMod.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[Dynamic Mallows] Marshmallow fallback failed: " + ex2.Message));
					}
				}
			}
			if ((Object)(object)val4 == (Object)null)
			{
				result = new List<PhotonView>();
				return true;
			}
			spawner.InitializePhysics(val4);
			result = new List<PhotonView> { val4 };
			if ((Object)(object)component != (Object)null)
			{
				MethodInfo method = ((object)component).GetType().GetMethod("TrackSpawnedItems");
				if (method != null)
				{
					method.Invoke(component, new object[1] { result });
				}
			}
			return true;
		}

		public static void TrackVanillaSpawnedViews(SingleItemSpawner spawner, List<PhotonView> views)
		{
			if (!PhotonNetwork.IsMasterClient || (Object)(object)spawner == (Object)null || views == null || views.Count == 0)
			{
				return;
			}
			GameObject val = FindCampfireRoot(((Component)spawner).transform);
			if ((Object)(object)val == (Object)null || !IsCampfireFoodSpawner(spawner))
			{
				return;
			}
			CampfireMallowState campfireMallowState = RegisterOrUpdate(val);
			if ((Object)(object)spawner.prefab != (Object)null && !string.IsNullOrEmpty(((Object)spawner.prefab).name))
			{
				campfireMallowState.PrefabName = ((Object)spawner.prefab).name;
			}
			for (int i = 0; i < views.Count; i++)
			{
				PhotonView val2 = views[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				bool flag = false;
				for (int j = 0; j < campfireMallowState.TrackedViews.Count; j++)
				{
					if ((Object)(object)campfireMallowState.TrackedViews[j] != (Object)null && campfireMallowState.TrackedViews[j].ViewID == val2.ViewID)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					campfireMallowState.TrackedViews.Add(val2);
				}
			}
		}

		private static bool IsCampfireFoodSpawner(SingleItemSpawner spawner)
		{
			if ((Object)(object)spawner == (Object)null)
			{
				return false;
			}
			if (IsCampfireFoodObjectName(((Object)((Component)spawner).gameObject).name))
			{
				return true;
			}
			Transform parent = ((Component)spawner).transform.parent;
			return (Object)(object)parent != (Object)null && ((Object)parent).name.IndexOf("Mallow", StringComparison.OrdinalIgnoreCase) >= 0 && (Object)(object)FindCampfireRoot(((Component)spawner).transform) != (Object)null;
		}

		public static void RequestDeferredSync(string reason, int rootId = 0)
		{
			_deferredSyncReason = reason ?? "sync";
			_deferredSyncAt = Time.time + 0.75f;
			_deferredSyncRootId = rootId;
		}

		public static void Tick()
		{
			if (!PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom || !CampfireHealingMod.syncedDynamicMallows)
			{
				return;
			}
			int roomPlayerCount = GetRoomPlayerCount();
			if (roomPlayerCount != _lastPlayerCount)
			{
				int lastPlayerCount = _lastPlayerCount;
				_lastPlayerCount = roomPlayerCount;
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Mallows] Player count {lastPlayerCount} -> {roomPlayerCount}. Target={GetTargetMallowCount()}.");
				}
				RequestDeferredSync("player-count-changed");
			}
			if (!(_deferredSyncAt < 0f) && !(Time.time < _deferredSyncAt))
			{
				_deferredSyncAt = -1f;
				string deferredSyncReason = _deferredSyncReason;
				int deferredSyncRootId = _deferredSyncRootId;
				_deferredSyncReason = string.Empty;
				_deferredSyncRootId = 0;
				if (deferredSyncRootId != 0)
				{
					SyncOneCampfire(deferredSyncRootId, deferredSyncReason);
				}
				else
				{
					SyncRelevantCampfires(deferredSyncReason);
				}
			}
		}

		public static void SyncAllCampfiresNow(string reason)
		{
			if (PhotonNetwork.IsMasterClient && CampfireHealingMod.syncedDynamicMallows)
			{
				SyncRelevantCampfires(reason ?? "manual");
			}
		}

		private static void SyncOneCampfire(int rootId, string reason)
		{
			if (CampfireHealingMod.IsModActive && CampfireHealingMod.syncedDynamicMallows && StatesByRootId.ContainsKey(rootId))
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Mallows] Syncing 1 campfire ({reason}). players={GetRoomPlayerCount()}, target={GetTargetMallowCount()}.");
				}
				SyncCampfire(rootId);
			}
		}

		private static void SyncRelevantCampfires(string reason)
		{
			if (!CampfireHealingMod.IsModActive || !CampfireHealingMod.syncedDynamicMallows)
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[Dynamic Mallows] Skip sync ({reason}): modActive={CampfireHealingMod.IsModActive}, enabled={CampfireHealingMod.syncedDynamicMallows}.");
				}
				return;
			}
			if (StatesByRootId.Count == 0)
			{
				DiscoverCampfires();
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, CampfireMallowState> item in StatesByRootId)
			{
				if (IsRelevantForPlayerCountSync(item.Value))
				{
					list.Add(item.Key);
				}
			}
			ManualLogSource log2 = CampfireHealingMod.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[Dynamic Mallows] Syncing {list.Count}/{StatesByRootId.Count} relevant campfire(s) ({reason}). players={GetRoomPlayerCount()}, target={GetTargetMallowCount()}, decrease={CampfireHealingMod.syncedMallowDecrease}, multOn={CampfireHealingMod.syncedMallowMultiplierEnabled}, mult={CampfireHealingMod.syncedMallowMultiplier}.");
			}
			for (int i = 0; i < list.Count; i++)
			{
				SyncCampfire(list[i]);
			}
		}

		private static bool IsRelevantForPlayerCountSync(CampfireMallowState state)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			if (state == null || (Object)(object)state.Root == (Object)null || !state.Root.activeInHierarchy)
			{
				return false;
			}
			if (Time.time - state.RegisteredAt <= 120f)
			{
				return true;
			}
			Campfire componentInChildren = state.Root.GetComponentInChildren<Campfire>(true);
			if ((Object)(object)componentInChildren != (Object)null && componentInChildren.Lit && !CampfireHealingMod.CampfireHelper.IsPortableStove(componentInChildren))
			{
				return true;
			}
			Vector3 mallowsCenter = GetMallowsCenter(state);
			float num = 6400f;
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null))
				{
					Vector3 val = allPlayerCharacter.Center - mallowsCenter;
					if (((Vector3)(ref val)).sqrMagnitude <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void DiscoverCampfires()
		{
			Transform[] array = Object.FindObjectsByType<Transform>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			foreach (Transform val in array)
			{
				if (!((Object)(object)val == (Object)null) && IsCampfireFoodObjectName(((Object)val).name))
				{
					GameObject val2 = FindCampfireRoot(val);
					if ((Object)(object)val2 != (Object)null)
					{
						RegisterOrUpdate(val2);
					}
				}
			}
		}

		private static bool IsCampfireFoodObjectName(string name)
		{
			return !string.IsNullOrEmpty(name) && name.IndexOf("CampfireFood", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static GameObject FindCampfireRoot(Transform start)
		{
			Transform val = start;
			GameObject result = null;
			while ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)((Component)val).GetComponentInChildren<Campfire>(true) != (Object)null)
				{
					result = ((Component)val).gameObject;
					if (((Object)val).name.IndexOf("Campfire", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return ((Component)val).gameObject;
					}
				}
				val = val.parent;
			}
			return result;
		}

		private static CampfireMallowState RegisterOrUpdate(GameObject campfireRoot)
		{
			int instanceID = ((Object)campfireRoot).GetInstanceID();
			if (!StatesByRootId.TryGetValue(instanceID, out var value))
			{
				value = new CampfireMallowState
				{
					Root = campfireRoot,
					RegisteredAt = Time.time
				};
				StatesByRootId[instanceID] = value;
			}
			else
			{
				value.Root = campfireRoot;
				value.RegisteredAt = Time.time;
			}
			value.SpawnPoints.Clear();
			if (string.IsNullOrEmpty(value.PrefabName))
			{
				value.PrefabName = "Marshmallow";
			}
			Transform[] componentsInChildren = campfireRoot.GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && IsCampfireFoodObjectName(((Object)val).name))
				{
					value.SpawnPoints.Add(val);
					TryReadPrefabName(val, value);
				}
			}
			if (value.SpawnPoints.Count == 0)
			{
				Component[] componentsInChildren2 = campfireRoot.GetComponentsInChildren(typeof(ISpawner), true);
				foreach (Component val2 in componentsInChildren2)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						Transform parent = val2.transform.parent;
						if (((Object)(object)parent != (Object)null && ((Object)parent).name.IndexOf("Mallow", StringComparison.OrdinalIgnoreCase) >= 0) || IsCampfireFoodObjectName(((Object)val2.gameObject).name))
						{
							value.SpawnPoints.Add(val2.transform);
							TryReadPrefabName(val2.transform, value);
						}
					}
				}
			}
			if (value.SpawnPoints.Count == 0)
			{
				value.SpawnPoints.Add(campfireRoot.transform);
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Dynamic Mallows] '" + ((Object)campfireRoot).name + "' had no CampfireFood children — using root transform. Child dump follows."));
				}
				LogChildNames(campfireRoot.transform, 0, 3);
			}
			return value;
		}

		private static void TryReadPrefabName(Transform t, CampfireMallowState state)
		{
			if ((Object)(object)t == (Object)null || state == null)
			{
				return;
			}
			SingleItemSpawner component = ((Component)t).GetComponent<SingleItemSpawner>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.prefab != (Object)null && !string.IsNullOrEmpty(((Object)component.prefab).name))
			{
				state.PrefabName = ((Object)component.prefab).name;
				return;
			}
			Component[] components = ((Component)t).GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				FieldInfo field = ((object)val).GetType().GetField("prefab");
				if (!(field == null) && !(field.FieldType != typeof(GameObject)))
				{
					object? value = field.GetValue(val);
					GameObject val2 = (GameObject)((value is GameObject) ? value : null);
					if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name))
					{
						state.PrefabName = ((Object)val2).name;
						break;
					}
				}
			}
		}

		private static void LogChildNames(Transform root, int depth, int maxDepth)
		{
			if ((Object)(object)root == (Object)null || depth > maxDepth)
			{
				return;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)("[Dynamic Mallows]   " + new string(' ', depth * 2) + "- " + ((Object)child).name));
				}
				LogChildNames(child, depth + 1, maxDepth);
			}
		}

		private static void SyncCampfire(int rootId)
		{
			if (!StatesByRootId.TryGetValue(rootId, out var value))
			{
				return;
			}
			if ((Object)(object)value.Root == (Object)null)
			{
				StatesByRootId.Remove(rootId);
				return;
			}
			if (value.SpawnPoints.Count == 0)
			{
				RegisterOrUpdate(value.Root);
			}
			if (value.SpawnPoints.Count == 0)
			{
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogWarning((object)("[Dynamic Mallows] '" + ((Object)value.Root).name + "' still has no spawn points."));
				}
				return;
			}
			PruneTracked(value);
			int num = CountPresentMallows(value);
			int targetMallowCount = GetTargetMallowCount();
			int num2 = 0;
			int num3 = 0;
			while (num < targetMallowCount && TrySpawnOne(value))
			{
				num2++;
				num = CountPresentMallows(value);
			}
			num = CountPresentMallows(value);
			if (CampfireHealingMod.syncedMallowDecrease)
			{
				while (num > targetMallowCount && TryDestroyOneExtra(value))
				{
					num3++;
					num = CountPresentMallows(value);
				}
			}
			value.LastSyncedAt = Time.time;
			ManualLogSource log2 = CampfireHealingMod.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[Dynamic Mallows] '{((Object)value.Root).name}': present~{num}, target={targetMallowCount}, spawned+{num2}, destroyed-{num3}, tracked={value.TrackedViews.Count}, prefab='{value.PrefabName}', points={value.SpawnPoints.Count}.");
			}
		}

		private static void PruneTracked(CampfireMallowState state)
		{
			for (int num = state.TrackedViews.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)state.TrackedViews[num] == (Object)null)
				{
					state.TrackedViews.RemoveAt(num);
				}
			}
		}

		private static bool MatchesMallowPrefab(Item item, string prefabName)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			string text = (((Object)(object)((Component)item).gameObject != (Object)null) ? ((Object)((Component)item).gameObject).name : string.Empty);
			string text2 = ((Object)item).name ?? string.Empty;
			if (!string.IsNullOrEmpty(prefabName) && (text.IndexOf(prefabName, StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf(prefabName, StringComparison.OrdinalIgnoreCase) >= 0))
			{
				return true;
			}
			return text.IndexOf("Marshmallow", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Glizzy", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Marshmallow", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Glizzy", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static int CountPresentMallows(CampfireMallowState state)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			PruneTracked(state);
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			for (int i = 0; i < state.TrackedViews.Count; i++)
			{
				PhotonView val = state.TrackedViews[i];
				if (!((Object)(object)val == (Object)null) && hashSet.Add(val.ViewID) && !IsHeldOrGone(val))
				{
					num++;
				}
			}
			string prefabName = state.PrefabName;
			Vector3 mallowsCenter = GetMallowsCenter(state);
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			foreach (Item val2 in array)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null) && MatchesMallowPrefab(val2, prefabName) && hashSet.Add(((MonoBehaviourPun)val2).photonView.ViewID) && !IsHeldOrGone(((MonoBehaviourPun)val2).photonView) && !(Vector3.Distance(((Component)val2).transform.position, mallowsCenter) > 12f))
				{
					state.TrackedViews.Add(((MonoBehaviourPun)val2).photonView);
					num++;
				}
			}
			return num;
		}

		private static bool IsHeldOrGone(PhotonView view)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			if ((Object)(object)view == (Object)null)
			{
				return true;
			}
			Item component = ((Component)view).GetComponent<Item>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			if ((Object)(object)component.holderCharacter != (Object)null)
			{
				return true;
			}
			return (int)component.itemState == 1 || (int)component.itemState == 2;
		}

		private static Vector3 GetMallowsCenter(CampfireMallowState state)
		{
			//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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			int num = 0;
			for (int i = 0; i < state.SpawnPoints.Count; i++)
			{
				if (!((Object)(object)state.SpawnPoints[i] == (Object)null))
				{
					val += state.SpawnPoints[i].position;
					num++;
				}
			}
			return (num > 0) ? (val / (float)num) : state.Root.transform.position;
		}

		private static bool TrySpawnOne(CampfireMallowState state)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (state.SpawnPoints.Count == 0)
			{
				return false;
			}
			int slotIndex = CountPresentMallows(state);
			int targetMallowCount = GetTargetMallowCount();
			string text = PickFoodPrefabName();
			Vector3 circleSpawnPosition = GetCircleSpawnPosition(state, slotIndex, targetMallowCount);
			Quaternion outwardSpawnRotation = GetOutwardSpawnRotation(state, circleSpawnPosition);
			if (!TryInstantiateExtra(state, text, circleSpawnPosition, outwardSpawnRotation))
			{
				if (!string.Equals(text, "Marshmallow", StringComparison.OrdinalIgnoreCase) && TryInstantiateExtra(state, "Marshmallow", circleSpawnPosition, outwardSpawnRotation))
				{
					return true;
				}
				return false;
			}
			return true;
		}

		private static string PickFoodPrefabName()
		{
			float num = Mathf.Clamp01(CampfireHealingMod.syncedGlizzyChance);
			if (num >= 1f)
			{
				return "Glizzy";
			}
			if (num <= 0f)
			{
				return "Marshmallow";
			}
			return (Random.value < num) ? "Glizzy" : "Marshmallow";
		}

		private static bool TryInstantiateExtra(CampfireMallowState state, string prefabName, Vector3 spawnPos, Quaternion spawnRot)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = PhotonNetwork.InstantiateItemRoom(prefabName, spawnPos, spawnRot);
				if ((Object)(object)val == (Object)null)
				{
					ManualLogSource log = CampfireHealingMod.Log;
					if (log != null)
					{
						log.LogWarning((object)("[Dynamic Mallows] InstantiateItemRoom returned null for '" + prefabName + "'."));
					}
					return false;
				}
				PhotonView component = val.GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					return false;
				}
				Item component2 = val.GetComponent<Item>();
				if ((Object)(object)component2 != (Object)null)
				{
					component.RPC("SetKinematicRPC", (RpcTarget)3, new object[3]
					{
						true,
						val.transform.position,
						val.transform.rotation
					});
				}
				state.TrackedViews.Add(component);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = CampfireHealingMod.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[Dynamic Mallows] Spawn failed for '" + prefabName + "': " + ex.Message));
				}
				return false;
			}
		}

		private static Vector3 GetFireCenter(CampfireMallowState state)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)state?.Root == (Object)null)
			{
				return Vector3.zero;
			}
			Campfire componentInChildren = state.Root.GetComponentInChildren<Campfire>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return componentInChildren.Center();
			}
			return state.Root.transform.position;
		}

		private static float GetSpawnHeight(CampfireMallowState state)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return GetMallowsCenter(state).y + 0.08f;
		}

		private static Vector3 GetCircleSpawnPosition(CampfireMallowState state, int slotIndex, int totalCount)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			Vector3 fireCenter = GetFireCenter(state);
			float spawnHeight = GetSpawnHeight(state);
			totalCount = Mathf.Max(1, totalCount);
			if (slotIndex < 0)
			{
				slotIndex = 0;
			}
			int num = 0;
			for (int i = 0; i < 12; i++)
			{
				float num2 = 1.2f + (float)i * 0.75f;
				int num3 = Mathf.Max(1, Mathf.FloorToInt((float)Math.PI * 2f * num2 / 0.7f));
				int num4 = Mathf.Min(num3, totalCount - num);
				if (num4 <= 0)
				{
					break;
				}
				if (slotIndex < num + num4)
				{
					int num5 = slotIndex - num;
					float num6 = (float)num5 / (float)num4 * ((float)Math.PI * 2f) + (float)i * 0.35f;
					return new Vector3(fireCenter.x + Mathf.Cos(num6) * num2, spawnHeight, fireCenter.z + Mathf.Sin(num6) * num2);
				}
				num += num4;
			}
			float num7 = (float)slotIndex / (float)totalCount * ((float)Math.PI * 2f);
			return new Vector3(fireCenter.x + Mathf.Cos(num7) * 1.2f, spawnHeight, fireCenter.z + Mathf.Sin(num7) * 1.2f);
		}

		private static Quaternion GetOutwardSpawnRotation(CampfireMallowState state, Vector3 spawnPos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Vector3 fireCenter = GetFireCenter(state);
			Vector3 val = spawnPos - fireCenter;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				return Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			}
			return Quaternion.LookRotation(((Vector3)(ref val)).normalized) * Quaternion.Euler(0f, Random.Range(-18f, 18f), 0f);
		}

		private static bool TryDestroyOneExtra(CampfireMallowState state)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			for (int num = state.TrackedViews.Count - 1; num >= 0; num--)
			{
				PhotonView val = state.TrackedViews[num];
				state.TrackedViews.RemoveAt(num);
				if (!((Object)(object)val == (Object)null) && !IsHeldOrGone(val))
				{
					PhotonNetwork.Destroy(val);
					return true;
				}
			}
			string prefabName = state.PrefabName;
			Vector3 mallowsCenter = GetMallowsCenter(state);
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsSortMode)0);
			for (int num2 = array.Length - 1; num2 >= 0; num2--)
			{
				Item val2 = array[num2];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null) && !IsHeldOrGone(((MonoBehaviourPun)val2).photonView) && MatchesMallowPrefab(val2, prefabName) && !(Vector3.Distance(((Component)val2).transform.position, mallowsCenter) > 10f))
				{
					PhotonNetwork.Destroy(((MonoBehaviourPun)val2).photonView);
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(MapHandler), "SpawnCampfireItems")]
	internal static class MapHandlerSpawnCampfireItemsMallowPatch
	{
		private static void Postfix(GameObject campfireRoot)
		{
			CampfireDynamicMallowService.OnCampfireItemsSpawned(campfireRoot);
		}
	}
	[HarmonyPatch(typeof(SingleItemSpawner), "TrySpawnItems")]
	internal static class SingleItemSpawnerTrySpawnItemsMallowPatch
	{
		private static bool Prefix(SingleItemSpawner __instance, ref List<PhotonView> __result)
		{
			if (!CampfireDynamicMallowService.TrySpawnCampfireFoodWithGlizzyChance(__instance, out var result))
			{
				return true;
			}
			__result = result ?? new List<PhotonView>();
			return false;
		}

		private static void Postfix(SingleItemSpawner __instance, List<PhotonView> __result)
		{
			CampfireDynamicMallowService.TrackVanillaSpawnedViews(__instance, __result);
		}
	}
	internal static class CampfireModAuthorizationService
	{
		public const string RoomConfigPropertyKey = "healingCampfiresConfigV2";

		private static PhotonScopedManager _photonManager;

		private static bool _photonManagerReady;

		private static bool _hostHasHealingCampfiresMod;

		private static string _pendingHostConfigPayload;

		public static bool IsGameplayEnabled { get; private set; }

		public static void Initialize()
		{
			Networking.AddHostHasPluginListeners("tony4twentys.Healing_Campfires", (Action)OnHostHasHealingCampfiresMod, (Action)OnHostMissingHealingCampfiresMod);
			if (PhotonCustomPropsUtilsPlugin.IsReady)
			{
				SetupPhotonManager();
			}
			else
			{
				PhotonCustomPropsUtilsPlugin.OnReady += SetupPhotonManager;
			}
			if (!PhotonNetwork.InRoom)
			{
				SetSoloAuthorized();
			}
		}

		public static void SetSoloAuthorized()
		{
			_hostHasHealingCampfiresMod = true;
			IsGameplayEnabled = true;
			CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
		}

		private static void SetupPhotonManager()
		{
			if (_photonManagerReady)
			{
				return;
			}
			_photonManagerReady = true;
			_photonManager = PhotonCustomPropsUtilsPlugin.GetManager("tony4twentys.Healing_Campfires");
			_photonManager.RegisterOnJoinedRoom((Action<Player>)delegate
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && _hostHasHealingCampfiresMod)
				{
					CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
					PublishHostConfigIfMaster();
				}
			});
			_photonManager.RegisterRoomProperty<string>("healingCampfiresConfigV2", (RoomEventType)2, (Action<string>)delegate(string value)
			{
				if (!PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(value))
				{
					if (!_hostHasHealingCampfiresMod)
					{
						_pendingHostConfigPayload = value;
					}
					else
					{
						CampfireConfigSyncService.ApplyRemoteSnapshot(value);
					}
				}
			});
		}

		private static void OnHostHasHealingCampfiresMod()
		{
			if (PhotonNetwork.InRoom)
			{
				_hostHasHealingCampfiresMod = true;
				IsGameplayEnabled = true;
				if (PhotonNetwork.IsMasterClient)
				{
					CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
					PublishHostConfigIfMaster();
				}
				else if (!string.IsNullOrEmpty(_pendingHostConfigPayload))
				{
					CampfireConfigSyncService.ApplyRemoteSnapshot(_pendingHostConfigPayload);
					_pendingHostConfigPayload = null;
				}
			}
		}

		private static void OnHostMissingHealingCampfiresMod()
		{
			if (PhotonNetwork.InRoom)
			{
				_hostHasHealingCampfiresMod = false;
				IsGameplayEnabled = false;
				_pendingHostConfigPayload = null;
				CampfireConfigSyncService.ClearRemoteHostConfig();
				CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
			}
		}

		public static void OnHostConfigChangedLocally()
		{
			if (!PhotonNetwork.InRoom)
			{
				CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
			}
			else if (IsGameplayEnabled && PhotonNetwork.IsMasterClient)
			{
				CampfireConfigSyncService.ApplyLocalAuthoritativeConfig();
				PublishHostConfigIfMaster();
			}
		}

		private static void PublishHostConfigIfMaster()
		{
			if (_photonManager != null && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && !((Object)(object)CampfireHealingMod.Instance == (Object)null))
			{
				string text = CampfireConfigSyncService.Serialize(CampfireHealingMod.Instance.BuildSnapshot());
				_photonManager.SetRoomProperty("healingCampfiresConfigV2", (object)text);
			}
		}
	}
	internal static class CampfireRadiusService
	{
		private static readonly Dictionary<int, float> OriginalRadiusById = new Dictionary<int, float>();

		public static void RegisterAndApply(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null) && !CampfireHealingMod.CampfireHelper.IsPortableStove(fire))
			{
				int instanceID = ((Object)fire).GetInstanceID();
				if (!OriginalRadiusById.ContainsKey(instanceID))
				{
					OriginalRadiusById[instanceID] = fire.moraleBoostRadius;
				}
				Apply(fire);
			}
		}

		public static void ApplyToAllCampfires()
		{
			Campfire[] array = Object.FindObjectsByType<Campfire>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				RegisterAndApply(array[i]);
			}
		}

		public static void Apply(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null) && !CampfireHealingMod.CampfireHelper.IsPortableStove(fire))
			{
				int instanceID = ((Object)fire).GetInstanceID();
				if (!OriginalRadiusById.TryGetValue(instanceID, out var value))
				{
					value = fire.moraleBoostRadius;
					OriginalRadiusById[instanceID] = value;
				}
				float syncedMoraleBoostRadius = CampfireHealingMod.syncedMoraleBoostRadius;
				fire.moraleBoostRadius = ((syncedMoraleBoostRadius > 0f) ? syncedMoraleBoostRadius : value);
			}
		}

		public static void Cleanup(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null))
			{
				OriginalRadiusById.Remove(((Object)fire).GetInstanceID());
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "Awake")]
	internal static class CampfireAwakeRadiusPatch
	{
		private static void Postfix(Campfire __instance)
		{
			CampfireRadiusService.RegisterAndApply(__instance);
		}
	}
	[HarmonyPatch(typeof(Campfire), "OnDestroy")]
	internal static class CampfireOnDestroyRadiusPatch
	{
		private static void Prefix(Campfire __instance)
		{
			CampfireRadiusService.Cleanup(__instance);
		}
	}
	internal static class CampfireRestrictionService
	{
		private sealed class PendingCampfireState
		{
			public Campfire Fire;

			public bool AwaitingUnlock;

			public bool UnlockRpcSent;

			public float UnlockNotBefore;
		}

		internal static readonly byte ReviveRequestEventCode = ComputeReviveEventCode();

		private const string ReviveRequestMagic = "HC_REVIVE_V1";

		private static readonly Dictionary<int, PendingCampfireState> PendingByInstanceId = new Dictionary<int, PendingCampfireState>();

		private static bool _eventsRegistered;

		public static bool HoldReviveActive => CampfireHealingMod.IsModActive && CampfireHealingMod.syncedRespawnEnabled;

		public static bool ShouldDeferUnlock => CampfireHealingMod.IsModActive && CampfireHealingMod.syncedRemoveRestriction;

		private static byte ComputeReviveEventCode()
		{
			int num = -2128831035;
			string text = "tony4twentys.Healing_Campfires";
			for (int i = 0; i < text.Length; i++)
			{
				num = (num ^ text[i]) * 16777619;
			}
			int num2 = ((num != int.MinValue) ? Math.Abs(num) : 0);
			return (byte)(180 + num2 % 20);
		}

		public static void RegisterPhotonEvents()
		{
			if (!_eventsRegistered)
			{
				PhotonNetwork.NetworkingClient.EventReceived += OnPhotonEvent;
				_eventsRegistered = true;
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)string.Format("[Healing Campfires] Hold-revive RaiseEvent code={0} (magic={1}).", ReviveRequestEventCode, "HC_REVIVE_V1"));
				}
			}
		}

		private static void OnPhotonEvent(EventData photonEvent)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (photonEvent != null && photonEvent.Code == ReviveRequestEventCode && PhotonNetwork.IsMasterClient && TryReadReviveRequest(photonEvent.CustomData, out var position))
			{
				CampfireHealingMod.RespawnAllDeadPlayers(position);
			}
		}

		private static bool TryReadReviveRequest(object customData, out Vector3 position)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			if (customData is object[] array && array.Length >= 4 && array[0] is string text && text == "HC_REVIVE_V1" && array[1] is float num && array[2] is float num2 && array[3] is float num3)
			{
				position = new Vector3(num, num2, num3);
				return true;
			}
			if (customData is Vector3 val)
			{
				position = val;
				return true;
			}
			return false;
		}

		public static void RequestReviveAt(Vector3 position)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0077: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (HoldReviveActive)
			{
				if (PhotonNetwork.IsMasterClient)
				{
					CampfireHealingMod.RespawnAllDeadPlayers(position);
					return;
				}
				object[] array = new object[4] { "HC_REVIVE_V1", position.x, position.y, position.z };
				PhotonNetwork.RaiseEvent(ReviveRequestEventCode, (object)array, new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)2
				}, SendOptions.SendReliable);
			}
		}

		public static string LocalizedPrompt(string key, string fallback)
		{
			try
			{
				string text = LocalizedText.GetText(key, false);
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return string.IsNullOrEmpty(fallback) ? key : fallback;
		}

		public static float GetMoraleRadius(Campfire fire)
		{
			return ((Object)(object)fire != (Object)null) ? fire.moraleBoostRadius : 0f;
		}

		public static bool HasRevivablePlayers()
		{
			List<Character> allCharacters = Character.AllCharacters;
			if (allCharacters == null)
			{
				return false;
			}
			foreach (Character item in allCharacters)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.data == (Object)null) && !item.isBot)
				{
					if (item.data.dead)
					{
						return true;
					}
					if (CampfireHealingMod.syncedRevivePassedOut && item.data.fullyPassedOut)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static bool AllPlayersAliveAndInMoraleRadius(Campfire fire)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			float moraleRadius = GetMoraleRadius(fire);
			Vector3 position = ((Component)fire).transform.position;
			bool result = false;
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null) && !((Object)(object)allPlayerCharacter.data == (Object)null) && !allPlayerCharacter.isBot)
				{
					result = true;
					if (allPlayerCharacter.data.dead || allPlayerCharacter.data.fullyPassedOut)
					{
						return false;
					}
					if (Vector3.Distance(position, allPlayerCharacter.Center) > moraleRadius)
					{
						return false;
					}
				}
			}
			return result;
		}

		public static string BuildFarPlayersPrintout(Campfire fire)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null)
			{
				return string.Empty;
			}
			float moraleRadius = GetMoraleRadius(fire);
			Vector3 position = ((Component)fire).transform.position;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null) && !((Object)(object)allPlayerCharacter.data == (Object)null) && !allPlayerCharacter.isBot)
				{
					string value = (((Object)(object)((MonoBehaviourPun)allPlayerCharacter).photonView != (Object)null && ((MonoBehaviourPun)allPlayerCharacter).photonView.Owner != null) ? ((MonoBehaviourPun)allPlayerCharacter).photonView.Owner.NickName : ((Object)((Component)allPlayerCharacter).gameObject).name);
					if (allPlayerCharacter.data.dead || allPlayerCharacter.data.fullyPassedOut)
					{
						stringBuilder.Append('\n');
						stringBuilder.Append(value);
						stringBuilder.Append(allPlayerCharacter.data.dead ? " DEAD" : " PASSED OUT");
					}
					else if (!(Vector3.Distance(position, allPlayerCharacter.Center) <= moraleRadius))
					{
						float num = Vector3.Distance(position, allPlayerCharacter.Center) * CharacterStats.unitsToMeters;
						stringBuilder.Append('\n');
						stringBuilder.Append(value);
						stringBuilder.Append(' ');
						stringBuilder.Append(Mathf.RoundToInt(num));
						stringBuilder.Append('m');
					}
				}
			}
			return stringBuilder.ToString();
		}

		public static void MarkAwaitingUnlock(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null))
			{
				int instanceID = ((Object)fire).GetInstanceID();
				PendingByInstanceId[instanceID] = new PendingCampfireState
				{
					Fire = fire,
					AwaitingUnlock = true,
					UnlockRpcSent = false,
					UnlockNotBefore = 0f
				};
			}
		}

		public static bool IsAwaitingUnlock(Campfire fire)
		{
			if ((Object)(object)fire == (Object)null)
			{
				return false;
			}
			PendingCampfireState value;
			return PendingByInstanceId.TryGetValue(((Object)fire).GetInstanceID(), out value) && value.AwaitingUnlock;
		}

		public static void ClearAwaitingUnlock(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null) && PendingByInstanceId.TryGetValue(((Object)fire).GetInstanceID(), out var value))
			{
				value.AwaitingUnlock = false;
			}
		}

		public static bool ShouldSuppressMoraleBoost(Vector3 origin)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (!ShouldDeferUnlock)
			{
				return false;
			}
			foreach (PendingCampfireState value in PendingByInstanceId.Values)
			{
				if (value != null && value.AwaitingUnlock && !((Object)(object)value.Fire == (Object)null))
				{
					Vector3 val = ((Component)value.Fire).transform.position - origin;
					if (((Vector3)(ref val)).sqrMagnitude <= 1f)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static void SkipVanillaFirstLightMorale(Campfire fire)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null || fire.fireHasStarted)
			{
				return;
			}
			if (fire.fireStart != null)
			{
				for (int i = 0; i < fire.fireStart.Length; i++)
				{
					if ((Object)(object)fire.fireStart[i] != (Object)null)
					{
						fire.fireStart[i].Play(((Component)fire).transform.position);
					}
				}
			}
			fire.fireHasStarted = true;
		}

		public static void DelayUnlockAfterRevive(Vector3 campfirePosition)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			foreach (PendingCampfireState value in PendingByInstanceId.Values)
			{
				if (value == null || !value.AwaitingUnlock || (Object)(object)value.Fire == (Object)null || value.UnlockRpcSent)
				{
					continue;
				}
				Vector3 val = ((Component)value.Fire).transform.position - campfirePosition;
				if (!(((Vector3)(ref val)).sqrMagnitude > 4f))
				{
					float num = Time.time + 0.75f;
					if (num > value.UnlockNotBefore)
					{
						value.UnlockNotBefore = num;
					}
				}
			}
		}

		public static void TryCompleteUnlock(Campfire fire)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null || !ShouldDeferUnlock || !IsAwaitingUnlock(fire) || !PhotonNetwork.IsMasterClient || !fire.Lit || CampfireHealingMod.CampfireHelper.IsPortableStove(fire) || !AllPlayersAliveAndInMoraleRadius(fire))
			{
				return;
			}
			int instanceID = ((Object)fire).GetInstanceID();
			if (!PendingByInstanceId.TryGetValue(instanceID, out var value) || value.UnlockRpcSent || Time.time < value.UnlockNotBefore)
			{
				return;
			}
			value.UnlockRpcSent = true;
			if ((Object)(object)fire.view != (Object)null)
			{
				fire.view.RPC("Light_Rpc", (RpcTarget)0, new object[2] { true, fire.beenBurningFor });
				ManualLogSource log = CampfireHealingMod.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Campfire unlock RPC sent at {((Component)fire).transform.position} (morale + next segment).");
				}
			}
		}

		public static void GrantDeferredMorale(Campfire fire)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fire == (Object)null)
			{
				return;
			}
			int num = (CampfireHealingMod.syncedEnableSoloMoraleBoost ? 1 : 2);
			float syncedMoraleBoostStamina = CampfireHealingMod.syncedMoraleBoostStamina;
			if (PhotonNetwork.IsMasterClient)
			{
				bool flag = MoraleBoost.SpawnMoraleBoost(((Component)fire).transform.position, fire.moraleBoostRadius, syncedMoraleBoostStamina, fire.moraleBoostPerAdditionalScout, true, num);
				if (flag && (Object)(object)Singleton<AchievementManager>.Instance != (Object)null)
				{
					Singleton<AchievementManager>.Instance.IncrementSteamStat((STEAMSTATTYPE)2, 1);
				}
				if (!flag)
				{
					return;
				}
			}
			if (fire.moraleBoost == null)
			{
				return;
			}
			for (int i = 0; i < fire.moraleBoost.Length; i++)
			{
				if ((Object)(object)fire.moraleBoost[i] != (Object)null)
				{
					fire.moraleBoost[i].Play(((Component)fire).transform.position);
				}
			}
		}

		internal static int CountCharactersInRadiusPublic(Vector3 origin, float radius)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			List<Character> allCharacters = Character.AllCharacters;
			if (allCharacters == null)
			{
				return 0;
			}
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && (radius == -1f || Vector3.Distance(val.Center, origin) <= radius))
				{
					num++;
				}
			}
			return num;
		}

		internal static void ApplyMoraleToCharactersInRadiusPublic(Vector3 origin, float radius, float stamina, bool sendToAll)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			List<Character> allCharacters = Character.AllCharacters;
			if (allCharacters == null)
			{
				return;
			}
			List<Character> list = new List<Character>();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && (radius == -1f || Vector3.Distance(val.Center, origin) <= radius))
				{
					list.Add(val);
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				Character val2 = list[j];
				if (!((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null))
				{
					if (sendToAll)
					{
						((MonoBehaviourPun)val2).photonView.RPC("MoraleBoost", (RpcTarget)0, new object[2] { stamina, list.Count });
					}
					else
					{
						val2.MoraleBoost(stamina, list.Count);
					}
				}
			}
		}

		public static void CleanupFire(Campfire fire)
		{
			if (!((Object)(object)fire == (Object)null))
			{
				PendingByInstanceId.Remove(((Object)fire).GetInstanceID());
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "Interact_CastFinished")]
	internal static class CampfireInteractCastFinishedPatch
	{
		private static bool Prefix(Campfire __instance, Character interactor)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!CampfireHealingMod.IsModActive || (Object)(object)__instance == (Object)null || CampfireHealingMod.CampfireHelper.IsPortableStove(__instance))
			{
				return true;
			}
			if (__instance.Lit)
			{
				if ((Object)(object)__instance.currentlyCookingItem != (Object)null)
				{
					return true;
				}
				if (CampfireRestrictionService.HoldReviveActive && CampfireRestrictionService.HasRevivablePlayers())
				{
					CampfireRestrictionService.RequestReviveAt(((Component)__instance).transform.position);
					return false;
				}
				return true;
			}
			if (!CampfireHealingMod.syncedRemoveRestriction)
			{
				return true;
			}
			if ((Object)(object)__instance.view != (Object)null)
			{
				__instance.view.RPC("Light_Rpc", (RpcTarget)0, new object[2] { true, 0f });
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Campfire), "Light_Rpc")]
	internal static class CampfireLightRpcRestrictionPatch
	{
		private static void Prefix(Campfire __instance, ref bool updateSegment, out int __state)
		{
			__state = 0;
			if (CampfireHealingMod.IsModActive && CampfireHealingMod.syncedRemoveRestriction && !((Object)(object)__instance == (Object)null) && !CampfireHealingMod.CampfireHelper.IsPortableStove(__instance))
			{
				if (updateSegment && __instance.Lit && CampfireRestrictionService.IsAwaitingUnlock(__instance))
				{
					CampfireRestrictionService.ClearAwaitingUnlock(__instance);
					__state = 2;
				}
				else if (updateSegment)
				{
					CampfireRestrictionService.MarkAwaitingUnlock(__instance);
					updateSegment = false;
					__state = 1;
				}
			}
		}

		private static void Postfix(Campfire __instance, bool updateSegment, int __state)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (CampfireHealingMod.IsModActive && !((Object)(object)__instance == (Object)null) && !CampfireHealingMod.CampfireHelper.IsPortableStove(__instance))
			{
				if ((__state == 1 || (__state == 0 && updateSegment && !CampfireHealingMod.syncedRemoveRestriction)) && CampfireHealingMod.syncedRespawnEnabled)
				{
					CampfireHealingMod.RespawnAllDeadPlayers(((Component)__instance).transform.position);
				}
				if (__state == 1)
				{
					CampfireRestrictionService.SkipVanillaFirstLightMorale(__instance);
				}
				if (__state == 2)
				{
					CampfireRestrictionService.GrantDeferredMorale(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(MoraleBoost), "SpawnMoraleBoost")]
	internal static class MoraleBoostSpawnPatch
	{
		private static bool Prefix(Vector3 origin, float radius, ref float baselineStaminaBoost, float staminaBoostPerAdditionalScout, bool sendToAll, int minScouts, ref bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (CampfireRestrictionService.ShouldSuppressMoraleBoost(origin))
			{
				__result = false;
				return false;
			}
			if (!CampfireHealingMod.IsModActive)
			{
				return true;
			}
			baselineStaminaBoost = CampfireHealingMod.syncedMoraleBoostStamina;
			int num = CampfireRestrictionService.CountCharactersInRadiusPublic(origin, radius);
			if (CampfireHealingMod.syncedEnableSoloMoraleBoost && num == 1 && minScouts > 1)
			{
				CampfireRestrictionService.ApplyMoraleToCharactersInRadiusPublic(origin, radius, baselineStaminaBoost, sendToAll);
				__result = true;
				return false;
			}
			if (!CampfireHealingMod.syncedEnableSoloMoraleBoost && num < 2)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class CampfireCanBurnOutPatch
	{
		private static void Postfix(Campfire __instance, ref bool __result)
		{
			if (__result && !((Object)(object)__instance == (Object)null) && CampfireRestrictionService.IsAwaitingUnlock(__instance))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "GetInteractionText")]
	internal static class CampfireGetInteractionTextPatch
	{
		private static bool Prefix(Campfire __instance, ref string __result)
		{
			if (!CampfireHealingMod.IsModActive || (Object)(object)__instance == (Object)null || CampfireHealingMod.CampfireHelper.IsPortableStove(__instance))
			{
				return true;
			}
			bool flag = (Object)(object)Character.localCharacter != (Object)null && (Object)(object)Character.localCharacter.data != (Object)null && (Object)(object)Character.localCharacter.data.currentItem != (Object)null && (Object)(object)Character.localCharacter.data.currentItem.cooking != (Object)null && Character.localCharacter.data.currentItem.cooking.canBeCooked;
			if (__instance.Lit && CampfireRestrictionService.HoldReviveActive && CampfireRestrictionService.HasRevivablePlayers() && !flag)
			{
				string text = (CampfireHealingMod.syncedRemoveRestriction ? CampfireRestrictionService.BuildFarPlayersPrintout(__instance) : string.Empty);
				__result = CampfireRestrictionService.LocalizedPrompt("REVIVE", "REVIVE") + text;
				return false;
			}
			if (!CampfireHealingMod.syncedRemoveRestriction)
			{
				return true;
			}
			string text2 = CampfireRestrictionService.BuildFarPlayersPrintout(__instance);
			if (!__instance.Lit)
			{
				__result = CampfireRestrictionService.LocalizedPrompt("LIGHT", "LIGHT") + text2;
				return false;
			}
			if (flag)
			{
				__result = CampfireRestrictionService.LocalizedPrompt("COOK", "COOK") + text2;
				return false;
			}
			__result = CampfireRestrictionService.LocalizedPrompt("COOK", "COOK") + text2;
			return false;
		}
	}
	[HarmonyPatch(typeof(Campfire), "IsInteractible")]
	internal static class CampfireIsInteractiblePatch
	{
		private static void Postfix(Campfire __instance, Character interactor, ref bool __result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			if (!__result && !((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null) && CampfireRestrictionService.HoldReviveActive && !CampfireHealingMod.CampfireHelper.IsPortableStove(__instance) && (int)__instance.state == 1 && CampfireRestrictionService.HasRevivablePlayers())
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "IsConstantlyInteractable")]
	internal static class CampfireIsConstantlyInteractablePatch
	{
		private static void Postfix(Campfire __instance, Character interactor, ref bool __result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			if (!__result && !((Object)(object)__instance == (Object)null) && !((Object)(object)interactor == (Object)null) && CampfireRestrictionService.HoldReviveActive && !CampfireHealingMod.CampfireHelper.IsPortableStove(__instance) && (int)__instance.state == 1 && CampfireRestrictionService.HasRevivablePlayers())
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "ApplyCampfireProtection")]
	internal static class CampfirePendingUnlockPatch
	{
		private static void Postfix(Campfire __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && __instance.Lit)
			{
				CampfireRestrictionService.TryCompleteUnlock(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Campfire), "Extinguish_Rpc")]
	internal static class CampfireExtinguishCleanupPatch
	{
		private static void Postfix(Campfire __instance)
		{
			CampfireRestrictionService.CleanupFire(__instance);
		}
	}
	[BepInPlugin("tony4twentys.Healing_Campfires", "Healing Campfires", "4.5.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class CampfireHealingMod : BaseUnityPlugin
	{
		internal static class CampfireHelp