Decompiled source of MoreStandsForShops v1.1.17

MoreStandsForShops.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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 MoreStandsForShops.Network;
using MoreStandsForShops.Rewriters;
using MoreStandsForShops.Shop;
using MoreStandsForShops.Spawners;
using MoreStandsForShops.Stands.Upgrade;
using MoreStandsForShops.Utilities;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MoreStandsForShops")]
[assembly: AssemblyDescription("More shop stands for R.E.P.O.")]
[assembly: AssemblyCompany("DarkSpider90")]
[assembly: AssemblyProduct("MoreStandsForShops")]
[assembly: AssemblyCopyright("Copyright (c) 2026 DarkSpider90")]
[assembly: ComVisible(false)]
[assembly: Guid("2BE30F9F-3160-41F9-BC85-989F4333B8B2")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 MoreStandsForShops
{
	public static class CleanPresetDatabase
	{
		private const string LevelPrefix = "Level Generator/Level/";

		public static List<SpawnPointData> GetSpawnPoints()
		{
			List<SpawnPointData> list = new List<SpawnPointData>();
			list.Add(Point("center_extract_right_rear", "Module - Shop - N - Center Extract(Clone)", 7.04f, 0.03f, -5.075f, 270f, 34, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Center Extract(Clone)/WALLS/RIGHT/Not Connected/shop sign lynx" }));
			list.Add(Point("center_extract_right_mid", "Module - Shop - N - Center Extract(Clone)", 7.04f, 0.03f, -1.635f, 270f, 1, Array.Empty<string>()));
			list.Add(Point("center_extract_top_mid", "Module - Shop - N - Center Extract(Clone)", 0.471f, 0.03f, 7.04f, 180f, 1, new string[2] { "Main/Level Generator/Level/Module - Shop - N - Center Extract(Clone)/WALLS/TOP/Not Connected/Candy Shelf 2", "Main/Level Generator/Level/Module - Shop - N - Center Extract(Clone)/WALLS/TOP/Not Connected/Shop prop fridge" }));
			list.Add(Point("corner_stands_bottom_left", "Module - Shop - N - Corner Stands(Clone)", -1.72f, 0.03f, -7.04f, 0f, 1, new string[3] { "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/Shop Ice Cream Freezer", "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/shop sign tyre (1)", "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/shop sign tyre (2)" }));
			list.Add(Point("corner_stands_bottom_mid", "Module - Shop - N - Corner Stands(Clone)", 0.637f, 0.03f, -7.04f, 0f, 8, new string[3] { "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/Candy Shelf 2", "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/Shop Ice Cream Freezer", "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/BOT/Not Connected/shop sign tyre (1)" }));
			list.Add(Point("corner_stands_left_mid", "Module - Shop - N - Corner Stands(Clone)", -7.04f, 0.03f, -1.868f, 90f, 5, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/LEFT/Not Connected/Shop Ice Cream Freezer (1)" }));
			list.Add(Point("corner_stands_right_secret", "Module - Shop - N - Corner Stands(Clone)", 7.04f, 0.03f, -1.349f, 270f, 1, new string[2] { "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/RIGHT/Not Connected/Shop Magazine Holder", "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/RIGHT/Not Connected/shop sign lynx" }));
			list.Add(Point("corner_stands_right_mid", "Module - Shop - N - Corner Stands(Clone)", 7.04f, 0.03f, -0.682f, 270f, 5, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Corner Stands(Clone)/WALLS/RIGHT/Not Connected/Shop Magazine Holder" }));
			list.Add(Point("corner_stands_top_mid", "Module - Shop - N - Corner Stands(Clone)", 0.054f, 0.03f, 7.04f, 180f, 9, Array.Empty<string>()));
			list.Add(Point("middle_stands_left_secret", "Module - Shop - N - Middle Stands(Clone)", -7.04f, 0.03f, -1.385f, 90f, 1, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/LEFT/Not Connected/shop sign ai" }));
			list.Add(Point("middle_stands_left_mid", "Module - Shop - N - Middle Stands(Clone)", -7.04f, 0.03f, -0.481f, 90f, 1, new string[2] { "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/LEFT/Not Connected/shop sign ai", "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/LEFT/Not Connected/shop sign hotdog" }));
			list.Add(Point("middle_stands_right_mid", "Module - Shop - N - Middle Stands(Clone)", 7.04f, 0.03f, -0.639f, 270f, 5, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/RIGHT/Not Connected/Shop Magazine Holder" }));
			list.Add(Point("middle_stands_top_left", "Module - Shop - N - Middle Stands(Clone)", -5.504f, 0.03f, 7.04f, 180f, 13, new string[2] { "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/RIGHT/Not Connected/Shop Magazine Holder", "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/TOP/Not Connected/Shop Magazine Stand (1)" }));
			list.Add(Point("middle_stands_top_car_service", "Module - Shop - N - Middle Stands(Clone)", -4.184f, 0.03f, 7.04f, 180f, 1, new string[1] { "Main/Level Generator/Level/Module - Shop - N - Middle Stands(Clone)/WALLS/TOP/Connected/Soda Machine (1)" }));
			list.Add(Point("middle_stands_top_mid", "Module - Shop - N - Middle Stands(Clone)", 0.051f, 0.03f, 7.04f, 180f, 13, Array.Empty<string>()));
			return list;
		}

		private static SpawnPointData Point(string id, string mainModule, float x, float y, float z, float yaw, int sourceCount, string[] disablePaths)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			return new SpawnPointData
			{
				VariantId = id,
				MainModule = "Level Generator/Level/" + mainModule,
				LocalPosition = new Vector3(x, y, z),
				LocalYaw = yaw,
				SourceCount = sourceCount,
				DisablePaths = disablePaths,
				RejectIfPresentPaths = Array.Empty<string>()
			};
		}
	}
	public class SpawnPointData
	{
		public string VariantId { get; set; }

		public string MainModule { get; set; }

		public Vector3 LocalPosition { get; set; }

		public float LocalYaw { get; set; }

		public int SourceCount { get; set; }

		public string[] DisablePaths { get; set; } = Array.Empty<string>();

		public string[] RejectIfPresentPaths { get; set; } = Array.Empty<string>();
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "DarkSpider90.MoreStandsForShops";

		public const string PLUGIN_NAME = "MoreStandsForShops";

		public const string PLUGIN_VERSION = "1.1.17";
	}
	[BepInPlugin("DarkSpider90.MoreStandsForShops", "MoreStandsForShops", "1.1.17")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<bool> EnableAdditionalUpgradeStand;

		internal static ConfigEntry<bool> EnableVanillaShelfTableRewrite;

		internal static ConfigEntry<bool> DisableShopPoolLimit;

		internal static ConfigEntry<bool> DebugLogs;

		internal static Dictionary<string, ConfigEntry<int>> ItemCounts = new Dictionary<string, ConfigEntry<int>>();

		internal static Dictionary<string, ConfigEntry<int>> SameItemCopies = new Dictionary<string, ConfigEntry<int>>();

		internal static Dictionary<string, ConfigEntry<int>> ItemSpawnChances = new Dictionary<string, ConfigEntry<int>>();

		private static readonly string[] VanillaItemSpawnChanceNames = new string[70]
		{
			"Duct Taped Grenades", "Feather Drone", "Grenade", "Human Grenade", "Indestructible Drone", "Recharge Drone", "Roll Drone", "Rubber Duck", "Shockwave Grenade", "Stun Grenade",
			"Zero Gravity Drone", "Zero Gravity Orb", "Boltzap", "Explosive Mine", "Gun", "Pulse Pistol", "Shockwave Mine", "Shotgun", "Tranq Gun", "Trapzap",
			"Defibro", "Duck Bucket", "Frying Pan", "Phase Bridge", "Photon Blaster", "C.A.R.T.", "Energy Crystal", "Baseball Bat", "C.A.R.T. Cannon", "C.A.R.T. Laser",
			"Extraction Tracker", "Inflatable Hammer", "Leaf Blower", "Prodzap", "Roll Staff", "Semibot Walkies", "Sledge Hammer", "Sword", "Valuable Tracker", "Void Staff",
			"Zero Gravity Staff", "Autoscan Upgrade", "Crouch Rest Upgrade", "Death Head Battery Upgrade", "Extra Jump Upgrade", "Extra Life Upgrade", "Health Upgrade", "Item Resist Upgrade", "Item Value Upgrade", "Mana Regeneration Upgrade",
			"Map Enemy Tracker Upgrade", "Map Player Count Upgrade", "Map Player Tracker Upgrade", "Map Zoom Upgrade", "Range Upgrade", "Scout Cooldown Upgrade", "Sprint Speed Upgrade", "Sprint Usage Upgrade", "Stamina Upgrade", "Strength Upgrade",
			"Tumble Climb Upgrade", "Tumble Launch Upgrade", "Tumble Wings Upgrade", "Valuable Count Upgrade", "Large Health Pack (100)", "Medium Health Pack (50)", "Small Health Pack (25)", "POCKET C.A.R.T.", "Hauler", "Scout"
		};

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			LoadConfig();
			_harmony = new Harmony("DarkSpider90.MoreStandsForShops");
			_harmony.PatchAll();
			Log.LogInfo((object)"MoreStandsForShops v1.1.17 loaded.");
		}

		private void LoadConfig()
		{
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Expected O, but got Unknown
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Expected O, but got Unknown
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Expected O, but got Unknown
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Expected O, but got Unknown
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Expected O, but got Unknown
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Expected O, but got Unknown
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: Expected O, but got Unknown
			//IL_040a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Expected O, but got Unknown
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_0451: Expected O, but got Unknown
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Expected O, but got Unknown
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Expected O, but got Unknown
			//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f6: Expected O, but got Unknown
			//IL_0523: Unknown result type (might be due to invalid IL or missing references)
			//IL_052d: Expected O, but got Unknown
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0564: Expected O, but got Unknown
			//IL_0591: Unknown result type (might be due to invalid IL or missing references)
			//IL_059b: Expected O, but got Unknown
			//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d2: Expected O, but got Unknown
			//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0609: Expected O, but got Unknown
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Mod", true, "Enable or disable the entire mod.");
			EnableAdditionalUpgradeStand = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Additional Upgrade Stand", true, "Spawn a second upgrade stand in the shop.");
			EnableVanillaShelfTableRewrite = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Vanilla Shelf Table Rewrite", true, "Move grenades to the lower health shelf and give vanilla table places safe adaptive item-size slots.");
			DisableShopPoolLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Disable Shop Pool Limit", true, "Attempt the complete configured current-shop pool instead of applying vanilla's accumulated purchase-based pool limit.");
			DebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Debug Logs", false, "Enable detailed debug logging for troubleshooting.");
			string text = "Item Counts";
			ItemCounts["Upgrades Per Stand"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Upgrades Per Stand", 8, new ConfigDescription("Upgrade items per stand (0-14).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 14), Array.Empty<object>()));
			ItemCounts["Total Upgrades"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Total Upgrades", 14, new ConfigDescription("Total upgrade items across the vanilla stand and passive second stand (0-28).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 28), Array.Empty<object>()));
			ItemCounts["Drones"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Drones", 4, new ConfigDescription("Drone items to spawn (0-8).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 8), Array.Empty<object>()));
			ItemCounts["Power Crystals"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Power Crystals", 3, new ConfigDescription("Power crystals (0-5).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 5), Array.Empty<object>()));
			ItemCounts["Orbs"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Orbs", 1, new ConfigDescription("Orbs (0-3).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
			ItemCounts["Grenades"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Grenades", 4, new ConfigDescription("Grenades (0-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			ItemCounts["Mines"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Mines", 2, new ConfigDescription("Mines (0-3).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
			ItemCounts["Melee"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Melee", 4, new ConfigDescription("Melee weapons (0-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			ItemCounts["Guns"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Guns", 4, new ConfigDescription("Guns (0-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			ItemCounts["Launchers"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Launchers (Staff)", 2, new ConfigDescription("Launchers/staffs (0-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			ItemCounts["Tools"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Tools", 2, new ConfigDescription("Tools (0-4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			ItemCounts["Health Packs"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Health Packs", 3, new ConfigDescription("Health packs (0-5).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 5), Array.Empty<object>()));
			ItemCounts["Carts"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Carts", 2, new ConfigDescription("Carts (0-4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			ItemCounts["Pocket Carts"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Pocket Carts", 1, new ConfigDescription("Pocket carts (0-4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			ItemCounts["Vehicles"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "Vehicles", 1, new ConfigDescription("Vehicles (0-4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			ItemCounts["C.A.R.T. Weapons"] = ((BaseUnityPlugin)this).Config.Bind<int>(text, "C.A.R.T. Weapons", 1, new ConfigDescription("Total C.A.R.T. Cannon and C.A.R.T. Laser items (0-4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 4), Array.Empty<object>()));
			string text2 = "Same Item Copies";
			SameItemCopies["Upgrades"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Upgrades", 3, new ConfigDescription("Max copies of the same upgrade item (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Drones"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Drones", 2, new ConfigDescription("Max copies of the same drone (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Guns"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Guns", 2, new ConfigDescription("Max copies of the same gun (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Melee"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Melee", 2, new ConfigDescription("Max copies of the same melee weapon (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Launchers"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Launchers (Staff)", 2, new ConfigDescription("Max copies of the same launcher (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Grenades"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Grenades", 3, new ConfigDescription("Max copies of the same grenade (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Mines"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Mines", 2, new ConfigDescription("Max copies of the same mine (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["Health Packs"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "Health Packs", 2, new ConfigDescription("Max copies of the same health pack (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			SameItemCopies["C.A.R.T. Weapons"] = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "C.A.R.T. Weapons", 1, new ConfigDescription("Max copies of the same C.A.R.T. Cannon or C.A.R.T. Laser item (1-6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>()));
			BindVanillaItemSpawnChanceConfigs();
		}

		private static void BindVanillaItemSpawnChanceConfigs()
		{
			bool createdAny = false;
			string[] vanillaItemSpawnChanceNames = VanillaItemSpawnChanceNames;
			for (int i = 0; i < vanillaItemSpawnChanceNames.Length; i++)
			{
				BindItemSpawnChanceConfig(vanillaItemSpawnChanceNames[i], ref createdAny);
			}
			SaveItemSpawnChanceConfigs(createdAny, $"Created vanilla item spawn chance config entries for {ItemSpawnChances.Count} items.");
		}

		internal static void EnsureItemSpawnChanceConfigs(IEnumerable<Item> items)
		{
			if ((Object)(object)Instance == (Object)null || items == null)
			{
				return;
			}
			bool createdAny = false;
			foreach (Item item in items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					BindItemSpawnChanceConfig(ItemConfigName(item), ref createdAny);
				}
			}
			SaveItemSpawnChanceConfigs(createdAny, $"Created/updated item spawn chance config entries for {ItemSpawnChances.Count} items.");
		}

		internal static int GetItemSpawnChance(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return 0;
			}
			string key = ItemConfigName(item);
			if (!ItemSpawnChances.TryGetValue(key, out var value))
			{
				return 100;
			}
			return value.Value;
		}

		private static void BindItemSpawnChanceConfig(string itemName, ref bool createdAny)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			if (string.IsNullOrWhiteSpace(itemName) || ItemSpawnChances.ContainsKey(itemName))
			{
				return;
			}
			string text = BuildItemSpawnChanceConfigKey(itemName);
			try
			{
				ConfigEntry<int> value = ((BaseUnityPlugin)Instance).Config.Bind<int>("Item Spawn Chances", text, 100, new ConfigDescription("Relative spawn chance/weight for '" + PrintableItemName(itemName) + "'. 0 disables it in this mod's shop pools; 100 is default.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
				ItemSpawnChances[itemName] = value;
				createdAny = true;
				ConfigEntry<bool> debugLogs = DebugLogs;
				if (debugLogs != null && debugLogs.Value && !string.Equals(text, itemName, StringComparison.Ordinal))
				{
					Log.LogInfo((object)("[Config] Unsafe item name mapped to config key '" + text + "'."));
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[Config] Could not create spawn chance setting for '" + PrintableItemName(itemName) + "'. Using default weight 100. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static string BuildItemSpawnChanceConfigKey(string itemName)
		{
			string text = itemName.Trim();
			bool flag = !string.Equals(text, itemName, StringComparison.Ordinal);
			string text2 = text;
			for (int i = 0; i < text2.Length; i++)
			{
				if (IsInvalidConfigKeyCharacter(text2[i]))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return itemName;
			}
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			text2 = text;
			foreach (char c in text2)
			{
				stringBuilder.Append(IsInvalidConfigKeyCharacter(c) ? ' ' : c);
			}
			string text3 = stringBuilder.ToString().Trim();
			if (string.IsNullOrWhiteSpace(text3))
			{
				text3 = "Unnamed Item";
			}
			return $"{text3} (MSFS-{StableConfigHash(itemName):X8})";
		}

		private static bool IsInvalidConfigKeyCharacter(char character)
		{
			bool flag;
			switch (character)
			{
			case '\t':
			case '\n':
			case '"':
			case '\'':
			case '=':
			case '[':
			case '\\':
			case ']':
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (!flag)
			{
				return char.IsControl(character);
			}
			return true;
		}

		private static uint StableConfigHash(string value)
		{
			uint num = 2166136261u;
			foreach (char c in value)
			{
				num ^= c;
				num *= 16777619;
			}
			return num;
		}

		private static string PrintableItemName(string itemName)
		{
			StringBuilder stringBuilder = new StringBuilder(itemName.Length);
			foreach (char c in itemName)
			{
				stringBuilder.Append(char.IsControl(c) ? ' ' : c);
			}
			return stringBuilder.ToString().Trim();
		}

		private static void SaveItemSpawnChanceConfigs(bool createdAny, string successMessage)
		{
			if (!createdAny)
			{
				return;
			}
			try
			{
				((BaseUnityPlugin)Instance).Config.Save();
				Log.LogInfo((object)successMessage);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[Config] Spawn chance settings were created in memory but could not be saved. Shop initialization will continue. " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static string ItemConfigName(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return "<null>";
			}
			if (!string.IsNullOrWhiteSpace(item.itemName))
			{
				return item.itemName;
			}
			return ((Object)item).name;
		}
	}
}
namespace MoreStandsForShops.Utilities
{
	public static class ItemVolumeHelper
	{
		private static readonly Vector3[] CrystalSlotPositions = (Vector3[])(object)new Vector3[5]
		{
			new Vector3(-0.72f, 1.68f, 0.5f),
			new Vector3(-0.36f, 1.68f, 0.5f),
			new Vector3(0f, 1.68f, 0.5f),
			new Vector3(0.36f, 1.68f, 0.5f),
			new Vector3(0.72f, 1.68f, 0.5f)
		};

		private static readonly Vector3[] DroneSlotPositions = (Vector3[])(object)new Vector3[8]
		{
			new Vector3(-0.77f, 1.18f, 0.5f),
			new Vector3(-0.55f, 1.18f, 0.5f),
			new Vector3(-0.33f, 1.18f, 0.5f),
			new Vector3(-0.11f, 1.18f, 0.5f),
			new Vector3(0.11f, 1.18f, 0.5f),
			new Vector3(0.33f, 1.18f, 0.5f),
			new Vector3(0.55f, 1.18f, 0.5f),
			new Vector3(0.77f, 1.18f, 0.5f)
		};

		public static void AssignVolumesForDroneCrystalStand(GameObject stand)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			ItemVolume[] componentsInChildren = stand.GetComponentsInChildren<ItemVolume>(true);
			if (componentsInChildren.Length == 0)
			{
				CreateDroneCrystalVolumes(stand);
				return;
			}
			Array.Sort(componentsInChildren, (ItemVolume a, ItemVolume b) => ((Component)a).transform.position.y.CompareTo(((Component)b).transform.position.y));
			int num = componentsInChildren.Length / 2;
			for (int num2 = 0; num2 < componentsInChildren.Length; num2++)
			{
				bool flag = num2 < num;
				componentsInChildren[num2].itemVolume = (itemVolume)((!flag) ? 4 : 0);
				componentsInChildren[num2].itemSecretShopType = (itemSecretShopType)0;
				MoreStandsShelfVolume obj = ((Component)componentsInChildren[num2]).gameObject.GetComponent<MoreStandsShelfVolume>() ?? ((Component)componentsInChildren[num2]).gameObject.AddComponent<MoreStandsShelfVolume>();
				obj.Zone = ((!flag) ? MoreStandsShelfZone.Crystal : MoreStandsShelfZone.Drone);
				obj.Handled = false;
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)string.Format("[ItemVolumeHelper] Volume {0} (Y={1:F3}) -> {2}", ((Object)componentsInChildren[num2]).name, ((Component)componentsInChildren[num2]).transform.position.y, (num2 < num) ? "small" : "power_crystal"));
				}
			}
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)$"[ItemVolumeHelper] Assigned {num} lower volume(s) to 'small' (drones) and {componentsInChildren.Length - num} upper volume(s) to 'power_crystal'.");
			}
		}

		private static void CreateDroneCrystalVolumes(GameObject stand)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)stand == (Object)null))
			{
				for (int i = 0; i < CrystalSlotPositions.Length; i++)
				{
					CreateVolumeSlot(stand.transform, $"MoreStandsForShops Crystal Slot {i + 1:00}", (itemVolume)4, MoreStandsShelfZone.Crystal, CrystalSlotPositions[i]);
				}
				for (int j = 0; j < DroneSlotPositions.Length; j++)
				{
					CreateVolumeSlot(stand.transform, $"MoreStandsForShops Drone Slot {j + 1:00}", (itemVolume)0, MoreStandsShelfZone.Drone, DroneSlotPositions[j]);
				}
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[ItemVolumeHelper] Created {CrystalSlotPositions.Length} crystal ItemVolume(s) and {DroneSlotPositions.Length} drone ItemVolume(s) on drone/crystal stand.");
				}
			}
		}

		private static ItemVolume CreateVolumeSlot(Transform parent, string name, itemVolume itemVolume, MoreStandsShelfZone zone, Vector3 localPosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.transform.localPosition = localPosition;
			val.transform.localRotation = Quaternion.identity;
			ItemVolume val2 = val.AddComponent<ItemVolume>();
			val2.itemVolume = itemVolume;
			val2.itemSecretShopType = (itemSecretShopType)0;
			MoreStandsShelfVolume moreStandsShelfVolume = val.AddComponent<MoreStandsShelfVolume>();
			moreStandsShelfVolume.Zone = zone;
			moreStandsShelfVolume.Handled = false;
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)$"[ItemVolumeHelper] Created {name} zone={itemVolume} local={localPosition}.");
			}
			return val2;
		}
	}
	public sealed class MoreStandsMultiSizeVolume : MonoBehaviour
	{
		public string GroupId;
	}
	public enum MoreStandsShelfZone
	{
		Drone,
		Crystal,
		Grenade,
		Health
	}
	public sealed class MoreStandsShelfVolume : MonoBehaviour
	{
		public MoreStandsShelfZone Zone;

		public bool Handled;
	}
	public sealed class MoreStandsUpgradeVolume : MonoBehaviour
	{
	}
	internal static class ScenePathUtility
	{
		public static Transform FindTransformByPath(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				return null;
			}
			return ShopSceneCache.Current.FindTransformByPath(path);
		}

		public static string GetTransformPath(Transform transform)
		{
			return ShopSceneCache.Current.GetTransformPath(transform);
		}

		public static List<string> DisableExactPaths(IEnumerable<string> paths, string logPrefix)
		{
			List<string> list = new List<string>();
			HashSet<string> hashSet = new HashSet<string>();
			if (paths == null)
			{
				return list;
			}
			foreach (string path in paths)
			{
				if (string.IsNullOrWhiteSpace(path) || !hashSet.Add(path))
				{
					continue;
				}
				Transform val = FindTransformByPath(path);
				if ((Object)(object)val == (Object)null)
				{
					if (Plugin.DebugLogs.Value)
					{
						Plugin.Log.LogInfo((object)(logPrefix + " Preset disable path not present: " + path));
					}
					continue;
				}
				int num = DisableTree(val, list);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"{logPrefix} Disabled preset blocker: {GetTransformPath(val)} (nodes={num})");
				}
			}
			return list;
		}

		private static int DisableTree(Transform root, List<string> disabled)
		{
			if ((Object)(object)root == (Object)null)
			{
				return 0;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			int num = 0;
			Transform[] array = componentsInChildren;
			foreach (Transform val in array)
			{
				if (!((Object)(object)val == (Object)null) && (((Component)val).gameObject.activeSelf || ((Component)val).gameObject.activeInHierarchy))
				{
					((Component)val).gameObject.SetActive(false);
					disabled.Add(GetTransformPath(val));
					num++;
				}
			}
			return num;
		}

		public static bool HasActivePath(IEnumerable<string> paths, out string activePath)
		{
			activePath = null;
			if (paths == null)
			{
				return false;
			}
			foreach (string path in paths)
			{
				Transform val = FindTransformByPath(path);
				if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy)
				{
					activePath = GetTransformPath(val);
					return true;
				}
			}
			return false;
		}

		public static void RestoreExactPaths(IEnumerable<string> paths, string logPrefix)
		{
			if (paths == null)
			{
				return;
			}
			foreach (string item in new List<string>(paths).OrderBy(PathDepth))
			{
				Transform val = FindTransformByPath(item);
				if (!((Object)(object)val == (Object)null) && !((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
					if (Plugin.DebugLogs.Value)
					{
						Plugin.Log.LogInfo((object)(logPrefix + " Restored: " + item));
					}
				}
			}
		}

		private static int PathDepth(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return 0;
			}
			int num = 1;
			for (int i = 0; i < path.Length; i++)
			{
				if (path[i] == '/')
				{
					num++;
				}
			}
			return num;
		}
	}
	internal sealed class ShopSceneCache
	{
		private static ShopSceneCache _current;

		private readonly Dictionary<int, string> pathByInstanceId = new Dictionary<int, string>();

		private readonly Dictionary<string, Transform> transformByPath = new Dictionary<string, Transform>(StringComparer.Ordinal);

		private readonly int sceneHandle;

		internal GameObject[] Roots { get; }

		internal Transform[] Transforms { get; }

		internal ItemVolume[] ItemVolumes { get; }

		internal Renderer[] Renderers { get; }

		internal static ShopSceneCache Current
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				if (_current == null || _current.sceneHandle != ((Scene)(ref activeScene)).handle)
				{
					_current = new ShopSceneCache();
				}
				return _current;
			}
		}

		private ShopSceneCache()
		{
			//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)
			Scene scene = SceneManager.GetActiveScene();
			sceneHandle = ((Scene)(ref scene)).handle;
			Roots = ((Scene)(ref scene)).GetRootGameObjects();
			Transforms = (from transform in Resources.FindObjectsOfTypeAll<Transform>()
				where (Object)(object)transform != (Object)null && ((Component)transform).gameObject.activeInHierarchy
				where ((Component)transform).gameObject.scene == scene
				select transform).ToArray();
			ItemVolumes = (from volume in Transforms.SelectMany((Transform transform) => ((Component)transform).GetComponents<ItemVolume>())
				where (Object)(object)volume != (Object)null && ((Component)volume).gameObject.activeInHierarchy
				select volume).ToArray();
			Renderers = (from renderer in Transforms.SelectMany((Transform transform) => ((Component)transform).GetComponents<Renderer>())
				where (Object)(object)renderer != (Object)null && ((Component)renderer).gameObject.activeInHierarchy
				select renderer).ToArray();
			Dictionary<int, string> dictionary = Transforms.ToDictionary((Transform transform) => ((Object)transform).GetInstanceID(), BuildPath);
			Dictionary<string, int> dictionary2 = dictionary.Values.GroupBy<string, string>((string path) => path, StringComparer.Ordinal).ToDictionary<IGrouping<string, string>, string, int>((IGrouping<string, string> group) => group.Key, (IGrouping<string, string> group) => group.Count(), StringComparer.Ordinal);
			Transform[] transforms = Transforms;
			foreach (Transform val in transforms)
			{
				string text = dictionary[((Object)val).GetInstanceID()];
				string text2 = ((dictionary2[text] > 1) ? BuildIndexedPath(text, val) : text);
				pathByInstanceId[((Object)val).GetInstanceID()] = text2;
				if (!transformByPath.ContainsKey(text2))
				{
					transformByPath.Add(text2, val);
				}
				if (!transformByPath.ContainsKey(text))
				{
					transformByPath.Add(text, val);
				}
			}
			ConfigEntry<bool> debugLogs = Plugin.DebugLogs;
			if (debugLogs != null && debugLogs.Value)
			{
				Plugin.Log.LogInfo((object)($"[ShopSceneCache] Built scene cache: transforms={Transforms.Length}, " + $"itemVolumes={ItemVolumes.Length}, renderers={Renderers.Length}."));
			}
		}

		internal static ShopSceneCache Rebuild()
		{
			_current = new ShopSceneCache();
			return _current;
		}

		internal static void Clear()
		{
			_current = null;
		}

		internal Transform FindTransformByPath(string path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				return null;
			}
			string[] pathCandidates = GetPathCandidates(path);
			foreach (string text in pathCandidates)
			{
				if (transformByPath.TryGetValue(text, out var value) && (Object)(object)value != (Object)null)
				{
					return value;
				}
				GameObject[] roots = Roots;
				foreach (GameObject val in roots)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Transform val2 = val.transform.Find(text);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
					if (text.StartsWith(((Object)val).name + "/", StringComparison.Ordinal))
					{
						string text2 = text.Substring(((Object)val).name.Length + 1);
						val2 = val.transform.Find(text2);
						if ((Object)(object)val2 != (Object)null)
						{
							return val2;
						}
					}
				}
			}
			return null;
		}

		internal string GetTransformPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<null>";
			}
			int instanceID = ((Object)transform).GetInstanceID();
			if (pathByInstanceId.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			string text = BuildPath(transform);
			value = text;
			if (transformByPath.TryGetValue(text, out var value2) && (Object)(object)value2 != (Object)null && (Object)(object)value2 != (Object)(object)transform)
			{
				value = BuildIndexedPath(text, transform);
			}
			pathByInstanceId[instanceID] = value;
			if (!transformByPath.ContainsKey(value))
			{
				transformByPath.Add(value, transform);
			}
			if (!transformByPath.ContainsKey(text))
			{
				transformByPath.Add(text, transform);
			}
			return value;
		}

		private static string[] GetPathCandidates(string path)
		{
			string text = path.Trim().Trim('/');
			if (!text.StartsWith("Main/", StringComparison.Ordinal))
			{
				return new string[1] { text };
			}
			return new string[2]
			{
				text,
				text.Substring("Main/".Length)
			};
		}

		private static string BuildPath(Transform transform)
		{
			Stack<string> stack = new Stack<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				stack.Push(((Object)val).name);
				val = val.parent;
			}
			return string.Join("/", stack);
		}

		private static string BuildIndexedPath(string legacyPath, Transform transform)
		{
			Stack<int> stack = new Stack<int>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				stack.Push(val.GetSiblingIndex());
				val = val.parent;
			}
			return legacyPath + "|MSFSIDX:" + string.Join(".", stack);
		}
	}
	internal static class StandNetworkSafety
	{
		private static readonly FieldInfo RuntimeViewIdField = typeof(PhotonView).GetField("viewIdField", BindingFlags.Instance | BindingFlags.NonPublic);

		internal static GameObject CloneVanillaSceneVisual(GameObject source, string context)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			PhotonView[] componentsInChildren = source.GetComponentsInChildren<PhotonView>(true);
			int[] array = new int[componentsInChildren.Length];
			try
			{
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					PhotonView val = componentsInChildren[i];
					if (!((Object)(object)val == (Object)null))
					{
						array[i] = val.sceneViewId;
						val.sceneViewId = 0;
					}
				}
				GameObject obj = Object.Instantiate<GameObject>(source);
				ClearInheritedPhotonViewIdentities(obj, context);
				return obj;
			}
			finally
			{
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					PhotonView val2 = componentsInChildren[j];
					if ((Object)(object)val2 != (Object)null)
					{
						val2.sceneViewId = array[j];
					}
				}
			}
		}

		internal static int DisableInheritedPhotonViews(GameObject standRoot, string context, bool includeChildren = true)
		{
			if ((Object)(object)standRoot == (Object)null)
			{
				return 0;
			}
			int num = 0;
			int num2 = 0;
			PhotonView[] array = (PhotonView[])(includeChildren ? ((Array)standRoot.GetComponentsInChildren<PhotonView>(true)) : ((Array)new PhotonView[1] { standRoot.GetComponent<PhotonView>() }));
			foreach (PhotonView val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					num++;
					ClearInheritedPhotonViewIdentity(val, context);
					if (((Behaviour)val).enabled)
					{
						((Behaviour)val).enabled = false;
						num2++;
					}
				}
			}
			if (Plugin.DebugLogs.Value && (num > 0 || num2 > 0))
			{
				Plugin.Log.LogInfo((object)("[" + context + "] Inherited vanilla PhotonViews made inert before stand activation: " + $"found={num}, disabled={num2}."));
			}
			return num2;
		}

		private static void ClearInheritedPhotonViewIdentities(GameObject standRoot, string context)
		{
			if ((Object)(object)standRoot == (Object)null)
			{
				return;
			}
			PhotonView[] componentsInChildren = standRoot.GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					ClearInheritedPhotonViewIdentity(val, context);
				}
			}
		}

		private static void ClearInheritedPhotonViewIdentity(PhotonView view, string context)
		{
			view.sceneViewId = 0;
			view.InstantiationId = 0;
			view.isRuntimeInstantiated = false;
			if (view.ViewID != 0)
			{
				if (RuntimeViewIdField == null)
				{
					throw new InvalidOperationException("[" + context + "] Cannot safely clear an inherited PhotonView identity; the PUN runtime field was not found.");
				}
				RuntimeViewIdField.SetValue(view, 0);
			}
		}

		internal static bool HasEnabledInheritedPhotonView(GameObject standRoot)
		{
			if ((Object)(object)standRoot == (Object)null)
			{
				return false;
			}
			PhotonView[] componentsInChildren = standRoot.GetComponentsInChildren<PhotonView>(true);
			foreach (PhotonView val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled)
				{
					return true;
				}
			}
			return false;
		}
	}
}
namespace MoreStandsForShops.Stands.Upgrade
{
	internal sealed class UpgradeStandRerollController : MonoBehaviour, IOnEventCallback, IInRoomCallbacks
	{
		private enum RerollState
		{
			Idle,
			Holding,
			Rollback,
			PressFail,
			PressSucceed,
			CloseHatch,
			RollStart,
			Rolling,
			RollEnd,
			OpenHatch,
			WaitingForHost,
			Broken
		}

