Decompiled source of PEAK Farts v1.0.0

tony4twentys-PEAK Farts.dll

Decompiled 3 days 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.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PEAKLib.Core;
using Photon.Pun;
using Photon.Realtime;
using PhotonCustomPropsUtils;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("PEAK Farts")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PEAK Farts")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("fda85fb6-044f-439f-a49e-4a178be5269f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace PEAK_Farts
{
	[BepInPlugin("peakfarts.customizable", "PEAK Farts", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("PEAK.exe")]
	public class PEAKFartsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "peakfarts.customizable";

		public static PEAKFartsPlugin Instance;

		private Harmony harmony;

		private ConfigEntry<KeyCode> cfgVisualFartModifier;

		private ConfigEntry<KeyCode> cfgVisualFartKey;

		private ConfigEntry<bool> cfgVisualFartRequireModifier;

		private ConfigEntry<KeyCode> cfgFartBoostKey;

		internal ConfigEntry<float> cfgFartForceX;

		internal ConfigEntry<float> cfgFartForceY;

		internal ConfigEntry<bool> cfgEnableVFX;

		internal ConfigEntry<FartColorMode> cfgFartColorMode;

		internal ConfigEntry<string> cfgFartColor;

		internal ConfigEntry<bool> cfgPoisonFartsEnabled;

		internal ConfigEntry<float> cfgPoisonFartChance;

		internal ConfigEntry<float> cfgPoisonFartCheckInterval;

		internal ConfigEntry<bool> cfgFartBoostEnabled;

		internal ConfigEntry<float> cfgFartBoostCooldown;

		internal ConfigEntry<float> cfgFartBoostJumpWindow;

		private Character localCharacter;

		private bool wasVisualFartPressed;

		private bool wasFartBoostPressed;

		private float lastFartBoostTime = float.NegativeInfinity;

		private float lastPoisonFartCheckTime;

		public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			try
			{
				Instance = this;
				Logger.LogInfo((object)"PEAK Farts plugin loaded!");
				InitializeConfig();
				harmony = new Harmony("peakfarts.customizable");
				harmony.PatchAll();
				Logger.LogInfo((object)"Harmony patches applied!");
				GameObject val = new GameObject("PEAKFarts_NetworkSync");
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<FartNetworkSync>();
				FartModAuthorizationService.Initialize();
				((BaseUnityPlugin)this).Config.SettingChanged += OnConfigChanged;
				FartNetworkSync.BroadcastOwnPlayerColor();
				Logger.LogInfo((object)("Config file location: " + ((BaseUnityPlugin)this).Config.ConfigFilePath));
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to initialize PEAK Farts plugin: " + ex.Message));
				Logger.LogError((object)ex.StackTrace);
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.SettingChanged -= OnConfigChanged;
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private void OnConfigChanged(object sender, SettingChangedEventArgs e)
		{
			if (IsColorSetting(e))
			{
				FartNetworkSync.BroadcastOwnPlayerColor();
			}
			if (IsHostSyncedSetting(e))
			{
				FartModAuthorizationService.OnHostConfigChangedLocally();
			}
		}

		private static bool IsColorSetting(SettingChangedEventArgs e)
		{
			if (((e != null) ? e.ChangedSetting : null) == null)
			{
				return true;
			}
			string section = e.ChangedSetting.Definition.Section;
			string key = e.ChangedSetting.Definition.Key;
			return section == "Fart Settings" && (key == "FartColorMode" || key == "FartColor");
		}

		private static bool IsHostSyncedSetting(SettingChangedEventArgs e)
		{
			if (((e != null) ? e.ChangedSetting : null) == null)
			{
				return true;
			}
			string section = e.ChangedSetting.Definition.Section;
			string key = e.ChangedSetting.Definition.Key;
			if (section == "Hotkeys")
			{
				return false;
			}
			if (section == "Fart Settings" && (key == "FartColorMode" || key == "FartColor"))
			{
				return false;
			}
			return true;
		}

		private void InitializeConfig()
		{
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			cfgVisualFartRequireModifier = ((BaseUnityPlugin)this).Config.Bind<bool>("Hotkeys", "VisualFart_RequireModifier", true, "Whether visual fart requires a modifier key to be held down");
			cfgVisualFartModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "VisualFart_ModifierKey", (KeyCode)308, "The modifier key for visual fart (only used if RequireModifier is true)");
			cfgVisualFartKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "VisualFart_MainKey", (KeyCode)103, "Trigger a visual-only fart visible to everyone (no launch force)");
			cfgFartBoostKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "FartBoost_MainKey", (KeyCode)102, "Boost yourself with a fart during the first moments of a jump");
			cfgFartForceX = ((BaseUnityPlugin)this).Config.Bind<float>("Fart Settings", "FartForceX", 0f, "Force applied forward/backward relative to where you are facing");
			cfgFartForceY = ((BaseUnityPlugin)this).Config.Bind<float>("Fart Settings", "FartForceY", 100f, "Force applied upward/downward (world vertical)");
			cfgEnableVFX = ((BaseUnityPlugin)this).Config.Bind<bool>("Fart Settings", "EnableVFX", true, "Enable fart visual/audio effects for ALL farts (vanilla, other mods, and PEAK Farts triggers). When false, spore VFX are blocked everywhere but launch force still applies.");
			cfgFartColorMode = ((BaseUnityPlugin)this).Config.Bind<FartColorMode>("Fart Settings", "FartColorMode", FartColorMode.Original, "Fart VFX color: Original (vanilla green), SkinColor (your scout color), or Custom (FartColor hex). Synced to other players.");
			cfgFartColor = ((BaseUnityPlugin)this).Config.Bind<string>("Fart Settings", "FartColor", "#88CC44FF", "Custom fart color as hex (#RRGGBB or #RRGGBBAA). Used when FartColorMode is Custom.");
			cfgPoisonFartsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Poison Farts", "Enabled", false, "Randomly fart while poisoned");
			cfgPoisonFartChance = ((BaseUnityPlugin)this).Config.Bind<float>("Poison Farts", "ChancePerCheck", 10f, "Percent chance to fart on each poison check (0-100)");
			cfgPoisonFartCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Poison Farts", "CheckIntervalSeconds", 2f, "How often to roll for a poison fart while poisoned");
			cfgFartBoostEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Fart Boost", "Enabled", false, "Allow an airborne fart boost hotkey");
			cfgFartBoostCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Fart Boost", "CooldownSeconds", 3f, "Minimum seconds between fart boosts");
			cfgFartBoostJumpWindow = ((BaseUnityPlugin)this).Config.Bind<float>("Fart Boost", "JumpWindowSeconds", 0.5f, "Seconds after jumping when fart boost is allowed. The game caps sinceJump at 0.5s, so values above 0.5 allow boosts for the rest of the jump (still requires isJumping). Use with CooldownSeconds for multiple boosts per jump.");
			Logger.LogInfo((object)"PEAK Farts configuration loaded:");
			Logger.LogInfo((object)string.Format("  Visual fart: {0}{1}", cfgVisualFartRequireModifier.Value ? (((object)cfgVisualFartModifier.Value/*cast due to .constrained prefix*/).ToString() + " + ") : "", cfgVisualFartKey.Value));
			Logger.LogInfo((object)$"  Fart boost key: {cfgFartBoostKey.Value}");
			Logger.LogInfo((object)$"  Fart Force: forward/back={cfgFartForceX.Value}, vertical={cfgFartForceY.Value}");
			Logger.LogInfo((object)("  Poison farts: " + (cfgPoisonFartsEnabled.Value ? (cfgPoisonFartChance.Value + "% every " + cfgPoisonFartCheckInterval.Value + "s") : "disabled")));
			Logger.LogInfo((object)("  Fart boost: " + (cfgFartBoostEnabled.Value ? (cfgFartBoostCooldown.Value + "s cooldown, " + cfgFartBoostJumpWindow.Value + "s jump window") : "disabled")));
			((BaseUnityPlugin)this).Config.Save();
		}

		internal FartSyncedSettings GetEffectiveSettings()
		{
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && FartModAuthorizationService.IsGameplayEnabled && FartHostConfigSyncService.HasRemoteHostSettings)
			{
				return FartHostConfigSyncService.RemoteHostSettings;
			}
			return FartSyncedSettings.FromPlugin(this);
		}

		private void Update()
		{
			if (!FartModAuthorizationService.CanUseModGameplay())
			{
				return;
			}
			if ((Object)(object)localCharacter == (Object)null)
			{
				localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter == (Object)null)
				{
					return;
				}
			}
			HandleVisualFartHotkey();
			HandleFartBoostHotkey();
			HandlePoisonFarts();
		}

		private void HandleVisualFartHotkey()
		{
			//IL_0013: 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)
			bool flag = CheckHotkey(cfgVisualFartRequireModifier.Value, cfgVisualFartModifier.Value, cfgVisualFartKey.Value);
			if (flag && !wasVisualFartPressed)
			{
				TriggerVisualFart();
			}
			wasVisualFartPressed = flag;
		}

		private void HandleFartBoostHotkey()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			FartSyncedSettings effectiveSettings = GetEffectiveSettings();
			if (effectiveSettings.FartBoostEnabled)
			{
				bool keyDown = Input.GetKeyDown(cfgFartBoostKey.Value);
				if (keyDown && !wasFartBoostPressed)
				{
					TryFartBoost(effectiveSettings);
				}
				wasFartBoostPressed = keyDown;
			}
		}

		private void HandlePoisonFarts()
		{
			FartSyncedSettings effectiveSettings = GetEffectiveSettings();
			if (!effectiveSettings.PoisonFartsEnabled || (Object)(object)localCharacter?.refs?.afflictions == (Object)null)
			{
				return;
			}
			float currentStatus = localCharacter.refs.afflictions.GetCurrentStatus((STATUSTYPE)3);
			if (!(currentStatus <= 0f) && !(Time.time - lastPoisonFartCheckTime < effectiveSettings.PoisonFartCheckInterval))
			{
				lastPoisonFartCheckTime = Time.time;
				float num = Mathf.Clamp(effectiveSettings.PoisonFartChance, 0f, 100f) / 100f;
				if (!(Random.value > num))
				{
					TriggerGameplayFart(localCharacter);
				}
			}
		}

		private bool CheckHotkey(bool requireModifier, KeyCode modifierKey, KeyCode mainKey)
		{
			//IL_001a: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			if (requireModifier)
			{
				return Input.GetKey(modifierKey) && Input.GetKeyDown(mainKey);
			}
			return Input.GetKeyDown(mainKey);
		}

		private void TriggerVisualFart()
		{
			if ((Object)(object)localCharacter == (Object)null)
			{
				return;
			}
			try
			{
				SpawnVisualFartVfx(localCharacter);
				Logger.LogInfo((object)"Visual fart triggered (everyone can see, no force).");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to trigger visual fart: " + ex.Message));
			}
		}

		private void TryFartBoost(FartSyncedSettings settings)
		{
			if ((Object)(object)localCharacter == (Object)null)
			{
				return;
			}
			if (!CanUseFartBoost(localCharacter, settings.FartBoostJumpWindow))
			{
				Logger.LogDebug((object)"Fart boost ignored: must be in the first moments of a jump while airborne.");
				return;
			}
			if (Time.time - lastFartBoostTime < settings.FartBoostCooldown)
			{
				Logger.LogDebug((object)"Fart boost ignored: on cooldown.");
				return;
			}
			try
			{
				lastFartBoostTime = Time.time;
				TriggerGameplayFart(localCharacter);
				Logger.LogInfo((object)"Fart boost triggered.");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to trigger fart boost: " + ex.Message));
			}
		}

		private static bool CanUseFartBoost(Character character, float jumpWindowSeconds)
		{
			CharacterData data = character.data;
			if ((Object)(object)data == (Object)null)
			{
				return false;
			}
			if (data.isGrounded)
			{
				return false;
			}
			if (data.isCarried)
			{
				return false;
			}
			if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing || data.isClimbingAnything)
			{
				return false;
			}
			if (!data.isJumping)
			{
				return false;
			}
			if (data.sinceJump > Mathf.Max(0f, jumpWindowSeconds))
			{
				return false;
			}
			return true;
		}

		internal static void SpawnVisualFartVfx(Character character)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			PEAKFartsPlugin instance = Instance;
			if (!((Object)(object)instance == (Object)null) && FartModAuthorizationService.CanUseModGameplay() && instance.GetEffectiveSettings().EnableVfx)
			{
				GameUtils.instance.SpawnResourceAtPositionNetworked("VFX_SporeExploExploEdibleSpawn_NoKnockback", character.Center, (RpcTarget)1);
				GameUtils.instance.RPC_SpawnResourceAtPosition("VFX_SporeExploExploEdibleSpawn_NoKnockback", character.Center);
			}
		}

		internal static void TriggerGameplayFart(Character character)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)character == (Object)null) && !((Object)(object)Instance == (Object)null) && FartModAuthorizationService.CanUseModGameplay())
			{
				FartSyncedSettings effectiveSettings = Instance.GetEffectiveSettings();
				if (effectiveSettings.EnableVfx)
				{
					GameUtils.instance.SpawnResourceAtPositionNetworked("VFX_SporeExploExploEdibleSpawn", character.Center, (RpcTarget)1);
					GameUtils.instance.RPC_SpawnResourceAtPosition("VFX_SporeExploExploEdibleSpawn_NoKnockback", character.Center);
				}
				ApplyFartForce(character, effectiveSettings);
			}
		}

		internal static void ApplyFartForce(Character character, FartSyncedSettings settings)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody bodypartRig = character.GetBodypartRig((BodypartType)0);
			if ((Object)(object)bodypartRig == (Object)null)
			{
				return;
			}
			Vector3 val = ComputeFartForce(character, settings.ForceForward, settings.ForceVertical);
			FartForceContext.MarkCustomApplication(character);
			try
			{
				character.AddForceToBodyPart(bodypartRig, val, Vector3.zero);
			}
			finally
			{
				FartForceContext.UnmarkCustomApplication(character);
			}
		}

		private static Vector3 ComputeFartForce(Character character, float forceForward, float forceVertical)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_004a: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = character.data.lookDirection_Flat;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = ((Component)character).transform.forward;
			}
			((Vector3)(ref val)).Normalize();
			return val * forceForward + Vector3.up * forceVertical;
		}

		internal static Vector3 ComputeFartForcePublic(Character character, FartSyncedSettings settings)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			return ComputeFartForce(character, settings.ForceForward, settings.ForceVertical);
		}

		internal static bool TryGetFartColorForSpawn(Vector3 position, out Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return FartPlayerColorRegistry.TryGetColorForPosition(position, out color);
		}

		internal bool TryResolveFartColor(Character character, out Color color)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return FartPlayerColorRegistry.ResolveColor(cfgFartColorMode.Value, GetFartColor(), character, out color);
		}

		internal static Color GetSkinColor(Character character)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)character?.refs?.customization != (Object)null)
				{
					return character.refs.customization.PlayerColor;
				}
			}
			catch
			{
			}
			return new Color(0.53f, 0.8f, 0.27f);
		}

		internal Color GetFartColor()
		{
			//IL_0041: 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)
			//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_0049: Unknown result type (might be due to invalid IL or missing references)
			if (TryParseHexColor(cfgFartColor.Value, out var color))
			{
				return color;
			}
			Logger.LogWarning((object)("Invalid FartColor '" + cfgFartColor.Value + "', using white."));
			return Color.white;
		}

		internal static bool TryParseHexColor(string hex, out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			if (string.IsNullOrWhiteSpace(hex))
			{
				return false;
			}
			hex = hex.Trim().TrimStart(new char[1] { '#' });
			if (hex.Length != 6 && hex.Length != 8)
			{
				return false;
			}
			if (!byte.TryParse(hex.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result) || !byte.TryParse(hex.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result2) || !byte.TryParse(hex.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result3))
			{
				return false;
			}
			byte result4 = byte.MaxValue;
			if (hex.Length == 8 && !byte.TryParse(hex.Substring(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result4))
			{
				return false;
			}
			color = new Color((float)(int)result / 255f, (float)(int)result2 / 255f, (float)(int)result3 / 255f, (float)(int)result4 / 255f);
			return true;
		}

		internal static void ApplyFartColor(GameObject root, Color color)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val in componentsInChildren)
			{
				MainModule main = val.main;
				((MainModule)(ref main)).startColor = new MinMaxGradient(color);
			}
			ParticleSystemRenderer[] componentsInChildren2 = root.GetComponentsInChildren<ParticleSystemRenderer>(true);
			foreach (ParticleSystemRenderer val2 in componentsInChildren2)
			{
				Material material = ((Renderer)val2).material;
				if (!((Object)(object)material == (Object)null))
				{
					if (material.HasProperty("_Color"))
					{
						material.SetColor("_Color", color);
					}
					if (material.HasProperty("_BaseColor"))
					{
						material.SetColor("_BaseColor", color);
					}
					if (material.HasProperty("_TintColor"))
					{
						material.SetColor("_TintColor", color);
					}
					if (material.HasProperty("_EmissionColor"))
					{
						material.SetColor("_EmissionColor", color * 0.35f);
					}
				}
			}
			Renderer[] componentsInChildren3 = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren3)
			{
				if (val3 is ParticleSystemRenderer)
				{
					continue;
				}
				Material material2 = val3.material;
				if (!((Object)(object)material2 == (Object)null))
				{
					if (material2.HasProperty("_Color"))
					{
						material2.color = color;
					}
					else if (material2.HasProperty("_BaseColor"))
					{
						material2.SetColor("_BaseColor", color);
					}
					else if (material2.HasProperty("_TintColor"))
					{
						material2.SetColor("_TintColor", color);
					}
				}
			}
		}

		internal static bool HandleIncomingFartVfxSpawn(string resourcePath, Vector3 pos)
		{
			//IL_0012: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!FartForceContext.IsFartVfxPath(resourcePath))
			{
				return true;
			}
			if (TryGetFartColorForSpawn(pos, out var color))
			{
				FartColorContext.TintNextInstantiate = true;
				FartColorContext.PendingColor = color;
			}
			if (!FartModAuthorizationService.CanUseModGameplay())
			{
				return true;
			}
			FartForceContext.RegisterFartVfxAt(pos);
			PEAKFartsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			if (!instance.GetEffectiveSettings().EnableVfx)
			{
				return false;
			}
			return true;
		}

		internal static bool ShouldAllowNetworkedFartVfx(string resourcePath)
		{
			if (!FartForceContext.IsFartVfxPath(resourcePath))
			{
				return true;
			}
			if (!FartModAuthorizationService.CanUseModGameplay())
			{
				return true;
			}
			PEAKFartsPlugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			return instance.GetEffectiveSettings().EnableVfx;
		}

		public static void ApplyCustomFartSettings(Character character)
		{
			if (!((Object)(object)Instance == (Object)null) && FartModAuthorizationService.CanUseModGameplay())
			{
				TriggerGameplayFart(character);
			}
		}
	}
	[HarmonyPatch(typeof(GameUtils), "SpawnResourceAtPositionNetworked")]
	public class GameUtils_SpawnResourceAtPositionNetworked_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(string resourcePath)
		{
			return PEAKFartsPlugin.ShouldAllowNetworkedFartVfx(resourcePath);
		}
	}
	[HarmonyPatch(typeof(GameUtils), "RPC_SpawnResourceAtPosition")]
	public class GameUtils_SpawnResourceAtPosition_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(string resourcePath, Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return PEAKFartsPlugin.HandleIncomingFartVfxSpawn(resourcePath, pos);
		}
	}
	[HarmonyPatch(typeof(Object), "Instantiate", new Type[]
	{
		typeof(GameObject),
		typeof(Vector3),
		typeof(Quaternion)
	})]
	public class Object_Instantiate_FartColor_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(Object __result)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (FartColorContext.TintNextInstantiate)
			{
				GameObject val = (GameObject)(object)((__result is GameObject) ? __result : null);
				if (val != null)
				{
					FartColorContext.TintNextInstantiate = false;
					PEAKFartsPlugin.ApplyFartColor(val, FartColorContext.PendingColor);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "AddForceToBodyPart")]
	public class Character_AddForceToBodyPart_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(Character __instance, ref Vector3 partForce, ref Vector3 wholeBodyForce)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)PEAKFartsPlugin.Instance == (Object)null) && FartModAuthorizationService.CanUseModGameplay() && !FartForceContext.IsCustomApplication(__instance) && FartForceContext.ShouldInterceptForce(__instance, partForce, wholeBodyForce))
			{
				FartSyncedSettings effectiveSettings = PEAKFartsPlugin.Instance.GetEffectiveSettings();
				partForce = PEAKFartsPlugin.ComputeFartForcePublic(__instance, effectiveSettings);
				wholeBodyForce = Vector3.zero;
				FartForceContext.MarkInterceptedFart(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_AddForceToBodyPart")]
	public class Character_RPCA_AddForceToBodyPart_Patch
	{
		[HarmonyPrefix]
		public static void Prefix(Character __instance, BodypartType bodypartType, ref Vector3 force, ref Vector3 wholeBodyForce)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (FartModAuthorizationService.CanUseModGameplay())
			{
				Vector3 launchForce = force + wholeBodyForce;
				if (!(((Vector3)(ref launchForce)).sqrMagnitude < 0.0001f) && FartForceContext.ShouldApplyVelocityChange(__instance, force, wholeBodyForce))
				{
					FartForceContext.ApplyFartVelocityChange(__instance, launchForce);
					FartForceContext.ClearPendingVelocityChange(__instance);
					force = Vector3.zero;
					wholeBodyForce = Vector3.zero;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Action_RandomMushroomEffect))]
	[HarmonyPatch("RunRandomEffect")]
	public class Action_RandomMushroomEffect_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix(Action_RandomMushroomEffect __instance, int effect, ref IEnumerator __result)
		{
			if (effect != 5)
			{
				return true;
			}
			if ((Object)(object)PEAKFartsPlugin.Instance == (Object)null || !FartModAuthorizationService.CanUseModGameplay())
			{
				return true;
			}
			Character val = null;
			try
			{
				Traverse val2 = Traverse.Create((object)__instance);
				val = val2.Property("character", (object[])null).GetValue<Character>() ?? val2.Field("character").GetValue<Character>();
			}
			catch (Exception ex)
			{
				PEAKFartsPlugin.Instance.Logger.LogWarning((object)("Failed to get character from Action_RandomMushroomEffect: " + ex.Message));
				return true;
			}
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			__result = RunCustomFartEffect(val);
			return false;
		}

		private static IEnumerator RunCustomFartEffect(Character character)
		{
			yield return (object)new WaitForSeconds(3f);
			PEAKFartsPlugin.ApplyCustomFartSettings(character);
		}
	}
	public enum FartColorMode
	{
		Original,
		SkinColor,
		Custom
	}
	internal struct FartPlayerColorState
	{
		internal FartColorMode Mode;

		internal Color CustomColor;
	}
	internal static class FartPlayerColorRegistry
	{
		private static readonly Dictionary<int, FartPlayerColorState> ColorsByActor = new Dictionary<int, FartPlayerColorState>();

		internal static void Set(int actorNumber, FartColorMode mode, Color customColor)
		{
			//IL_0026: 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)
			if (actorNumber > 0)
			{
				ColorsByActor[actorNumber] = new FartPlayerColorState
				{
					Mode = mode,
					CustomColor = customColor
				};
			}
		}

		internal static void Remove(int actorNumber)
		{
			if (actorNumber > 0)
			{
				ColorsByActor.Remove(actorNumber);
			}
		}

		internal static void Clear()
		{
			ColorsByActor.Clear();
		}

		internal static bool TryGetColorForPosition(Vector3 position, out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			Character characterNear = FartForceContext.GetCharacterNear(position);
			return TryGetColorForCharacter(characterNear, out color);
		}

		internal static bool TryGetColorForCharacter(Character character, out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			int actorNumber = GetActorNumber(character);
			if (actorNumber > 0 && ColorsByActor.TryGetValue(actorNumber, out var value))
			{
				return ResolveColor(value.Mode, value.CustomColor, character, out color);
			}
			if (IsLocalCharacter(character))
			{
				return TryGetLocalColor(character, out color);
			}
			return false;
		}

		internal static bool TryGetLocalColor(Character character, out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			PEAKFartsPlugin instance = PEAKFartsPlugin.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			return instance.TryResolveFartColor(character, out color);
		}

		internal static bool ResolveColor(FartColorMode mode, Color customColor, Character character, out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			color = Color.white;
			switch (mode)
			{
			case FartColorMode.Original:
				return false;
			case FartColorMode.SkinColor:
				color = PEAKFartsPlugin.GetSkinColor(character);
				return true;
			case FartColorMode.Custom:
				color = customColor;
				return true;
			default:
				return false;
			}
		}

		internal static int GetLocalActorNumber()
		{
			if (PhotonNetwork.LocalPlayer != null)
			{
				return PhotonNetwork.LocalPlayer.ActorNumber;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)((localCharacter != null) ? ((MonoBehaviourPun)localCharacter).photonView : null) != (Object)null)
			{
				return ((MonoBehaviourPun)localCharacter).photonView.OwnerActorNr;
			}
			return 0;
		}

		private static int GetActorNumber(Character character)
		{
			if ((Object)(object)((character != null) ? ((MonoBehaviourPun)character).photonView : null) != (Object)null && ((MonoBehaviourPun)character).photonView.OwnerActorNr > 0)
			{
				return ((MonoBehaviourPun)character).photonView.OwnerActorNr;
			}
			if ((Object)(object)character != (Object)null && IsLocalCharacter(character))
			{
				return GetLocalActorNumber();
			}
			return 0;
		}

		private static bool IsLocalCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			try
			{
				if (character.IsLocal)
				{
					return true;
				}
			}
			catch
			{
			}
			return (Object)(object)((MonoBehaviourPun)character).photonView != (Object)null && ((MonoBehaviourPun)character).photonView.IsMine;
		}
	}
	internal static class FartColorContext
	{
		internal static bool TintNextInstantiate;

		internal static Color PendingColor = Color.white;
	}
	internal static class FartForceContext
	{
		private const float FartVfxMatchDistance = 3f;

		private const float FartForceWindowSeconds = 0.5f;

		internal const float VelocityChangeScale = 0.08f;

		private static readonly Dictionary<Character, float> RecentFartTimes = new Dictionary<Character, float>();

		private static readonly HashSet<Character> CustomApplications = new HashSet<Character>();

		private static readonly HashSet<Character> PendingVelocityChange = new HashSet<Character>();

		internal static void MarkCustomApplication(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				CustomApplications.Add(character);
				PendingVelocityChange.Add(character);
				RecentFartTimes[character] = Time.time;
			}
		}

		internal static void UnmarkCustomApplication(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				CustomApplications.Remove(character);
			}
		}

		internal static void RegisterFartVfxAt(Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Character characterNear = GetCharacterNear(position);
			if (!((Object)(object)characterNear == (Object)null))
			{
				RecentFartTimes[characterNear] = Time.time;
			}
		}

		internal static Character GetCharacterNear(Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return FindCharacterNear(position);
		}

		internal static void MarkInterceptedFart(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				RecentFartTimes[character] = Time.time;
				PendingVelocityChange.Add(character);
			}
		}

		internal static bool ShouldInterceptForce(Character character, Vector3 partForce, Vector3 wholeBodyForce)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)PEAKFartsPlugin.Instance == (Object)null)
			{
				return false;
			}
			if (CustomApplications.Contains(character))
			{
				return false;
			}
			return LooksLikeLegacyFartForce(partForce, wholeBodyForce);
		}

		internal static bool ShouldApplyVelocityChange(Character character, Vector3 partForce, Vector3 wholeBodyForce)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			if (PendingVelocityChange.Contains(character))
			{
				return true;
			}
			if (!IsRecentFart(character))
			{
				return false;
			}
			return ((Vector3)(ref partForce)).sqrMagnitude > 0.0001f || ((Vector3)(ref wholeBodyForce)).sqrMagnitude > 0.0001f;
		}

		internal static void ClearPendingVelocityChange(Character character)
		{
			if ((Object)(object)character != (Object)null)
			{
				PendingVelocityChange.Remove(character);
			}
		}

		internal static Vector3 ToVelocityChange(Vector3 configuredForce)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return configuredForce * 0.08f;
		}

		internal static void ApplyFartVelocityChange(Character character, Vector3 launchForce)
		{
			//IL_002e: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (character?.refs?.ragdoll?.partList == null)
			{
				return;
			}
			Vector3 val = ToVelocityChange(launchForce);
			foreach (Bodypart part in character.refs.ragdoll.partList)
			{
				if (!((Object)(object)part?.rig == (Object)null) && !part.rig.isKinematic)
				{
					part.rig.AddForce(val, (ForceMode)2);
				}
			}
		}

		internal static bool IsRecentFart(Character character)
		{
			if (!RecentFartTimes.TryGetValue(character, out var value))
			{
				return false;
			}
			return Time.time - value <= 0.5f;
		}

		internal static bool IsCustomApplication(Character character)
		{
			return (Object)(object)character != (Object)null && CustomApplications.Contains(character);
		}

		internal static bool IsFartVfxPath(string resourcePath)
		{
			return resourcePath == "VFX_SporeExploExploEdibleSpawn" || resourcePath == "VFX_SporeExploExploEdibleSpawn_NoKnockback";
		}

		internal static bool LooksLikeLegacyFartForce(Vector3 partForce, Vector3 wholeBodyForce)
		{
			//IL_002d: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref partForce)).sqrMagnitude > 0.0001f)
			{
				return false;
			}
			if (((Vector3)(ref wholeBodyForce)).sqrMagnitude < 0.0001f)
			{
				return false;
			}
			return Mathf.Abs(wholeBodyForce.x) < 0.01f && Mathf.Abs(wholeBodyForce.z) < 0.01f && wholeBodyForce.y > 0.01f;
		}

		private static Character FindCharacterNear(Vector3 position)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Character result = null;
			float num = 3f;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null))
				{
					float num2 = Vector3.Distance(allCharacter.Center, position);
					if (num2 <= num)
					{
						num = num2;
						result = allCharacter;
					}
				}
			}
			return result;
		}

		internal static void CleanupCharacter(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				RecentFartTimes.Remove(character);
				CustomApplications.Remove(character);
				PendingVelocityChange.Remove(character);
			}
		}
	}
	internal static class FartHostConfigSyncService
	{
		public const int SchemaVersion = 1;

		public const char PairSeparator = ';';

		public const char KeyValueSeparator = '=';

		internal static bool HasRemoteHostSettings { get; private set; }

		internal static FartSyncedSettings RemoteHostSettings { get; private set; }

		internal static void ClearRemoteHostConfig()
		{
			HasRemoteHostSettings = false;
			RemoteHostSettings = default(FartSyncedSettings);
		}

		internal static void ApplyRemoteSnapshot(string payload)
		{
			if (PhotonNetwork.IsMasterClient || string.IsNullOrEmpty(payload))
			{
				return;
			}
			if (!TryDeserialize(payload, out var settings))
			{
				PEAKFartsPlugin instance = PEAKFartsPlugin.Instance;
				if (instance != null)
				{
					instance.Logger.LogError((object)"[PEAK Farts] Failed to apply host config snapshot.");
				}
			}
			else
			{
				HasRemoteHostSettings = true;
				RemoteHostSettings = settings;
			}
		}

		internal static string Serialize(FartSyncedSettings settings)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			AppendPair(stringBuilder, "v", 1.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "forceX", settings.ForceForward.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "forceY", settings.ForceVertical.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "vfx", settings.EnableVfx ? "1" : "0");
			AppendPair(stringBuilder, "poison", settings.PoisonFartsEnabled ? "1" : "0");
			AppendPair(stringBuilder, "poisonChance", settings.PoisonFartChance.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "poisonInterval", settings.PoisonFartCheckInterval.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "boost", settings.FartBoostEnabled ? "1" : "0");
			AppendPair(stringBuilder, "boostCd", settings.FartBoostCooldown.ToString(CultureInfo.InvariantCulture));
			AppendPair(stringBuilder, "boostWindow", settings.FartBoostJumpWindow.ToString(CultureInfo.InvariantCulture));
			return stringBuilder.ToString();
		}

		internal static bool TryDeserialize(string payload, out FartSyncedSettings settings)
		{
			settings = default(FartSyncedSettings);
			if (string.IsNullOrEmpty(payload))
			{
				return false;
			}
			settings = default(FartSyncedSettings);
			string[] array = payload.Split(new char[1] { ';' });
			int result = 0;
			bool flag = false;
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num > 0)
				{
					string text2 = text.Substring(0, num);
					string text3 = text.Substring(num + 1);
					switch (text2)
					{
					case "v":
						flag = int.TryParse(text3, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
						break;
					case "forceX":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.ForceForward);
						break;
					case "forceY":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.ForceVertical);
						break;
					case "vfx":
						settings.EnableVfx = text3 == "1";
						break;
					case "poison":
						settings.PoisonFartsEnabled = text3 == "1";
						break;
					case "poisonChance":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.PoisonFartChance);
						break;
					case "poisonInterval":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.PoisonFartCheckInterval);
						break;
					case "boost":
						settings.FartBoostEnabled = text3 == "1";
						break;
					case "boostCd":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.FartBoostCooldown);
						break;
					case "boostWindow":
						float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out settings.FartBoostJumpWindow);
						break;
					}
				}
			}
			return flag && result == 1;
		}

		private static void AppendPair(StringBuilder builder, string key, string value)
		{
			if (builder.Length > 0)
			{
				builder.Append(';');
			}
			builder.Append(key);
			builder.Append('=');
			builder.Append(value ?? string.Empty);
		}
	}
	internal static class FartModAuthorizationService
	{
		public const string PhotonCustomPropsPluginGuid = "com.snosz.photoncustompropsutils";

		public const string RoomConfigPropertyKey = "peakFartsConfigV1";

		private static PhotonScopedManager _photonManager;

		private static bool _photonManagerReady;

		private static string _pendingHostConfigPayload;

		internal static bool IsGameplayEnabled { get; private set; }

		internal static void Initialize()
		{
			Networking.AddHostHasPluginListeners("peakfarts.customizable", (Action)OnHostHasPeaktFartsMod, (Action)OnHostMissingPeaktFartsMod);
			if (PhotonCustomPropsUtilsPlugin.IsReady)
			{
				SetupPhotonManager();
			}
			else
			{
				PhotonCustomPropsUtilsPlugin.OnReady += SetupPhotonManager;
			}
			if (!PhotonNetwork.InRoom)
			{
				SetSoloAuthorized();
			}
		}

		internal static bool CanUseModGameplay()
		{
			if (!PhotonNetwork.InRoom)
			{
				return true;
			}
			if (!IsGameplayEnabled)
			{
				return false;
			}
			if (PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			return FartHostConfigSyncService.HasRemoteHostSettings;
		}

		internal static void SetSoloAuthorized()
		{
			IsGameplayEnabled = true;
			FartHostConfigSyncService.ClearRemoteHostConfig();
		}

		private static void SetupPhotonManager()
		{
			if (_photonManagerReady)
			{
				return;
			}
			_photonManagerReady = true;
			_photonManager = PhotonCustomPropsUtilsPlugin.GetManager("peakfarts.customizable");
			_photonManager.RegisterOnJoinedRoom((Action<Player>)delegate
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && IsGameplayEnabled)
				{
					PublishHostConfigIfMaster();
				}
			});
			_photonManager.RegisterRoomProperty<string>("peakFartsConfigV1", (RoomEventType)2, (Action<string>)delegate(string value)
			{
				if (!PhotonNetwork.IsMasterClient && !string.IsNullOrEmpty(value))
				{
					if (!IsGameplayEnabled)
					{
						_pendingHostConfigPayload = value;
					}
					else
					{
						FartHostConfigSyncService.ApplyRemoteSnapshot(value);
					}
				}
			});
		}

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

		private static void OnHostMissingPeaktFartsMod()
		{
			if (PhotonNetwork.InRoom)
			{
				IsGameplayEnabled = false;
				_pendingHostConfigPayload = null;
				FartHostConfigSyncService.ClearRemoteHostConfig();
			}
		}

		internal static void OnHostConfigChangedLocally()
		{
			if (!PhotonNetwork.InRoom)
			{
				FartHostConfigSyncService.ClearRemoteHostConfig();
			}
			else if (IsGameplayEnabled && PhotonNetwork.IsMasterClient)
			{
				PublishHostConfigIfMaster();
			}
		}

		private static void PublishHostConfigIfMaster()
		{
			if (_photonManager != null && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient && IsGameplayEnabled && !((Object)(object)PEAKFartsPlugin.Instance == (Object)null))
			{
				FartSyncedSettings settings = FartSyncedSettings.FromPlugin(PEAKFartsPlugin.Instance);
				string text = FartHostConfigSyncService.Serialize(settings);
				_photonManager.SetRoomProperty("peakFartsConfigV1", (object)text);
			}
		}
	}
	internal class FartNetworkSync : MonoBehaviourPunCallbacks, IOnEventCallback
	{
		internal const byte EventCode = 148;

		internal const int ProtocolVersion = 5;

		private const byte SubTypePlayerColor = 3;

		public override void OnJoinedRoom()
		{
			RegisterAndBroadcastOwnColor();
		}

		public override void OnLeftRoom()
		{
			FartPlayerColorRegistry.Clear();
		}

		public override void OnPlayerEnteredRoom(Player newPlayer)
		{
			SendOwnColorToPlayer(newPlayer);
		}

		public override void OnPlayerLeftRoom(Player otherPlayer)
		{
			if (otherPlayer != null)
			{
				FartPlayerColorRegistry.Remove(otherPlayer.ActorNumber);
			}
		}

		public void OnEvent(EventData eventData)
		{
			if (eventData?.Code == 148 && eventData.CustomData is object[] array && array.Length >= 2 && Convert.ToInt32(array[0]) == 5)
			{
				byte b = Convert.ToByte(array[1]);
				if (b == 3)
				{
					ApplyPlayerColorEvent(array);
				}
			}
		}

		internal static void BroadcastOwnPlayerColor()
		{
			RegisterLocalColor();
			if (PhotonNetwork.InRoom)
			{
				SendOwnColor((ReceiverGroup)0);
			}
		}

		private static void RegisterAndBroadcastOwnColor()
		{
			RegisterLocalColor();
			if (PhotonNetwork.InRoom)
			{
				SendOwnColor((ReceiverGroup)0);
			}
		}

		private static void RegisterLocalColor()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			PEAKFartsPlugin instance = PEAKFartsPlugin.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				int localActorNumber = FartPlayerColorRegistry.GetLocalActorNumber();
				if (localActorNumber > 0)
				{
					FartPlayerColorRegistry.Set(localActorNumber, instance.cfgFartColorMode.Value, instance.GetFartColor());
				}
			}
		}

		private static void SendOwnColor(ReceiverGroup receivers)
		{
			//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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			PEAKFartsPlugin instance = PEAKFartsPlugin.Instance;
			if (!((Object)(object)instance == (Object)null) && PhotonNetwork.InRoom)
			{
				int localActorNumber = FartPlayerColorRegistry.GetLocalActorNumber();
				if (localActorNumber > 0)
				{
					Color fartColor = instance.GetFartColor();
					object[] array = new object[8]
					{
						5,
						(byte)3,
						localActorNumber,
						(int)instance.cfgFartColorMode.Value,
						fartColor.r,
						fartColor.g,
						fartColor.b,
						fartColor.a
					};
					PhotonNetwork.RaiseEvent((byte)148, (object)array, new RaiseEventOptions
					{
						Receivers = receivers
					}, SendOptions.SendReliable);
				}
			}
		}

		private static void SendOwnColorToPlayer(Player player)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			if (player == null || !PhotonNetwork.InRoom)
			{
				return;
			}
			PEAKFartsPlugin instance = PEAKFartsPlugin.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				int localActorNumber = FartPlayerColorRegistry.GetLocalActorNumber();
				if (localActorNumber > 0)
				{
					Color fartColor = instance.GetFartColor();
					object[] array = new object[8]
					{
						5,
						(byte)3,
						localActorNumber,
						(int)instance.cfgFartColorMode.Value,
						fartColor.r,
						fartColor.g,
						fartColor.b,
						fartColor.a
					};
					RaiseEventOptions val = new RaiseEventOptions();
					val.TargetActors = new int[1] { player.ActorNumber };
					PhotonNetwork.RaiseEvent((byte)148, (object)array, val, SendOptions.SendReliable);
				}
			}
		}

		private static void ApplyPlayerColorEvent(object[] data)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (data.Length < 8)
			{
				return;
			}
			try
			{
				int actorNumber = Convert.ToInt32(data[2]);
				FartColorMode mode = (FartColorMode)Convert.ToInt32(data[3]);
				Color customColor = default(Color);
				((Color)(ref customColor))..ctor(Convert.ToSingle(data[4]), Convert.ToSingle(data[5]), Convert.ToSingle(data[6]), Convert.ToSingle(data[7]));
				FartPlayerColorRegistry.Set(actorNumber, mode, customColor);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[PEAK Farts] Failed to apply player fart color: " + ex.Message));
			}
		}
	}
	internal struct FartSyncedSettings
	{
		internal float ForceForward;

		internal float ForceVertical;

		internal bool EnableVfx;

		internal bool PoisonFartsEnabled;

		internal float PoisonFartChance;

		internal float PoisonFartCheckInterval;

		internal bool FartBoostEnabled;

		internal float FartBoostCooldown;

		internal float FartBoostJumpWindow;

		internal static FartSyncedSettings FromPlugin(PEAKFartsPlugin plugin)
		{
			return new FartSyncedSettings
			{
				ForceForward = plugin.cfgFartForceX.Value,
				ForceVertical = plugin.cfgFartForceY.Value,
				EnableVfx = plugin.cfgEnableVFX.Value,
				PoisonFartsEnabled = plugin.cfgPoisonFartsEnabled.Value,
				PoisonFartChance = plugin.cfgPoisonFartChance.Value,
				PoisonFartCheckInterval = plugin.cfgPoisonFartCheckInterval.Value,
				FartBoostEnabled = plugin.cfgFartBoostEnabled.Value,
				FartBoostCooldown = plugin.cfgFartBoostCooldown.Value,
				FartBoostJumpWindow = plugin.cfgFartBoostJumpWindow.Value
			};
		}
	}
}