Decompiled source of StagePhysicsEvents v4.1.0

StagePhysicsEvents.dll

Decompiled 2 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.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("Codex")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("4.1.0.0")]
[assembly: AssemblyInformationalVersion("4.1.0")]
[assembly: AssemblyProduct("StagePhysicsEvents")]
[assembly: AssemblyTitle("StagePhysicsEvents")]
[assembly: AssemblyVersion("4.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOJP.StagePhysicsEvents
{
	[BepInPlugin("REPOJP.StagePhysicsEvents", "Stage Physics Events", "4.1.0")]
	public sealed class StagePhysicsEventsPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "REPOJP.StagePhysicsEvents";

		public const string PluginName = "Stage Physics Events";

		public const string PluginVersion = "4.1.0";

		private Harmony? _harmony;

		private GameObject? _controllerObject;

		internal static StagePhysicsEventsPlugin Instance { get; private set; }

		internal static ManualLogSource ModLogger { get; private set; }

		internal StagePhysicsConfig Settings { get; private set; }

		internal StagePhysicsEventController Controller { get; private set; }

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			Instance = this;
			ModLogger = ((BaseUnityPlugin)this).Logger;
			Settings = new StagePhysicsConfig(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			_controllerObject = new GameObject("StagePhysicsEvents_Controller");
			((Object)_controllerObject).hideFlags = (HideFlags)61;
			_controllerObject.transform.SetParent(((Component)this).transform, false);
			_controllerObject.SetActive(false);
			Controller = _controllerObject.AddComponent<StagePhysicsEventController>();
			Controller.Initialize(Settings);
			((Component)this).gameObject.AddComponent<StagePhysicsEventHud>().Initialize(Settings, Controller);
			_harmony = new Harmony("REPOJP.StagePhysicsEvents");
			try
			{
				_harmony.PatchAll(typeof(LifecyclePatches));
				SceneManager.activeSceneChanged += ActiveSceneChanged;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Stage Physics Events 4.1.0 loaded.");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to apply Harmony patches: {arg}");
				_harmony.UnpatchSelf();
				((Behaviour)Controller).enabled = false;
			}
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= ActiveSceneChanged;
			Controller?.Shutdown();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			PhysGrabObjectRegistry.Clear();
			if ((Object)(object)_controllerObject != (Object)null)
			{
				Object.Destroy((Object)(object)_controllerObject);
			}
		}

		private void ActiveSceneChanged(Scene previous, Scene current)
		{
			Controller?.StageEnding();
		}
	}
	internal sealed class StagePhysicsConfig
	{
		private const int CurrentConfigRevision = 2;

		private static readonly PropertyInfo? OrphanedEntriesProperty = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);

		private readonly ManualLogSource _logger;

		private string _lastProbabilityWarning = string.Empty;

		private string _lastRangeWarning = string.Empty;

		internal ConfigEntry<bool> Enabled { get; }

		internal ConfigEntry<string> Mode { get; }

		internal ConfigEntry<int> StageEffectChancePercent { get; }

		internal ConfigEntry<int> MaxSimultaneousEffects { get; }

		internal ConfigEntry<int> IntervalMinSeconds { get; }

		internal ConfigEntry<int> IntervalMaxSeconds { get; }

		internal ConfigEntry<int> EffectDurationMinSeconds { get; }

		internal ConfigEntry<int> EffectDurationMaxSeconds { get; }

		internal ConfigEntry<bool> FeatherEnabled { get; }

		internal ConfigEntry<int> FeatherChance { get; }

		internal ConfigEntry<bool> ZeroGravityEnabled { get; }

		internal ConfigEntry<int> ZeroGravityChance { get; }

		internal ConfigEntry<int> ZeroGravityIndestructibleReleaseDelaySeconds { get; }

		internal ConfigEntry<bool> BatteryEnabled { get; }

		internal ConfigEntry<int> BatteryChance { get; }

		internal ConfigEntry<int> BatteryChargeAmount { get; }

		internal ConfigEntry<int> BatteryChargeIntervalSeconds { get; }

		internal ConfigEntry<bool> HealEnabled { get; }

		internal ConfigEntry<int> HealChance { get; }

		internal ConfigEntry<int> HealAmount { get; }

		internal ConfigEntry<int> HealIntervalSeconds { get; }

		internal ConfigEntry<bool> IndestructibleEnabled { get; }

		internal ConfigEntry<int> IndestructibleChance { get; }

		internal ConfigEntry<bool> RollEnabled { get; }

		internal ConfigEntry<int> RollChance { get; }

		internal ConfigEntry<int> RollIndestructibleReleaseDelaySeconds { get; }

		internal ConfigEntry<bool> VoidEnabled { get; }

		internal ConfigEntry<int> VoidChance { get; }

		internal ConfigEntry<int> VoidIndestructibleReleaseDelaySeconds { get; }

		internal ConfigEntry<int> VoidSpawnCountMin { get; }

		internal ConfigEntry<int> VoidSpawnCountMax { get; }

		internal ConfigEntry<bool> FloatValuables { get; }

		internal ConfigEntry<bool> FloatItems { get; }

		internal ConfigEntry<bool> FloatDoors { get; }

		internal ConfigEntry<bool> FloatWeapons { get; }

		internal ConfigEntry<bool> FloatPlayers { get; }

		internal ConfigEntry<bool> FloatEnemies { get; }

		internal ConfigEntry<bool> UiEnabled { get; }

		internal ConfigEntry<bool> StageStartChatEnabled { get; }

		internal ConfigEntry<bool> CountdownEnabled { get; }

		internal ConfigEntry<string> UiAnchor { get; }

		internal ConfigEntry<string> UiAlignment { get; }

		internal ConfigEntry<int> UiOffsetX { get; }

		internal ConfigEntry<int> UiOffsetY { get; }

		internal ConfigEntry<int> UiScalePercent { get; }

		internal (int Min, int Max) EffectiveIntervalRange => OrderedRange(IntervalMinSeconds.Value, IntervalMaxSeconds.Value, "Interval");

		internal (int Min, int Max) EffectiveDurationRange => OrderedRange(EffectDurationMinSeconds.Value, EffectDurationMaxSeconds.Value, "EffectDuration");

		internal bool HasSelectableEffect
		{
			get
			{
				foreach (StageEffect individualEffect in StageEffectSet.IndividualEffects)
				{
					if (GetChance(individualEffect) > 0)
					{
						return true;
					}
				}
				return false;
			}
		}

		internal StagePhysicsConfig(ConfigFile config, ManualLogSource logger)
		{
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Expected O, but got Unknown
			//IL_077a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0784: Expected O, but got Unknown
			//IL_07c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d1: Expected O, but got Unknown
			//IL_084d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0857: Expected O, but got Unknown
			//IL_085f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0869: Expected O, but got Unknown
			//IL_0875: Unknown result type (might be due to invalid IL or missing references)
			//IL_087f: Expected O, but got Unknown
			//IL_088b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0895: Expected O, but got Unknown
			//IL_08a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ab: Expected O, but got Unknown
			//IL_08b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c1: Expected O, but got Unknown
			//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d7: Expected O, but got Unknown
			//IL_08e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ed: Expected O, but got Unknown
			//IL_08f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0903: Expected O, but got Unknown
			//IL_090f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0919: Expected O, but got Unknown
			_logger = logger;
			bool saveOnConfigSet = config.SaveOnConfigSet;
			config.SaveOnConfigSet = false;
			string text = "Light" + "weight";
			ConfigEntry<bool> val = BindBool(config, text, "Enabled", value: true, "Legacy setting migrated to Feather.");
			ConfigEntry<int> val2 = BindInt(config, text, "ChancePercent", 15, 0, 100, "Legacy setting migrated to Feather.");
			BindBool(config, "Magnet", "Enabled", value: true, "Obsolete setting removed in 4.1.0.");
			BindInt(config, "Magnet", "ChancePercent", 10, 0, 100, "Obsolete setting removed in 4.1.0.");
			ConfigEntry<bool> val3 = BindBool(config, "Torque", "Enabled", value: false, "Legacy Torque setting migrated to Roll.");
			ConfigEntry<int> val4 = BindInt(config, "Torque", "ChancePercent", 10, 0, 100, "Legacy Torque setting migrated to Roll.");
			ConfigEntry<bool> val5 = BindBool(config, "Roll Staff", "Enabled", val3.Value, "Legacy Roll Staff setting migrated to Roll.");
			ConfigEntry<int> val6 = BindInt(config, "Roll Staff", "ChancePercent", val4.Value, 0, 100, "Legacy Roll Staff setting migrated to Roll.");
			BindBool(config, "Boost", "Enabled", value: true, "Obsolete setting removed in 4.1.0.");
			BindInt(config, "Boost", "ChancePercent", 3, 0, 100, "Obsolete setting removed in 4.1.0.");
			Enabled = BindBool(config, "General", "Enabled", value: true, "Enables the mod. Stage event behavior uses the host's settings.");
			Mode = config.Bind<string>("General", "Mode", "RandomEachEvent", new ConfigDescription("AllMode selects one of the other four modes with equal probability when each stage begins. RandomEachEvent rerolls every event. FixedForStage keeps the stage's first effect combination, duration, and interval. FixedPerExtraction keeps the stage's duration and interval but rerolls the effect combination after each completed extraction. PersistentForStage keeps the selected effect combination active until the stage ends.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "AllMode", "RandomEachEvent", "FixedForStage", "FixedPerExtraction", "PersistentForStage" }), Array.Empty<object>()));
			StageEffectChancePercent = BindInt(config, "General", "StageEffectChancePercent", 20, 0, 100, "Chance that stage effects are enabled for a stage. A failed roll disables both effects and the HUD for that stage.");
			MaxSimultaneousEffects = BindInt(config, "General", "MaxSimultaneousEffects", 3, 1, StageEffectSet.IndividualEffects.Count, "Maximum number of effects that can be selected for one event. Successful effects above this limit are reduced randomly.");
			IntervalMinSeconds = BindInt(config, "Timing", "IntervalMinSeconds", 45, 10, 300, "Minimum number of seconds before the next event roll.");
			IntervalMaxSeconds = BindInt(config, "Timing", "IntervalMaxSeconds", 90, 10, 300, "Maximum number of seconds before the next event roll.");
			EffectDurationMinSeconds = BindInt(config, "Timing", "EffectDurationMinSeconds", 15, 10, 300, "Minimum effect duration in seconds.");
			EffectDurationMaxSeconds = BindInt(config, "Timing", "EffectDurationMaxSeconds", 30, 10, 300, "Maximum effect duration in seconds.");
			FeatherEnabled = BindBool(config, "Feather", "Enabled", val.Value, "Includes Feather in each event's independent rolls.");
			FeatherChance = BindInt(config, "Feather", "ChancePercent", val2.Value, 0, 100, "Independent chance for Feather in each event.");
			ConfigDefinition definition = new ConfigDefinition("Internal", "ConfigRevision");
			int num = ReadConfigRevision(config, definition);
			if (num < 1 && FeatherChance.Value == 30)
			{
				FeatherChance.Value = 15;
				_logger.LogInfo((object)"Migrated the previous default Feather chance from 30% to 15%.");
			}
			ZeroGravityEnabled = BindBool(config, "Zero Gravity", "Enabled", value: true, "Includes Zero Gravity in each event's independent rolls.");
			ZeroGravityChance = BindInt(config, "Zero Gravity", "ChancePercent", 10, 0, 100, "Independent chance for Zero Gravity in each event.");
			ZeroGravityIndestructibleReleaseDelaySeconds = BindInt(config, "Zero Gravity", "IndestructibleReleaseDelaySeconds", 2, 1, 5, "Seconds to keep valuables Indestructible after Zero Gravity ends.");
			BatteryEnabled = BindBool(config, "Battery", "Enabled", value: true, "Includes the Battery Orb effect in each event's independent rolls.");
			BatteryChance = BindInt(config, "Battery", "ChancePercent", 5, 0, 100, "Independent chance for Battery in each event.");
			BatteryChargeAmount = BindInt(config, "Battery", "ChargeAmount", 5, 1, 100, "Battery percentage points restored to each targeted battery per charge tick.");
			BatteryChargeIntervalSeconds = BindInt(config, "Battery", "ChargeIntervalSeconds", 4, 1, 300, "Seconds between Battery charge ticks.");
			if (num < 2)
			{
				if (BatteryChargeAmount.Value == 10)
				{
					BatteryChargeAmount.Value = 5;
					_logger.LogInfo((object)"Migrated the previous default Battery charge amount from 10 to 5.");
				}
				if (BatteryChargeIntervalSeconds.Value == 2)
				{
					BatteryChargeIntervalSeconds.Value = 4;
					_logger.LogInfo((object)"Migrated the previous default Battery charge interval from 2 seconds to 4 seconds.");
				}
			}
			if (num < 2)
			{
				WriteConfigRevision(config, definition);
			}
			HealEnabled = BindBool(config, "Heal", "Enabled", value: true, "Includes the Heal Orb effect in each event's independent rolls.");
			HealChance = BindInt(config, "Heal", "ChancePercent", 5, 0, 100, "Independent chance for Heal in each event.");
			HealAmount = BindInt(config, "Heal", "HealAmount", 10, 1, 100, "Health restored to each targeted player per Heal tick.");
			HealIntervalSeconds = BindInt(config, "Heal", "HealIntervalSeconds", 2, 1, 300, "Seconds between Heal ticks.");
			IndestructibleEnabled = BindBool(config, "Indestructible", "Enabled", value: true, "Includes the Indestructible Orb effect in each event's independent rolls.");
			IndestructibleChance = BindInt(config, "Indestructible", "ChancePercent", 5, 0, 100, "Independent chance for Indestructible in each event.");
			RollEnabled = BindBool(config, "Roll", "Enabled", val5.Value, "Includes Roll in each event's independent rolls.");
			RollChance = BindInt(config, "Roll", "ChancePercent", val6.Value, 0, 100, "Independent chance for Roll in each event.");
			RollIndestructibleReleaseDelaySeconds = BindInt(config, "Roll", "IndestructibleReleaseDelaySeconds", 2, 1, 5, "Seconds to keep valuables Indestructible after Roll ends.");
			VoidEnabled = BindBool(config, "Void", "Enabled", value: false, "Includes the Void Staff effect in each event's independent rolls.");
			VoidChance = BindInt(config, "Void", "ChancePercent", 5, 0, 100, "Independent chance for Void in each event.");
			VoidIndestructibleReleaseDelaySeconds = BindInt(config, "Void", "IndestructibleReleaseDelaySeconds", 2, 1, 5, "Seconds to keep valuables Indestructible after Void ends.");
			VoidSpawnCountMin = BindInt(config, "Void", "SpawnCountMin", 3, 2, 30, "Minimum number of Void effects created at random stage points.");
			VoidSpawnCountMax = BindInt(config, "Void", "SpawnCountMax", 5, 2, 30, "Maximum number of Void effects created at random stage points.");
			FloatValuables = BindBool(config, "What floats", "Valuables", value: true, "Targets valuables.");
			FloatItems = BindBool(config, "What floats", "Items", value: true, "Targets general items, carts, and movable props.");
			FloatDoors = BindBool(config, "What floats", "Doors", value: false, "Targets doors, lids, and other hinged movable objects.");
			FloatWeapons = BindBool(config, "What floats", "Weapons", value: true, "Targets weapons.");
			FloatPlayers = BindBool(config, "What floats", "Players", value: true, "Targets players.");
			FloatEnemies = BindBool(config, "What floats", "Enemies", value: true, "Targets enemies.");
			UiEnabled = BindBool(config, "UI", "Enabled", value: true, "Shows the event HUD on this client.");
			StageStartChatEnabled = BindBool(config, "UI", "StageStartChatEnabled", value: true, "Broadcasts the stage summary, effect names, countdowns, and End notifications through vanilla chat.");
			CountdownEnabled = BindBool(config, "UI", "CountdownEnabled", value: true, "Enables the five-second start countdown and three-second end countdown. When disabled, effects start and end immediately after their announcements.");
			UiAnchor = config.Bind<string>("UI", "Anchor", "BottomRight", new ConfigDescription("Anchor point used to position the HUD.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[9] { "TopLeft", "TopCenter", "TopRight", "MiddleLeft", "MiddleCenter", "MiddleRight", "BottomLeft", "BottomCenter", "BottomRight" }), Array.Empty<object>()));
			UiAlignment = config.Bind<string>("UI", "Alignment", "Right", new ConfigDescription("Horizontal alignment of the HUD text.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Left", "Center", "Right" }), Array.Empty<object>()));
			UiOffsetX = BindInt(config, "UI", "OffsetX", 0, -3840, 3840, "Horizontal offset from the anchor in pixels.");
			UiOffsetY = BindInt(config, "UI", "OffsetY", 0, -2160, 2160, "Vertical offset from the anchor in pixels.");
			UiScalePercent = BindInt(config, "UI", "ScalePercent", 70, 50, 200, "HUD scale percentage.");
			config.Remove(new ConfigDefinition(text, "Enabled"));
			config.Remove(new ConfigDefinition(text, "ChancePercent"));
			config.Remove(new ConfigDefinition("Magnet", "Enabled"));
			config.Remove(new ConfigDefinition("Magnet", "ChancePercent"));
			config.Remove(new ConfigDefinition("Torque", "Enabled"));
			config.Remove(new ConfigDefinition("Torque", "ChancePercent"));
			config.Remove(new ConfigDefinition("Roll Staff", "Enabled"));
			config.Remove(new ConfigDefinition("Roll Staff", "ChancePercent"));
			config.Remove(new ConfigDefinition("Boost", "Enabled"));
			config.Remove(new ConfigDefinition("Boost", "ChancePercent"));
			config.SaveOnConfigSet = saveOnConfigSet;
			config.Save();
			FeatherEnabled.SettingChanged += ProbabilitySettingChanged;
			FeatherChance.SettingChanged += ProbabilitySettingChanged;
			ZeroGravityEnabled.SettingChanged += ProbabilitySettingChanged;
			ZeroGravityChance.SettingChanged += ProbabilitySettingChanged;
			BatteryEnabled.SettingChanged += ProbabilitySettingChanged;
			BatteryChance.SettingChanged += ProbabilitySettingChanged;
			HealEnabled.SettingChanged += ProbabilitySettingChanged;
			HealChance.SettingChanged += ProbabilitySettingChanged;
			IndestructibleEnabled.SettingChanged += ProbabilitySettingChanged;
			IndestructibleChance.SettingChanged += ProbabilitySettingChanged;
			RollEnabled.SettingChanged += ProbabilitySettingChanged;
			RollChance.SettingChanged += ProbabilitySettingChanged;
			VoidEnabled.SettingChanged += ProbabilitySettingChanged;
			VoidChance.SettingChanged += ProbabilitySettingChanged;
		}

		internal int RollIntervalSeconds()
		{
			var (num, num2) = EffectiveIntervalRange;
			return Random.Range(num, num2 + 1);
		}

		internal int RollDurationSeconds()
		{
			var (num, num2) = EffectiveDurationRange;
			return Random.Range(num, num2 + 1);
		}

		internal int RollVoidSpawnCount()
		{
			var (num, num2) = OrderedRange(VoidSpawnCountMin.Value, VoidSpawnCountMax.Value, "VoidSpawnCount");
			return Random.Range(num, num2 + 1);
		}

		internal StageEffect RollEffects()
		{
			List<StageEffect> list = new List<StageEffect>();
			foreach (StageEffect individualEffect in StageEffectSet.IndividualEffects)
			{
				int chance = GetChance(individualEffect);
				if (chance >= 100 || (chance > 0 && Random.Range(1, 101) <= chance))
				{
					list.Add(individualEffect);
				}
			}
			int num = Mathf.Clamp(MaxSimultaneousEffects.Value, 1, StageEffectSet.IndividualEffects.Count);
			if (list.Count > num)
			{
				for (int i = 0; i < num; i++)
				{
					int num2 = Random.Range(i, list.Count);
					List<StageEffect> list2 = list;
					int index = i;
					int index2 = num2;
					StageEffect value = list[num2];
					StageEffect value2 = list[i];
					list2[index] = value;
					list[index2] = value2;
				}
				_logger.LogDebug((object)$"Effect roll produced {list.Count} successful effects; randomly limiting the event to {num}.");
			}
			StageEffect stageEffect = StageEffect.None;
			int num3 = Mathf.Min(list.Count, num);
			for (int j = 0; j < num3; j++)
			{
				stageEffect |= list[j];
			}
			return stageEffect;
		}

		internal bool RollStageEnabled()
		{
			if (StageEffectChancePercent.Value < 100)
			{
				if (StageEffectChancePercent.Value > 0)
				{
					return Random.Range(1, 101) <= StageEffectChancePercent.Value;
				}
				return false;
			}
			return true;
		}

		internal bool IsEffectSelectable(StageEffect effect)
		{
			return GetChance(effect) > 0;
		}

		internal EventMode CaptureMode()
		{
			if (string.Equals(Mode.Value, "AllMode", StringComparison.Ordinal))
			{
				return Random.Range(0, 4) switch
				{
					1 => EventMode.FixedForStage, 
					2 => EventMode.FixedPerExtraction, 
					3 => EventMode.PersistentForStage, 
					_ => EventMode.RandomEachEvent, 
				};
			}
			if (string.Equals(Mode.Value, "FixedForStage", StringComparison.Ordinal))
			{
				return EventMode.FixedForStage;
			}
			if (string.Equals(Mode.Value, "FixedPerExtraction", StringComparison.Ordinal))
			{
				return EventMode.FixedPerExtraction;
			}
			if (string.Equals(Mode.Value, "PersistentForStage", StringComparison.Ordinal))
			{
				return EventMode.PersistentForStage;
			}
			return EventMode.RandomEachEvent;
		}

		internal void LogProbabilityPolicy()
		{
			if (!HasSelectableEffect)
			{
				if (_lastProbabilityWarning != "zero")
				{
					_lastProbabilityWarning = "zero";
					_logger.LogWarning((object)"All enabled effect probabilities are 0%; no stage event can be selected.");
				}
			}
			else
			{
				_lastProbabilityWarning = string.Empty;
			}
		}

		internal TargetFilter CaptureTargetFilter()
		{
			return new TargetFilter(FloatValuables.Value, FloatItems.Value, FloatDoors.Value, FloatWeapons.Value, FloatPlayers.Value, FloatEnemies.Value);
		}

		private void ProbabilitySettingChanged(object sender, EventArgs eventArgs)
		{
			LogProbabilityPolicy();
		}

		private int GetChance(StageEffect effect)
		{
			return effect switch
			{
				StageEffect.Feather => FeatherEnabled.Value ? FeatherChance.Value : 0, 
				StageEffect.ZeroGravity => ZeroGravityEnabled.Value ? ZeroGravityChance.Value : 0, 
				StageEffect.Battery => BatteryEnabled.Value ? BatteryChance.Value : 0, 
				StageEffect.Heal => HealEnabled.Value ? HealChance.Value : 0, 
				StageEffect.Indestructible => IndestructibleEnabled.Value ? IndestructibleChance.Value : 0, 
				StageEffect.Roll => RollEnabled.Value ? RollChance.Value : 0, 
				StageEffect.Void => VoidEnabled.Value ? VoidChance.Value : 0, 
				_ => 0, 
			};
		}

		private (int Min, int Max) OrderedRange(int first, int second, string name)
		{
			if (first <= second)
			{
				return (Min: first, Max: second);
			}
			string text = $"{name}:{first}:{second}";
			if (_lastRangeWarning != text)
			{
				_lastRangeWarning = text;
				_logger.LogWarning((object)$"{name} minimum ({first}) exceeds maximum ({second}); using {second}..{first} without rewriting config.");
			}
			return (Min: second, Max: first);
		}

		private static ConfigEntry<bool> BindBool(ConfigFile file, string section, string key, bool value, string description)
		{
			return file.Bind<bool>(section, key, value, description);
		}

		private static ConfigEntry<int> BindInt(ConfigFile file, string section, string key, int value, int min, int max, string description)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return file.Bind<int>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>()));
		}

		private int ReadConfigRevision(ConfigFile config, ConfigDefinition definition)
		{
			try
			{
				IDictionary<ConfigDefinition, string> orphanedEntries = GetOrphanedEntries(config);
				if (orphanedEntries != null && orphanedEntries.TryGetValue(definition, out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
				{
					return result;
				}
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)("Could not read the internal configuration revision: " + ex.Message));
			}
			return 0;
		}

		private void WriteConfigRevision(ConfigFile config, ConfigDefinition definition)
		{
			try
			{
				IDictionary<ConfigDefinition, string> orphanedEntries = GetOrphanedEntries(config);
				if (orphanedEntries != null)
				{
					orphanedEntries[definition] = 2.ToString(CultureInfo.InvariantCulture);
					return;
				}
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)("Could not write the internal configuration revision: " + ex.Message));
				return;
			}
			_logger.LogWarning((object)"Could not access the internal configuration revision store.");
		}

		private static IDictionary<ConfigDefinition, string>? GetOrphanedEntries(ConfigFile config)
		{
			return OrphanedEntriesProperty?.GetValue(config) as IDictionary<ConfigDefinition, string>;
		}
	}
	internal enum EventRunState
	{
		Inactive,
		Waiting,
		Active,
		Countdown
	}
	internal enum EventMode
	{
		RandomEachEvent,
		FixedForStage,
		FixedPerExtraction,
		PersistentForStage
	}
	[Flags]
	internal enum StageEffect
	{
		None = 0,
		Feather = 1,
		ZeroGravity = 2,
		Battery = 4,
		Heal = 8,
		Indestructible = 0x10,
		Roll = 0x20,
		Void = 0x40
	}
	internal static class StageEffectSet
	{
		internal const StageEffect All = StageEffect.Feather | StageEffect.ZeroGravity | StageEffect.Battery | StageEffect.Heal | StageEffect.Indestructible | StageEffect.Roll | StageEffect.Void;

		internal static readonly IReadOnlyList<StageEffect> IndividualEffects = new StageEffect[7]
		{
			StageEffect.Feather,
			StageEffect.ZeroGravity,
			StageEffect.Battery,
			StageEffect.Heal,
			StageEffect.Indestructible,
			StageEffect.Roll,
			StageEffect.Void
		};

		internal static bool Contains(StageEffect effects, StageEffect effect)
		{
			if (effect != StageEffect.None)
			{
				return (effects & effect) == effect;
			}
			return false;
		}

		internal static bool IsValid(StageEffect effects)
		{
			return (effects & ~(StageEffect.Feather | StageEffect.ZeroGravity | StageEffect.Battery | StageEffect.Heal | StageEffect.Indestructible | StageEffect.Roll | StageEffect.Void)) == 0;
		}

		internal static string Format(StageEffect effects, string separator, bool compactZeroGravity = false)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (StageEffect individualEffect in IndividualEffects)
			{
				if (!Contains(effects, individualEffect))
				{
					continue;
				}
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(separator);
				}
				StringBuilder stringBuilder2 = stringBuilder;
				StageEffect stageEffect = individualEffect;
				string value;
				if (stageEffect != StageEffect.ZeroGravity)
				{
					if (stageEffect != StageEffect.Roll)
					{
						goto IL_005b;
					}
					value = "Roll";
				}
				else
				{
					if (compactZeroGravity)
					{
						goto IL_005b;
					}
					value = "Zero Gravity";
				}
				goto IL_006a;
				IL_005b:
				value = individualEffect.ToString();
				goto IL_006a;
				IL_006a:
				stringBuilder2.Append(value);
			}
			if (stringBuilder.Length <= 0)
			{
				return "None";
			}
			return stringBuilder.ToString();
		}
	}
	internal readonly struct HudState
	{
		internal EventRunState State { get; }

		internal StageEffect Effect { get; }

		internal int DurationSeconds { get; }

		internal int IntervalSeconds { get; }

		internal int RemainingSeconds { get; }

		internal HudState(EventRunState state, StageEffect effect, int durationSeconds, int intervalSeconds, int remainingSeconds)
		{
			State = state;
			Effect = effect;
			DurationSeconds = durationSeconds;
			IntervalSeconds = intervalSeconds;
			RemainingSeconds = remainingSeconds;
		}
	}
	internal readonly struct TargetFilter
	{
		internal bool Valuables { get; }

		internal bool Items { get; }

		internal bool Doors { get; }

		internal bool Weapons { get; }

		internal bool Players { get; }

		internal bool Enemies { get; }

		internal TargetFilter(bool valuables, bool items, bool doors, bool weapons, bool players, bool enemies)
		{
			Valuables = valuables;
			Items = items;
			Doors = doors;
			Weapons = weapons;
			Players = players;
			Enemies = enemies;
		}

		internal bool Allows(PhysGrabObject physObject)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)physObject).GetComponentInParent<PlayerAvatar>() != (Object)null)
			{
				return Players;
			}
			if ((Object)(object)((Component)physObject).GetComponent<EnemyRigidbody>() != (Object)null || (Object)(object)((Component)physObject).GetComponentInParent<EnemyRigidbody>() != (Object)null || (Object)(object)((Component)physObject).GetComponentInParent<EnemyParent>() != (Object)null)
			{
				return Enemies;
			}
			if ((Object)(object)((Component)physObject).GetComponent<PhysGrabHinge>() != (Object)null || (Object)(object)((Component)physObject).GetComponentInParent<PhysGrabHinge>() != (Object)null || (Object)(object)((Component)physObject).GetComponentInChildren<PhysGrabHinge>(true) != (Object)null)
			{
				return Doors;
			}
			if ((Object)(object)((Component)physObject).GetComponent<ValuableObject>() != (Object)null)
			{
				return Valuables;
			}
			ItemAttributes component = ((Component)physObject).GetComponent<ItemAttributes>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.item != (Object)null && IsWeapon(component.item.itemType))
			{
				return Weapons;
			}
			return Items;
		}

		private static bool IsWeapon(itemType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			if ((int)type != 9 && (int)type != 7 && (int)type != 15 && (int)type != 6)
			{
				return (int)type == 11;
			}
			return true;
		}
	}
	internal sealed class StagePhysicsEffectCarrierMarker : MonoBehaviour
	{
	}
	internal static class PhysGrabObjectRegistry
	{
		private static readonly HashSet<PhysGrabObject> Objects = new HashSet<PhysGrabObject>();

		private static readonly List<PhysGrabObject> Stale = new List<PhysGrabObject>();

		internal static void Register(PhysGrabObject? physObject)
		{
			if ((Object)(object)physObject != (Object)null)
			{
				Objects.Add(physObject);
			}
		}

		internal static void SeedFromScene()
		{
			PhysGrabObject[] array = Object.FindObjectsOfType<PhysGrabObject>();
			for (int i = 0; i < array.Length; i++)
			{
				Register(array[i]);
			}
		}

		internal static List<PhysGrabObject> Snapshot(TargetFilter filter, bool discoverEnemies = true)
		{
			List<PhysGrabObject> list = new List<PhysGrabObject>(Objects.Count);
			HashSet<PhysGrabObject> hashSet = new HashSet<PhysGrabObject>();
			Stale.Clear();
			foreach (PhysGrabObject @object in Objects)
			{
				if ((Object)(object)@object == (Object)null)
				{
					continue;
				}
				try
				{
					if ((Object)(object)((Component)@object).GetComponent<StagePhysicsEffectCarrierMarker>() == (Object)null && ((Component)@object).gameObject.activeInHierarchy && (Object)(object)@object.rb != (Object)null && filter.Allows(@object) && hashSet.Add(@object))
					{
						list.Add(@object);
					}
				}
				catch
				{
					Stale.Add(@object);
				}
			}
			foreach (PhysGrabObject item in Stale)
			{
				Objects.Remove(item);
			}
			Objects.RemoveWhere((PhysGrabObject physObject) => (Object)(object)physObject == (Object)null);
			if (filter.Enemies && discoverEnemies)
			{
				EnemyRigidbody[] array = Object.FindObjectsOfType<EnemyRigidbody>();
				foreach (EnemyRigidbody val in array)
				{
					if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy)
					{
						PhysGrabObject val2 = ((Component)val).GetComponent<PhysGrabObject>() ?? ((Component)val).GetComponentInChildren<PhysGrabObject>(true) ?? ((Component)val).GetComponentInParent<PhysGrabObject>();
						if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.rb == (Object)null) && !((Object)(object)((Component)val2).GetComponent<StagePhysicsEffectCarrierMarker>() != (Object)null) && hashSet.Add(val2))
						{
							Objects.Add(val2);
							list.Add(val2);
						}
					}
				}
			}
			return list;
		}

		internal static void Clear()
		{
			Objects.Clear();
			Stale.Clear();
		}
	}
	internal sealed class VanillaEffectResolver
	{
		private const int MaxAttempts = 5;

		private int _featherAttempts;

		private int _zeroGravityAttempts;

		private int _rollStaffAttempts;

		private int _voidAttempts;

		private bool _featherFailed;

		private bool _zeroGravityFailed;

		private bool _rollStaffFailed;

		private bool _voidFailed;

		private readonly Dictionary<StageEffect, GameObject> _orbPrefabs = new Dictionary<StageEffect, GameObject>();

		private readonly Dictionary<StageEffect, string> _orbResourcePaths = new Dictionary<StageEffect, string>();

		private readonly Dictionary<StageEffect, int> _orbAttempts = new Dictionary<StageEffect, int>();

		private readonly HashSet<StageEffect> _orbFailures = new HashSet<StageEffect>();

		internal GameObject? FeatherPrefab { get; private set; }

		internal string? FeatherResourcePath { get; private set; }

		internal GameObject? ZeroGravityProjectilePrefab { get; private set; }

		internal GameObject? ZeroGravityAffectPrefab { get; private set; }

		internal string? ZeroGravityProjectileResourcePath { get; private set; }

		internal GameObject? RollStaffProjectilePrefab { get; private set; }

		internal GameObject? RollStaffAffectPrefab { get; private set; }

		internal string? RollStaffProjectileResourcePath { get; private set; }

		internal GameObject? VoidPrefab { get; private set; }

		internal string? VoidResourcePath { get; private set; }

		internal bool TryResolveOrb(StageEffect effect, out GameObject? prefab, out string? resourcePath)
		{
			if (_orbPrefabs.TryGetValue(effect, out GameObject value) && _orbResourcePaths.TryGetValue(effect, out string value2))
			{
				prefab = value;
				resourcePath = value2;
				return true;
			}
			prefab = null;
			resourcePath = null;
			if (_orbFailures.Contains(effect))
			{
				return false;
			}
			Type type = OrbComponentType(effect);
			string text = OrbItemName(effect);
			if (type == null || string.IsNullOrEmpty(text))
			{
				return false;
			}
			Item val = Resources.Load<Item>("Items/" + text) ?? Resources.Load<Item>("Items/Removed Items/" + text);
			if (!IsOrbItem(val, type))
			{
				Item[] array = Resources.FindObjectsOfTypeAll<Item>();
				foreach (Item val2 in array)
				{
					if (IsOrbItem(val2, type))
					{
						val = val2;
						break;
					}
				}
			}
			if (IsOrbItem(val, type))
			{
				prefab = ((PrefabRef<GameObject>)(object)val.prefab).Prefab;
				resourcePath = ((PrefabRef<GameObject>)(object)val.prefab).ResourcePath;
				_orbPrefabs[effect] = prefab;
				_orbResourcePaths[effect] = resourcePath;
				StagePhysicsEventsPlugin.ModLogger.LogInfo((object)$"Resolved vanilla {effect} Orb: {resourcePath}");
				return true;
			}
			int value3;
			int num = ((!_orbAttempts.TryGetValue(effect, out value3)) ? 1 : (value3 + 1));
			_orbAttempts[effect] = num;
			if (num >= 5)
			{
				_orbFailures.Add(effect);
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Vanilla {effect} Orb could not be resolved; the event is unavailable.");
			}
			return false;
		}

		internal bool ResolveFeather()
		{
			if ((Object)(object)FeatherPrefab != (Object)null && !string.IsNullOrEmpty(FeatherResourcePath))
			{
				return true;
			}
			if (_featherFailed)
			{
				return false;
			}
			Item val = Resources.Load<Item>("Items/Item Orb Feather") ?? Resources.Load<Item>("Items/Removed Items/Item Orb Feather");
			if (!IsFeatherItem(val))
			{
				Item[] array = Resources.FindObjectsOfTypeAll<Item>();
				foreach (Item val2 in array)
				{
					if (IsFeatherItem(val2))
					{
						val = val2;
						break;
					}
				}
			}
			if (IsFeatherItem(val))
			{
				FeatherPrefab = ((PrefabRef<GameObject>)(object)val.prefab).Prefab;
				FeatherResourcePath = ((PrefabRef<GameObject>)(object)val.prefab).ResourcePath;
				StagePhysicsEventsPlugin.ModLogger.LogInfo((object)("Resolved vanilla Feather Orb: " + FeatherResourcePath));
				return true;
			}
			if (++_featherAttempts >= 5)
			{
				_featherFailed = true;
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Vanilla Feather Orb could not be resolved; Feather events are unavailable.");
			}
			return false;
		}

		internal bool ResolveZeroGravity()
		{
			if ((Object)(object)ZeroGravityProjectilePrefab != (Object)null && (Object)(object)ZeroGravityAffectPrefab != (Object)null && !string.IsNullOrEmpty(ZeroGravityProjectileResourcePath))
			{
				return true;
			}
			if (_zeroGravityFailed || (Object)(object)StatsManager.instance == (Object)null)
			{
				return false;
			}
			int num = 0;
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				GameObject val = ((!((Object)(object)value != (Object)null)) ? null : ((PrefabRef<GameObject>)(object)value.prefab)?.Prefab);
				ItemStaffZeroGravity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<ItemStaffZeroGravity>(true) : null);
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				PrefabRef projectilePrefab = val2.projectilePrefab;
				if (projectilePrefab == null || (Object)(object)((PrefabRef<GameObject>)(object)projectilePrefab).Bundle != (Object)null || !((PrefabRef<GameObject>)(object)projectilePrefab).IsValid() || string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)projectilePrefab).ResourcePath))
				{
					num++;
					continue;
				}
				GameObject prefab = ((PrefabRef<GameObject>)(object)projectilePrefab).Prefab;
				GameObject val3 = ((PrefabRef<GameObject>)(object)(((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<SemiAreaOfEffect>(true) : null)?.semiAffectPrefab)?.Prefab;
				if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponentInChildren<SemiAffectZeroGravity>(true) == (Object)null)
				{
					continue;
				}
				ZeroGravityProjectilePrefab = prefab;
				ZeroGravityAffectPrefab = val3;
				ZeroGravityProjectileResourcePath = ((PrefabRef<GameObject>)(object)projectilePrefab).ResourcePath;
				StagePhysicsEventsPlugin.ModLogger.LogInfo((object)$"Resolved vanilla zero-gravity projectile: {ZeroGravityProjectileResourcePath} (skipped look-alikes: {num}).");
				return true;
			}
			if (++_zeroGravityAttempts >= 5)
			{
				_zeroGravityFailed = true;
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Vanilla zero-gravity staff could not be resolved; Zero Gravity events are unavailable.");
			}
			return false;
		}

		internal bool ResolveRollStaff()
		{
			if ((Object)(object)RollStaffProjectilePrefab != (Object)null && (Object)(object)RollStaffAffectPrefab != (Object)null && !string.IsNullOrEmpty(RollStaffProjectileResourcePath))
			{
				return true;
			}
			if (_rollStaffFailed || (Object)(object)StatsManager.instance == (Object)null)
			{
				return false;
			}
			int num = 0;
			foreach (Item value in StatsManager.instance.itemDictionary.Values)
			{
				GameObject val = ((!((Object)(object)value != (Object)null)) ? null : ((PrefabRef<GameObject>)(object)value.prefab)?.Prefab);
				ItemStaffTorque val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<ItemStaffTorque>(true) : null);
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				PrefabRef projectilePrefab = val2.projectilePrefab;
				if (projectilePrefab == null || (Object)(object)((PrefabRef<GameObject>)(object)projectilePrefab).Bundle != (Object)null || !((PrefabRef<GameObject>)(object)projectilePrefab).IsValid() || string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)projectilePrefab).ResourcePath))
				{
					num++;
					continue;
				}
				GameObject prefab = ((PrefabRef<GameObject>)(object)projectilePrefab).Prefab;
				GameObject val3 = ((PrefabRef<GameObject>)(object)(((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<SemiAreaOfEffect>(true) : null)?.semiAffectPrefab)?.Prefab;
				if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetComponentInChildren<SemiAffectTorque>(true) == (Object)null)
				{
					continue;
				}
				RollStaffProjectilePrefab = prefab;
				RollStaffAffectPrefab = val3;
				RollStaffProjectileResourcePath = ((PrefabRef<GameObject>)(object)projectilePrefab).ResourcePath;
				StagePhysicsEventsPlugin.ModLogger.LogInfo((object)$"Resolved vanilla Roll Staff projectile: {RollStaffProjectileResourcePath} (skipped look-alikes: {num}).");
				return true;
			}
			if (++_rollStaffAttempts >= 5)
			{
				_rollStaffFailed = true;
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Vanilla Roll Staff could not be resolved; Roll Staff events are unavailable.");
			}
			return false;
		}

		internal bool ResolveVoid()
		{
			if ((Object)(object)VoidPrefab != (Object)null && !string.IsNullOrEmpty(VoidResourcePath))
			{
				return true;
			}
			if (_voidFailed)
			{
				return false;
			}
			ItemStaffVoid val = ResolveVoidStaff(Resources.Load<Item>("Items/Item Staff Void") ?? Resources.Load<Item>("Items/Removed Items/Item Staff Void"));
			if ((Object)(object)val == (Object)null)
			{
				Item[] array = Resources.FindObjectsOfTypeAll<Item>();
				for (int i = 0; i < array.Length; i++)
				{
					val = ResolveVoidStaff(array[i]);
					if ((Object)(object)val != (Object)null)
					{
						break;
					}
				}
			}
			PrefabRef val2 = val?.prefabToInstantiateOnHit;
			if (val2 != null && (Object)(object)((PrefabRef<GameObject>)(object)val2).Bundle == (Object)null && ((PrefabRef<GameObject>)(object)val2).IsValid() && !string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)val2).ResourcePath))
			{
				VoidPrefab = ((PrefabRef<GameObject>)(object)val2).Prefab;
				VoidResourcePath = ((PrefabRef<GameObject>)(object)val2).ResourcePath;
				StagePhysicsEventsPlugin.ModLogger.LogInfo((object)("Resolved vanilla Void Staff effect: " + VoidResourcePath));
				return true;
			}
			if (++_voidAttempts >= 5)
			{
				_voidFailed = true;
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Vanilla Void Staff effect could not be resolved; the Void event is unavailable.");
			}
			return false;
		}

		private static bool IsFeatherItem(Item? item)
		{
			try
			{
				if ((Object)(object)item == (Object)null || item.prefab == null || (Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Bundle != (Object)null || !((PrefabRef<GameObject>)(object)item.prefab).IsValid() || string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)item.prefab).ResourcePath))
				{
					return false;
				}
				GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab;
				return (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponentInChildren<ItemOrbFeather>(true) != (Object)null;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static bool IsOrbItem(Item? item, Type componentType)
		{
			try
			{
				if ((Object)(object)item == (Object)null || item.prefab == null || (Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Bundle != (Object)null || !((PrefabRef<GameObject>)(object)item.prefab).IsValid() || string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)item.prefab).ResourcePath))
				{
					return false;
				}
				GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab;
				return (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponentInChildren(componentType, true) != (Object)null;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static ItemStaffVoid? ResolveVoidStaff(Item? item)
		{
			try
			{
				if ((Object)(object)item == (Object)null || item.prefab == null || (Object)(object)((PrefabRef<GameObject>)(object)item.prefab).Bundle != (Object)null || !((PrefabRef<GameObject>)(object)item.prefab).IsValid() || string.IsNullOrEmpty(((PrefabRef<GameObject>)(object)item.prefab).ResourcePath))
				{
					return null;
				}
				GameObject prefab = ((PrefabRef<GameObject>)(object)item.prefab).Prefab;
				return (prefab != null) ? prefab.GetComponentInChildren<ItemStaffVoid>(true) : null;
			}
			catch (Exception)
			{
				return null;
			}
		}

		private static Type? OrbComponentType(StageEffect effect)
		{
			return effect switch
			{
				StageEffect.Battery => typeof(ItemOrbBattery), 
				StageEffect.Heal => typeof(ItemOrbHeal), 
				StageEffect.Indestructible => typeof(ItemOrbIndestructible), 
				_ => null, 
			};
		}

		private static string? OrbItemName(StageEffect effect)
		{
			return effect switch
			{
				StageEffect.Battery => "Item Orb Battery", 
				StageEffect.Heal => "Item Orb Heal", 
				StageEffect.Indestructible => "Item Orb Indestructible", 
				_ => null, 
			};
		}
	}
	internal sealed class FeatherOrbEffectAdapter
	{
		private sealed class FollowOrb
		{
			internal PlayerAvatar Player { get; }

			internal GameObject Orb { get; }

			internal FollowOrb(PlayerAvatar player, GameObject orb)
			{
				Player = player;
				Orb = orb;
			}
		}

		private static readonly FieldInfo? ObjectAffectedField = AccessTools.Field(typeof(ItemOrb), "objectAffected");

		private static readonly FieldInfo? LocalPlayerAffectedField = AccessTools.Field(typeof(ItemOrb), "localPlayerAffected");

		private readonly MonoBehaviour _coroutineOwner;

		private readonly VanillaEffectResolver _resolver;

		private readonly Dictionary<int, FollowOrb> _followOrbs = new Dictionary<int, FollowOrb>();

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

		private readonly List<PhysGrabObject> _targets = new List<PhysGrabObject>();

		private GameObject? _virtualOrb;

		private ItemOrb? _virtualItemOrb;

		internal FeatherOrbEffectAdapter(MonoBehaviour coroutineOwner, VanillaEffectResolver resolver)
		{
			_coroutineOwner = coroutineOwner;
			_resolver = resolver;
		}

		internal bool EnsureAvailable()
		{
			if (ObjectAffectedField != null)
			{
				return _resolver.ResolveFeather();
			}
			return false;
		}

		internal void ApplyOnce(IReadOnlyList<PhysGrabObject> targets, IReadOnlyList<PlayerAvatar> players)
		{
			if (!EnsureAvailable())
			{
				return;
			}
			EnsureVirtualOrb();
			_targets.Clear();
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PhysGrabObject target in targets)
			{
				if ((Object)(object)target != (Object)null && hashSet.Add(((Object)target).GetInstanceID()))
				{
					_targets.Add(target);
				}
			}
			if ((Object)(object)_virtualItemOrb != (Object)null)
			{
				try
				{
					ObjectAffectedField.SetValue(_virtualItemOrb, new List<PhysGrabObject>(_targets));
					_virtualItemOrb.itemActive = true;
				}
				catch (Exception ex)
				{
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)("Could not refresh virtual Feather Orb targets: " + ex.Message));
				}
			}
			SyncFollowOrbs(players);
			UpdateFollowOrbPositions();
		}

		internal void AddTarget(PhysGrabObject target)
		{
			if (!EnsureAvailable() || (Object)(object)target == (Object)null || (Object)(object)((Component)target).GetComponent<StagePhysicsEffectCarrierMarker>() != (Object)null)
			{
				return;
			}
			foreach (PhysGrabObject target2 in _targets)
			{
				if ((Object)(object)target2 == (Object)(object)target)
				{
					return;
				}
			}
			_targets.Add(target);
			EnsureVirtualOrb();
			if (!((Object)(object)_virtualItemOrb != (Object)null))
			{
				return;
			}
			try
			{
				ObjectAffectedField.SetValue(_virtualItemOrb, new List<PhysGrabObject>(_targets));
				_virtualItemOrb.itemActive = true;
			}
			catch (Exception ex)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)("Could not add a new Feather target: " + ex.Message));
			}
		}

		internal void TickFollowOrbs()
		{
			_staleKeys.Clear();
			UpdateFollowOrbPositions();
			foreach (KeyValuePair<int, FollowOrb> followOrb in _followOrbs)
			{
				FollowOrb value = followOrb.Value;
				if ((Object)(object)value.Player == (Object)null || (Object)(object)value.Orb == (Object)null)
				{
					DestroyFollowOrb(value.Orb);
					_staleKeys.Add(followOrb.Key);
					continue;
				}
				ItemBattery component = value.Orb.GetComponent<ItemBattery>();
				if ((Object)(object)component != (Object)null)
				{
					component.autoDrain = false;
					component.batteryLife = 100f;
				}
			}
			foreach (int staleKey in _staleKeys)
			{
				_followOrbs.Remove(staleKey);
			}
		}

		internal void RefreshPlayer(PlayerAvatar player)
		{
			if (!EnsureAvailable() || (Object)(object)player == (Object)null || !((Component)player).gameObject.activeInHierarchy)
			{
				return;
			}
			if ((Object)(object)player.photonView != (Object)null)
			{
				int key = ((player.photonView.ViewID != 0) ? player.photonView.ViewID : ((Object)player).GetInstanceID());
				if (_followOrbs.TryGetValue(key, out FollowOrb value))
				{
					DestroyFollowOrb(value.Orb);
					_followOrbs.Remove(key);
				}
			}
			EnsureFollowOrb(player);
			UpdateFollowOrbPositions();
		}

		internal void Stop()
		{
			if ((Object)(object)_virtualItemOrb != (Object)null)
			{
				_virtualItemOrb.itemActive = false;
				try
				{
					ObjectAffectedField?.SetValue(_virtualItemOrb, new List<PhysGrabObject>());
				}
				catch
				{
				}
			}
			if ((Object)(object)_virtualOrb != (Object)null)
			{
				Object.Destroy((Object)(object)_virtualOrb);
			}
			_virtualOrb = null;
			_virtualItemOrb = null;
			_targets.Clear();
			foreach (FollowOrb value in _followOrbs.Values)
			{
				DestroyFollowOrb(value.Orb);
			}
			_followOrbs.Clear();
		}

		private void EnsureVirtualOrb()
		{
			//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)
			if ((Object)(object)_virtualOrb != (Object)null)
			{
				return;
			}
			_virtualOrb = Object.Instantiate<GameObject>(_resolver.FeatherPrefab, new Vector3(0f, -1000f, 0f), Quaternion.identity);
			((Object)_virtualOrb).name = "StagePhysicsEvents_VirtualFeatherOrb";
			((Object)_virtualOrb).hideFlags = (HideFlags)61;
			_virtualItemOrb = _virtualOrb.GetComponent<ItemOrb>();
			if ((Object)(object)_virtualItemOrb == (Object)null)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Resolved Feather Orb prefab has no ItemOrb component.");
				Object.Destroy((Object)(object)_virtualOrb);
				_virtualOrb = null;
				return;
			}
			_virtualItemOrb.itemActive = true;
			Behaviour[] componentsInChildren = _virtualOrb.GetComponentsInChildren<Behaviour>(true);
			foreach (Behaviour obj in componentsInChildren)
			{
				obj.enabled = obj is ItemOrbFeather;
			}
			Renderer[] componentsInChildren2 = _virtualOrb.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			Collider[] componentsInChildren3 = _virtualOrb.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				componentsInChildren3[i].enabled = false;
			}
			AudioSource[] componentsInChildren4 = _virtualOrb.GetComponentsInChildren<AudioSource>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				((Behaviour)componentsInChildren4[i]).enabled = false;
			}
			Rigidbody[] componentsInChildren5 = _virtualOrb.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj2 in componentsInChildren5)
			{
				obj2.isKinematic = true;
				obj2.detectCollisions = false;
			}
		}

		private void SyncFollowOrbs(IReadOnlyList<PlayerAvatar> players)
		{
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PlayerAvatar player in players)
			{
				if (!((Object)(object)player == (Object)null) && !((Object)(object)player.photonView == (Object)null) && ((Component)player).gameObject.activeInHierarchy)
				{
					int item = ((player.photonView.ViewID != 0) ? player.photonView.ViewID : ((Object)player).GetInstanceID());
					hashSet.Add(item);
					EnsureFollowOrb(player);
				}
			}
			_staleKeys.Clear();
			foreach (KeyValuePair<int, FollowOrb> followOrb in _followOrbs)
			{
				if (!hashSet.Contains(followOrb.Key) || (Object)(object)followOrb.Value.Player == (Object)null || (Object)(object)followOrb.Value.Orb == (Object)null)
				{
					DestroyFollowOrb(followOrb.Value.Orb);
					_staleKeys.Add(followOrb.Key);
				}
			}
			foreach (int staleKey in _staleKeys)
			{
				_followOrbs.Remove(staleKey);
			}
		}

		private void EnsureFollowOrb(PlayerAvatar player)
		{
			if ((Object)(object)player.photonView == (Object)null)
			{
				return;
			}
			int key = ((player.photonView.ViewID != 0) ? player.photonView.ViewID : ((Object)player).GetInstanceID());
			if (!_followOrbs.TryGetValue(key, out FollowOrb value) || !((Object)(object)value.Orb != (Object)null))
			{
				GameObject val = CreateFollowOrb(player);
				if ((Object)(object)val != (Object)null)
				{
					_followOrbs[key] = new FollowOrb(player, val);
				}
			}
		}

		private GameObject? CreateFollowOrb(PlayerAvatar player)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 position = ((Component)player).transform.position;
				GameObject val;
				if (SemiFunc.IsMultiplayer())
				{
					object[] array = new object[3] { 0.01f, 0.01f, 0.01f };
					val = PhotonNetwork.Instantiate(_resolver.FeatherResourcePath, position, Quaternion.identity, (byte)0, array);
				}
				else
				{
					val = Object.Instantiate<GameObject>(_resolver.FeatherPrefab, position, Quaternion.identity);
					val.transform.localScale = Vector3.one * 0.01f;
				}
				((Object)val).name = "StagePhysicsEvents_PlayerFeatherOrb";
				val.AddComponent<StagePhysicsEffectCarrierMarker>();
				_coroutineOwner.StartCoroutine(InitializeFollowOrbAfterStart(val, player));
				return val;
			}
			catch (Exception arg)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Could not create player Feather Orb: {arg}");
				return null;
			}
		}

		private static IEnumerator InitializeFollowOrbAfterStart(GameObject orb, PlayerAvatar player)
		{
			yield return null;
			if ((Object)(object)orb == (Object)null || (Object)(object)player == (Object)null)
			{
				yield break;
			}
			try
			{
				ItemOrb component = orb.GetComponent<ItemOrb>();
				if ((Object)(object)component == (Object)null)
				{
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Player Feather Orb has no ItemOrb component after initialization.");
					yield break;
				}
				component.targetEnemies = false;
				component.targetNonValuables = false;
				component.targetValuables = false;
				component.targetPlayers = true;
				ItemBattery component2 = orb.GetComponent<ItemBattery>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.autoDrain = false;
					component2.batteryLife = 100f;
				}
				ItemToggle component3 = orb.GetComponent<ItemToggle>();
				if ((Object)(object)component3 == (Object)null)
				{
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Player Feather Orb has no ItemToggle component after initialization.");
					yield break;
				}
				component3.ToggleItem(true, 0);
				ObjectAffectedField?.SetValue(component, new List<PhysGrabObject>());
				bool flag = (Object)(object)PlayerController.instance?.playerAvatarScript == (Object)(object)player;
				LocalPlayerAffectedField?.SetValue(component, flag);
				component.itemActive = true;
				((Behaviour)component).enabled = false;
				ManualLogSource modLogger = StagePhysicsEventsPlugin.ModLogger;
				PhotonView photonView = player.photonView;
				object arg = ((photonView != null) ? photonView.ViewID : 0);
				object arg2 = flag;
				PhotonView component4 = orb.GetComponent<PhotonView>();
				modLogger.LogDebug((object)$"Player Feather Orb activated: playerView={arg}, hostLocal={arg2}, orbView={((component4 != null) ? component4.ViewID : 0)}");
			}
			catch (Exception arg3)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Could not initialize player Feather Orb: {arg3}");
			}
		}

		private void UpdateFollowOrbPositions()
		{
			//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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			foreach (FollowOrb value in _followOrbs.Values)
			{
				if (!((Object)(object)value.Orb == (Object)null) && !((Object)(object)value.Player == (Object)null))
				{
					Vector3 position = ((Component)value.Player).transform.position;
					PhysGrabObject component = value.Orb.GetComponent<PhysGrabObject>();
					if ((Object)(object)component != (Object)null && (Object)(object)component.rb != (Object)null)
					{
						component.rb.position = position;
						component.rb.velocity = Vector3.zero;
						component.rb.angularVelocity = Vector3.zero;
					}
					value.Orb.transform.position = position;
				}
			}
		}

		private static void DestroyFollowOrb(GameObject? orb)
		{
			if ((Object)(object)orb == (Object)null)
			{
				return;
			}
			try
			{
				ItemOrb component = orb.GetComponent<ItemOrb>();
				if ((Object)(object)component != (Object)null)
				{
					component.itemActive = false;
					ObjectAffectedField?.SetValue(component, new List<PhysGrabObject>());
					LocalPlayerAffectedField?.SetValue(component, false);
				}
				ItemToggle component2 = orb.GetComponent<ItemToggle>();
				if (component2 != null)
				{
					component2.ToggleItem(false, 0);
				}
				if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
				{
					PhotonView component3 = orb.GetComponent<PhotonView>();
					if (component3 == null || component3.ViewID != 0)
					{
						PhotonNetwork.Destroy(orb);
						return;
					}
				}
				Object.Destroy((Object)(object)orb);
			}
			catch (Exception ex)
			{
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)("Feather Orb cleanup deferred to scene unload: " + ex.Message));
			}
		}
	}
	internal sealed class AdditionalOrbEffectAdapter
	{
		private static readonly FieldInfo? ObjectAffectedField = AccessTools.Field(typeof(ItemOrb), "objectAffected");

		private readonly MonoBehaviour _coroutineOwner;

		private readonly VanillaEffectResolver _resolver;

		private readonly StagePhysicsConfig _config;

		private readonly List<PhysGrabObject> _targets = new List<PhysGrabObject>();

		private readonly List<PlayerAvatar> _healPlayers = new List<PlayerAvatar>();

		private GameObject? _carrier;

		private ItemOrb? _itemOrb;

		private StageEffect _effect;

		private Coroutine? _batteryCoroutine;

		private Coroutine? _healCoroutine;

		private int _carrierGeneration;

		internal AdditionalOrbEffectAdapter(MonoBehaviour coroutineOwner, VanillaEffectResolver resolver, StagePhysicsConfig config)
		{
			_coroutineOwner = coroutineOwner;
			_resolver = resolver;
			_config = config;
		}

		internal static bool Supports(StageEffect effect)
		{
			if (effect != StageEffect.Battery && effect != StageEffect.Heal)
			{
				return effect == StageEffect.Indestructible;
			}
			return true;
		}

		internal bool EnsureAvailable(StageEffect effect)
		{
			GameObject prefab;
			string resourcePath;
			if (Supports(effect) && (effect == StageEffect.Heal || ObjectAffectedField != null))
			{
				return _resolver.TryResolveOrb(effect, out prefab, out resourcePath);
			}
			return false;
		}

		internal void ApplyOnce(StageEffect effect, IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureAvailable(effect))
			{
				return;
			}
			if (_effect != effect)
			{
				Stop();
				_effect = effect;
			}
			if (effect == StageEffect.Heal)
			{
				_healPlayers.Clear();
				foreach (PlayerAvatar player in players)
				{
					if ((Object)(object)player != (Object)null && ((Component)player).gameObject.activeInHierarchy)
					{
						_healPlayers.Add(player);
					}
				}
				if (_healCoroutine == null)
				{
					_healCoroutine = _coroutineOwner.StartCoroutine(HealLoop());
				}
				return;
			}
			_targets.Clear();
			foreach (PhysGrabObject @object in objects)
			{
				if (!((Object)(object)@object == (Object)null) && !((Object)(object)((Component)@object).GetComponent<StagePhysicsEffectCarrierMarker>() != (Object)null) && (effect != StageEffect.Battery || !((Object)(object)((Component)@object).GetComponent<ItemBattery>() == (Object)null)))
				{
					_targets.Add(@object);
				}
			}
			if (effect == StageEffect.Battery)
			{
				if (_batteryCoroutine == null)
				{
					_batteryCoroutine = _coroutineOwner.StartCoroutine(BatteryLoop());
				}
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)$"Battery charge loop activated with {_targets.Count} stage target(s).");
			}
			else if ((Object)(object)_carrier == (Object)null)
			{
				CreateCarrier(effect, HiddenPosition());
			}
			else
			{
				SetCarrierPosition(HiddenPosition());
				SetTargets();
			}
		}

		internal void Tick()
		{
			if (!((Object)(object)_carrier == (Object)null) && !((Object)(object)_itemOrb == (Object)null))
			{
				_itemOrb.itemActive = true;
				ItemBattery component = _carrier.GetComponent<ItemBattery>();
				if ((Object)(object)component != (Object)null)
				{
					component.autoDrain = false;
					component.batteryLife = 100f;
				}
			}
		}

		internal void AddPlayer(PlayerAvatar player)
		{
			if (_effect == StageEffect.Heal && !((Object)(object)player == (Object)null) && ((Component)player).gameObject.activeInHierarchy && !_healPlayers.Contains(player))
			{
				_healPlayers.Add(player);
				if (_healCoroutine == null)
				{
					_healCoroutine = _coroutineOwner.StartCoroutine(HealLoop());
				}
			}
		}

		internal void AddTarget(PhysGrabObject target)
		{
			if ((_effect != StageEffect.Battery && _effect != StageEffect.Indestructible) || (Object)(object)target == (Object)null || (Object)(object)((Component)target).GetComponent<StagePhysicsEffectCarrierMarker>() != (Object)null || (_effect == StageEffect.Battery && (Object)(object)((Component)target).GetComponent<ItemBattery>() == (Object)null))
			{
				return;
			}
			foreach (PhysGrabObject target2 in _targets)
			{
				if ((Object)(object)target2 == (Object)(object)target)
				{
					return;
				}
			}
			_targets.Add(target);
			SetTargets();
		}

		internal void Stop()
		{
			_carrierGeneration++;
			if (_batteryCoroutine != null)
			{
				_coroutineOwner.StopCoroutine(_batteryCoroutine);
				_batteryCoroutine = null;
			}
			if (_healCoroutine != null)
			{
				_coroutineOwner.StopCoroutine(_healCoroutine);
				_healCoroutine = null;
			}
			_healPlayers.Clear();
			_targets.Clear();
			if ((Object)(object)_itemOrb != (Object)null)
			{
				_itemOrb.itemActive = false;
				try
				{
					ObjectAffectedField?.SetValue(_itemOrb, new List<PhysGrabObject>());
				}
				catch
				{
				}
			}
			if ((Object)(object)_carrier != (Object)null)
			{
				Object.Destroy((Object)(object)_carrier);
			}
			_carrier = null;
			_itemOrb = null;
			_effect = StageEffect.None;
		}

		private void CreateCarrier(StageEffect effect, Vector3 position)
		{
			//IL_001f: 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)
			if (!_resolver.TryResolveOrb(effect, out GameObject prefab, out string _) || (Object)(object)prefab == (Object)null)
			{
				return;
			}
			try
			{
				_carrier = Object.Instantiate<GameObject>(prefab, position, Quaternion.identity);
				((Object)_carrier).name = $"StagePhysicsEvents_Virtual{effect}Orb";
				((Object)_carrier).hideFlags = (HideFlags)61;
				_carrier.AddComponent<StagePhysicsEffectCarrierMarker>();
				Renderer[] componentsInChildren = _carrier.GetComponentsInChildren<Renderer>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].enabled = false;
				}
				Collider[] componentsInChildren2 = _carrier.GetComponentsInChildren<Collider>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
				AudioSource[] componentsInChildren3 = _carrier.GetComponentsInChildren<AudioSource>(true);
				for (int i = 0; i < componentsInChildren3.Length; i++)
				{
					((Behaviour)componentsInChildren3[i]).enabled = false;
				}
				DisableCarrierPhysics(_carrier);
				int generation = ++_carrierGeneration;
				_coroutineOwner.StartCoroutine(InitializeCarrierAfterStart(effect, generation));
			}
			catch (Exception arg)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Could not create virtual {effect} Orb: {arg}");
				Stop();
			}
		}

		private IEnumerator InitializeCarrierAfterStart(StageEffect effect, int generation)
		{
			yield return null;
			if ((Object)(object)_carrier == (Object)null || _effect != effect || generation != _carrierGeneration)
			{
				yield break;
			}
			try
			{
				_itemOrb = _carrier.GetComponent<ItemOrb>();
				Behaviour val = ResolveEffectBehaviour(_carrier, effect);
				if ((Object)(object)_itemOrb == (Object)null || (Object)(object)val == (Object)null)
				{
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Resolved {effect} Orb prefab is missing its required component.");
					Stop();
					yield break;
				}
				Behaviour[] componentsInChildren = _carrier.GetComponentsInChildren<Behaviour>(true);
				foreach (Behaviour obj in componentsInChildren)
				{
					obj.enabled = (Object)(object)obj == (Object)(object)val;
				}
				DisableCarrierPhysics(_carrier);
				ItemBattery component = _carrier.GetComponent<ItemBattery>();
				if ((Object)(object)component != (Object)null)
				{
					component.autoDrain = false;
					component.batteryLife = 100f;
				}
				_itemOrb.itemActive = true;
				SetTargets();
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)$"Virtual {effect} Orb activated with {_targets.Count} stage target(s).");
			}
			catch (Exception arg)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Could not initialize virtual {effect} Orb: {arg}");
				Stop();
			}
		}

		private IEnumerator HealLoop()
		{
			while (_effect == StageEffect.Heal)
			{
				yield return (object)new WaitForSeconds((float)_config.HealIntervalSeconds.Value);
				if (_effect != StageEffect.Heal)
				{
					break;
				}
				foreach (PlayerAvatar healPlayer in _healPlayers)
				{
					if (!((Object)(object)healPlayer == (Object)null) && ((Component)healPlayer).gameObject.activeInHierarchy && !((Object)(object)healPlayer.playerHealth == (Object)null))
					{
						try
						{
							healPlayer.playerHealth.HealOther(_config.HealAmount.Value, true);
						}
						catch (Exception ex)
						{
							ManualLogSource modLogger = StagePhysicsEventsPlugin.ModLogger;
							PhotonView photonView = healPlayer.photonView;
							modLogger.LogDebug((object)$"Heal Orb target skipped for player view {((photonView != null) ? photonView.ViewID : 0)}: {ex.Message}");
						}
					}
				}
			}
			_healCoroutine = null;
		}

		private IEnumerator BatteryLoop()
		{
			while (_effect == StageEffect.Battery)
			{
				yield return (object)new WaitForSeconds((float)_config.BatteryChargeIntervalSeconds.Value);
				if (_effect != StageEffect.Battery)
				{
					break;
				}
				float num = (float)_config.BatteryChargeAmount.Value * 10f;
				foreach (PhysGrabObject target in _targets)
				{
					if ((Object)(object)target == (Object)null || !((Component)target).gameObject.activeInHierarchy)
					{
						continue;
					}
					ItemBattery component = ((Component)target).GetComponent<ItemBattery>();
					if (!((Object)(object)component == (Object)null) && !(component.batteryLife >= 100f))
					{
						try
						{
							component.ChargeBattery(((Component)_coroutineOwner).gameObject, num);
						}
						catch (Exception ex)
						{
							StagePhysicsEventsPlugin.ModLogger.LogDebug((object)("Battery target skipped for " + ((Object)target).name + ": " + ex.Message));
						}
					}
				}
			}
			_batteryCoroutine = null;
		}

		private void SetTargets()
		{
			if (!((Object)(object)_itemOrb == (Object)null))
			{
				ObjectAffectedField?.SetValue(_itemOrb, new List<PhysGrabObject>(_targets));
				_itemOrb.itemActive = true;
			}
		}

		private void SetCarrierPosition(Vector3 position)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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)
			if (!((Object)(object)_carrier == (Object)null))
			{
				_carrier.transform.position = position;
				PhysGrabObject component = _carrier.GetComponent<PhysGrabObject>();
				if ((Object)(object)component != (Object)null && (Object)(object)component.rb != (Object)null)
				{
					component.rb.position = position;
					component.rb.velocity = Vector3.zero;
					component.rb.angularVelocity = Vector3.zero;
				}
			}
		}

		private static Vector3 HiddenPosition()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(0f, -1000f, 0f);
		}

		private static Behaviour? ResolveEffectBehaviour(GameObject carrier, StageEffect effect)
		{
			return (Behaviour?)(effect switch
			{
				StageEffect.Battery => carrier.GetComponent<ItemOrbBattery>(), 
				StageEffect.Indestructible => carrier.GetComponent<ItemOrbIndestructible>(), 
				_ => null, 
			});
		}

		private static void DisableCarrierPhysics(GameObject carrier)
		{
			//IL_001e: 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)
			Rigidbody[] componentsInChildren = carrier.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody obj in componentsInChildren)
			{
				obj.isKinematic = true;
				obj.detectCollisions = false;
				obj.velocity = Vector3.zero;
				obj.angularVelocity = Vector3.zero;
			}
		}
	}
	internal sealed class VoidStaffEffectAdapter
	{
		private readonly VanillaEffectResolver _resolver;

		private readonly List<GameObject> _spawned = new List<GameObject>();

		internal VoidStaffEffectAdapter(VanillaEffectResolver resolver)
		{
			_resolver = resolver;
		}

		internal bool EnsureAvailable()
		{
			return _resolver.ResolveVoid();
		}

		internal void ApplyOnce(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players, int spawnCount)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureAvailable() || spawnCount <= 0)
			{
				return;
			}
			Stop();
			List<Vector3> list = CollectStagePositions(objects, players);
			if (list.Count == 0)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)"Void event found no valid stage positions.");
				return;
			}
			Shuffle(list);
			int num = 0;
			for (int i = 0; i < spawnCount; i++)
			{
				Vector3 val = list[i % list.Count] + Vector3.up * 0.1f;
				try
				{
					GameObject val2 = (SemiFunc.IsMultiplayer() ? PhotonNetwork.Instantiate(_resolver.VoidResourcePath, val, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(_resolver.VoidPrefab, val, Quaternion.identity));
					((Object)val2).name = "StagePhysicsEvents_Void";
					val2.AddComponent<StagePhysicsEffectCarrierMarker>();
					_spawned.Add(val2);
					num++;
				}
				catch (Exception ex)
				{
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Could not create Void Staff effect at {val}: {ex.Message}");
				}
			}
			StagePhysicsEventsPlugin.ModLogger.LogInfo((object)$"Void Staff event created {num}/{spawnCount} effect(s) at random stage points.");
		}

		internal void Stop()
		{
			foreach (GameObject item in _spawned)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				try
				{
					PhotonView val = item.GetComponent<PhotonView>() ?? item.GetComponentInParent<PhotonView>() ?? item.GetComponentInChildren<PhotonView>(true);
					if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient && (Object)(object)val != (Object)null && val.ViewID != 0)
					{
						PhotonNetwork.Destroy(((Component)val).gameObject);
					}
					else if (!SemiFunc.IsMultiplayer())
					{
						Object.Destroy((Object)(object)item);
					}
				}
				catch (Exception ex)
				{
					StagePhysicsEventsPlugin.ModLogger.LogDebug((object)("Void effect cleanup deferred to scene unload: " + ex.Message));
				}
			}
			_spawned.Clear();
		}

		private static List<Vector3> CollectStagePositions(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players)
		{
			//IL_00d9: 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_012e: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			HashSet<int> hashSet = new HashSet<int>();
			try
			{
				List<LevelPoint> list2 = SemiFunc.LevelPointsGetAll();
				if (list2 != null)
				{
					foreach (LevelPoint item in list2)
					{
						if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy && hashSet.Add(((Object)item).GetInstanceID()))
						{
							list.Add(((Component)item).transform.position);
						}
					}
				}
			}
			catch (Exception ex)
			{
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)("Level-point collection for Void event failed: " + ex.Message));
			}
			if (list.Count > 0)
			{
				return list;
			}
			foreach (PhysGrabObject @object in objects)
			{
				if ((Object)(object)@object != (Object)null && hashSet.Add(((Object)@object).GetInstanceID()))
				{
					list.Add(((Component)@object).transform.position);
				}
			}
			foreach (PlayerAvatar player in players)
			{
				if ((Object)(object)player != (Object)null && hashSet.Add(((Object)player).GetInstanceID()))
				{
					list.Add(((Component)player).transform.position);
				}
			}
			return list;
		}

		private static void Shuffle(IList<Vector3> positions)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			for (int num = positions.Count - 1; num > 0; num--)
			{
				int num2 = Random.Range(0, num + 1);
				int index = num;
				int index2 = num2;
				Vector3 value = positions[num2];
				Vector3 value2 = positions[num];
				positions[index] = value;
				positions[index2] = value2;
			}
		}
	}
	internal sealed class ValuableIndestructibleProtection
	{
		private readonly List<PhysGrabObject> _valuables = new List<PhysGrabObject>();

		private float _startsAt;

		private float _endsAt;

		internal void Schedule(IReadOnlyList<PhysGrabObject> valuables, float startsAt, float endsAt)
		{
			_valuables.Clear();
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PhysGrabObject valuable in valuables)
			{
				if ((Object)(object)valuable != (Object)null && (Object)(object)((Component)valuable).GetComponent<ValuableObject>() != (Object)null && hashSet.Add(((Object)valuable).GetInstanceID()))
				{
					_valuables.Add(valuable);
				}
			}
			_startsAt = startsAt;
			_endsAt = Mathf.Max(startsAt, endsAt);
			StagePhysicsEventsPlugin.ModLogger.LogDebug((object)($"Valuable Indestructible protection scheduled: targets={_valuables.Count}, " + $"startsIn={Mathf.Max(0f, _startsAt - Time.time):0.##}s, duration={Mathf.Max(0f, _endsAt - _startsAt):0.##}s."));
		}

		internal void Tick()
		{
			if (_valuables.Count == 0 || Time.time < _startsAt)
			{
				return;
			}
			if (Time.time > _endsAt)
			{
				Stop();
				return;
			}
			for (int num = _valuables.Count - 1; num >= 0; num--)
			{
				PhysGrabObject val = _valuables[num];
				if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
				{
					_valuables.RemoveAt(num);
				}
				else
				{
					val.OverrideIndestructible(0.1f);
				}
			}
		}

		internal void AddTarget(PhysGrabObject valuable)
		{
			if ((Object)(object)valuable == (Object)null || (Object)(object)((Component)valuable).GetComponent<ValuableObject>() == (Object)null)
			{
				return;
			}
			foreach (PhysGrabObject valuable2 in _valuables)
			{
				if ((Object)(object)valuable2 == (Object)(object)valuable)
				{
					return;
				}
			}
			_valuables.Add(valuable);
		}

		internal void Stop()
		{
			_valuables.Clear();
			_startsAt = 0f;
			_endsAt = 0f;
		}
	}
	internal enum StaffAffectKind
	{
		ZeroGravity,
		Roll
	}
	internal sealed class StaffAffectBroadcaster
	{
		private const int BatchSize = 96;

		private static readonly FieldInfo? SingleplayerObjectsField = AccessTools.Field(typeof(SemiAreaOfEffect), "targetPhysObjectsForSingleplayer");

		private static readonly FieldInfo? SingleplayerPlayersField = AccessTools.Field(typeof(SemiAreaOfEffect), "playerAvatars");

		private static readonly MethodInfo? CreateAffectsMethod = AccessTools.Method(typeof(SemiAreaOfEffect), "CreateAffectsRPC", (Type[])null, (Type[])null);

		private readonly MonoBehaviour _coroutineOwner;

		private readonly VanillaEffectResolver _resolver;

		private readonly StaffAffectKind _kind;

		private GameObject? ProjectilePrefab
		{
			get
			{
				if (_kind != StaffAffectKind.ZeroGravity)
				{
					return _resolver.RollStaffProjectilePrefab;
				}
				return _resolver.ZeroGravityProjectilePrefab;
			}
		}

		private GameObject? AffectPrefab
		{
			get
			{
				if (_kind != StaffAffectKind.ZeroGravity)
				{
					return _resolver.RollStaffAffectPrefab;
				}
				return _resolver.ZeroGravityAffectPrefab;
			}
		}

		private string? ProjectileResourcePath
		{
			get
			{
				if (_kind != StaffAffectKind.ZeroGravity)
				{
					return _resolver.RollStaffProjectileResourcePath;
				}
				return _resolver.ZeroGravityProjectileResourcePath;
			}
		}

		private string EffectLabel
		{
			get
			{
				if (_kind != StaffAffectKind.ZeroGravity)
				{
					return "Roll";
				}
				return "Zero Gravity";
			}
		}

		internal StaffAffectBroadcaster(MonoBehaviour coroutineOwner, VanillaEffectResolver resolver, StaffAffectKind kind)
		{
			_coroutineOwner = coroutineOwner;
			_resolver = resolver;
			_kind = kind;
		}

		internal bool EnsureAvailable()
		{
			if (_kind != StaffAffectKind.ZeroGravity)
			{
				return _resolver.ResolveRollStaff();
			}
			return _resolver.ResolveZeroGravity();
		}

		internal void ApplyOnce(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players, float durationSeconds)
		{
			//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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			if (!EnsureAvailable() || durationSeconds <= 0f)
			{
				return;
			}
			float affectTime = Mathf.Max(0.05f, durationSeconds * ((_kind == StaffAffectKind.ZeroGravity) ? 0.5f : 1f));
			float affectTime2 = Mathf.Max(0.05f, durationSeconds * 0.5f);
			Vector3 direction = EffectDirection();
			BuildSingleplayerTargets(objects, players, out List<PhysGrabObject> targetObjects, out List<PlayerAvatar> targetPlayers);
			if (!SemiFunc.IsMultiplayer())
			{
				if (_kind == StaffAffectKind.Roll)
				{
					foreach (PhysGrabObject item in targetObjects)
					{
						ApplySingleplayer((IReadOnlyList<PhysGrabObject>)(object)new PhysGrabObject[1] { item }, Array.Empty<PlayerAvatar>(), affectTime, RandomHorizontalDirection());
					}
					ApplySingleplayer(Array.Empty<PhysGrabObject>(), targetPlayers, affectTime2, direction);
				}
				else
				{
					ApplySingleplayer(targetObjects, targetPlayers, affectTime, direction);
				}
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			HashSet<int> hashSet2 = new HashSet<int>();
			foreach (PlayerAvatar item2 in targetPlayers)
			{
				if ((Object)(object)item2 != (Object)null && (Object)(object)item2.photonView != (Object)null && item2.photonView.ViewID != 0)
				{
					hashSet2.Add(item2.photonView.ViewID);
				}
			}
			foreach (PhysGrabObject item3 in targetObjects)
			{
				PhotonView val = ResolveTargetView(item3);
				if ((Object)(object)val != (Object)null && val.ViewID != 0)
				{
					hashSet.Add(val.ViewID);
				}
			}
			if (_kind == StaffAffectKind.Roll)
			{
				FireViewIds(hashSet, affectTime, direction, individualRandomDirections: true);
				FireViewIds(hashSet2, affectTime2, direction);
			}
			else
			{
				hashSet.UnionWith(hashSet2);
				FireViewIds(hashSet, affectTime, direction);
			}
		}

		private void FireViewIds(HashSet<int> viewIds, float affectTime, Vector3 direction, bool individualRandomDirections = false)
		{
			//IL_002d: 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)
			List<int> list = new List<int>(96);
			foreach (int viewId in viewIds)
			{
				list.Add(viewId);
				if (list.Count == 96)
				{
					FireBatch(list, affectTime, direction, individualRandomDirections);
					list.Clear();
				}
			}
			if (list.Count > 0)
			{
				FireBatch(list, affectTime, direction, individualRandomDirections);
			}
		}

		internal void Stop()
		{
		}

		private void FireBatch(List<int> viewIds, float affectTime, Vector3 direction, bool individualRandomDirections)
		{
			//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_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(0f, -1000f, 0f);
				GameObject val2 = PhotonNetwork.Instantiate(ProjectileResourcePath, val, Quaternion.identity, (byte)0, (object[])null);
				val2.AddComponent<StagePhysicsEffectCarrierMarker>();
				SlowProjectile component = val2.GetComponent<SlowProjectile>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				SemiAreaOfEffect componentInChildren = val2.GetComponentInChildren<SemiAreaOfEffect>(true);
				PhotonView val3 = (((Object)(object)componentInChildren != (Object)null) ? (((Component)componentInChildren).GetComponent<PhotonView>() ?? ((Component)componentInChildren).GetComponentInParent<PhotonView>() ?? ((Component)componentInChildren).GetComponentInChildren<PhotonView>(true)) : null);
				if ((Object)(object)componentInChildren == (Object)null || (Object)(object)val3 == (Object)null)
				{
					PhotonNetwork.Destroy(val2);
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)(EffectLabel + " carrier has no accessible SemiAreaOfEffect PhotonView; RPC batch was skipped."));
					return;
				}
				if (individualRandomDirections)
				{
					foreach (int viewId in viewIds)
					{
						val3.RPC("CreateAffectsRPC", (RpcTarget)0, new object[4]
						{
							new int[1] { viewId },
							new float[1] { affectTime },
							val,
							RandomHorizontalDirection()
						});
					}
					StagePhysicsEventsPlugin.ModLogger.LogDebug((object)$"{EffectLabel} RPC batch sent: targets={viewIds.Count}, effectTimer={affectTime:0.##}s, direction=random-horizontal, view={val3.ViewID}.");
				}
				else
				{
					int[] array = viewIds.ToArray();
					float[] array2 = new float[array.Length];
					Array.Fill(array2, affectTime);
					val3.RPC("CreateAffectsRPC", (RpcTarget)0, new object[4] { array, array2, val, direction });
					StagePhysicsEventsPlugin.ModLogger.LogDebug((object)$"{EffectLabel} RPC batch sent: targets={array.Length}, effectTimer={affectTime:0.##}s, direction={direction}, view={val3.ViewID}.");
				}
				_coroutineOwner.StartCoroutine(DestroyCarrierLater(val2, networked: true));
			}
			catch (Exception ex)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)(EffectLabel + " RPC batch failed: " + ex.Message));
			}
		}

		private void ApplySingleplayer(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players, float affectTime, Vector3 direction)
		{
			//IL_0213: 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_006f: 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)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			if (SingleplayerObjectsField == null || SingleplayerPlayersField == null || CreateAffectsMethod == null)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)("Standard singleplayer " + EffectLabel + " carrier API is unavailable; using direct vanilla SemiAffect fallback."));
				ApplySingleplayerDirect(objects, players, affectTime, direction);
				return;
			}
			try
			{
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(0f, -1000f, 0f);
				GameObject val2 = Object.Instantiate<GameObject>(ProjectilePrefab, val, Quaternion.identity);
				val2.AddComponent<StagePhysicsEffectCarrierMarker>();
				SlowProjectile component = val2.GetComponent<SlowProjectile>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				SemiAreaOfEffect componentInChildren = val2.GetComponentInChildren<SemiAreaOfEffect>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					Object.Destroy((Object)(object)val2);
					StagePhysicsEventsPlugin.ModLogger.LogWarning((object)("Singleplayer " + EffectLabel + " carrier has no SemiAreaOfEffect; using direct vanilla SemiAffect fallback."));
					ApplySingleplayerDirect(objects, players, affectTime, direction);
					return;
				}
				BuildSingleplayerTargets(objects, players, out List<PhysGrabObject> targetObjects, out List<PlayerAvatar> targetPlayers);
				if (targetObjects.Count == 0 && targetPlayers.Count == 0)
				{
					Object.Destroy((Object)(object)val2);
					return;
				}
				SingleplayerObjectsField.SetValue(componentInChildren, targetObjects);
				SingleplayerPlayersField.SetValue(componentInChildren, targetPlayers);
				componentInChildren.affectTimeMin = affectTime;
				componentInChildren.affectTimeMax = affectTime;
				componentInChildren.enemyLowestDifficultyTimeMin = affectTime;
				componentInChildren.enemyLowestDifficultyTimeMax = affectTime;
				componentInChildren.enemyHighestDifficultyTimeMin = affectTime;
				componentInChildren.enemyHighestDifficultyTimeMax = affectTime;
				CreateAffectsMethod.Invoke(componentInChildren, new object[5]
				{
					Array.Empty<int>(),
					Array.Empty<float>(),
					val,
					direction,
					(object)default(PhotonMessageInfo)
				});
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)$"Singleplayer {EffectLabel} carrier applied: objects={targetObjects.Count}, players={targetPlayers.Count}, effectTimer={affectTime:0.##}s.");
				_coroutineOwner.StartCoroutine(DestroyCarrierLater(val2, networked: false));
			}
			catch (Exception arg)
			{
				StagePhysicsEventsPlugin.ModLogger.LogWarning((object)$"Singleplayer {EffectLabel} carrier failed; using direct vanilla SemiAffect fallback: {arg}");
				ApplySingleplayerDirect(objects, players, affectTime, direction);
			}
		}

		private static void BuildSingleplayerTargets(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players, out List<PhysGrabObject> targetObjects, out List<PlayerAvatar> targetPlayers)
		{
			targetObjects = new List<PhysGrabObject>();
			targetPlayers = new List<PlayerAvatar>();
			HashSet<int> hashSet = new HashSet<int>();
			HashSet<int> hashSet2 = new HashSet<int>();
			foreach (PhysGrabObject @object in objects)
			{
				if ((Object)(object)@object == (Object)null || !hashSet.Add(((Object)@object).GetInstanceID()))
				{
					continue;
				}
				PlayerAvatar componentInParent = ((Component)@object).GetComponentInParent<PlayerAvatar>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					if (hashSet2.Add(((Object)componentInParent).GetInstanceID()))
					{
						targetPlayers.Add(componentInParent);
					}
				}
				else
				{
					targetObjects.Add(@object);
				}
			}
			foreach (PlayerAvatar player in players)
			{
				if ((Object)(object)player != (Object)null && hashSet2.Add(((Object)player).GetInstanceID()))
				{
					targetPlayers.Add(player);
				}
			}
		}

		private void ApplySingleplayerDirect(IReadOnlyList<PhysGrabObject> objects, IReadOnlyList<PlayerAvatar> players, float affectTime, Vector3 direction)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			HashSet<int> hashSet = new HashSet<int>();
			foreach (PhysGrabObject @object in objects)
			{
				if (!((Object)(object)@object == (Object)null) && hashSet.Add(((Object)@object).GetInstanceID()))
				{
					PlayerAvatar componentInParent = ((Component)@object).GetComponentInParent<PlayerAvatar>();
					SpawnSingleplayerAffect(@object, componentInParent, affectTime, direction);
				}
			}
			foreach (PlayerAvatar player in players)
			{
				if (!((Object)(object)player == (Object)null))
				{
					PhysGrabObject componentInChildren = ((Component)player).GetComponentInChildren<PhysGrabObject>(true);
					if ((Object)(object)componentInChildren != (Object)null && hashSet.Add(((Object)componentInChildren).GetInstanceID()))
					{
						SpawnSingleplayerAffect(componentInChildren, player, affectTime, direction);
					}
				}
			}
		}

		private void SpawnSingleplayerAffect(PhysGrabObject target, PlayerAvatar? player, float affectTime, Vector3 direction)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = Object.Instantiate<GameObject>(AffectPrefab, ((Component)target).transform.position, Quaternion.identity);
				SemiAffect component = val.GetComponent<SemiAffect>();
				if ((Object)(object)component == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return;
				}
				component.direction = direction;
				component.positionOfOriginalAreaOfEffect = ((Component)target).transform.position;
				component.SetupSingleplayer(((Component)target).transform, target, affectTime, player);
			}
			catch (Exception ex)
			{
				StagePhysicsEventsPlugin.ModLogger.LogDebug((object)("Singleplayer " + EffectLabel + " target skipped: " + ex.Message));
			}
		}

		private Vector3 EffectDirection()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (_kind == StaffAffectKind.ZeroGravity)
			{
				return Vector3.up;
			}
			return Vector3.forward;
		}

		private static Vector3 RandomHorizontalDirection()
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			float num = Random.Range(0f, 360f);
			return Quaternion.Euler(0f, num, 0f) * Vector3.forward;
		}

		private static PhotonView? ResolveTargetView(PhysGrabObject physObject)
		{
			PlayerAvatar componentInParent = ((Component)physObject).GetComponentInParent<PlayerAvatar>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return componentInParent.photonView;
			}
			return ((Component)physObject).GetComponent<PhotonView>() ?? ((Component)physObject).GetComponentInParent<PhotonView>() ?? ((Component)physObject).GetComponentInChildren<PhotonView>(true);
		}

		private static IEnumerator DestroyCarrierLater(GameObject carrier, bool networked)
		{
			yield return (object)new WaitForSeconds(1f);
			if (!((Object)(object)carrier == (Object)null))
			{
				if (networked && PhotonNetwork.IsMasterClient)
				{
					PhotonNetwork.Destroy(carrier);
				}
				else if (!networked)
				{
					Object.Destroy((Object)(object)carrier);
				}
			}
		}
	}
	internal sealed class VanillaEventNotifier
	{
		private readonly MonoBehaviour _coroutineOwner;

		private readonly StagePhysicsConfig _config;

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

		private int _stageGeneration;

		private string _stageMessage = string.Empty;

		internal VanillaEventNotifier(MonoBehaviour coroutineOwner, StagePhysicsConfig config)
		{
			_coroutineOwner = coroutineOwner;
			_config = config;
		}

		internal void BeginStage(int stageGeneration, string stageMessage)
		{
			_stageGeneration = stageGeneration;
			_stageMessage = stageMessage;
			_notifiedActors.Clear();
			if (_config.StageStartChatEnabled.Value && !string.IsNullOrEmpty(_stageMessage) && SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				_coroutineOwner.StartCoroutine(NotifyAllAfterCapabilityGrace(stageGeneration));
			}
		}

		internal void PlayerEntered(Player player)
		{
			if (_config.StageStartChatEnabled.Value && !string.IsNullOrEmpty(_stageMessage) && PhotonNetwork.IsMasterClient)
			{
				_coroutineOwner.StartCoroutine(NotifyPlayerAfterCapabilityGrace(player, _stageGeneration));
			}
		}

		internal void EndStage()
		{
			_stageGeneration++;
			_notifiedActors.Clear();
			_stageMessage = string.Empty;
		}

		internal void EventStarted(StageEffect effect)
		{
			SendEventMessage(StageEffectSet.Format(effect, "/", compactZeroGravity: true));
		}

		internal void Countdown(int seconds)
		{
			SendEventMessage(seconds.ToString());
		}

		internal void EventEnded()
		{
			SendEventMessage("End");
		}

		private IEnumerator NotifyAllAfterCapabilityGrace(int generation)
		{
			yield return (object)new WaitForSeconds(2f);
			yield return WaitUntilReady(generation);
			if (CanNotify(generation))
			{
				Player[] playerListOthers = PhotonNetwork.PlayerListOthers;
				foreach (Player val in playerListOthers)
				{
					_notifiedActors.Add(val.ActorNumber);
				}
				if (!ForceAllPlayersToSpeak(_stageMessage))
				{
					_notifiedActors.Clear();
				}
			}
		}

		private IEnumerator NotifyPlayerAfterCapabilityGrace(Player player, int generation)
		{
			yield return (object)new WaitForSeconds(2f);
			yield return WaitUntilReady(generation);
			if (CanNotify(generation) && player != null)
			{
				NotifyLateJoiner(player);
			}
		}

		private bool CanNotify(int generation)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (generation == _stageGeneration && PhotonNetwork.IsMasterClient && (Object)(object)GameDirector.instance != (Object)null)
			{
				return (int)GameDirector.instance.currentState == 2;
			}
			return false;
		}

		private IEnumerator WaitUntilReady(int generation)
		{
			float deadline = Time.time + 10f;
			while (generation == _stageGeneration && PhotonNetwork.IsMasterClient && !CanNot