		private readonly struct CachedUpgrade
		{
			internal readonly ItemUpgrade Upgrade;

			internal readonly Item Item;

			internal readonly Vector3 Position;

			internal readonly Quaternion Rotation;

			internal CachedUpgrade(ItemUpgrade upgrade, Item item, Vector3 position, Quaternion rotation)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				Upgrade = upgrade;
				Item = item;
				Position = position;
				Rotation = rotation;
			}
		}

		private readonly struct PendingReplacement
		{
			internal readonly ItemUpgrade OriginalUpgrade;

			internal readonly Item Item;

			internal readonly Vector3 Position;

			internal readonly Quaternion Rotation;

			internal PendingReplacement(ItemUpgrade originalUpgrade, Item item, Vector3 position, Quaternion rotation)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				OriginalUpgrade = originalUpgrade;
				Item = item;
				Position = position;
				Rotation = rotation;
			}
		}

		private sealed class PreparedReplacement
		{
			private readonly GameObject _gameObject;

			private readonly Vector3 _position;

			private readonly Quaternion _rotation;

			private readonly Rigidbody _body;

			private readonly PhysGrabObject _grabObject;

			private readonly bool _originalIsKinematic;

			private readonly bool _originalDetectCollisions;

			private readonly RigidbodyConstraints _originalConstraints;

			internal GameObject GameObject => _gameObject;

			internal PreparedReplacement(GameObject gameObject, Vector3 position, Quaternion rotation)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
				_gameObject = gameObject ?? throw new ArgumentNullException("gameObject");
				_position = position;
				_rotation = rotation;
				_grabObject = gameObject.GetComponent<PhysGrabObject>() ?? gameObject.GetComponentInChildren<PhysGrabObject>(true);
				_body = (((Object)(object)_grabObject != (Object)null && (Object)(object)_grabObject.rb != (Object)null) ? _grabObject.rb : (gameObject.GetComponent<Rigidbody>() ?? gameObject.GetComponentInChildren<Rigidbody>(true)));
				_originalIsKinematic = (Object)(object)_body != (Object)null && _body.isKinematic;
				_originalDetectCollisions = (Object)(object)_body == (Object)null || _body.detectCollisions;
				_originalConstraints = (RigidbodyConstraints)(((Object)(object)_body != (Object)null) ? ((int)_body.constraints) : 0);
				MaintainStagedPose();
			}

			internal bool MaintainStagedPose()
			{
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: 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)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_gameObject == (Object)null)
				{
					return false;
				}
				if ((Object)(object)_grabObject != (Object)null)
				{
					_grabObject.OverrideKinematic(0.25f);
				}
				else if ((Object)(object)_body != (Object)null)
				{
					_body.isKinematic = true;
				}
				if ((Object)(object)_body != (Object)null)
				{
					_body.detectCollisions = false;
				}
				Vector3 val = _gameObject.transform.position - _position;
				if (((Vector3)(ref val)).sqrMagnitude > 1E-06f || Quaternion.Angle(_gameObject.transform.rotation, _rotation) > 0.05f)
				{
					ApplyFinalPose();
				}
				return true;
			}

			internal void ReleaseAtFinalPose()
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_gameObject == (Object)null)
				{
					return;
				}
				ApplyFinalPose();
				Physics.SyncTransforms();
				if (!((Object)(object)_body == (Object)null))
				{
					_body.constraints = _originalConstraints;
					_body.detectCollisions = _originalDetectCollisions;
					if ((Object)(object)_grabObject == (Object)null)
					{
						_body.isKinematic = _originalIsKinematic;
					}
				}
			}

			internal bool TrySettleAfterVanillaEnable()
			{
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_gameObject == (Object)null || (Object)(object)_body == (Object)null)
				{
					return true;
				}
				if ((Object)(object)_grabObject != (Object)null && _body.isKinematic)
				{
					return false;
				}
				ApplyFinalPose();
				Physics.SyncTransforms();
				if (!_body.isKinematic)
				{
					_body.velocity = Vector3.zero;
					_body.angularVelocity = Vector3.zero;
					_body.Sleep();
				}
				return true;
			}

			private void ApplyFinalPose()
			{
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_007f: Unknown result type (might be due to invalid IL or missing references)
				PhotonTransformView component = _gameObject.GetComponent<PhotonTransformView>();
				if ((Object)(object)component != (Object)null)
				{
					component.Teleport(_position, _rotation);
				}
				else
				{
					_gameObject.transform.SetPositionAndRotation(_position, _rotation);
				}
				if ((Object)(object)_body != (Object)null)
				{
					_body.position = ((Component)_body).transform.position;
					_body.rotation = ((Component)_body).transform.rotation;
				}
			}
		}

		private const byte RerollSyncEvent = 187;

		private const string SyncMagic = "MSFS_REROLL_V1";

		private const string SyncStandId = "additional-upgrade-stand";

		private const string MsgHoldRequestStart = "HoldRequestStart";

		private const string MsgHoldRequestStop = "HoldRequestStop";

		private const string MsgHoldVisualStart = "HoldVisualStart";

		private const string MsgHoldVisualStop = "HoldVisualStop";

		private const string MsgHoldVisualProgress = "HoldVisualProgress";

		private const string MsgRerollRequest = "RerollRequest";

		private const string MsgRerollVisual = "RerollVisual";

		private const string MsgBreakBuildUpVisual = "BreakBuildUpVisual";

		private const string MsgBrokenVisual = "BrokenVisual";

		private const string MsgStateCorrection = "StateCorrection";

		private const float HoldProgressSyncInterval = 0.15f;

		private const float ButtonUseDistance = 3.25f;

		private const float ButtonCastRadius = 0.06f;

		private const float BuildUpStageDuration = 0.3f;

		private const float BuildUpFinalHoldDuration = 0.5f;

		[SerializeField]
		private Transform scanBox;

		[SerializeField]
		private Transform buttonRoot;

		[SerializeField]
		private Transform buttonColliderRoot;

		[SerializeField]
		private Transform hatch;

		[SerializeField]
		private Transform upgradeCompartment;

		[SerializeField]
		private Transform allMeshesTransform;

		[SerializeField]
		private StaticGrabObject buttonGrabObject;

		[SerializeField]
		private GameObject hatchClosed;

		[SerializeField]
		private GameObject hatchHurtCollider;

		[SerializeField]
		private GameObject rerollCompartmentHurtColliders;

		[SerializeField]
		private GameObject buttonRubble;

		[SerializeField]
		private GameObject fireHurtCollider;

		[SerializeField]
		private Light fireLight;

		[SerializeField]
		private Light buildUpLight;

		[SerializeField]
		private ParticleSystem hatchParticles;

		[SerializeField]
		private ParticleSystem rollingParticles;

		[SerializeField]
		private ParticleSystem particleButtonBreak;

		[SerializeField]
		private ParticleSystem particleFireLoop;

		[SerializeField]
		private ParticleSystem buildUpParticles;

		[SerializeField]
		private MeshRenderer buttonRenderer;

		[SerializeField]
		private Material buttonNormalMaterial;

		[SerializeField]
		private Material buttonDenyMaterial;

		[SerializeField]
		private LocalizedAsset interactLocalized;

		[SerializeField]
		private AnimationCurve buttonPressAnimationCurve;

		[SerializeField]
		private AnimationCurve buttonDenyCurve;

		[SerializeField]
		private AnimationCurve hatchAnimationCurve;

		[SerializeField]
		private AnimationCurve rollStartShakeCurve;

		[SerializeField]
		private AnimationCurve rollCurve;

		[SerializeField]
		private AnimationCurve rollEndShakeCurve;

		[SerializeField]
		private AnimationCurve buildUpIntroCurve;

		[SerializeField]
		private AnimationCurve buildUpOutroCurve;

		[SerializeField]
		private AnimationCurve flickerFadeLightCurve;

		[SerializeField]
		private BuildUpStage[] buildUpStages;

		[SerializeField]
		private SpringQuaternion meshRotationSpring;

		[SerializeField]
		private SpringVector3 meshPositionSpring;

		[SerializeField]
		private SpringFloat buttonRotationSpring;

		[SerializeField]
		private Sound soundButtonPress;

		[SerializeField]
		private Sound soundButtonDeny;

		[SerializeField]
		private Sound soundHatchClose;

		[SerializeField]
		private Sound soundRollStart;

		[SerializeField]
		private Sound soundRolling;

		[SerializeField]
		private Sound soundRollEnd;

		[SerializeField]
		private Sound soundHatchOpen;

		[SerializeField]
		private Sound soundButtonTwistUp;

		[SerializeField]
		private Sound soundButtonTwistDown;

		[SerializeField]
		private Sound soundStageBeep;

		[SerializeField]
		private Sound soundStateOn;

		[SerializeField]
		private Sound soundStateOff;

		[SerializeField]
		private Sound soundRerollStart;

		[SerializeField]
		private Sound soundRerollEnd;

		[SerializeField]
		private Sound soundRerollTick;

		[SerializeField]
		private Sound soundRerollSettle;

		[SerializeField]
		private Sound soundFinalRollSqueak;

		[SerializeField]
		private Sound soundHatchCloseImpact;

		[SerializeField]
		private Sound soundHatchOpenImpact;

		[SerializeField]
		private Sound soundButtonBreak;

		[SerializeField]
		private Sound soundBuildUpLoop;

		[SerializeField]
		private Sound soundFluorescentLightTurnOff;

		[SerializeField]
		private Sound soundLilButtonFire;

		private RerollState state;

		private Vector3 buttonOriginalPosition;

		private Vector3 hatchOriginalPosition;

		private Vector3 hatchOriginalScale;

		private Vector3 allMeshesOriginalPosition;

		private Quaternion buttonOriginalRotation;

		private Quaternion compartmentOriginalRotation;

		private Quaternion allMeshesOriginalRotation;

		private Color rollbackCurrentStageStartLightColor;

		private Color rollbackCurrentStageEndLightColor;

		private bool stateStart = true;

		private bool activationHeld;

		private bool activationStartedThisFrame;

		private bool activationReleasedThisFrame;

		private bool remoteHoldVisual;

		private bool holdVisualBroadcasted;

		private bool isBroken;

		private bool replacementsCommitted;

		private bool visualOnlyReroll;

		private bool finalRollSqueakPlayed;

		private bool hatchCloseImpactPlayed;

		private bool hatchOpenImpactPlayed;

		private bool fireActive;

		private bool[] chargeStageTriggered;

		private bool buildUpActive;

		private bool holdRequestSent;

		private bool resumeChargeFromRollback;

		private bool rollbackResumeRequested;

		private bool buttonSpringActive;

		private bool meshSpringsActive;

		private float stateTimer;

		private float stateTimerMax;

		private float chargeElapsed;

		private float buttonAnimationEval;

		private float buttonRotationTarget;

		private float buttonRotationAngle;

		private float buttonStageRotationAngle = 45f;

		private float hatchAnimationEval;

		private float compartmentAnimationEval;

		private float firePerlinOffsetX;

		private float firePerlinOffsetY;

		private float fireLightFadeInTimer;

		private float buildUpTimer;

		private float holdProgressSyncTimer;

		private float rollbackCurrentStageElapsed;

		private float rollbackCurrentStageStartEmission;

		private float rollbackCurrentStageStartLightIntensity;

		private float rollbackCurrentStageEndLightIntensity;

		private readonly List<CachedUpgrade> cachedUpgrades = new List<CachedUpgrade>();

		private readonly List<PendingReplacement> pendingReplacements = new List<PendingReplacement>();

		private readonly List<PreparedReplacement> preparedReplacements = new List<PreparedReplacement>();

		private readonly RaycastHit[] buttonCastHits = (RaycastHit[])(object)new RaycastHit[64];

		private Collider[] buttonTargetColliders;

		private int rollbackTopStage;

		private int rollbackCurrentStage = -1;

		private int rerollCount;

		private int maxRerollCount = -1;

		private int rerollTicksPlayed;

		private int remoteHoldActorNumber = -1;

		private int activeRerollTransactionId;

		private int pendingRerollCost;

		private int meshSpringSettledFrames;

		private static readonly FieldInfo SpringQuaternionVelocityField = typeof(SpringQuaternion).GetField("springVelocity", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo SpringVector3VelocityField = typeof(SpringVector3).GetField("springVelocity", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo SpringFloatVelocityField = typeof(SpringFloat).GetField("springVelocity", BindingFlags.Instance | BindingFlags.NonPublic);

		private int RerollCost => 5 + rerollCount * 5;

		private Vector3 ButtonSoundPosition
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)buttonRoot != (Object)null))
				{
					return ((Component)this).transform.position;
				}
				return buttonRoot.position;
			}
		}

		private Vector3 HatchSoundPosition
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)hatch != (Object)null))
				{
					return ((Component)this).transform.position;
				}
				return hatch.position;
			}
		}

		private Vector3 CompartmentSoundPosition
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)upgradeCompartment != (Object)null))
				{
					return ((Component)this).transform.position;
				}
				return upgradeCompartment.position;
			}
		}

		private float HoldDuration
		{
			get
			{
				if (buildUpStages != null && buildUpStages.Length != 0)
				{
					return (float)buildUpStages.Length * 0.3f + 0.5f;
				}
				return 1.7f;
			}
		}

		private float ChargeStageDuration => 0.3f;

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 187 || !(photonEvent.CustomData is object[] array) || array.Length < 2 || !(array[0] is string text) || text != "MSFS_REROLL_V1" || !(array[1] is string text2) || !IsCurrentStandEvent(array) || (IsHostBroadcast(text2) && !WasSentByCurrentMaster(photonEvent.Sender)))
			{
				return;
			}
			float syncedChargeElapsed = ((array.Length > 2) ? ReadProgressPayload(array[2], chargeElapsed) : chargeElapsed);
			if (isBroken && text2 != "BrokenVisual" && text2 != "BreakBuildUpVisual" && text2 != "StateCorrection")
			{
				return;
			}
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Sync] Event received. " + $"msg={text2}, sender={photonEvent.Sender}, " + $"isMaster={PhotonNetwork.IsMasterClient}, state={state}."));
			}
			if (text2 == null)
			{
				return;
			}
			switch (text2.Length)
			{
			case 15:
				switch (text2[4])
				{
				case 'R':
					if (text2 == "HoldRequestStop" && PhotonNetwork.IsMasterClient && remoteHoldActorNumber == photonEvent.Sender)
					{
						StopRemoteHoldVisual(syncedChargeElapsed);
						BroadcastHoldVisualStop();
						remoteHoldActorNumber = -1;
					}
					break;
				case 'V':
					if (text2 == "HoldVisualStart" && !PhotonNetwork.IsMasterClient)
					{
						BeginRemoteHoldVisual(syncedChargeElapsed);
					}
					break;
				case 'e':
				{
					if (!(text2 == "StateCorrection") || PhotonNetwork.IsMasterClient)
					{
						break;
					}
					int synchronizedRerollCount2 = ((array.Length > 2) ? ReadIntPayload(array[2], rerollCount) : rerollCount);
					int synchronizedMaxRerollCount2 = ((array.Length > 3) ? ReadIntPayload(array[3], maxRerollCount) : maxRerollCount);
					bool flag = default(bool);
					int num;
					if (array.Length > 4)
					{
						object obj = array[4];
						if (obj is bool)
						{
							flag = (bool)obj;
							num = 1;
						}
						else
						{
							num = 0;
						}
					}
					else
					{
						num = 0;
					}
					bool synchronizedBroken = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
					ApplySynchronizedState(synchronizedRerollCount2, synchronizedMaxRerollCount2, synchronizedBroken);
					break;
				}
				}
				break;
			case 18:
				switch (text2[0])
				{
				case 'H':
					if (text2 == "HoldVisualProgress" && !PhotonNetwork.IsMasterClient)
					{
						ApplyRemoteHoldProgress(syncedChargeElapsed);
					}
					break;
				case 'B':
					if (text2 == "BreakBuildUpVisual" && !PhotonNetwork.IsMasterClient)
					{
						StartBreakBuildUpVisual();
					}
					break;
				}
				break;
			case 12:
				switch (text2[0])
				{
				case 'R':
					if (text2 == "RerollVisual" && !PhotonNetwork.IsMasterClient)
					{
						int synchronizedRerollCount = ((array.Length > 2) ? ReadIntPayload(array[2], rerollCount) : rerollCount);
						int synchronizedMaxRerollCount = ((array.Length > 3) ? ReadIntPayload(array[3], maxRerollCount) : maxRerollCount);
						ApplySynchronizedState(synchronizedRerollCount, synchronizedMaxRerollCount, synchronizedBroken: false);
						BeginVisualReroll();
					}
					break;
				case 'B':
					if (text2 == "BrokenVisual" && !PhotonNetwork.IsMasterClient)
					{
						BreakButton();
					}
					break;
				}
				break;
			case 16:
				if (text2 == "HoldRequestStart" && PhotonNetwork.IsMasterClient && (state == RerollState.Idle || state == RerollState.Rollback || state == RerollState.WaitingForHost) && (remoteHoldActorNumber <= 0 || remoteHoldActorNumber == photonEvent.Sender))
				{
					remoteHoldActorNumber = photonEvent.Sender;
					BeginRemoteHoldVisual(syncedChargeElapsed);
					BroadcastHoldVisualStart();
				}
				break;
			case 14:
				if (text2 == "HoldVisualStop" && !PhotonNetwork.IsMasterClient)
				{
					StopRemoteHoldVisual(syncedChargeElapsed);
				}
				break;
			case 13:
				if (text2 == "RerollRequest" && PhotonNetwork.IsMasterClient)
				{
					HandleRemoteRerollRequest(photonEvent.Sender);
				}
				break;
			case 17:
				break;
			}
		}

		private void RaiseRerollEvent(string message, ReceiverGroup receivers, float? progress = null)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if (SemiFunc.IsMultiplayer())
			{
				object[] array = (progress.HasValue ? CreateEventPayload(message, progress.Value) : CreateEventPayload(message));
				PhotonNetwork.RaiseEvent((byte)187, (object)array, new RaiseEventOptions
				{
					Receivers = receivers
				}, SendOptions.SendReliable);
			}
		}

		private void BroadcastRerollVisual()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (SemiFunc.IsMultiplayer())
			{
				PhotonNetwork.RaiseEvent((byte)187, (object)CreateEventPayload("RerollVisual", rerollCount, maxRerollCount), new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)0
				}, SendOptions.SendReliable);
			}
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Broadcast reroll visual.");
			}
		}

		private void BroadcastHoldVisualStop()
		{
			if (!holdVisualBroadcasted)
			{
				return;
			}
			holdVisualBroadcasted = false;
			holdProgressSyncTimer = 0f;
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				float num = Mathf.Clamp(chargeElapsed, 0f, HoldDuration);
				RaiseRerollEvent("HoldVisualStop", (ReceiverGroup)0, num);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Broadcast hold visual stop. progress={num:0.00}.");
				}
			}
		}

		private void BroadcastHoldVisualProgress(bool force)
		{
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient && holdVisualBroadcasted)
			{
				holdProgressSyncTimer += Time.deltaTime;
				if (force || !(holdProgressSyncTimer < 0.15f))
				{
					holdProgressSyncTimer = 0f;
					RaiseRerollEvent("HoldVisualProgress", (ReceiverGroup)0, Mathf.Clamp(chargeElapsed, 0f, HoldDuration));
				}
			}
		}

		private void BroadcastHoldVisualStart()
		{
			if (holdVisualBroadcasted)
			{
				return;
			}
			holdVisualBroadcasted = true;
			holdProgressSyncTimer = 0f;
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				float num = Mathf.Clamp(chargeElapsed, 0f, HoldDuration);
				RaiseRerollEvent("HoldVisualStart", (ReceiverGroup)0, num);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Broadcast hold visual start. progress={num:0.00}.");
				}
			}
		}

		private void BeginVisualReroll()
		{
			if (state != RerollState.Idle && state != RerollState.WaitingForHost && state != RerollState.Holding && state != RerollState.Rollback)
			{
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Ignored visual reroll in state={state}.");
				}
			}
			else
			{
				remoteHoldVisual = false;
				holdRequestSent = false;
				visualOnlyReroll = true;
				StateSet(RerollState.PressSucceed);
			}
		}

		private void BeginRemoteHoldVisual(float syncedChargeElapsed = -1f)
		{
			if (isBroken)
			{
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Ignored remote hold visual: stand is broken.");
				}
				return;
			}
			if (state != RerollState.Idle && state != RerollState.Rollback && state != RerollState.WaitingForHost)
			{
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Ignored remote hold visual in state={state}.");
				}
				return;
			}
			if (syncedChargeElapsed >= 0f)
			{
				chargeElapsed = Mathf.Clamp(syncedChargeElapsed, 0f, HoldDuration);
				resumeChargeFromRollback = chargeElapsed > 0f;
			}
			else
			{
				resumeChargeFromRollback = state == RerollState.Rollback;
			}
			remoteHoldVisual = true;
			visualOnlyReroll = true;
			StateSet(RerollState.Holding);
		}

		private void StopRemoteHoldVisual(float syncedChargeElapsed = -1f)
		{
			if (remoteHoldVisual)
			{
				remoteHoldVisual = false;
				if (syncedChargeElapsed >= 0f)
				{
					chargeElapsed = Mathf.Clamp(syncedChargeElapsed, 0f, HoldDuration);
				}
				if (state == RerollState.Holding)
				{
					StateSet(RerollState.Rollback);
				}
			}
		}

		private void ApplyRemoteHoldProgress(float syncedChargeElapsed)
		{
			if (remoteHoldVisual && state == RerollState.Holding)
			{
				chargeElapsed = Mathf.Clamp(syncedChargeElapsed, 0f, HoldDuration);
				SyncChargeStageTriggers(chargeElapsed);
				ApplyChargeVisualsSilent(chargeElapsed);
			}
		}

		private void RequestHostReroll()
		{
			if (SemiFunc.IsMultiplayer())
			{
				RaiseRerollEvent("RerollRequest", (ReceiverGroup)2);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Sent reroll request to host.");
				}
			}
		}

		private void HandleRemoteRerollRequest(int senderActorNumber)
		{
			if (remoteHoldActorNumber != senderActorNumber)
			{
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Rejected reroll request from actor {senderActorNumber}: no matching hold owner.");
				}
			}
			else
			{
				remoteHoldVisual = false;
				remoteHoldActorNumber = -1;
				BroadcastHoldVisualStop();
				TryStartReroll(visualOnly: false, broadcastVisual: true);
			}
		}

		private void RequestHostHoldStart()
		{
			if (!holdRequestSent && SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient)
			{
				holdRequestSent = true;
				RaiseRerollEvent("HoldRequestStart", (ReceiverGroup)2, Mathf.Clamp(chargeElapsed, 0f, HoldDuration));
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Sent hold-start request to host.");
				}
			}
		}

		private void RequestHostHoldStop()
		{
			if (holdRequestSent && SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient)
			{
				holdRequestSent = false;
				RaiseRerollEvent("HoldRequestStop", (ReceiverGroup)2, Mathf.Clamp(chargeElapsed, 0f, HoldDuration));
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Sent hold-stop request to host.");
				}
			}
		}

		private void BroadcastBroken()
		{
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				ShopLayoutSync.SetUpgradeRerollState(rerollCount, maxRerollCount, broken: true);
				RaiseRerollEvent("BrokenVisual", (ReceiverGroup)0);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Broadcast broken visual.");
				}
			}
		}

		private void BroadcastBreakBuildUpVisual()
		{
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				RaiseRerollEvent("BreakBuildUpVisual", (ReceiverGroup)0);
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)"[UpgradeStandReroll.Sync] Broadcast break build-up visual.");
				}
			}
		}

		private void BroadcastStateCorrection()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0064: Expected O, but got Unknown
			if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient)
			{
				PhotonNetwork.RaiseEvent((byte)187, (object)CreateEventPayload("StateCorrection", rerollCount, maxRerollCount, isBroken), new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)0
				}, SendOptions.SendReliable);
			}
		}

		private static object[] CreateEventPayload(string message, params object[] values)
		{
			int num = ((values != null) ? values.Length : 0);
			object[] array = new object[num + 4];
			array[0] = "MSFS_REROLL_V1";
			array[1] = message;
			if (num > 0)
			{
				Array.Copy(values, 0, array, 2, num);
			}
			array[^2] = ShopLayoutSync.GetSequence();
			array[^1] = "additional-upgrade-stand";
			return array;
		}

		private static bool IsCurrentStandEvent(object[] data)
		{
			if (data.Length < 4 || !(data[^1] is string a))
			{
				return true;
			}
			if (!(data[^2] is int num))
			{
				return true;
			}
			if (!string.Equals(a, "additional-upgrade-stand", StringComparison.Ordinal))
			{
				return false;
			}
			int sequence = ShopLayoutSync.GetSequence();
			if (sequence > 0)
			{
				return num == sequence;
			}
			return true;
		}

		private static bool IsHostBroadcast(string message)
		{
			switch (message)
			{
			default:
				return message == "StateCorrection";
			case "HoldVisualStart":
			case "HoldVisualStop":
			case "HoldVisualProgress":
			case "RerollVisual":
			case "BreakBuildUpVisual":
			case "BrokenVisual":
				return true;
			}
		}

		private static bool WasSentByCurrentMaster(int senderActorNumber)
		{
			if (PhotonNetwork.MasterClient != null)
			{
				return PhotonNetwork.MasterClient.ActorNumber == senderActorNumber;
			}
			return true;
		}

		public void OnPlayerEnteredRoom(Player newPlayer)
		{
		}

		public void OnPlayerLeftRoom(Player otherPlayer)
		{
			if (PhotonNetwork.IsMasterClient && otherPlayer != null && remoteHoldActorNumber == otherPlayer.ActorNumber)
			{
				StopRemoteHoldVisual();
				remoteHoldActorNumber = -1;
				BroadcastHoldVisualStop();
				if (Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Sync] Released disconnected hold owner actor={otherPlayer.ActorNumber}.");
				}
			}
		}

		public void OnMasterClientSwitched(Player newMasterClient)
		{
			remoteHoldActorNumber = -1;
			holdRequestSent = false;
			activationHeld = false;
			RerollState rerollState = state;
			if (((uint)(rerollState - 1) <= 1u || rerollState == RerollState.WaitingForHost) ? true : false)
			{
				remoteHoldVisual = false;
				holdVisualBroadcasted = false;
				StateSet(isBroken ? RerollState.Broken : RerollState.Idle);
			}
			if (!PhotonNetwork.IsMasterClient)
			{
				ReleasePreparedReplacementsImmediately();
				return;
			}
			RefreshSynchronizedStateForHost();
			RecoverPendingRerollAsNewMaster();
		}

		public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
		}

		public void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		private static float ReadProgressPayload(object data, float fallback)
		{
			if (!(data is float result))
			{
				if (!(data is double num))
				{
					if (data is int num2)
					{
						return num2;
					}
					return fallback;
				}
				return (float)num;
			}
			return result;
		}

		private static int ReadIntPayload(object data, int fallback)
		{
			if (!(data is int result))
			{
				if (!(data is short result2))
				{
					if (data is byte result3)
					{
						return result3;
					}
					return fallback;
				}
				return result2;
			}
			return result;
		}

		internal void ApplySynchronizedState(int synchronizedRerollCount, int synchronizedMaxRerollCount, bool synchronizedBroken)
		{
			bool flag = isBroken;
			rerollCount = Mathf.Max(0, synchronizedRerollCount);
			maxRerollCount = Mathf.Max(-1, synchronizedMaxRerollCount);
			isBroken = synchronizedBroken;
			if (isBroken)
			{
				state = RerollState.Broken;
				stateStart = true;
			}
			else if (flag && state == RerollState.Broken)
			{
				state = RerollState.Idle;
				stateStart = true;
			}
		}

		private void OnEnable()
		{
			PhotonNetwork.AddCallbackTarget((object)this);
		}

		private void OnDisable()
		{
			ReleasePreparedReplacementsImmediately();
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		private void Start()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			ResolveReferences();
			CaptureOriginalTransforms();
			DisableVanillaButtonNetworking();
			ResetBuildUpVisuals();
			if (buildUpStages == null || buildUpStages.Length == 0)
			{
				buildUpStages = (BuildUpStage[])(object)new BuildUpStage[4];
			}
			chargeStageTriggered = new bool[buildUpStages.Length];
			buttonStageRotationAngle = 180f / (float)Mathf.Max(1, buildUpStages.Length);
			if (buttonRotationSpring == null)
			{
				buttonRotationSpring = new SpringFloat();
			}
			if (meshRotationSpring == null)
			{
				meshRotationSpring = new SpringQuaternion();
			}
			if (meshPositionSpring == null)
			{
				meshPositionSpring = new SpringVector3();
			}
			buttonRotationSpring.speed = 80f;
			buttonRotationSpring.damping = 0.25f;
			SpringQuaternion obj = meshRotationSpring;
			obj.speed *= 0.75f;
			SpringVector3 obj2 = meshPositionSpring;
			obj2.speed *= 0.75f;
			if ((Object)(object)buttonRenderer != (Object)null && (Object)(object)buttonNormalMaterial != (Object)null)
			{
				((Renderer)buttonRenderer).material = buttonNormalMaterial;
			}
			if ((Object)(object)buttonRubble != (Object)null)
			{
				buttonRubble.SetActive(false);
			}
			if ((Object)(object)fireHurtCollider != (Object)null)
			{
				fireHurtCollider.SetActive(false);
			}
			if ((Object)(object)fireLight != (Object)null)
			{
				((Component)fireLight).gameObject.SetActive(false);
			}
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[UpgradeStandReroll] Controller ready. scanBox=" + NameOrNull(scanBox) + ", button=" + NameOrNull(buttonRoot) + ", collider=" + NameOrNull(buttonColliderRoot) + "."));
			}
		}

		private void Update()
		{
			ReadActivationInput();
			bool buttonFocused = IsLocalPlayerLookingAtButton();
			UpdateHover(buttonFocused);
			UpdateState(buttonFocused);
			if (ButtonSpringNeedsUpdate())
			{
				UpdateButtonRotationSpring();
				ApplyButtonRotation();
			}
			UpdateMeshSprings();
			UpdateFire();
			UpdateBuildUpLoop();
			if (stateTimer <= stateTimerMax)
			{
				stateTimer += Time.deltaTime;
			}
		}

		private void LateUpdate()
		{
			MaintainPreparedReplacementStaging();
		}

		private void ReadActivationInput()
		{
			activationStartedThisFrame = false;
			activationReleasedThisFrame = false;
			if (!((Object)(object)InputManager.instance == (Object)null))
			{
				if (InputManager.instance.KeyDown((InputKey)10) || InputManager.instance.KeyDown((InputKey)2))
				{
					activationHeld = true;
					activationStartedThisFrame = true;
				}
				if (InputManager.instance.KeyUp((InputKey)10) || InputManager.instance.KeyUp((InputKey)2))
				{
					activationHeld = false;
					activationReleasedThisFrame = true;
				}
			}
		}

		private void UpdateHover(bool buttonFocused)
		{
			bool flag = !buttonFocused || isBroken;
			if (!flag)
			{
				RerollState rerollState = state;
				bool flag2 = (uint)rerollState <= 2u;
				flag = !flag2;
			}
			if (!flag)
			{
				if ((Object)(object)Aim.instance != (Object)null)
				{
					Aim.instance.SetState((State)((state != RerollState.Holding) ? 1 : 2));
				}
				string text = BuildHoverText();
				if ((Object)(object)buttonGrabObject != (Object)null)
				{
					buttonGrabObject.hoverText = text;
					buttonGrabObject.ShowHoverText();
				}
				else if ((Object)(object)ItemInfoUI.instance != (Object)null)
				{
					ItemInfoUI.instance.ItemInfoText((ItemAttributes)null, text, false);
				}
			}
		}

		private string BuildHoverText()
		{
			string text = "<color=#FF0000>-" + SemiFunc.DollarGetString(RerollCost) + "k</color>";
			if ((Object)(object)interactLocalized != (Object)null)
			{
				return interactLocalized.GetLocalizedString((IList<object>)new object[1]
				{
					new
					{
						cost = text
					}
				});
			}
			return "Reroll upgrades " + text;
		}

		private bool IsLocalPlayerLookingAtButton()
		{
			//IL_0038: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val == (Object)null || (Object)(object)val.localCamera == (Object)null)
			{
				return false;
			}
			Transform overrideTransform = val.localCamera.GetOverrideTransform();
			if ((Object)(object)overrideTransform == (Object)null)
			{
				return false;
			}
			if (!CanPossiblyReachButton(overrideTransform.position))
			{
				return false;
			}
			Ray val2 = default(Ray);
			((Ray)(ref val2))..ctor(overrideTransform.position, overrideTransform.forward);
			RaycastHit val3 = default(RaycastHit);
			if (Physics.Raycast(val2, ref val3, 3.25f, -1, (QueryTriggerInteraction)2) && IsButtonTarget(((RaycastHit)(ref val3)).transform))
			{
				return true;
			}
			int num = Physics.SphereCastNonAlloc(val2, 0.06f, buttonCastHits, 3.25f, -1, (QueryTriggerInteraction)2);
			for (int i = 0; i < num; i++)
			{
				RaycastHit val4 = buttonCastHits[i];
				if (!((Object)(object)((RaycastHit)(ref val4)).transform == (Object)null) && IsButtonTarget(((RaycastHit)(ref val4)).transform))
				{
					return true;
				}
			}
			return false;
		}

		private bool CanPossiblyReachButton(Vector3 cameraPosition)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (buttonTargetColliders == null || buttonTargetColliders.Length == 0)
			{
				return true;
			}
			float num = 3.31f * 3.31f;
			bool flag = false;
			Collider[] array = buttonTargetColliders;
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.enabled && ((Component)val).gameObject.activeInHierarchy)
				{
					flag = true;
					Bounds bounds = val.bounds;
					if (((Bounds)(ref bounds)).SqrDistance(cameraPosition) <= num)
					{
						return true;
					}
				}
			}
			return !flag;
		}

		private bool IsButtonTarget(Transform hitTransform)
		{
			if ((Object)(object)hitTransform == (Object)null)
			{
				return false;
			}
			if ((Object)(object)buttonRoot != (Object)null && ((Object)(object)hitTransform == (Object)(object)buttonRoot || hitTransform.IsChildOf(buttonRoot)))
			{
				return true;
			}
			if ((Object)(object)buttonColliderRoot != (Object)null && ((Object)(object)hitTransform == (Object)(object)buttonColliderRoot || hitTransform.IsChildOf(buttonColliderRoot)))
			{
				return true;
			}
			StaticGrabObject componentInParent = ((Component)hitTransform).GetComponentInParent<StaticGrabObject>();
			if ((Object)(object)componentInParent != (Object)null)
			{
				return (Object)(object)componentInParent == (Object)(object)buttonGrabObject;
			}
			return false;
		}

		private List<PendingReplacement> BuildPendingReplacements(List<CachedUpgrade> upgrades)
		{
			//IL_007c: 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)
			Dictionary<string, int> dictionary = BuildDisplayedCounts(upgrades);
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			List<PendingReplacement> list = new List<PendingReplacement>();
			foreach (CachedUpgrade upgrade in upgrades)
			{
				string key = ItemKey(upgrade.Item);
				DecrementCount(dictionary, key);
				Item val = SelectReplacement(upgrade.Item, dictionary, dictionary2);
				if ((Object)(object)val == (Object)null)
				{
					IncrementCount(dictionary, key);
					continue;
				}
				string key2 = ItemKey(val);
				IncrementCount(dictionary2, key2);
				list.Add(new PendingReplacement(upgrade.Upgrade, val, upgrade.Position, upgrade.Rotation));
			}
			if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] Built replacement list. " + $"source={upgrades.Count}, replacements={list.Count}."));
			}
			return list;
		}

		private static void IncrementCount(Dictionary<string, int> counts, string key)
		{
			counts[key] = ((!counts.TryGetValue(key, out var value)) ? 1 : (value + 1));
		}

		private static void DecrementCount(Dictionary<string, int> counts, string key)
		{
			if (counts.TryGetValue(key, out var value))
			{
				if (value <= 1)
				{
					counts.Remove(key);
				}
				else
				{
					counts[key] = value - 1;
				}
			}
		}

		private List<CachedUpgrade> ScanUpgradesInside()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			List<CachedUpgrade> list = new List<CachedUpgrade>();
			if ((Object)(object)scanBox == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[UpgradeStandReroll.Items] Missing scan box; cannot scan upgrades.");
				return list;
			}
			HashSet<ItemUpgrade> hashSet = new HashSet<ItemUpgrade>();
			Collider[] array = Physics.OverlapBox(scanBox.position, scanBox.localScale * 0.5f, scanBox.rotation);
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				ItemUpgrade val2 = ((Component)val).GetComponent<ItemUpgrade>() ?? ((Component)val).GetComponentInParent<ItemUpgrade>();
				if (!((Object)(object)val2 == (Object)null) && hashSet.Add(val2))
				{
					ItemAttributes component = ((Component)val2).GetComponent<ItemAttributes>();
					if (!((Object)(object)component == (Object)null) && !((Object)(object)component.item == (Object)null))
					{
						list.Add(new CachedUpgrade(val2, component.item, ((Component)val2).transform.position, ((Component)val2).transform.rotation));
					}
				}
			}
			if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] Scan complete. " + $"colliders={array.Length}, upgrades={list.Count}, " + $"scanBox={NameOrNull(scanBox)}, position={scanBox.position}, scale={scanBox.localScale}."));
			}
			return list;
		}

		private int BeginPendingRerollTransaction(IEnumerable<PendingReplacement> replacements)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMultiplayer())
			{
				return 0;
			}
			List<UpgradeRerollTransactionEntry> list = new List<UpgradeRerollTransactionEntry>();
			foreach (PendingReplacement replacement in replacements)
			{
				PhotonView val = FindOwningPhotonView(replacement.OriginalUpgrade);
				if ((Object)(object)val == (Object)null || val.ViewID <= 0)
				{
					Plugin.Log.LogError((object)("[UpgradeStandReroll.Items] Cannot start a recoverable transaction: " + ItemKey(replacement.Item) + " has no owning PhotonView."));
					return 0;
				}
				int viewID = val.ViewID;
				Item item = replacement.Item;
				object resourcePath;
				if (item == null)
				{
					resourcePath = null;
				}
				else
				{
					PrefabRef prefab = item.prefab;
					resourcePath = ((prefab != null) ? prefab.ResourcePath : null);
				}
				list.Add(new UpgradeRerollTransactionEntry(viewID, (string)resourcePath, replacement.Position, replacement.Rotation));
			}
			return ShopLayoutSync.BeginUpgradeRerollTransaction(UpgradeRerollTransactionCodec.Encode(list));
		}

		private bool CommitPendingReplacementsAtomically()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)$"[UpgradeStandReroll.Items] Committing replacement upgrades atomically. count={pendingReplacements.Count}.");
			}
			if (pendingReplacements.Count == 0)
			{
				ShopLayoutSync.CompleteUpgradeRerollTransaction(activeRerollTransactionId);
				activeRerollTransactionId = 0;
				replacementsCommitted = true;
				return true;
			}
			List<PreparedReplacement> list = new List<PreparedReplacement>(pendingReplacements.Count);
			try
			{
				foreach (PendingReplacement pendingReplacement in pendingReplacements)
				{
					GameObject val = SpawnReplacement(pendingReplacement.Item, pendingReplacement.Position, pendingReplacement.Rotation);
					if ((Object)(object)val == (Object)null)
					{
						throw new InvalidOperationException("Spawn returned null for " + ItemKey(pendingReplacement.Item) + ".");
					}
					list.Add(new PreparedReplacement(val, pendingReplacement.Position, pendingReplacement.Rotation));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"[UpgradeStandReroll.Items] Atomic replacement commit failed; rolling back new objects and preserving originals. {arg}");
				foreach (PreparedReplacement item in list)
				{
					try
					{
						DestroySpawnedReplacement(item.GameObject);
					}
					catch (Exception arg2)
					{
						Plugin.Log.LogError((object)$"[UpgradeStandReroll.Items] Failed to remove a rollback replacement safely. {arg2}");
					}
				}
				return false;
			}
			foreach (PendingReplacement pendingReplacement2 in pendingReplacements)
			{
				if (!((Object)(object)pendingReplacement2.OriginalUpgrade == (Object)null))
				{
					try
					{
						DestroyUpgrade(pendingReplacement2.OriginalUpgrade);
					}
					catch (Exception arg3)
					{
						Plugin.Log.LogError((object)$"[UpgradeStandReroll.Items] Replacement exists, but an original could not be removed; preserving both is safer than item loss. {arg3}");
					}
				}
			}
			preparedReplacements.AddRange(list);
			ShopLayoutSync.CompleteUpgradeRerollTransaction(activeRerollTransactionId);
			activeRerollTransactionId = 0;
			replacementsCommitted = true;
			return true;
		}

		private void MaintainPreparedReplacementStaging()
		{
			if (preparedReplacements.Count == 0 || (SemiFunc.IsMultiplayer() && !PhotonNetwork.IsMasterClient))
			{
				return;
			}
			for (int num = preparedReplacements.Count - 1; num >= 0; num--)
			{
				if (!preparedReplacements[num].MaintainStagedPose())
				{
					preparedReplacements.RemoveAt(num);
				}
			}
		}

		private void ActivatePreparedReplacementsForReveal()
		{
			if (preparedReplacements.Count == 0)
			{
				return;
			}
			List<PreparedReplacement> list = new List<PreparedReplacement>(preparedReplacements);
			preparedReplacements.Clear();
			foreach (PreparedReplacement item in list)
			{
				try
				{
					item.ReleaseAtFinalPose();
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[UpgradeStandReroll.Items] Replacement reveal placement failed. {arg}");
				}
			}
			((MonoBehaviour)this).StartCoroutine(SettleReleasedReplacements(list));
		}

		private IEnumerator SettleReleasedReplacements(List<PreparedReplacement> released)
		{
			for (int attempt = 0; attempt < 20; attempt++)
			{
				if (released.Count <= 0)
				{
					break;
				}
				yield return (object)new WaitForFixedUpdate();
				for (int num = released.Count - 1; num >= 0; num--)
				{
					if (released[num].TrySettleAfterVanillaEnable())
					{
						released.RemoveAt(num);
					}
				}
			}
		}

		private void ReleasePreparedReplacementsImmediately()
		{
			if (preparedReplacements.Count == 0)
			{
				return;
			}
			foreach (PreparedReplacement preparedReplacement in preparedReplacements)
			{
				try
				{
					preparedReplacement.ReleaseAtFinalPose();
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[UpgradeStandReroll.Items] Emergency replacement release failed. {arg}");
				}
			}
			preparedReplacements.Clear();
		}

		private static void DestroySpawnedReplacement(GameObject spawned)
		{
			if (!((Object)(object)spawned == (Object)null))
			{
				PhotonView val = spawned.GetComponent<PhotonView>() ?? spawned.GetComponentInChildren<PhotonView>(true);
				if (SemiFunc.IsMultiplayer() && (Object)(object)val != (Object)null && PhotonNetwork.IsMasterClient)
				{
					PhotonNetwork.Destroy(((Component)val).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)spawned);
				}
			}
		}

		private static PhotonView FindOwningPhotonView(ItemUpgrade upgrade)
		{
			if ((Object)(object)upgrade == (Object)null)
			{
				return null;
			}
			Transform val = ((Component)upgrade).transform;
			while ((Object)(object)val != (Object)null && !((Object)(object)((Component)val).GetComponent<UpgradeStandRerollController>() != (Object)null))
			{
				PhotonView component = ((Component)val).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
				val = val.parent;
			}
			return ((Component)upgrade).GetComponentInChildren<PhotonView>(true);
		}

		private void RecoverPendingRerollAsNewMaster()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMultiplayer() || !PhotonNetwork.IsMasterClient || !ShopLayoutSync.TryGetUpgradeRerollTransaction(out var transactionId, out var encodedPlan))
			{
				return;
			}
			if (!UpgradeRerollTransactionCodec.TryDecode(encodedPlan, out var entries))
			{
				Plugin.Log.LogError((object)$"[UpgradeStandReroll.Recovery] Pending transaction {transactionId} is malformed; originals were left untouched.");
				return;
			}
			List<PendingReplacement> list = new List<PendingReplacement>();
			int num = 0;
			foreach (UpgradeRerollTransactionEntry item in entries)
			{
				PhotonView val = ((item.OriginalViewId > 0) ? PhotonView.Find(item.OriginalViewId) : null);
				if (!((Object)(object)val == (Object)null))
				{
					ItemUpgrade val2 = ((Component)val).GetComponent<ItemUpgrade>() ?? ((Component)val).GetComponentInChildren<ItemUpgrade>(true);
					Item val3 = ResolveItemByResourcePath(item.ResourcePath);
					if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
					{
						num++;
					}
					else
					{
						list.Add(new PendingReplacement(val2, val3, item.Position, item.Rotation));
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogError((object)$"[UpgradeStandReroll.Recovery] Transaction {transactionId} could not resolve {num} entry/entries; originals were preserved and no partial recovery was attempted.");
				return;
			}
			activeRerollTransactionId = transactionId;
			pendingRerollCost = 0;
			pendingReplacements.Clear();
			pendingReplacements.AddRange(list);
			visualOnlyReroll = false;
			if (!CommitPendingReplacementsAtomically())
			{
				Plugin.Log.LogError((object)$"[UpgradeStandReroll.Recovery] Transaction {transactionId} remains pending after a safe commit failure.");
				return;
			}
			BroadcastRerollVisual();
			if (state == RerollState.Idle)
			{
				visualOnlyReroll = false;
				StateSet(RerollState.PressSucceed);
			}
			if (Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)($"[UpgradeStandReroll.Recovery] Transaction {transactionId} recovered after host migration. " + $"remainingOriginals={list.Count}."));
			}
		}

		private static Item ResolveItemByResourcePath(string resourcePath)
		{
			if ((Object)(object)StatsManager.instance == (Object)null || string.IsNullOrWhiteSpace(resourcePath))
			{
				return null;
			}
			return StatsManager.instance.itemDictionary.Values.Where((Item item) => item?.prefab != null && string.Equals(item.prefab.ResourcePath, resourcePath, StringComparison.Ordinal)).FirstOrDefault();
		}

		private static Dictionary<string, int> BuildDisplayedCounts(IEnumerable<CachedUpgrade> upgrades)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (CachedUpgrade upgrade in upgrades)
			{
				string key = ItemKey(upgrade.Item);
				dictionary[key] = ((!dictionary.TryGetValue(key, out var value)) ? 1 : (value + 1));
			}
			return dictionary;
		}

		private static Item SelectReplacement(Item previous, Dictionary<string, int> displayedCounts, Dictionary<string, int> selectedCounts)
		{
			return SelectReplacementInternal(previous, displayedCounts, selectedCounts, allowPrevious: false) ?? SelectReplacementInternal(previous, displayedCounts, selectedCounts, allowPrevious: true);
		}

		private static Item SelectReplacementInternal(Item previous, Dictionary<string, int> displayedCounts, Dictionary<string, int> selectedCounts, bool allowPrevious)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Invalid comparison between Unknown and I4
			if ((Object)(object)StatsManager.instance == (Object)null)
			{
				return null;
			}
			ConfigEntry<int> value;
			int num = (Plugin.SameItemCopies.TryGetValue("Upgrades", out value) ? value.Value : 6);
			int num2 = ((!((Object)(object)GameDirector.instance != (Object)null)) ? 1 : GameDirector.instance.PlayerList.Count);
			List<(Item, int)> list = new List<(Item, int)>();
			foreach (Item item2 in from @group in StatsManager.instance.itemDictionary.Values.Where((Item val2) => (Object)(object)val2 != (Object)null).GroupBy<Item, string>(ItemKey, StringComparer.Ordinal)
				select @group.First())
			{
				if ((Object)(object)item2 == (Object)null || item2.disabled || (int)item2.itemType != 3 || item2.prefab == null || !item2.prefab.IsValid() || (!allowPrevious && string.Equals(ItemKey(item2), ItemKey(previous), StringComparison.Ordinal)))
				{
					continue;
				}
				int itemSpawnChance = Plugin.GetItemSpawnChance(item2);
				if (itemSpawnChance > 0)
				{
					string key = ItemKey(item2);
					int value2;
					int num3 = (displayedCounts.TryGetValue(key, out value2) ? value2 : 0);
					int value3;
					int num4 = (selectedCounts.TryGetValue(key, out value3) ? value3 : 0);
					if (num3 + num4 < num && (!item2.maxPurchase || StatsManager.instance.GetItemsUpgradesPurchasedTotal(((Object)item2).name) < item2.maxPurchaseAmount) && (item2.minPlayerCount <= 1 || num2 >= item2.minPlayerCount))
					{
						list.Add((item2, Mathf.Max(1, itemSpawnChance)));
					}
				}
			}
			if (list.Count == 0)
			{
				if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] No replacement candidates. " + $"previous={ItemKey(previous)}, allowPrevious={allowPrevious}, sameLimit={num}."));
				}
				return null;
			}
			int num5 = list.Sum<(Item, int)>(((Item item, int weight) candidate) => candidate.weight);
			int num6 = Random.Range(0, num5);
			foreach (var (val, num7) in list)
			{
				if (num6 < num7)
				{
					if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
					{
						Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] Selected replacement. previous=" + ItemKey(previous) + ", selected=" + ((Object)val).name + ", " + $"allowPrevious={allowPrevious}, candidates={list.Count}, totalWeight={num5}."));
					}
					return val;
				}
				num6 -= num7;
			}
			Item item = list[list.Count - 1].Item1;
			if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
			{
				Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] Selected fallback replacement. " + $"previous={ItemKey(previous)}, selected={((Object)item).name}, candidates={list.Count}."));
			}
			return item;
		}

		private static void DestroyUpgrade(ItemUpgrade upgrade)
		{
			if (!((Object)(object)upgrade == (Object)null))
			{
				PhotonView val = FindOwningPhotonView(upgrade);
				GameObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)upgrade).gameObject);
				if (Plugin.DebugLogs.Value && Plugin.DebugLogs.Value)
				{
					Plugin.Log.LogInfo((object)("[UpgradeStandReroll.Items] Destroy upgrade. " + $"object={((Object)val2).name}, hasPhotonView={(Object)(object)val != (Object)null}, multiplayer={SemiFunc.IsMultiplayer()}."));
				}
				if (SemiFunc.IsMultiplayer() && (Object)(object)val != (Object)null)
				{
					PhotonNetwork.Destroy(val2);
				}
				else
				{
					Object.Destroy((Object)(object)val2);
				}
			}
		}

		private GameObject SpawnReplacement(Item item, Vector3 position, Quaternion fallbackRotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might b