Decompiled source of BlastBuddy v1.0.0

plugins/com.github.Thanks.BlastBuddy.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
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("com.github.Thanks.BlastBuddy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("com.github.Thanks.BlastBuddy")]
[assembly: AssemblyTitle("com.github.Thanks.BlastBuddy")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 BlastBuddy
{
	[BepInPlugin("com.github.Thanks.BlastBuddy", "Blast Buddy", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class BlastBuddyPlugin : BaseUnityPlugin
	{
		private enum ConfigKey
		{
			ModEnabled,
			ActivationDelaySeconds,
			TriggerRadius,
			ExitRadius,
			BlastRadius,
			TriggerCooldownSeconds,
			ScanIntervalSeconds,
			SafetyCheckIntervalSeconds,
			FartForce,
			TriggerChance,
			NarrowSpaceCheckRadius,
			NarrowSpaceColliderThreshold,
			EnableRescueSuppression,
			EnableNarrowSpaceSuppression
		}

		[CompilerGenerated]
		private sealed class <EnumerateCandidateTransforms>d__97 : IEnumerable<Transform>, IEnumerable, IEnumerator<Transform>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private Transform <>2__current;

			private int <>l__initialThreadId;

			private object menuInstance;

			public object <>3__menuInstance;

			private Type menuType;

			public Type <>3__menuType;

			Transform IEnumerator<Transform>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <EnumerateCandidateTransforms>d__97(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				object? obj2;
				Transform val2;
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					object obj = menuInstance;
					Component val = (Component)((obj is Component) ? obj : null);
					if (val != null)
					{
						<>2__current = val.transform;
						<>1__state = 1;
						return true;
					}
					goto IL_004d;
				}
				case 1:
					<>1__state = -1;
					goto IL_004d;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_004d:
					obj2 = menuType.GetProperty("Content", InstanceBindingFlags)?.GetValue(menuInstance);
					val2 = (Transform)((obj2 is Transform) ? obj2 : null);
					if (val2 != null)
					{
						<>2__current = val2;
						<>1__state = 2;
						return true;
					}
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator()
			{
				<EnumerateCandidateTransforms>d__97 <EnumerateCandidateTransforms>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<EnumerateCandidateTransforms>d__ = this;
				}
				else
				{
					<EnumerateCandidateTransforms>d__ = new <EnumerateCandidateTransforms>d__97(0);
				}
				<EnumerateCandidateTransforms>d__.menuInstance = <>3__menuInstance;
				<EnumerateCandidateTransforms>d__.menuType = <>3__menuType;
				return <EnumerateCandidateTransforms>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<Transform>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <EnumerateModConfigUiRoots>d__96 : IEnumerable<Transform>, IEnumerable, IEnumerator<Transform>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private Transform <>2__current;

			private int <>l__initialThreadId;

			private object menuInstance;

			public object <>3__menuInstance;

			private Type menuType;

			public Type <>3__menuType;

			private HashSet<int> <visited>5__2;

			private IEnumerator<Transform> <>7__wrap2;

			Transform IEnumerator<Transform>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <EnumerateModConfigUiRoots>d__96(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<visited>5__2 = null;
				<>7__wrap2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<visited>5__2 = new HashSet<int>();
						<>7__wrap2 = EnumerateCandidateTransforms(menuInstance, menuType).GetEnumerator();
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap2.MoveNext())
					{
						Transform current = <>7__wrap2.Current;
						if ((Object)(object)current != (Object)null && <visited>5__2.Add(((Object)current).GetInstanceID()))
						{
							<>2__current = current;
							<>1__state = 1;
							return true;
						}
					}
					<>m__Finally1();
					<>7__wrap2 = null;
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				if (<>7__wrap2 != null)
				{
					<>7__wrap2.Dispose();
				}
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator()
			{
				<EnumerateModConfigUiRoots>d__96 <EnumerateModConfigUiRoots>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<EnumerateModConfigUiRoots>d__ = this;
				}
				else
				{
					<EnumerateModConfigUiRoots>d__ = new <EnumerateModConfigUiRoots>d__96(0);
				}
				<EnumerateModConfigUiRoots>d__.menuInstance = <>3__menuInstance;
				<EnumerateModConfigUiRoots>d__.menuType = <>3__menuType;
				return <EnumerateModConfigUiRoots>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<Transform>)this).GetEnumerator();
			}
		}

		[CompilerGenerated]
		private sealed class <GetAliasDefinitions>d__86 : IEnumerable<ConfigDefinition>, IEnumerable, IEnumerator<ConfigDefinition>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private ConfigDefinition <>2__current;

			private int <>l__initialThreadId;

			private ConfigKey configKey;

			public ConfigKey <>3__configKey;

			private string <englishSection>5__2;

			private string <chineseSection>5__3;

			private string <englishKey>5__4;

			private string <chineseKey>5__5;

			ConfigDefinition IEnumerator<ConfigDefinition>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetAliasDefinitions>d__86(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<englishSection>5__2 = null;
				<chineseSection>5__3 = null;
				<englishKey>5__4 = null;
				<chineseKey>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Expected O, but got Unknown
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a8: Expected O, but got Unknown
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Expected O, but got Unknown
				//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f6: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<englishSection>5__2 = GetSectionName(isChineseLanguage: false);
					<chineseSection>5__3 = GetSectionName(isChineseLanguage: true);
					<englishKey>5__4 = GetKeyName(configKey, isChineseLanguage: false);
					<chineseKey>5__5 = GetKeyName(configKey, isChineseLanguage: true);
					<>2__current = new ConfigDefinition(<englishSection>5__2, <englishKey>5__4);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = new ConfigDefinition(<englishSection>5__2, <chineseKey>5__5);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					<>2__current = new ConfigDefinition(<chineseSection>5__3, <englishKey>5__4);
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<>2__current = new ConfigDefinition(<chineseSection>5__3, <chineseKey>5__5);
					<>1__state = 4;
					return true;
				case 4:
				{
					<>1__state = -1;
					if (TryGetLegacyDefinition(configKey, out ConfigDefinition definition))
					{
						<>2__current = definition;
						<>1__state = 5;
						return true;
					}
					break;
				}
				case 5:
					<>1__state = -1;
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<ConfigDefinition> IEnumerable<ConfigDefinition>.GetEnumerator()
			{
				<GetAliasDefinitions>d__86 <GetAliasDefinitions>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetAliasDefinitions>d__ = this;
				}
				else
				{
					<GetAliasDefinitions>d__ = new <GetAliasDefinitions>d__86(0);
				}
				<GetAliasDefinitions>d__.configKey = <>3__configKey;
				return <GetAliasDefinitions>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<ConfigDefinition>)this).GetEnumerator();
			}
		}

		public const string PluginGuid = "com.github.Thanks.BlastBuddy";

		public const string PluginName = "Blast Buddy";

		public const string PluginVersion = "0.0.1";

		private const string ModConfigPluginGuid = "com.github.PEAKModding.PEAKLib.ModConfig";

		private const int SimplifiedChineseLanguageIndex = 9;

		private const float DefaultActivationDelaySeconds = 30f;

		private const float DefaultTriggerRadius = 2.2f;

		private const float DefaultExitRadius = 3.8f;

		private const float DefaultBlastRadius = 3.4f;

		private const float DefaultTriggerCooldownSeconds = 1.4f;

		private const float DefaultScanIntervalSeconds = 0.18f;

		private const float DefaultSafetyCheckIntervalSeconds = 0.25f;

		private const float DefaultFartForce = 320f;

		private const float DefaultTriggerChance = 1f;

		private const float DefaultNarrowSpaceCheckRadius = 1.1f;

		private const int DefaultNarrowSpaceColliderThreshold = 16;

		private const string ExplosionVfxPath = "VFX_SporeExploExploEdibleSpawn";

		private const string ExplosionNoKnockbackVfxPath = "VFX_SporeExploExploEdibleSpawn_NoKnockback";

		private static readonly BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly BindingFlags StaticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly PropertyInfo? ConfigFileEntriesProperty = typeof(ConfigFile).GetProperty("Entries", InstanceBindingFlags);

		private static BlastBuddyPlugin? _instance;

		private readonly HashSet<int> _nearbyActivePlayers = new HashSet<int>();

		private readonly Dictionary<int, HashSet<int>> _hostNearbyPlayersBySource = new Dictionary<int, HashSet<int>>();

		private readonly List<Character> _scanBuffer = new List<Character>();

		private readonly List<Character> _roomCharacterBuffer = new List<Character>();

		private readonly List<int> _actorIdBuffer = new List<int>();

		private readonly Collider[] _narrowSpaceBuffer = (Collider[])(object)new Collider[24];

		private float _nextAllowedTriggerAt;

		private float _nextScanAt;

		private float _nextSafetyCheckAt;

		private float _gameplayEnteredAt = -1f;

		private bool _cachedSafetySuppressed;

		private bool _loggedActivationDelay;

		private bool _loggedSafetySuppression;

		private bool _loggedRescueSuppression;

		private string? _lastSafetyReason;

		private bool _lastDetectedChineseLanguage;

		private ConfigEntry<bool>? _modEnabledConfig;

		private ConfigEntry<float>? _activationDelaySecondsConfig;

		private ConfigEntry<float>? _triggerRadiusConfig;

		private ConfigEntry<float>? _exitRadiusConfig;

		private ConfigEntry<float>? _blastRadiusConfig;

		private ConfigEntry<float>? _triggerCooldownSecondsConfig;

		private ConfigEntry<float>? _scanIntervalSecondsConfig;

		private ConfigEntry<float>? _safetyCheckIntervalSecondsConfig;

		private ConfigEntry<float>? _fartForceConfig;

		private ConfigEntry<float>? _triggerChanceConfig;

		private ConfigEntry<float>? _narrowSpaceCheckRadiusConfig;

		private ConfigEntry<int>? _narrowSpaceColliderThresholdConfig;

		private ConfigEntry<bool>? _enableRescueSuppressionConfig;

		private ConfigEntry<bool>? _enableNarrowSpaceSuppressionConfig;

		private void Awake()
		{
			_instance = this;
			_lastDetectedChineseLanguage = DetectChineseLanguage();
			BindConfig(_lastDetectedChineseLanguage);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[Blast Buddy] Loaded. Hosts drive room-wide syncing, guests fall back to local behavior, and both paths now share one unified trigger cooldown.");
			ResetState();
		}

		private void Update()
		{
			HandleLanguageChangeIfNeeded();
			if (!IsModEnabled())
			{
				ResetState();
				return;
			}
			if ((Object)(object)GameHandler.Instance == (Object)null || !GameHandler.IsInGameplayScene)
			{
				ResetState();
				return;
			}
			if (!IsGameplayActivationReady())
			{
				_nearbyActivePlayers.Clear();
				_scanBuffer.Clear();
				return;
			}
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				HandleHostAuthoritativeRoom();
				return;
			}
			if (!TryGetLocalCharacter(out Character character))
			{
				_nearbyActivePlayers.Clear();
				_scanBuffer.Clear();
				return;
			}
			if (!IsCompatibleMultiplayerSession())
			{
				_nearbyActivePlayers.Clear();
				_scanBuffer.Clear();
				return;
			}
			if (IsSafetySuppressed(character))
			{
				if (!_loggedSafetySuppression)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("[Blast Buddy] Paused because a safety condition is active: " + (_lastSafetyReason ?? "unknown") + "."));
					_loggedSafetySuppression = true;
				}
				_nearbyActivePlayers.Clear();
				_scanBuffer.Clear();
				return;
			}
			_loggedSafetySuppression = false;
			if (Time.time < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.time + GetScanIntervalSeconds();
			if (ScanNearbyPlayers(character))
			{
				if (!_loggedRescueSuppression)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Blast Buddy] Paused because a downed teammate is nearby.");
					_loggedRescueSuppression = true;
				}
				_nearbyActivePlayers.Clear();
				return;
			}
			_loggedRescueSuppression = false;
			Character val = null;
			bool flag = false;
			foreach (Character item in _scanBuffer)
			{
				int characterIdentity = GetCharacterIdentity(item);
				if (_nearbyActivePlayers.Add(characterIdentity))
				{
					flag = true;
					if (val == null)
					{
						val = item;
					}
				}
			}
			SyncTrackedActorIds(_nearbyActivePlayers, _scanBuffer);
			if (flag && !((Object)(object)val == (Object)null) && !(Time.time < _nextAllowedTriggerAt))
			{
				if (!ShouldTriggerForThisEntry())
				{
					_nextAllowedTriggerAt = Time.time + GetTriggerCooldownSeconds();
				}
				else if (TryTriggerEffect(character, val))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Blast Buddy] Local blast triggered.");
					_nextAllowedTriggerAt = Time.time + GetTriggerCooldownSeconds();
				}
			}
		}

		private void HandleHostAuthoritativeRoom()
		{
			if (Time.time < _nextScanAt)
			{
				return;
			}
			_nextScanAt = Time.time + GetScanIntervalSeconds();
			_roomCharacterBuffer.Clear();
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			if (allPlayerCharacters == null || allPlayerCharacters.Count <= 1)
			{
				_hostNearbyPlayersBySource.Clear();
				return;
			}
			foreach (Character item in allPlayerCharacters)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.data == (Object)null) && ((Component)item).gameObject.activeInHierarchy)
				{
					_roomCharacterBuffer.Add(item);
				}
			}
			if (IsRescueSuppressionEnabled() && HasNearbyDownedPair(_roomCharacterBuffer))
			{
				if (!_loggedRescueSuppression)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Blast Buddy] Host scan paused because a downed teammate is nearby.");
					_loggedRescueSuppression = true;
				}
				_hostNearbyPlayersBySource.Clear();
				return;
			}
			_loggedRescueSuppression = false;
			Character val = null;
			foreach (Character item2 in _roomCharacterBuffer)
			{
				if (IsSafetySuppressedForCharacter(item2))
				{
					_hostNearbyPlayersBySource.Remove(GetCharacterIdentity(item2));
					continue;
				}
				bool num = ScanNearbyPlayersForSource(item2, _roomCharacterBuffer);
				int characterIdentity = GetCharacterIdentity(item2);
				if (num)
				{
					_hostNearbyPlayersBySource.Remove(characterIdentity);
					continue;
				}
				if (!_hostNearbyPlayersBySource.TryGetValue(characterIdentity, out HashSet<int> value))
				{
					value = new HashSet<int>();
					_hostNearbyPlayersBySource[characterIdentity] = value;
				}
				bool flag = false;
				foreach (Character item3 in _scanBuffer)
				{
					int characterIdentity2 = GetCharacterIdentity(item3);
					if (value.Add(characterIdentity2))
					{
						flag = true;
					}
				}
				SyncTrackedActorIds(value, _scanBuffer);
				if (flag && (Object)(object)val == (Object)null)
				{
					val = item2;
				}
			}
			if (!((Object)(object)val == (Object)null) && !(Time.time < _nextAllowedTriggerAt))
			{
				if (!ShouldTriggerForThisEntry())
				{
					_nextAllowedTriggerAt = Time.time + GetTriggerCooldownSeconds();
				}
				else if (TryTriggerBlast(val, _roomCharacterBuffer))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}] Host blast triggered for actor {1}.", "Blast Buddy", GetCharacterIdentity(val)));
					_nextAllowedTriggerAt = Time.time + GetTriggerCooldownSeconds();
				}
			}
		}

		private bool ScanNearbyPlayers(Character localCharacter)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			_scanBuffer.Clear();
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			if (allPlayerCharacters == null || allPlayerCharacters.Count <= 1)
			{
				return false;
			}
			Vector3 center = localCharacter.Center;
			foreach (Character item in allPlayerCharacters)
			{
				if (!IsRelevantOtherCharacter(localCharacter, item))
				{
					continue;
				}
				int characterIdentity = GetCharacterIdentity(item);
				float num = (_nearbyActivePlayers.Contains(characterIdentity) ? GetExitRadius() : GetTriggerRadius());
				Vector3 val = item.Center - center;
				if (!(((Vector3)(ref val)).sqrMagnitude > num * num))
				{
					if (IsRescueSuppressionEnabled() && IsDowned(item))
					{
						return true;
					}
					_scanBuffer.Add(item);
				}
			}
			return false;
		}

		private bool ScanNearbyPlayersForSource(Character sourceCharacter, List<Character> characters)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//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)
			_scanBuffer.Clear();
			int characterIdentity = GetCharacterIdentity(sourceCharacter);
			_hostNearbyPlayersBySource.TryGetValue(characterIdentity, out HashSet<int> value);
			Vector3 center = sourceCharacter.Center;
			foreach (Character character in characters)
			{
				if (!IsRelevantOtherCharacter(sourceCharacter, character))
				{
					continue;
				}
				int characterIdentity2 = GetCharacterIdentity(character);
				float num = ((value != null && value.Contains(characterIdentity2)) ? GetExitRadius() : GetTriggerRadius());
				Vector3 val = character.Center - center;
				if (!(((Vector3)(ref val)).sqrMagnitude > num * num))
				{
					if (IsRescueSuppressionEnabled() && IsDowned(character))
					{
						return true;
					}
					_scanBuffer.Add(character);
				}
			}
			return false;
		}

		private bool HasNearbyDownedPair(List<Character> characters)
		{
			//IL_0039: 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_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)
			float exitRadiusSquared = GetExitRadiusSquared();
			for (int i = 0; i < characters.Count; i++)
			{
				Character val = characters[i];
				for (int j = 0; j < characters.Count; j++)
				{
					if (i == j)
					{
						continue;
					}
					Character val2 = characters[j];
					if (IsRelevantOtherCharacter(val, val2) && IsDowned(val2))
					{
						Vector3 val3 = val2.Center - val.Center;
						if (((Vector3)(ref val3)).sqrMagnitude <= exitRadiusSquared)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private void SyncTrackedActorIds(HashSet<int> trackedActorIds, List<Character> characters)
		{
			_actorIdBuffer.Clear();
			foreach (Character character in characters)
			{
				_actorIdBuffer.Add(GetCharacterIdentity(character));
			}
			trackedActorIds.IntersectWith(_actorIdBuffer);
		}

		private static bool TryGetLocalCharacter(out Character? character)
		{
			character = null;
			if ((Object)(object)Player.localPlayer == (Object)null)
			{
				return false;
			}
			character = Player.localPlayer.character;
			if ((Object)(object)character == (Object)null || !character.IsLocal || !((Component)character).gameObject.activeInHierarchy)
			{
				character = null;
				return false;
			}
			return true;
		}

		private bool IsGameplayActivationReady()
		{
			if (!GameHandler.IsInGameplayScene)
			{
				_gameplayEnteredAt = -1f;
				_loggedActivationDelay = false;
				return false;
			}
			if (_gameplayEnteredAt < 0f)
			{
				_gameplayEnteredAt = Time.time;
			}
			if (Time.time - _gameplayEnteredAt >= GetActivationDelaySeconds())
			{
				_loggedActivationDelay = false;
				return true;
			}
			if (!_loggedActivationDelay)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}] Waiting {1:0} seconds after gameplay starts before enabling effects.", "Blast Buddy", GetActivationDelaySeconds()));
				_loggedActivationDelay = true;
			}
			return false;
		}

		private bool ShouldSuppressForSafety(Character character, out string? reason)
		{
			if (IsRescueSuppressionEnabled() && IsCharacterReviving(character))
			{
				reason = (DetectChineseLanguage() ? "正在救人" : "reviving");
				return true;
			}
			if (IsNarrowSpaceSuppressionEnabled() && IsInNarrowSpace(character))
			{
				reason = (DetectChineseLanguage() ? "狭窄地形" : "narrow space");
				return true;
			}
			reason = null;
			return false;
		}

		private bool IsSafetySuppressed(Character localCharacter)
		{
			if (Time.time >= _nextSafetyCheckAt)
			{
				_nextSafetyCheckAt = Time.time + GetSafetyCheckIntervalSeconds();
				_cachedSafetySuppressed = ShouldSuppressForSafety(localCharacter, out _lastSafetyReason);
			}
			return _cachedSafetySuppressed;
		}

		private bool IsSafetySuppressedForCharacter(Character character)
		{
			string reason;
			return ShouldSuppressForSafety(character, out reason);
		}

		private static bool IsCompatibleMultiplayerSession()
		{
			if (PhotonNetwork.InRoom)
			{
				return true;
			}
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			if (allPlayerCharacters != null)
			{
				return allPlayerCharacters.Count > 1;
			}
			return false;
		}

		private static bool IsCharacterReviving(Character character)
		{
			if (HasTruthyMember(character, "revive", "reviving", "isreviving"))
			{
				return true;
			}
			PhotonView component = ((Component)character).GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null && component.IsMine)
			{
				return HasTruthyMember(Player.localPlayer, "revive", "reviving", "isreviving");
			}
			return false;
		}

		private bool IsInNarrowSpace(Character character)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(character.Center, GetNarrowSpaceCheckRadius(), _narrowSpaceBuffer, -1, (QueryTriggerInteraction)1);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				Collider val = _narrowSpaceBuffer[i];
				if (!((Object)(object)val == (Object)null))
				{
					Rigidbody attachedRigidbody = val.attachedRigidbody;
					if (!((Object)(object)attachedRigidbody != (Object)null) || !((Component)attachedRigidbody).transform.IsChildOf(((Component)character).transform))
					{
						num2++;
					}
				}
			}
			Array.Clear(_narrowSpaceBuffer, 0, _narrowSpaceBuffer.Length);
			return num2 >= GetNarrowSpaceColliderThreshold();
		}

		private static bool IsRelevantOtherCharacter(Character sourceCharacter, Character otherCharacter)
		{
			if ((Object)(object)otherCharacter != (Object)null && (Object)(object)otherCharacter != (Object)(object)sourceCharacter && (Object)(object)otherCharacter.data != (Object)null && !otherCharacter.data.dead)
			{
				return ((Component)otherCharacter).gameObject.activeInHierarchy;
			}
			return false;
		}

		private static bool IsDowned(Character character)
		{
			if (!character.data.dead && !character.data.passedOut)
			{
				return character.data.fullyPassedOut;
			}
			return true;
		}

		private static int GetCharacterIdentity(Character character)
		{
			PhotonView component = ((Component)character).GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null && component.OwnerActorNr > 0)
			{
				return component.OwnerActorNr;
			}
			return ((Object)character).GetInstanceID();
		}

		private static bool HasTruthyMember(object? target, params string[] tokens)
		{
			if (target == null)
			{
				return false;
			}
			Type type = target.GetType();
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			PropertyInfo[] properties = type.GetProperties(bindingAttr);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (!NameMatches(propertyInfo.Name, tokens) || propertyInfo.GetIndexParameters().Length != 0)
				{
					continue;
				}
				try
				{
					if (IsTruthy(propertyInfo.GetValue(target)))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			FieldInfo[] fields = type.GetFields(bindingAttr);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (!NameMatches(fieldInfo.Name, tokens))
				{
					continue;
				}
				try
				{
					if (IsTruthy(fieldInfo.GetValue(target)))
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static bool NameMatches(string name, string[] tokens)
		{
			string text = name.Replace("_", string.Empty).ToLowerInvariant();
			foreach (string value in tokens)
			{
				if (text.Contains(value))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsTruthy(object? value)
		{
			if (value != null)
			{
				if (!(value is bool result))
				{
					if (!(value is int num))
					{
						if (!(value is long num2))
						{
							if (!(value is float value2))
							{
								if (value is double value3)
								{
									return Math.Abs(value3) > 0.001;
								}
								return false;
							}
							return Math.Abs(value2) > 0.001f;
						}
						return num2 != 0;
					}
					return num != 0;
				}
				return result;
			}
			return false;
		}

		private static bool ShouldTriggerForThisEntry()
		{
			return Random.value <= GetTriggerChance();
		}

		private static float GetTriggerChance()
		{
			return GetConfiguredChance(GetPluginInstance()._triggerChanceConfig, 1f);
		}

		private static float GetTriggerCooldownSeconds()
		{
			return GetConfiguredPositiveFloat(GetPluginInstance()._triggerCooldownSecondsConfig, 1.4f);
		}

		private bool TryTriggerEffect(Character localCharacter, Character triggerCharacter)
		{
			try
			{
				return (PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient) ? TryTriggerBlast(triggerCharacter, _roomCharacterBuffer) : ApplyOriginalFartBlast(localCharacter, _scanBuffer);
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] Failed to trigger the fart effect: {1}", "Blast Buddy", arg));
				return false;
			}
		}

		private bool TryTriggerBlast(Character sourceCharacter, List<Character> characters)
		{
			return ApplyOriginalFartBlast(sourceCharacter, characters);
		}

		private bool ApplyOriginalFartBlast(Character sourceCharacter, IEnumerable<Character> potentialTargets)
		{
			//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_001e: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			Vector3 center = sourceCharacter.Center;
			if ((Object)(object)GameUtils.instance != (Object)null)
			{
				GameUtils.instance.SpawnResourceAtPositionNetworked("VFX_SporeExploExploEdibleSpawn", center, (RpcTarget)5);
				GameUtils.instance.RPC_SpawnResourceAtPosition("VFX_SporeExploExploEdibleSpawn_NoKnockback", center);
			}
			bool result = false;
			foreach (Character potentialTarget in potentialTargets)
			{
				if (IsValidBlastTarget(sourceCharacter, potentialTarget, center))
				{
					PhotonView val = potentialTarget.refs?.view ?? ((Component)potentialTarget).GetComponent<PhotonView>();
					if (!((Object)(object)val == (Object)null))
					{
						val.RPC("RPCA_AddForceToBodyPart", (RpcTarget)5, new object[3]
						{
							(object)(BodypartType)0,
							Vector3.zero,
							Vector3.up * GetFartForce()
						});
						result = true;
					}
				}
			}
			return result;
		}

		private bool IsValidBlastTarget(Character sourceCharacter, Character targetCharacter, Vector3 blastCenter)
		{
			//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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)targetCharacter == (Object)null || (Object)(object)targetCharacter == (Object)(object)sourceCharacter || (Object)(object)targetCharacter.data == (Object)null || !((Component)targetCharacter).gameObject.activeInHierarchy || IsDowned(targetCharacter))
			{
				return false;
			}
			Vector3 val = targetCharacter.Center - blastCenter;
			return ((Vector3)(ref val)).sqrMagnitude <= GetBlastRadiusSquared();
		}

		private void ResetState()
		{
			_nearbyActivePlayers.Clear();
			_hostNearbyPlayersBySource.Clear();
			_scanBuffer.Clear();
			_roomCharacterBuffer.Clear();
			_nextAllowedTriggerAt = Time.time;
			_nextScanAt = Time.time;
			_nextSafetyCheckAt = Time.time;
			_gameplayEnteredAt = -1f;
			_cachedSafetySuppressed = false;
			_loggedActivationDelay = false;
			_loggedSafetySuppression = false;
			_loggedRescueSuppression = false;
			_lastSafetyReason = null;
		}

		private void BindConfig(bool isChineseLanguage)
		{
			string sectionName = GetSectionName(isChineseLanguage);
			_modEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>(sectionName, GetKeyName(ConfigKey.ModEnabled, isChineseLanguage), true, CreateConfigDescription(ConfigKey.ModEnabled, isChineseLanguage));
			_activationDelaySecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.ActivationDelaySeconds, isChineseLanguage), 30f, CreateConfigDescription(ConfigKey.ActivationDelaySeconds, isChineseLanguage));
			_triggerRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.TriggerRadius, isChineseLanguage), 2.2f, CreateConfigDescription(ConfigKey.TriggerRadius, isChineseLanguage));
			_exitRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.ExitRadius, isChineseLanguage), 3.8f, CreateConfigDescription(ConfigKey.ExitRadius, isChineseLanguage));
			_blastRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.BlastRadius, isChineseLanguage), 3.4f, CreateConfigDescription(ConfigKey.BlastRadius, isChineseLanguage));
			_triggerCooldownSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.TriggerCooldownSeconds, isChineseLanguage), 1.4f, CreateConfigDescription(ConfigKey.TriggerCooldownSeconds, isChineseLanguage));
			_scanIntervalSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.ScanIntervalSeconds, isChineseLanguage), 0.18f, CreateConfigDescription(ConfigKey.ScanIntervalSeconds, isChineseLanguage));
			_safetyCheckIntervalSecondsConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.SafetyCheckIntervalSeconds, isChineseLanguage), 0.25f, CreateConfigDescription(ConfigKey.SafetyCheckIntervalSeconds, isChineseLanguage));
			_fartForceConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.FartForce, isChineseLanguage), 320f, CreateConfigDescription(ConfigKey.FartForce, isChineseLanguage));
			_triggerChanceConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.TriggerChance, isChineseLanguage), 1f, CreateConfigDescription(ConfigKey.TriggerChance, isChineseLanguage));
			_narrowSpaceCheckRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>(sectionName, GetKeyName(ConfigKey.NarrowSpaceCheckRadius, isChineseLanguage), 1.1f, CreateConfigDescription(ConfigKey.NarrowSpaceCheckRadius, isChineseLanguage));
			_narrowSpaceColliderThresholdConfig = ((BaseUnityPlugin)this).Config.Bind<int>(sectionName, GetKeyName(ConfigKey.NarrowSpaceColliderThreshold, isChineseLanguage), 16, CreateConfigDescription(ConfigKey.NarrowSpaceColliderThreshold, isChineseLanguage));
			_enableRescueSuppressionConfig = ((BaseUnityPlugin)this).Config.Bind<bool>(sectionName, GetKeyName(ConfigKey.EnableRescueSuppression, isChineseLanguage), true, CreateConfigDescription(ConfigKey.EnableRescueSuppression, isChineseLanguage));
			_enableNarrowSpaceSuppressionConfig = ((BaseUnityPlugin)this).Config.Bind<bool>(sectionName, GetKeyName(ConfigKey.EnableNarrowSpaceSuppression, isChineseLanguage), true, CreateConfigDescription(ConfigKey.EnableNarrowSpaceSuppression, isChineseLanguage));
			MigrateLocalizedConfigEntries();
			ClampConfigValues();
		}

		private ConfigDescription CreateConfigDescription(ConfigKey configKey, bool isChineseLanguage)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Expected O, but got Unknown
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			return (ConfigDescription)(configKey switch
			{
				ConfigKey.ActivationDelaySeconds => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 180f), Array.Empty<object>()), 
				ConfigKey.TriggerRadius => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 6f), Array.Empty<object>()), 
				ConfigKey.ExitRadius => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>()), 
				ConfigKey.BlastRadius => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), Array.Empty<object>()), 
				ConfigKey.TriggerCooldownSeconds => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 10f), Array.Empty<object>()), 
				ConfigKey.ScanIntervalSeconds => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()), 
				ConfigKey.SafetyCheckIntervalSeconds => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()), 
				ConfigKey.FartForce => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 1200f), Array.Empty<object>()), 
				ConfigKey.TriggerChance => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()), 
				ConfigKey.NarrowSpaceCheckRadius => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 3f), Array.Empty<object>()), 
				ConfigKey.NarrowSpaceColliderThreshold => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 32), Array.Empty<object>()), 
				_ => (object)new ConfigDescription(GetLocalizedDescription(configKey, isChineseLanguage), (AcceptableValueBase)null, Array.Empty<object>()), 
			});
		}

		private void MigrateLocalizedConfigEntries()
		{
			IDictionary orphanedEntries = GetOrphanedEntries(((BaseUnityPlugin)this).Config);
			if (orphanedEntries == null || orphanedEntries.Count == 0)
			{
				return;
			}
			bool flag = false;
			ConfigEntryBase[] configEntriesSnapshot = GetConfigEntriesSnapshot(((BaseUnityPlugin)this).Config);
			foreach (ConfigEntryBase val in configEntriesSnapshot)
			{
				if (!(((val != null) ? val.Definition : null) == (ConfigDefinition)null) && TryGetConfigKey(val.Definition.Key, out var configKey))
				{
					flag |= TryMigrateConfigValue(val, configKey, orphanedEntries);
				}
			}
			if (flag)
			{
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		private static bool TryMigrateConfigValue(ConfigEntryBase entry, ConfigKey configKey, IDictionary orphanedEntries)
		{
			foreach (ConfigDefinition aliasDefinition in GetAliasDefinitions(configKey))
			{
				if (!DefinitionsEqual(aliasDefinition, entry.Definition) && orphanedEntries.Contains(aliasDefinition))
				{
					object obj = orphanedEntries[aliasDefinition];
					if (obj != null)
					{
						entry.SetSerializedValue(obj.ToString());
					}
					orphanedEntries.Remove(aliasDefinition);
					return true;
				}
			}
			return false;
		}

		[IteratorStateMachine(typeof(<GetAliasDefinitions>d__86))]
		private static IEnumerable<ConfigDefinition> GetAliasDefinitions(ConfigKey configKey)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetAliasDefinitions>d__86(-2)
			{
				<>3__configKey = configKey
			};
		}

		private static bool TryGetLegacyDefinition(ConfigKey configKey, out ConfigDefinition definition)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			switch (configKey)
			{
			case ConfigKey.ActivationDelaySeconds:
				definition = new ConfigDefinition("Timing", "ActivationDelaySeconds");
				return true;
			case ConfigKey.TriggerRadius:
				definition = new ConfigDefinition("Range", "TriggerRadius");
				return true;
			case ConfigKey.ExitRadius:
				definition = new ConfigDefinition("Range", "ExitRadius");
				return true;
			case ConfigKey.BlastRadius:
				definition = new ConfigDefinition("Range", "BlastRadius");
				return true;
			case ConfigKey.TriggerCooldownSeconds:
				definition = new ConfigDefinition("Timing", "TriggerCooldownSeconds");
				return true;
			case ConfigKey.FartForce:
				definition = new ConfigDefinition("Effects", "FartForce");
				return true;
			case ConfigKey.ScanIntervalSeconds:
				definition = new ConfigDefinition("Timing", "ScanIntervalSeconds");
				return true;
			case ConfigKey.SafetyCheckIntervalSeconds:
				definition = new ConfigDefinition("Timing", "SafetyCheckIntervalSeconds");
				return true;
			case ConfigKey.TriggerChance:
				definition = new ConfigDefinition("Chance", "TriggerChance");
				return true;
			case ConfigKey.NarrowSpaceCheckRadius:
				definition = new ConfigDefinition("Safety", "NarrowSpaceCheckRadius");
				return true;
			case ConfigKey.NarrowSpaceColliderThreshold:
				definition = new ConfigDefinition("Safety", "NarrowSpaceColliderThreshold");
				return true;
			case ConfigKey.EnableRescueSuppression:
				definition = new ConfigDefinition("Safety", "EnableRescueSuppression");
				return true;
			case ConfigKey.EnableNarrowSpaceSuppression:
				definition = new ConfigDefinition("Safety", "EnableNarrowSpaceSuppression");
				return true;
			default:
				definition = new ConfigDefinition(string.Empty, string.Empty);
				return false;
			}
		}

		private static IDictionary? GetOrphanedEntries(ConfigFile configFile)
		{
			return ((object)configFile)?.GetType().GetProperty("OrphanedEntries", InstanceBindingFlags)?.GetValue(configFile) as IDictionary;
		}

		private static ConfigEntryBase[] GetConfigEntriesSnapshot(ConfigFile configFile)
		{
			if (!(ConfigFileEntriesProperty?.GetValue(configFile) is IDictionary dictionary) || dictionary.Count == 0)
			{
				return Array.Empty<ConfigEntryBase>();
			}
			ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[dictionary.Count];
			dictionary.Values.CopyTo(array, 0);
			return array;
		}

		private static bool DefinitionsEqual(ConfigDefinition left, ConfigDefinition right)
		{
			if (string.Equals(left.Section, right.Section, StringComparison.Ordinal))
			{
				return string.Equals(left.Key, right.Key, StringComparison.Ordinal);
			}
			return false;
		}

		private void HandleLanguageChangeIfNeeded()
		{
			bool flag = DetectChineseLanguage();
			if (flag != _lastDetectedChineseLanguage)
			{
				_lastDetectedChineseLanguage = flag;
				ApplyLocalizedConfigMetadata(flag);
			}
			TryLocalizeVisibleModConfigUi();
		}

		private void ApplyLocalizedConfigMetadata(bool isChineseLanguage)
		{
			ConfigEntryBase[] configEntriesSnapshot = GetConfigEntriesSnapshot(((BaseUnityPlugin)this).Config);
			foreach (ConfigEntryBase val in configEntriesSnapshot)
			{
				if (!(((val != null) ? val.Definition : null) == (ConfigDefinition)null) && val.Description != null && TryGetConfigKey(val.Definition.Key, out var configKey))
				{
					((object)val.Description).GetType().GetField("<Description>k__BackingField", InstanceBindingFlags)?.SetValue(val.Description, GetLocalizedDescription(configKey, isChineseLanguage));
				}
			}
		}

		private static bool TryGetConfigKey(string keyName, out ConfigKey configKey)
		{
			foreach (ConfigKey value in Enum.GetValues(typeof(ConfigKey)))
			{
				if (string.Equals(keyName, GetKeyName(value, isChineseLanguage: false), StringComparison.OrdinalIgnoreCase) || string.Equals(keyName, GetKeyName(value, isChineseLanguage: true), StringComparison.OrdinalIgnoreCase))
				{
					configKey = value;
					return true;
				}
			}
			configKey = ConfigKey.ModEnabled;
			return false;
		}

		private void TryLocalizeVisibleModConfigUi()
		{
			if (!TryGetModConfigMenuInstance(out Type menuType, out object menuInstance))
			{
				return;
			}
			Behaviour val = (Behaviour)((menuInstance is Behaviour) ? menuInstance : null);
			if (val == null || !val.isActiveAndEnabled || !((Component)val).gameObject.activeInHierarchy)
			{
				return;
			}
			Dictionary<string, string> dictionary = BuildModConfigUiLocalizationMap(DetectChineseLanguage());
			foreach (Transform item in EnumerateModConfigUiRoots(menuInstance, menuType))
			{
				TMP_Text[] componentsInChildren = ((Component)item).GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text val2 in componentsInChildren)
				{
					string text = val2.text?.Trim() ?? string.Empty;
					if (!string.IsNullOrWhiteSpace(text) && dictionary.TryGetValue(text, out var value) && !string.Equals(val2.text, value, StringComparison.Ordinal))
					{
						val2.text = value;
					}
				}
			}
		}

		private static bool TryGetModConfigMenuInstance(out Type? menuType, out object? menuInstance)
		{
			menuType = null;
			menuInstance = null;
			if (!Chainloader.PluginInfos.TryGetValue("com.github.PEAKModding.PEAKLib.ModConfig", out var value) || (Object)(object)((value != null) ? value.Instance : null) == (Object)null)
			{
				return false;
			}
			Assembly assembly = ((object)value.Instance).GetType().Assembly;
			menuType = assembly.GetType("PEAKLib.ModConfig.Components.ModdedSettingsMenu");
			menuInstance = menuType?.GetProperty("Instance", StaticBindingFlags)?.GetValue(null);
			if (menuType != null)
			{
				return menuInstance != null;
			}
			return false;
		}

		[IteratorStateMachine(typeof(<EnumerateModConfigUiRoots>d__96))]
		private IEnumerable<Transform> EnumerateModConfigUiRoots(object menuInstance, Type menuType)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <EnumerateModConfigUiRoots>d__96(-2)
			{
				<>3__menuInstance = menuInstance,
				<>3__menuType = menuType
			};
		}

		[IteratorStateMachine(typeof(<EnumerateCandidateTransforms>d__97))]
		private static IEnumerable<Transform> EnumerateCandidateTransforms(object menuInstance, Type menuType)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <EnumerateCandidateTransforms>d__97(-2)
			{
				<>3__menuInstance = menuInstance,
				<>3__menuType = menuType
			};
		}

		private Dictionary<string, string> BuildModConfigUiLocalizationMap(bool isChineseLanguage)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			AddUiLocalizationPair(dictionary, "Blast Buddy", GetLocalizedModDisplayName(isChineseLanguage));
			AddUiLocalizationPair(dictionary, GetLocalizedModDisplayName(!isChineseLanguage), GetLocalizedModDisplayName(isChineseLanguage));
			AddUiLocalizationPair(dictionary, GetSectionName(isChineseLanguage: false), GetSectionName(isChineseLanguage));
			AddUiLocalizationPair(dictionary, GetSectionName(isChineseLanguage: true), GetSectionName(isChineseLanguage));
			foreach (ConfigKey value in Enum.GetValues(typeof(ConfigKey)))
			{
				AddUiLocalizationPair(dictionary, GetKeyName(value, isChineseLanguage: false), GetKeyName(value, isChineseLanguage));
				AddUiLocalizationPair(dictionary, GetKeyName(value, isChineseLanguage: true), GetKeyName(value, isChineseLanguage));
				AddUiLocalizationPair(dictionary, GetLocalizedDescription(value, isChineseLanguage: false), GetLocalizedDescription(value, isChineseLanguage));
				AddUiLocalizationPair(dictionary, GetLocalizedDescription(value, isChineseLanguage: true), GetLocalizedDescription(value, isChineseLanguage));
			}
			return dictionary;
		}

		private static void AddUiLocalizationPair(Dictionary<string, string> map, string source, string localized)
		{
			if (!string.IsNullOrWhiteSpace(source) && !string.IsNullOrWhiteSpace(localized))
			{
				string key = source.Trim();
				string text2 = (map[key] = localized.Trim());
				map[text2] = text2;
			}
		}

		private static bool DetectChineseLanguage()
		{
			if (TryGetConfiguredGameLanguage(out var isChineseLanguage))
			{
				return isChineseLanguage;
			}
			if (TryGetLocalizedTextLanguageName(out string languageName))
			{
				return IsChineseLanguageName(languageName);
			}
			return false;
		}

		private static bool TryGetConfiguredGameLanguage(out bool isChineseLanguage)
		{
			isChineseLanguage = false;
			try
			{
				if (!PlayerPrefs.HasKey("LanguageSetting"))
				{
					return false;
				}
				int result = PlayerPrefs.GetInt("LanguageSetting", int.MinValue);
				if (result != int.MinValue)
				{
					isChineseLanguage = result == 9;
					return true;
				}
				string @string = PlayerPrefs.GetString("LanguageSetting", string.Empty);
				if (string.IsNullOrWhiteSpace(@string))
				{
					return false;
				}
				if (int.TryParse(@string, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
				{
					isChineseLanguage = result == 9;
					return true;
				}
				isChineseLanguage = IsChineseLanguageName(@string);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryGetLocalizedTextLanguageName(out string languageName)
		{
			languageName = string.Empty;
			try
			{
				languageName = ((object)(Language)(ref LocalizedText.CURRENT_LANGUAGE)).ToString();
				return !string.IsNullOrWhiteSpace(languageName);
			}
			catch
			{
				return false;
			}
		}

		private static bool IsChineseLanguageName(string languageName)
		{
			if (string.IsNullOrWhiteSpace(languageName))
			{
				return false;
			}
			if (languageName.IndexOf("Chinese", StringComparison.OrdinalIgnoreCase) < 0 && languageName.IndexOf("中文", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return languageName.StartsWith("zh", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		private static string GetSectionName(bool isChineseLanguage)
		{
			if (!isChineseLanguage)
			{
				return "Blast Buddy";
			}
			return "屁友冲击波";
		}

		private static string GetLocalizedModDisplayName(bool isChineseLanguage)
		{
			if (!isChineseLanguage)
			{
				return "Blast Buddy";
			}
			return "屁友冲击波";
		}

		private static string GetKeyName(ConfigKey configKey, bool isChineseLanguage)
		{
			return configKey switch
			{
				ConfigKey.ModEnabled => isChineseLanguage ? "模组总开关" : "Enable Mod", 
				ConfigKey.ActivationDelaySeconds => isChineseLanguage ? "生效延迟(秒)" : "Activation Delay (Seconds)", 
				ConfigKey.TriggerRadius => isChineseLanguage ? "进入判定距离(米)" : "Enter Radius (Meters)", 
				ConfigKey.ExitRadius => isChineseLanguage ? "离开判定距离(米)" : "Exit Radius (Meters)", 
				ConfigKey.BlastRadius => isChineseLanguage ? "爆炸影响半径(米)" : "Blast Radius (Meters)", 
				ConfigKey.TriggerCooldownSeconds => isChineseLanguage ? "触发冷却(秒)" : "Trigger Cooldown (Seconds)", 
				ConfigKey.ScanIntervalSeconds => isChineseLanguage ? "距离扫描间隔(秒)" : "Proximity Scan Interval (Seconds)", 
				ConfigKey.SafetyCheckIntervalSeconds => isChineseLanguage ? "安全检查间隔(秒)" : "Safety Check Interval (Seconds)", 
				ConfigKey.FartForce => isChineseLanguage ? "放屁冲击力" : "Fart Force", 
				ConfigKey.TriggerChance => isChineseLanguage ? "触发概率" : "Trigger Chance", 
				ConfigKey.NarrowSpaceCheckRadius => isChineseLanguage ? "狭窄地形检测半径(米)" : "Narrow Space Check Radius (Meters)", 
				ConfigKey.NarrowSpaceColliderThreshold => isChineseLanguage ? "狭窄地形判定碰撞体数量" : "Narrow Space Collider Threshold", 
				ConfigKey.EnableRescueSuppression => isChineseLanguage ? "救人相关保护" : "Rescue Safety Protection", 
				ConfigKey.EnableNarrowSpaceSuppression => isChineseLanguage ? "狭窄地形保护" : "Narrow Space Protection", 
				_ => string.Empty, 
			};
		}

		private static string GetLocalizedDescription(ConfigKey configKey, bool isChineseLanguage)
		{
			return configKey switch
			{
				ConfigKey.ModEnabled => isChineseLanguage ? "总开关。关闭后模组完全停止工作,不再扫描距离,也不会触发放屁效果。适合排查问题或临时停用。" : "Master switch for the mod. When disabled, the system stops scanning and stops triggering the fart effect.", 
				ConfigKey.ActivationDelaySeconds => isChineseLanguage ? "进入正式游戏后等待多久才开始生效。大厅和载入阶段不会触发;默认 30 秒,避免开局立刻干扰队友。" : "How long to wait after gameplay begins before the effect can activate. The lobby and loading screens never trigger it. Default: 30 seconds.", 
				ConfigKey.TriggerRadius => isChineseLanguage ? "进入判定距离。队友首次靠近到该距离内,才算真正进入触发范围。默认 2.2 米,减少过远误判。" : "Entry radius. A teammate must come within this distance before the mod counts them as entering the trigger zone. Default: 2.2 meters.", 
				ConfigKey.ExitRadius => isChineseLanguage ? "离开判定距离。已经进入后,必须离开到这个更大的距离外才会真正重置状态,用来减少边界反复抖动。默认 3.8 米。" : "Exit radius. Once someone has entered, they must move beyond this larger distance before the state resets. Default: 3.8 meters.", 
				ConfigKey.BlastRadius => isChineseLanguage ? "真正会受到原版 Fart 爆炸影响的队友范围。默认 3.4 米,体感仍然明显,但不会像大范围乱炸那样混乱。" : "The real teammate impact radius of the replicated vanilla Fart blast. Default: 3.4 meters for noticeable feedback without excessive room-wide chaos.", 
				ConfigKey.TriggerCooldownSeconds => isChineseLanguage ? "统一触发冷却。无论主机同步还是客机本地回退,都共用这一个冷却时间。默认 1.4 秒,专门为多人房降低连环爆炸频率。" : "Unified trigger cooldown shared by both host-driven syncing and client-side fallback. Default: 1.4 seconds to reduce chain blasts in busy rooms.", 
				ConfigKey.ScanIntervalSeconds => isChineseLanguage ? "距离扫描频率。默认 0.18 秒,仍然足够灵敏,但比更激进的扫描更适合多人房稳定体验。" : "How often proximity is scanned. Default: 0.18 seconds for good responsiveness without over-scanning crowded rooms.", 
				ConfigKey.SafetyCheckIntervalSeconds => isChineseLanguage ? "安全条件检查频率。默认 0.25 秒,用于救人和狭窄地形保护。" : "How often safety conditions are checked. Default: 0.25 seconds for revive and cramped-terrain protection.", 
				ConfigKey.FartForce => isChineseLanguage ? "原版 Fart 炸飞力度。只作用于附近队友,不影响放屁者自己。默认 320,仍然明显,但比更高数值更不容易把多人房炸成失控状态。" : "Launch force used by the vanilla-style Fart blast. It affects nearby teammates but not the source player. Default: 320 for a strong feel without turning every room into chaos.", 
				ConfigKey.TriggerChance => isChineseLanguage ? "统一触发概率,范围 0 到 1。无论主机同步还是客机本地回退,都使用这一套概率。1 表示 100% 触发。" : "Unified trigger chance from 0 to 1. Both host-driven syncing and client-side fallback use this same value. A value of 1 means 100%.", 
				ConfigKey.NarrowSpaceCheckRadius => isChineseLanguage ? "狭窄地形检测半径。默认 1.1 米,会统计该范围内碰撞体数量来判断当前位置是否过于拥挤。" : "Detection radius for cramped terrain checks. Default: 1.1 meters.", 
				ConfigKey.NarrowSpaceColliderThreshold => isChineseLanguage ? "狭窄地形判定阈值。默认 16;达到该数量时会临时停用效果,减少狭窄地形误炸。" : "Cramped-terrain threshold. Default: 16 colliders before the effect pauses.", 
				ConfigKey.EnableRescueSuppression => isChineseLanguage ? "启用后,附近有倒地玩家或你正在救人时,模组会临时停用,避免干扰救援。" : "When enabled, the mod pauses if a downed teammate is nearby or if you are reviving someone.", 
				ConfigKey.EnableNarrowSpaceSuppression => isChineseLanguage ? "启用后,在狭窄地形中临时停用放屁效果,减少把队友炸下去或卡进地形的问题。" : "When enabled, the mod pauses in cramped terrain to reduce accidental launches into hazards or geometry.", 
				_ => string.Empty, 
			};
		}

		private static void ClampConfigValues()
		{
			BlastBuddyPlugin pluginInstance = GetPluginInstance();
			if (pluginInstance._activationDelaySecondsConfig != null)
			{
				pluginInstance._activationDelaySecondsConfig.Value = Mathf.Clamp(pluginInstance._activationDelaySecondsConfig.Value, 0f, 180f);
			}
			if (pluginInstance._triggerRadiusConfig != null)
			{
				pluginInstance._triggerRadiusConfig.Value = Mathf.Clamp(pluginInstance._triggerRadiusConfig.Value, 1f, 6f);
			}
			if (pluginInstance._exitRadiusConfig != null)
			{
				pluginInstance._exitRadiusConfig.Value = Mathf.Clamp(pluginInstance._exitRadiusConfig.Value, 1f, 8f);
			}
			if (pluginInstance._blastRadiusConfig != null)
			{
				pluginInstance._blastRadiusConfig.Value = Mathf.Clamp(pluginInstance._blastRadiusConfig.Value, 1f, 8f);
			}
			if (pluginInstance._triggerCooldownSecondsConfig != null)
			{
				pluginInstance._triggerCooldownSecondsConfig.Value = Mathf.Clamp(pluginInstance._triggerCooldownSecondsConfig.Value, 0.05f, 10f);
			}
			if (pluginInstance._scanIntervalSecondsConfig != null)
			{
				pluginInstance._scanIntervalSecondsConfig.Value = Mathf.Clamp(pluginInstance._scanIntervalSecondsConfig.Value, 0.05f, 2f);
			}
			if (pluginInstance._safetyCheckIntervalSecondsConfig != null)
			{
				pluginInstance._safetyCheckIntervalSecondsConfig.Value = Mathf.Clamp(pluginInstance._safetyCheckIntervalSecondsConfig.Value, 0.05f, 2f);
			}
			if (pluginInstance._fartForceConfig != null)
			{
				pluginInstance._fartForceConfig.Value = Mathf.Clamp(pluginInstance._fartForceConfig.Value, 50f, 1200f);
			}
			if (pluginInstance._triggerChanceConfig != null)
			{
				pluginInstance._triggerChanceConfig.Value = Mathf.Clamp01(pluginInstance._triggerChanceConfig.Value);
			}
			if (pluginInstance._narrowSpaceCheckRadiusConfig != null)
			{
				pluginInstance._narrowSpaceCheckRadiusConfig.Value = Mathf.Clamp(pluginInstance._narrowSpaceCheckRadiusConfig.Value, 0.5f, 3f);
			}
			if (pluginInstance._narrowSpaceColliderThresholdConfig != null)
			{
				pluginInstance._narrowSpaceColliderThresholdConfig.Value = Mathf.Clamp(pluginInstance._narrowSpaceColliderThresholdConfig.Value, 1, 32);
			}
			if (pluginInstance._triggerRadiusConfig != null && pluginInstance._exitRadiusConfig != null)
			{
				pluginInstance._exitRadiusConfig.Value = Mathf.Max(pluginInstance._exitRadiusConfig.Value, pluginInstance._triggerRadiusConfig.Value);
			}
		}

		private bool IsModEnabled()
		{
			return _modEnabledConfig?.Value ?? true;
		}

		private bool IsRescueSuppressionEnabled()
		{
			return _enableRescueSuppressionConfig?.Value ?? true;
		}

		private bool IsNarrowSpaceSuppressionEnabled()
		{
			return _enableNarrowSpaceSuppressionConfig?.Value ?? true;
		}

		private float GetActivationDelaySeconds()
		{
			return GetConfiguredNonNegativeFloat(_activationDelaySecondsConfig, 30f);
		}

		private float GetTriggerRadius()
		{
			return GetConfiguredPositiveFloat(_triggerRadiusConfig, 2.2f);
		}

		private float GetExitRadius()
		{
			return Math.Max(GetTriggerRadius(), GetConfiguredPositiveFloat(_exitRadiusConfig, 3.8f));
		}

		private float GetBlastRadius()
		{
			return GetConfiguredPositiveFloat(_blastRadiusConfig, 3.4f);
		}

		private float GetBlastRadiusSquared()
		{
			float blastRadius = GetBlastRadius();
			return blastRadius * blastRadius;
		}

		private float GetExitRadiusSquared()
		{
			float exitRadius = GetExitRadius();
			return exitRadius * exitRadius;
		}

		private float GetTriggerCooldownSecondsValue()
		{
			return GetConfiguredPositiveFloat(_triggerCooldownSecondsConfig, 1.4f);
		}

		private float GetScanIntervalSeconds()
		{
			return GetConfiguredPositiveFloat(_scanIntervalSecondsConfig, 0.18f);
		}

		private float GetSafetyCheckIntervalSeconds()
		{
			return GetConfiguredPositiveFloat(_safetyCheckIntervalSecondsConfig, 0.25f);
		}

		private float GetFartForce()
		{
			return GetConfiguredPositiveFloat(_fartForceConfig, 320f);
		}

		private float GetNarrowSpaceCheckRadius()
		{
			return GetConfiguredPositiveFloat(_narrowSpaceCheckRadiusConfig, 1.1f);
		}

		private int GetNarrowSpaceColliderThreshold()
		{
			return Math.Max(1, _narrowSpaceColliderThresholdConfig?.Value ?? 16);
		}

		private static float GetConfiguredPositiveFloat(ConfigEntry<float>? entry, float fallback)
		{
			float num = entry?.Value ?? fallback;
			if (!(num > 0f))
			{
				return fallback;
			}
			return num;
		}

		private static float GetConfiguredNonNegativeFloat(ConfigEntry<float>? entry, float fallback)
		{
			float num = entry?.Value ?? fallback;
			if (!(num >= 0f))
			{
				return fallback;
			}
			return num;
		}

		private static float GetConfiguredChance(ConfigEntry<float>? entry, float fallback)
		{
			return Mathf.Clamp01(entry?.Value ?? fallback);
		}

		private static BlastBuddyPlugin GetPluginInstance()
		{
			return _instance ?? throw new InvalidOperationException("BlastBuddyPlugin instance is not available yet.");
		}
	}
}