Decompiled source of CampfireFaerieAura v1.2.4

plugins\youxia173.CampfireFaerieAura.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("youxia173")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.4.0")]
[assembly: AssemblyInformationalVersion("1.2.4")]
[assembly: AssemblyProduct("CampfireFaerieAura")]
[assembly: AssemblyTitle("youxia173.CampfireFaerieAura")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CampfireFaerieAura
{
	internal static class AuraHeal
	{
		private const float TeammateHealInterval = 0.1f;

		private const float PetrifyMinChunk = 0.01f;

		private const float StoveBuffRefreshInterval = 2f;

		private static float _teammateHealAcc;

		private static float _petrifyLocalAcc;

		private static float _petrifyRpcAcc;

		private static float _stoveBuffLastApplied;

		private static readonly Affliction_NoHunger StoveCampfireBuff = new Affliction_NoHunger
		{
			totalTime = 3f
		};

		internal static readonly STATUSTYPE[] HealTypes;

		public static bool ShouldSkipSelfHealAsClient()
		{
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				return HostAuraSync.HostIsProvidingTeammateAura();
			}
			return false;
		}

		private static float GetStatusAmount(CharacterAfflictions aff, STATUSTYPE type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 13)
			{
				CharacterData val = aff.character?.data;
				if (!((Object)(object)val != (Object)null))
				{
					return 0f;
				}
				return (float)val.petrifyAmount / 100f;
			}
			return aff.GetCurrentStatus(type);
		}

		private static float TakePetrifyChunk(ref float acc, float add)
		{
			if (add <= 0f)
			{
				return 0f;
			}
			acc += add;
			if (acc < 0.01f)
			{
				return 0f;
			}
			float num = Mathf.Floor(acc * 100f) / 100f;
			acc -= num;
			return num;
		}

		public static void HealLocal(CharacterAfflictions? aff, float dt, bool applyModCold)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)aff == (Object)null)
			{
				return;
			}
			STATUSTYPE[] healTypes = HealTypes;
			foreach (STATUSTYPE val in healTypes)
			{
				float healAmount = Plugin.GetHealAmount(val, dt, applyModCold);
				if (healAmount <= 0f)
				{
					continue;
				}
				if ((int)val == 13)
				{
					if (GetStatusAmount(aff, val) <= 0f)
					{
						_petrifyLocalAcc = 0f;
						continue;
					}
					float num = TakePetrifyChunk(ref _petrifyLocalAcc, healAmount);
					if (num > 0f)
					{
						aff.SubtractStatus(val, num, false, false);
					}
				}
				else if (!(GetStatusAmount(aff, val) <= 0f))
				{
					aff.SubtractStatus(val, healAmount, false, false);
				}
			}
		}

		public static void ApplyAura(IEnumerable<Character> inRangeCharacters, float dt, bool applyModCold, bool restoreExtraStamina = false)
		{
			if (dt <= 0f)
			{
				return;
			}
			Character localCharacter = Character.localCharacter;
			bool flag = ShouldSkipSelfHealAsClient();
			foreach (Character inRangeCharacter in inRangeCharacters)
			{
				if (!((Object)(object)inRangeCharacter == (Object)null) && !((Object)(object)inRangeCharacter.data == (Object)null) && !inRangeCharacter.data.dead && (Object)(object)inRangeCharacter == (Object)(object)localCharacter)
				{
					if (!flag)
					{
						HealLocal(inRangeCharacter.refs?.afflictions, dt, applyModCold);
					}
					if (restoreExtraStamina)
					{
						RestoreLocalExtraStamina(localCharacter, dt);
					}
				}
			}
			if (!HostAuraSync.IsProvidingTeammateAura() || !PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			_teammateHealAcc += dt;
			if (_teammateHealAcc < 0.1f)
			{
				return;
			}
			float teammateHealAcc = _teammateHealAcc;
			_teammateHealAcc = 0f;
			float[] array = BuildHealDeltas(teammateHealAcc, applyModCold);
			if (array == null)
			{
				return;
			}
			foreach (Character inRangeCharacter2 in inRangeCharacters)
			{
				if (!((Object)(object)inRangeCharacter2 == (Object)null) && !((Object)(object)inRangeCharacter2 == (Object)(object)localCharacter) && !((Object)(object)inRangeCharacter2.data == (Object)null) && !inRangeCharacter2.data.dead)
				{
					CharacterAfflictions val = inRangeCharacter2.refs?.afflictions;
					if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null))
					{
						((MonoBehaviourPun)val).photonView.RPC("RPC_ApplyStatusesFromFloatArray", (RpcTarget)0, new object[1] { array });
					}
				}
			}
		}

		private static void RestoreLocalExtraStamina(Character? local, float dt)
		{
			if ((Object)(object)local == (Object)null || !local.IsLocal || !Plugin.RestoreExtraStamina.Value)
			{
				return;
			}
			float num = Plugin.ExtraStaminaPerSecond.Value * dt;
			if (num <= 0f)
			{
				return;
			}
			float num2 = 1f - (float)local.data.petrifyAmount * 0.01f;
			float num3 = Mathf.Clamp(Plugin.ExtraStaminaCap.Value, 0f, 1f);
			float num4 = Mathf.Min(num2, num3);
			float extraStamina = local.data.extraStamina;
			if (extraStamina >= num4 - 0.0001f)
			{
				return;
			}
			num = Mathf.Min(num, num4 - extraStamina);
			if (!(num <= 0f))
			{
				local.AddExtraStamina(num);
				if ((Object)(object)GUIManager.instance?.bar != (Object)null)
				{
					GUIManager.instance.bar.ChangeBar();
				}
			}
		}

		private static float[]? BuildHealDeltas(float dt, bool applyModCold)
		{
			//IL_001a: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected I4, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			float[] array = new float[CharacterAfflictions.NumStatusTypes];
			bool flag = false;
			STATUSTYPE[] healTypes = HealTypes;
			foreach (STATUSTYPE val in healTypes)
			{
				float healAmount = Plugin.GetHealAmount(val, dt, applyModCold);
				if (healAmount <= 0f)
				{
					continue;
				}
				int num = (int)val;
				if (num < 0 || num >= array.Length)
				{
					continue;
				}
				if ((int)val == 13)
				{
					float num2 = TakePetrifyChunk(ref _petrifyRpcAcc, healAmount);
					if (!(num2 <= 0f))
					{
						array[num] = 0f - num2;
						flag = true;
					}
				}
				else
				{
					array[num] = 0f - healAmount;
					flag = true;
				}
			}
			if (!flag)
			{
				return null;
			}
			return array;
		}

		public static bool IsPortableStoveColdEmitter(StatusEmitter emitter)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if ((Object)(object)emitter == (Object)null)
			{
				return false;
			}
			if ((int)emitter.statusType != 2)
			{
				return false;
			}
			if (emitter.amount >= 0f)
			{
				return false;
			}
			Transform val = ((Component)emitter).transform;
			while ((Object)(object)val != (Object)null)
			{
				string name = ((Object)val).name;
				if (name.IndexOf("PortableStove", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("PortableStovetop", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Portable Stove", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		public static bool IsPortableStoveFireLit(StatusEmitter emitter)
		{
			if ((Object)(object)emitter == (Object)null)
			{
				return false;
			}
			Campfire componentInParent = ((Component)emitter).GetComponentInParent<Campfire>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				if (!componentInParent.Lit)
				{
					return false;
				}
				if ((Object)(object)componentInParent.enableWhenLit != (Object)null && !componentInParent.enableWhenLit.activeInHierarchy)
				{
					return false;
				}
				return true;
			}
			return ((Behaviour)emitter).isActiveAndEnabled;
		}

		public static void RefreshStoveCampfireIconForLocal(bool localInStoveRange)
		{
			if (!Plugin.ShowCampfireIconOnStove.Value || !localInStoveRange)
			{
				return;
			}
			CharacterAfflictions val = Character.localCharacter?.refs?.afflictions;
			if (!((Object)(object)val == (Object)null))
			{
				float totalTime = Mathf.Max(1f, Plugin.PortableStoveBuffDuration.Value);
				((Affliction)StoveCampfireBuff).totalTime = totalTime;
				if (val.canGetHungry || Time.time - _stoveBuffLastApplied > 2f)
				{
					val.AddAffliction((Affliction)(object)StoveCampfireBuff, false);
					_stoveBuffLastApplied = Time.time;
				}
			}
		}

		public static void ClearStoveCampfireIconForLocal()
		{
			Character localCharacter = Character.localCharacter;
			CharacterAfflictions val = localCharacter?.refs?.afflictions;
			if (!((Object)(object)val == (Object)null) && !((Object)(object)localCharacter == (Object)null) && !IsLocalNearLitCampfire(localCharacter))
			{
				if (!val.canGetHungry)
				{
					val.RemoveAffliction((AfflictionType)21);
				}
				_stoveBuffLastApplied = 0f;
			}
		}

		private static bool IsLocalNearLitCampfire(Character local)
		{
			if ((Object)(object)local == (Object)null)
			{
				return false;
			}
			if (!(AccessTools.Field(typeof(Campfire), "ALL_CAMPFIRES")?.GetValue(null) is List<Campfire> list))
			{
				return false;
			}
			foreach (Campfire item in list)
			{
				if (!((Object)(object)item == (Object)null) && item.Lit)
				{
					List<Character> list2 = item.PlayerCharactersInRadius(item.moraleBoostRadius);
					if (list2 != null && list2.Contains(local))
					{
						return true;
					}
				}
			}
			return false;
		}

		static AuraHeal()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			STATUSTYPE[] array = new STATUSTYPE[9];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			HealTypes = (STATUSTYPE[])(object)array;
		}
	}
	internal static class HostAuraSync
	{
		public const string RoomPropertyKey = "yx173_CFA_HTA";

		private static bool? _lastSyncedProviding;

		public static bool IsProvidingTeammateAura()
		{
			if (Plugin.Enabled.Value)
			{
				return Plugin.AffectTeammatesAsHost.Value;
			}
			return false;
		}

		public static void SyncIfHost()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_005b: Expected O, but got Unknown
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
			{
				if (!PhotonNetwork.InRoom)
				{
					_lastSyncedProviding = null;
				}
				return;
			}
			bool flag = IsProvidingTeammateAura();
			if (_lastSyncedProviding != flag)
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"yx173_CFA_HTA", (object)flag);
				Hashtable val2 = val;
				PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
				_lastSyncedProviding = flag;
				Plugin.Log.LogInfo((object)$"已同步主机队友光环状态到房间: {flag}");
			}
		}

		public static bool HostIsProvidingTeammateAura()
		{
			if (!PhotonNetwork.InRoom)
			{
				return false;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) == null)
			{
				return false;
			}
			if (((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"yx173_CFA_HTA", out object value) && value is bool)
			{
				return (bool)value;
			}
			return false;
		}

		public static void ResetLocalCache()
		{
			_lastSyncedProviding = null;
		}
	}
	[HarmonyPatch(typeof(Campfire), "ApplyCampfireProtection")]
	internal static class Campfire_ApplyCampfireProtection_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(Campfire __instance)
		{
			if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null || !__instance.Lit)
			{
				return;
			}
			float deltaTime = Time.deltaTime;
			if (!(deltaTime <= 0f))
			{
				List<Character> list = __instance.PlayerCharactersInRadius(__instance.moraleBoostRadius);
				if (list != null && list.Count != 0)
				{
					AuraHeal.ApplyAura(list, deltaTime, applyModCold: true, restoreExtraStamina: true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(StatusEmitter), "Update")]
	internal static class StatusEmitter_Update_Patch
	{
		[HarmonyPostfix]
		private static void Postfix(StatusEmitter __instance)
		{
			if (Plugin.Enabled.Value && Plugin.EnablePortableStove.Value && !((Object)(object)__instance == (Object)null) && ((Behaviour)__instance).isActiveAndEnabled && !__instance.emitterDisabledByWind && AuraHeal.IsPortableStoveColdEmitter(__instance) && AuraHeal.IsPortableStoveFireLit(__instance))
			{
				StoveAuraTracker.NotifyLitEmitter(__instance);
			}
		}
	}
	[BepInPlugin("youxia173.CampfireFaerieAura", "CampfireFaerieAura", "1.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<bool> AffectTeammatesAsHost;

		public static ConfigEntry<bool> EnablePortableStove;

		public static ConfigEntry<bool> HealHot;

		public static ConfigEntry<bool> HealCold;

		public static ConfigEntry<bool> HealPoison;

		public static ConfigEntry<bool> HealDrowsy;

		public static ConfigEntry<bool> HealInjury;

		public static ConfigEntry<bool> HealSpores;

		public static ConfigEntry<bool> HealHunger;

		public static ConfigEntry<bool> HealPetrify;

		public static ConfigEntry<bool> HealCurse;

		public static ConfigEntry<bool> RestoreExtraStamina;

		public static ConfigEntry<bool> ShowCampfireIconOnStove;

		public static ConfigEntry<float> PortableStoveBuffDuration;

		public static ConfigEntry<float> HotPerSecond;

		public static ConfigEntry<float> ColdPerSecond;

		public static ConfigEntry<float> PoisonPerSecond;

		public static ConfigEntry<float> DrowsyPerSecond;

		public static ConfigEntry<float> InjuryPerSecond;

		public static ConfigEntry<float> SporesPerSecond;

		public static ConfigEntry<float> HungerRestorePerSecond;

		public static ConfigEntry<float> PetrifyPerSecond;

		public static ConfigEntry<float> CursePerSecond;

		public static ConfigEntry<float> ExtraStaminaPerSecond;

		public static ConfigEntry<float> ExtraStaminaCap;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Expected O, but got Unknown
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Expected O, but got Unknown
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Expected O, but got Unknown
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Expected O, but got Unknown
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Expected O, but got Unknown
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Expected O, but got Unknown
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Expected O, but got Unknown
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Expected O, but got Unknown
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Expected O, but got Unknown
			//IL_0498: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Expected O, but got Unknown
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "总开关。关闭后完全不生效(含主机队友光环)。 / Master switch. When off, the mod does nothing (including host teammate aura).");
			AffectTeammatesAsHost = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectTeammatesAsHost", false, "仅主机:篝火/便携炉范围内队友也享受疗愈(队友可不装本模组)。写入房间属性;装了本模组的客机会跳过自疗避免双倍。 / Host only: also heal teammates in campfire/stove range (they need not install this mod). Writes a room property; clients with this mod skip self-heal to avoid double healing.");
			EnablePortableStove = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePortableStove", true, "便携炉范围内也套用本模组疗愈。寒冷仍只走原版炉子(不叠加模组减寒);篝火寒冷用 HealCold / ColdPerSecond。 / Apply mod heals near portable stoves. Cold still uses vanilla stove only (no mod cold stack); campfire cold uses HealCold / ColdPerSecond.");
			HealHot = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealHot", false, "是否疗愈灼热。 / Heal Hot.");
			HealCold = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealCold", true, "是否疗愈寒冷(仅篝火;便携炉用原版)。 / Heal Cold (campfire only; stove uses vanilla).");
			HealPoison = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealPoison", true, "是否疗愈中毒。 / Heal Poison.");
			HealDrowsy = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealDrowsy", true, "是否疗愈昏睡。 / Heal Drowsy.");
			HealInjury = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealInjury", true, "是否疗愈受伤。 / Heal Injury.");
			HealSpores = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealSpores", true, "是否疗愈孢子。 / Heal Spores.");
			HealHunger = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealHunger", true, "是否降低饥饿(恢复饱食)。 / Reduce Hunger (restore satiety).");
			HealPetrify = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealPetrify", true, "是否疗愈石化。 / Heal Petrify.");
			HealCurse = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "HealCurse", true, "是否疗愈诅咒。 / Heal Curse.");
			RestoreExtraStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "RestoreExtraStamina", true, "篝火/便携炉范围内是否缓慢恢复额外体力条(便携炉还需 EnablePortableStove)。 / Slowly restore bonus/extra stamina near lit campfire or portable stove (stove also needs EnablePortableStove).");
			ShowCampfireIconOnStove = ((BaseUnityPlugin)this).Config.Bind<bool>("HealToggles", "ShowCampfireIconOnStove", true, "便携炉疗愈生效时点亮体力条篝火图标(与原版篝火相同)。 / Light the stamina-bar campfire icon while portable-stove aura is active.");
			PortableStoveBuffDuration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PortableStoveBuffDuration", 5f, new ConfigDescription("便携炉熄灭后,若仍站在炉旁(原减寒范围),模组疗愈与图标再持续的秒数。炉子燃烧期间不受此限制;不影响原版减寒。0 = 熄灭立刻结束。 / Seconds our stove heal+icon continues after the stove extinguishes while still in cold-emitter range. Unlimited while the stove is lit; does not affect vanilla cold. 0 = end immediately on extinguish.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
			HotPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "HotPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ColdPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ColdPerSecond", 0.05f, new ConfigDescription("每秒减少的寒冷(0~1)。原版便携炉约 0.05/秒。0 = 关闭。 / Cold removed per second (0~1). Vanilla stove is about 0.05/s. 0 = off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			PoisonPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "PoisonPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			DrowsyPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "DrowsyPerSecond", 0.01f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			InjuryPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "InjuryPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			SporesPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "SporesPerSecond", 0.005f, new ConfigDescription("每秒减少的状态量(0~1)。例如 0.005 ≈ 每秒 0.5%。0 = 关闭。默认约仙子提灯的 1/5。 / Status removed per second (0~1). e.g. 0.005 ≈ 0.5%/s. 0 = off. Default ~1/5 of Faerie lantern.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			HungerRestorePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "HungerPerSecond", 0.005f, new ConfigDescription("每秒减少的饥饿。篝火原版只会暂停饥饿上涨;此项会主动降低 Hunger。 / Hunger reduced per second. Vanilla campfire only pauses hunger gain; this actively lowers it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			PetrifyPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "PetrifyPerSecond", 0.005f, new ConfigDescription("每秒减少的石化(0~1)。引擎按 1% 步进取整,需累计到 ≥0.01。 / Petrify removed per second (0~1). Engine floors to 1% steps; accumulates until >= 0.01.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			CursePerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "CursePerSecond", 0.005f, new ConfigDescription("每秒减少的诅咒(0~1)。默认与石化相同。 / Curse removed per second (0~1). Default same as Petrify.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ExtraStaminaPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ExtraStaminaPerSecond", 0.01f, new ConfigDescription("篝火/便携炉旁每秒增加的额外体力(0~1)。0.01 ≈ 每秒 1%。0 = 关闭。 / Extra stamina gained per second near campfire/stove (0~1). 0.01 ≈ 1%/s. 0 = off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			ExtraStaminaCap = ((BaseUnityPlugin)this).Config.Bind<float>("HealRates", "ExtraStaminaCap", 0.5f, new ConfigDescription("本模组恢复额外体力的上限(0~1)。默认 0.5 = 最多回满到 50%;已高于上限则不再回。仍受石化对额外体力上限的限制。 / Cap for mod-restored extra stamina (0~1). Default 0.5 = stop at 50%. Won't restore if already above. Still limited by petrify.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Enabled.SettingChanged += delegate
			{
				HostAuraSync.ResetLocalCache();
			};
			AffectTeammatesAsHost.SettingChanged += delegate
			{
				HostAuraSync.ResetLocalCache();
			};
			_harmony = new Harmony("youxia173.CampfireFaerieAura");
			_harmony.PatchAll();
			Log.LogInfo((object)("CampfireFaerieAura v1.2.4 by youxia173 loaded. " + $"Enabled={Enabled.Value} AffectTeammatesAsHost={AffectTeammatesAsHost.Value}"));
		}

		private void Update()
		{
			HostAuraSync.SyncIfHost();
			StoveAuraTracker.Tick(Time.deltaTime);
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		public static float GetHealAmount(STATUSTYPE type, float dt, bool applyModCold = true)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected I4, but got Unknown
			if (dt <= 0f)
			{
				return 0f;
			}
			switch ((int)type)
			{
			case 8:
				if (!HealHot.Value)
				{
					return 0f;
				}
				return HotPerSecond.Value * dt;
			case 2:
				if (!applyModCold || !HealCold.Value)
				{
					return 0f;
				}
				return ColdPerSecond.Value * dt;
			case 3:
				if (!HealPoison.Value)
				{
					return 0f;
				}
				return PoisonPerSecond.Value * dt;
			case 6:
				if (!HealDrowsy.Value)
				{
					return 0f;
				}
				return DrowsyPerSecond.Value * dt;
			case 0:
				if (!HealInjury.Value)
				{
					return 0f;
				}
				return InjuryPerSecond.Value * dt;
			case 10:
				if (!HealSpores.Value)
				{
					return 0f;
				}
				return SporesPerSecond.Value * dt;
			case 1:
				if (!HealHunger.Value)
				{
					return 0f;
				}
				return HungerRestorePerSecond.Value * dt;
			case 13:
				if (!HealPetrify.Value)
				{
					return 0f;
				}
				return PetrifyPerSecond.Value * dt;
			case 5:
				if (!HealCurse.Value)
				{
					return 0f;
				}
				return CursePerSecond.Value * dt;
			default:
				return 0f;
			}
		}
	}
	internal static class StoveAuraTracker
	{
		private sealed class StoveState
		{
			public StatusEmitter? Emitter;

			public Vector3 LastPos;

			public float Range;

			public bool WasLit;

			public float ExtinguishedAt = -1f;

			public bool LingerActive;
		}

		private static readonly Dictionary<int, StoveState> _stoves = new Dictionary<int, StoveState>();

		private static bool _iconForcedOff;

		public static void NotifyLitEmitter(StatusEmitter emitter)
		{
			//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 (!((Object)(object)emitter == (Object)null))
			{
				int instanceID = ((Object)emitter).GetInstanceID();
				if (!_stoves.TryGetValue(instanceID, out StoveState value))
				{
					value = new StoveState();
					_stoves[instanceID] = value;
				}
				value.Emitter = emitter;
				value.LastPos = ((Component)emitter).transform.position;
				value.Range = emitter.radius + emitter.outerFade;
				value.WasLit = true;
				value.ExtinguishedAt = -1f;
				value.LingerActive = false;
			}
		}

		public static void Tick(float dt)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || !Plugin.EnablePortableStove.Value)
			{
				if (_stoves.Count > 0)
				{
					ClearAllAndExtinguishIcon();
				}
			}
			else
			{
				if (dt <= 0f)
				{
					return;
				}
				float num = Mathf.Max(0f, Plugin.PortableStoveBuffDuration.Value);
				Character localCharacter = Character.localCharacter;
				bool flag = false;
				List<int> list = new List<int>();
				foreach (KeyValuePair<int, StoveState> stofe in _stoves)
				{
					StoveState value = stofe.Value;
					bool flag2 = IsEmitterLit(value);
					if (flag2)
					{
						if ((Object)(object)value.Emitter != (Object)null)
						{
							value.LastPos = ((Component)value.Emitter).transform.position;
							value.Range = value.Emitter.radius + value.Emitter.outerFade;
						}
						value.WasLit = true;
						value.ExtinguishedAt = -1f;
						value.LingerActive = false;
					}
					else if (value.WasLit)
					{
						value.WasLit = false;
						if (!((Object)(object)localCharacter != (Object)null) || !IsNear(localCharacter, value) || !(num > 0f))
						{
							list.Add(stofe.Key);
							continue;
						}
						value.ExtinguishedAt = Time.time;
						value.LingerActive = true;
					}
					else
					{
						if (!value.LingerActive)
						{
							list.Add(stofe.Key);
							continue;
						}
						if (Time.time - value.ExtinguishedAt >= num || (Object)(object)localCharacter == (Object)null || !IsNear(localCharacter, value))
						{
							list.Add(stofe.Key);
							continue;
						}
					}
					if (!flag2 && !value.LingerActive)
					{
						list.Add(stofe.Key);
						continue;
					}
					List<Character> list2 = CollectInRange(value);
					if (list2.Count == 0)
					{
						if (value.LingerActive)
						{
							list.Add(stofe.Key);
						}
						continue;
					}
					AuraHeal.ApplyAura(list2, dt, applyModCold: false, restoreExtraStamina: true);
					if ((Object)(object)localCharacter != (Object)null && list2.Contains(localCharacter))
					{
						flag = true;
					}
				}
				foreach (int item in list)
				{
					_stoves.Remove(item);
				}
				if (flag)
				{
					_iconForcedOff = false;
					AuraHeal.RefreshStoveCampfireIconForLocal(localInStoveRange: true);
				}
				else if (!_iconForcedOff)
				{
					AuraHeal.ClearStoveCampfireIconForLocal();
					_iconForcedOff = true;
				}
			}
		}

		private static bool IsEmitterLit(StoveState state)
		{
			StatusEmitter emitter = state.Emitter;
			if ((Object)(object)emitter == (Object)null)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)emitter))
			{
				state.Emitter = null;
				return false;
			}
			if (emitter.emitterDisabledByWind)
			{
				return false;
			}
			if (!AuraHeal.IsPortableStoveColdEmitter(emitter))
			{
				return false;
			}
			if (!AuraHeal.IsPortableStoveFireLit(emitter))
			{
				return false;
			}
			return true;
		}

		private static bool IsNear(Character c, StoveState state)
		{
			//IL_0024: 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)
			if ((Object)(object)c?.data == (Object)null || c.data.dead)
			{
				return false;
			}
			return Vector3.Distance(state.LastPos, c.Center) <= state.Range;
		}

		private static List<Character> CollectInRange(StoveState state)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			List<Character> list = new List<Character>();
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null) && !((Object)(object)allPlayerCharacter.data == (Object)null) && !allPlayerCharacter.data.dead && !(Vector3.Distance(state.LastPos, allPlayerCharacter.Center) > state.Range))
				{
					list.Add(allPlayerCharacter);
				}
			}
			return list;
		}

		private static void ClearAllAndExtinguishIcon()
		{
			_stoves.Clear();
			AuraHeal.ClearStoveCampfireIconForLocal();
			_iconForcedOff = true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "youxia173.CampfireFaerieAura";

		public const string PLUGIN_NAME = "CampfireFaerieAura";

		public const string PLUGIN_VERSION = "1.2.4";
	}
}