Decompiled source of Floppy v0.4.2

BepInEx/plugins/Floppy/Floppy.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon;
using Pigeon.Movement;
using Pigeon.UI;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Floppy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.4.1.0")]
[assembly: AssemblyInformationalVersion("0.4.1")]
[assembly: AssemblyProduct("Floppy")]
[assembly: AssemblyTitle("Floppy")]
[assembly: AssemblyVersion("0.4.1.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 Horse.Floppy
{
	internal static class ExchangeRules
	{
		private sealed class EquippedSlot
		{
			internal IUpgradable Gear;

			internal sbyte X;

			internal sbyte Y;

			internal byte Rotation;
		}

		private static readonly FieldInfo UpgradeBufferField = AccessTools.Field(typeof(PlayerData), "upgradeBuffer");

		private static readonly FieldInfo UpgradeDupeBufferField = AccessTools.Field(typeof(PlayerData), "upgradeDupeBuffer");

		internal static bool CanSubmit(UpgradeInstance input, out string reason)
		{
			reason = null;
			if ((Object)(object)((input != null) ? input.Upgrade : null) == (Object)null || !input.IsCollected || input.Upgrade.IsSkin())
			{
				reason = "Select a module from your inventory.";
			}
			else if (!input.RemoveAfterMission)
			{
				reason = "Only temporary Ouroboros modules are accepted.";
			}
			return reason == null;
		}

		internal static List<ResourceCost> Cost(UpgradeInstance input)
		{
			return new List<ResourceCost>(input.Upgrade.GetOuroborosCost());
		}

		internal static UpgradeInstance Prepare(UpgradeInstance input, int seed)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			if (!CanSubmit(input, out var _) || input.Gear == null)
			{
				return null;
			}
			bool flag = (int)input.Gear.GearType == 5;
			UpgradeFilterParams val = default(UpgradeFilterParams);
			((UpgradeFilterParams)(ref val))..ctor(input.Upgrade.Rarity, flag ? null : input.Gear, (DuplicateMode)2, (UnlockFlags)0, false, false, false);
			val.isTempMissionUpgrade = true;
			PlayerData.FindRandomUpgrade(val, false, seed);
			List<FilterResult> list = UpgradeBufferField?.GetValue(null) as List<FilterResult>;
			List<FilterResult> list2 = UpgradeDupeBufferField?.GetValue(null) as List<FilterResult>;
			if (list == null || list2 == null)
			{
				FloppyPlugin.Log.LogError((object)"Floppy could not read the game's eligible module pool.");
				return null;
			}
			List<FilterResult> pool = new List<FilterResult>();
			HashSet<Tuple<int, Upgrade>> seen = new HashSet<Tuple<int, Upgrade>>();
			Add(list);
			Add(list2);
			if (pool.Count == 0)
			{
				return null;
			}
			FilterResult val2 = pool[new Random(seed).Next(pool.Count)];
			UpgradeInstance obj = PlayerData.CreateUpgradeInstance(val2.gear, val2.info.Upgrade, false);
			obj.RemoveAfterMission = true;
			return obj;
			void Add(List<FilterResult> source)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				foreach (FilterResult item in source)
				{
					UpgradeInfo info = item.info;
					Upgrade val3 = ((info != null) ? info.Upgrade : null);
					if (item.gear != null && !((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)input.Upgrade) && val3.Rarity == input.Upgrade.Rarity && !val3.IsSkin() && IsAllowedGear(input.Gear, item.gear) && seen.Add(Tuple.Create<int, Upgrade>(item.gear.Info.ID, val3)))
					{
						pool.Add(item);
					}
				}
			}
		}

		private static bool SameGear(IUpgradable first, IUpgradable second)
		{
			if (first != null && second != null)
			{
				return first.Info.ID == second.Info.ID;
			}
			return false;
		}

		private static bool IsAllowedGear(IUpgradable input, IUpgradable output)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if (input == null || output == null)
			{
				return false;
			}
			if ((int)input.GearType != 5)
			{
				return SameGear(input, output);
			}
			Character second = (((Object)(object)Player.LocalPlayer != (Object)null) ? Player.LocalPlayer.Character : null);
			if (!SameGear(output, (IUpgradable)(object)Global.Instance))
			{
				return SameGear(output, (IUpgradable)(object)second);
			}
			return true;
		}

		internal static bool Commit(UpgradeInstance input, UpgradeInstance output, out string reason)
		{
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!CanSubmit(input, out reason))
			{
				return false;
			}
			if ((Object)(object)((output != null) ? output.Upgrade : null) == (Object)null || output.Gear == null || output.IsCollected || !output.RemoveAfterMission || !IsAllowedGear(input.Gear, output.Gear) || (Object)(object)output.Upgrade == (Object)(object)input.Upgrade || output.Upgrade.IsSkin() || output.Upgrade.Rarity != input.Upgrade.Rarity)
			{
				reason = "No eligible module of the same rarity could be selected.";
				return false;
			}
			List<ResourceCost> list = Cost(input);
			UpgradeInfo upgradeInfo = PlayerData.GetUpgradeInfo(output.Gear, output.Upgrade);
			int totalInstancesCollected = upgradeInfo.TotalInstancesCollected;
			List<EquippedSlot> list2 = new List<EquippedSlot>();
			sbyte x = default(sbyte);
			sbyte y = default(sbyte);
			byte rotation = default(byte);
			foreach (GearData value in PlayerData.Instance.collectedGear.Values)
			{
				if (input.GetPosition(value.Gear, ref x, ref y, ref rotation))
				{
					list2.Add(new EquippedSlot
					{
						Gear = value.Gear,
						X = x,
						Y = y,
						Rotation = rotation
					});
				}
			}
			if (!PlayerData.Instance.TryRemoveResources(list))
			{
				reason = "Not enough currency for this exchange.";
				return false;
			}
			try
			{
				input.UnequipFromAll();
				if (!input.Destroy())
				{
					throw new InvalidOperationException("Input not removed");
				}
				PlayerData.CollectInstance(output, (UnlockFlags)0);
				if (!output.IsCollected)
				{
					throw new InvalidOperationException("Reward not collected");
				}
				Reapply();
				return true;
			}
			catch (Exception ex)
			{
				upgradeInfo.SetTotalInstancesCollected(totalInstancesCollected);
				if (!input.IsCollected)
				{
					PlayerData.GetUpgradeInfo(input.Gear, input.Upgrade).Instances.Add(input);
				}
				if (output.IsCollected)
				{
					output.UnequipFromAll();
					PlayerData.GetUpgradeInfo(output.Gear, output.Upgrade).Instances.Remove(output);
				}
				foreach (EquippedSlot item in list2)
				{
					input.Equip(item.Gear, item.X, item.Y, item.Rotation, true, false);
				}
				foreach (ResourceCost item2 in list)
				{
					PlayerData.Instance.AddResource(item2.resource, item2.count, false);
				}
				Reapply();
				FloppyPlugin.Log.LogError((object)("Exchange rolled back: " + ex));
				reason = "Exchange cancelled. Your module and payment were returned.";
				return false;
			}
		}

		private static void Reapply()
		{
			try
			{
				GearUtil.ReapplyUpgrades();
			}
			catch (Exception ex)
			{
				FloppyPlugin.Log.LogError((object)("Could not refresh equipment after exchange: " + ex));
			}
		}
	}
	internal static class FloppyAvailability
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnState;

			public static HandleNamedMessageDelegate <1>__OnRequest;

			public static Action<ulong> <2>__OnConnected;

			public static Action<ulong> <3>__OnDisconnected;
		}

		private const string StateMessage = "horse.mycopunk.floppy.availability.v1";

		private const string RequestMessage = "horse.mycopunk.floppy.availability-request.v1";

		private static NetworkManager manager;

		private static CustomMessagingManager messages;

		private static bool remoteKnown;

		private static bool remoteEnabled;

		private static bool lastPreference;

		private static float nextRequest;

		internal static bool CanEdit
		{
			get
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsListening)
				{
					return singleton.IsServer;
				}
				return true;
			}
		}

		internal static bool IsSynchronized
		{
			get
			{
				if (!CanEdit)
				{
					if ((Object)(object)manager == (Object)(object)NetworkManager.Singleton && messages != null)
					{
						return remoteKnown;
					}
					return false;
				}
				return true;
			}
		}

		internal static bool Enabled
		{
			get
			{
				if (!CanEdit)
				{
					if (IsSynchronized)
					{
						return remoteEnabled;
					}
					return false;
				}
				return FloppyPlugin.Instance?.Enabled.Value ?? false;
			}
		}

		internal static void SetEnabled(bool enabled)
		{
			if (CanEdit && !((Object)(object)FloppyPlugin.Instance == (Object)null))
			{
				FloppyPlugin.Instance.Enabled.Value = enabled;
				((BaseUnityPlugin)FloppyPlugin.Instance).Config.Save();
				lastPreference = enabled;
				if ((Object)(object)manager != (Object)null && manager.IsServer)
				{
					Broadcast();
				}
			}
		}

		internal unsafe static void Tick(float now)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			CustomMessagingManager val = (((Object)(object)singleton != (Object)null && singleton.IsListening) ? singleton.CustomMessagingManager : null);
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening || val == null)
			{
				if (messages != null || (Object)(object)manager != (Object)null)
				{
					Dispose();
				}
				return;
			}
			if ((Object)(object)manager != (Object)(object)singleton || messages != val)
			{
				Dispose();
				manager = singleton;
				messages = val;
				remoteKnown = false;
				nextRequest = now;
				lastPreference = FloppyPlugin.Instance?.Enabled.Value ?? false;
				CustomMessagingManager obj = messages;
				object obj2 = <>O.<0>__OnState;
				if (obj2 == null)
				{
					HandleNamedMessageDelegate val2 = OnState;
					<>O.<0>__OnState = val2;
					obj2 = (object)val2;
				}
				obj.RegisterNamedMessageHandler("horse.mycopunk.floppy.availability.v1", (HandleNamedMessageDelegate)obj2);
				CustomMessagingManager obj3 = messages;
				object obj4 = <>O.<1>__OnRequest;
				if (obj4 == null)
				{
					HandleNamedMessageDelegate val3 = OnRequest;
					<>O.<1>__OnRequest = val3;
					obj4 = (object)val3;
				}
				obj3.RegisterNamedMessageHandler("horse.mycopunk.floppy.availability-request.v1", (HandleNamedMessageDelegate)obj4);
				manager.OnClientConnectedCallback += OnConnected;
				manager.OnClientDisconnectCallback += OnDisconnected;
				if (manager.IsServer)
				{
					Broadcast();
				}
			}
			bool flag = FloppyPlugin.Instance?.Enabled.Value ?? false;
			if (manager.IsServer && flag != lastPreference)
			{
				lastPreference = flag;
				Broadcast();
			}
			if (manager.IsServer || !manager.IsConnectedClient || remoteKnown || !(now >= nextRequest))
			{
				return;
			}
			nextRequest = now + 0.75f;
			FastBufferWriter val4 = default(FastBufferWriter);
			((FastBufferWriter)(ref val4))..ctor(1, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val4)).WriteByteSafe((byte)1);
				messages.SendNamedMessage("horse.mycopunk.floppy.availability-request.v1", 0uL, val4, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val4))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static void OnConnected(ulong clientId)
		{
			if (!((Object)(object)manager == (Object)null))
			{
				if (manager.IsServer)
				{
					SendState(clientId);
				}
				else if (clientId == manager.LocalClientId)
				{
					remoteKnown = false;
					nextRequest = 0f;
				}
			}
		}

		private static void OnDisconnected(ulong clientId)
		{
			if ((Object)(object)manager != (Object)null && !manager.IsServer && clientId == manager.LocalClientId)
			{
				remoteKnown = false;
			}
		}

		private static void OnRequest(ulong sender, FastBufferReader reader)
		{
			if (!((Object)(object)manager == (Object)null) && manager.IsServer && ((FastBufferReader)(ref reader)).TryBeginRead(1))
			{
				byte b = default(byte);
				((FastBufferReader)(ref reader)).ReadByteSafe(ref b);
				if (b == 1)
				{
					SendState(sender);
				}
			}
		}

		private static void OnState(ulong sender, FastBufferReader reader)
		{
			if (!((Object)(object)manager == (Object)null) && !manager.IsServer && sender == 0L && ((FastBufferReader)(ref reader)).TryBeginRead(2))
			{
				byte b = default(byte);
				((FastBufferReader)(ref reader)).ReadByteSafe(ref b);
				byte b2 = default(byte);
				((FastBufferReader)(ref reader)).ReadByteSafe(ref b2);
				if (b == 1 && b2 <= 1)
				{
					remoteEnabled = b2 == 1;
					remoteKnown = true;
				}
			}
		}

		private unsafe static void SendState(ulong clientId)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (messages == null || (Object)(object)manager == (Object)null || !manager.IsServer)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(2, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteByteSafe((byte)1);
				((FastBufferWriter)(ref val)).WriteByteSafe(Enabled ? ((byte)1) : ((byte)0));
				messages.SendNamedMessage("horse.mycopunk.floppy.availability.v1", clientId, val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private unsafe static void Broadcast()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (messages == null || (Object)(object)manager == (Object)null || !manager.IsServer)
			{
				return;
			}
			FastBufferWriter val = default(FastBufferWriter);
			((FastBufferWriter)(ref val))..ctor(2, (Allocator)2, -1);
			try
			{
				((FastBufferWriter)(ref val)).WriteByteSafe((byte)1);
				((FastBufferWriter)(ref val)).WriteByteSafe(Enabled ? ((byte)1) : ((byte)0));
				messages.SendNamedMessageToAll("horse.mycopunk.floppy.availability.v1", val, (NetworkDelivery)3);
			}
			finally
			{
				((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		internal static void Dispose()
		{
			if ((Object)(object)manager != (Object)null)
			{
				manager.OnClientConnectedCallback -= OnConnected;
				manager.OnClientDisconnectCallback -= OnDisconnected;
			}
			if (messages != null)
			{
				messages.UnregisterNamedMessageHandler("horse.mycopunk.floppy.availability.v1");
				messages.UnregisterNamedMessageHandler("horse.mycopunk.floppy.availability-request.v1");
			}
			manager = null;
			messages = null;
			remoteKnown = false;
			remoteEnabled = false;
			nextRequest = 0f;
		}
	}
	internal sealed class FloppyDeferredShop : MonoBehaviour
	{
		private OuroStoreRoom shop;

		private OuroObjective objective;

		private OuroItemPositions positions;

		private OuroRoom room;

		private int seed;

		private bool pending;

		internal void Defer(OuroStoreRoom owner, OuroObjective source, OuroItemPositions itemPositions, OuroRoom sourceRoom, int shopSeed)
		{
			shop = owner;
			objective = source;
			positions = itemPositions;
			room = sourceRoom;
			seed = shopSeed;
			pending = true;
			((Component)owner).gameObject.SetActive(true);
		}

		internal void Clear()
		{
			pending = false;
		}

		internal static void DisposeAll()
		{
			FloppyDeferredShop[] array = Object.FindObjectsByType<FloppyDeferredShop>((FindObjectsInactive)1);
			foreach (FloppyDeferredShop floppyDeferredShop in array)
			{
				bool num = floppyDeferredShop.pending;
				floppyDeferredShop.pending = false;
				if (num && (Object)(object)floppyDeferredShop.shop != (Object)null && (Object)(object)floppyDeferredShop.objective != (Object)null && !((ObjectiveBase)floppyDeferredShop.objective).HasEnded && (Object)(object)GameManager.Instance != (Object)null)
				{
					try
					{
						floppyDeferredShop.shop.Setup(floppyDeferredShop.objective, floppyDeferredShop.positions, floppyDeferredShop.room, floppyDeferredShop.seed);
					}
					catch (Exception ex)
					{
						ManualLogSource log = FloppyPlugin.Log;
						if (log != null)
						{
							log.LogWarning((object)("Could not restore deferred shop: " + ex));
						}
					}
				}
				Object.Destroy((Object)(object)floppyDeferredShop);
			}
		}

		private void Update()
		{
			if (pending && FloppyAvailability.IsSynchronized)
			{
				pending = false;
				if ((Object)(object)shop != (Object)null && (Object)(object)objective != (Object)null)
				{
					shop.Setup(objective, positions, room, seed);
				}
			}
		}

		private void OnDisable()
		{
			pending = false;
		}
	}
	internal static class FloppyExchangeDiagnostics
	{
		private static readonly FieldInfo GridStealerField = AccessTools.Field(typeof(OuroObjective), "gridStealerUpgrade");

		internal static void LogState(string phase, UpgradeInstance input, UpgradeInstance output)
		{
			try
			{
				Player localPlayer = Player.LocalPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				OuroObjective val = (((Object)(object)MissionManager.Instance != (Object)null) ? MissionManager.Instance.GetObjective<OuroObjective>() : null);
				Upgrade gridStealer = (Upgrade)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
				HashSet<int> seen = new HashSet<int>();
				StringBuilder grids = new StringBuilder();
				Add((IUpgradable)(object)localPlayer.Character);
				if (localPlayer.Gear != null)
				{
					IGear[] gear = localPlayer.Gear;
					foreach (IGear val2 in gear)
					{
						if (val2 != null)
						{
							Add(((IUpgradable)val2).Prefab);
						}
					}
				}
				FloppyPlugin.Log.LogInfo((object)("Exchange " + phase + ": input=" + Describe(input) + "; reward=" + Describe(output) + "; autoApply=" + OuroObjective.AutoApplyUpgrades + "; grids=[" + grids?.ToString() + "]"));
				void Add(IUpgradable val3)
				{
					if (val3 != null && val3.Info.HasUpgradeGrid && seen.Add(val3.Info.ID))
					{
						int value = default(int);
						int value2 = default(int);
						val3.Info.GetUpgradeGridSize(ref value, ref value2, false);
						int num = 0;
						if ((Object)(object)gridStealer != (Object)null)
						{
							EquippedUpgradeEnumerator val4 = default(EquippedUpgradeEnumerator);
							((EquippedUpgradeEnumerator)(ref val4))..ctor(val3, true);
							while (((EquippedUpgradeEnumerator)(ref val4)).MoveNext())
							{
								if (((EquippedUpgradeEnumerator)(ref val4)).Upgrade != null && (Object)(object)((EquippedUpgradeEnumerator)(ref val4)).Upgrade.Upgrade == (Object)(object)gridStealer)
								{
									num++;
								}
							}
						}
						if (grids.Length > 0)
						{
							grids.Append("; ");
						}
						grids.Append(val3.Info.APIName).Append('#').Append(val3.Info.ID)
							.Append('=')
							.Append(value)
							.Append('x')
							.Append(value2)
							.Append("/gridStealers=")
							.Append(num);
					}
				}
			}
			catch (Exception ex)
			{
				FloppyPlugin.Log.LogDebug((object)("Exchange grid diagnostics unavailable: " + ex.Message));
			}
		}

		private static string Describe(UpgradeInstance module)
		{
			if (!((Object)(object)((module != null) ? module.Upgrade : null) == (Object)null))
			{
				string[] obj = new string[7]
				{
					module.InstanceID.ToString(),
					"/",
					module.Upgrade.NumberID.ToString(),
					"/",
					module.Upgrade.GetInstanceName(module),
					"/gear=",
					null
				};
				IUpgradable gear = module.Gear;
				obj[6] = ((gear != null) ? new int?(gear.Info.ID) : ((int?)null)).ToString();
				return string.Concat(obj);
			}
			return "none";
		}
	}
	internal static class FloppyInventorySelection
	{
		private static FloppyStation owner;

		private static Action<UpgradeInstance> selected;

		private static readonly Action<UpgradeInstance> receive = Receive;

		internal static bool Active
		{
			get
			{
				if ((Object)(object)owner != (Object)null && OuroGearWindow.OpenAsUpgradeSelect)
				{
					return OuroGearWindow.OnUpgradeSelected == receive;
				}
				return false;
			}
		}

		internal static void Open(FloppyStation station, Action<UpgradeInstance> callback)
		{
			Cancel();
			GameManager.Instance.OpenMenu(true);
			owner = station;
			selected = callback;
			OuroGearWindow.OpenAsUpgradeSelect = true;
			OuroGearWindow.OnUpgradeSelected = receive;
		}

		private static void Receive(UpgradeInstance upgrade)
		{
			if (Active)
			{
				Action<UpgradeInstance> action = selected;
				Cancel();
				action?.Invoke(upgrade);
			}
		}

		internal static bool AllowNonStackable(UpgradeInstance upgrade)
		{
			if (!Active)
			{
				return upgrade.CanStack;
			}
			return true;
		}

		internal static void Cancel(FloppyStation station = null)
		{
			if (!((Object)(object)station != (Object)null) || !((Object)(object)owner != (Object)(object)station))
			{
				if (OuroGearWindow.OnUpgradeSelected == receive)
				{
					OuroGearWindow.OnUpgradeSelected = null;
					OuroGearWindow.OpenAsUpgradeSelect = false;
				}
				owner = null;
				selected = null;
			}
		}
	}
	[HarmonyPatch(typeof(OuroGearWindow), "AddUpgrade")]
	internal static class FloppyInventoryStackFilter
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo getter = AccessTools.PropertyGetter(typeof(UpgradeInstance), "CanStack");
			MethodInfo replacement = AccessTools.Method(typeof(FloppyInventorySelection), "AllowNonStackable", (Type[])null, (Type[])null);
			int replaced = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, getter))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = replacement;
					replaced++;
				}
				yield return instruction;
			}
			if (replaced != 1)
			{
				throw new InvalidOperationException("OuroGearWindow stack filter changed; Floppy patch was not applied.");
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "OnClose")]
	internal static class FloppyInventoryClose
	{
		private static void Postfix()
		{
			FloppyInventorySelection.Cancel();
		}
	}
	[HarmonyPatch(typeof(MissionInfoWindow), "Setup")]
	internal static class FloppyMissionTogglePatch
	{
		private static readonly FieldInfo ToggleField = AccessTools.Field(typeof(MissionInfoWindow), "toggleButton");

		private static bool reportedError;

		private static void Prefix(MissionInfoWindow __instance)
		{
			((Component)__instance).GetComponent<FloppyMissionToggle>()?.RestoreNativeLayout();
		}

		private static void Postfix(MissionInfoWindow __instance)
		{
			FloppyMissionToggle floppyMissionToggle = ((Component)__instance).GetComponent<FloppyMissionToggle>();
			if ((Object)(object)FloppyPlugin.Instance == (Object)null || !(((MissionData)(ref __instance.Mission)).Mission is OuroMission))
			{
				floppyMissionToggle?.Hide();
				return;
			}
			try
			{
				object? obj = ToggleField?.GetValue(__instance);
				DefaultButton val = (DefaultButton)((obj is DefaultButton) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					throw new InvalidOperationException("The mission options toggle is unavailable.");
				}
				if ((Object)(object)floppyMissionToggle == (Object)null)
				{
					floppyMissionToggle = ((Component)__instance).gameObject.AddComponent<FloppyMissionToggle>();
				}
				floppyMissionToggle.Setup(__instance, val);
			}
			catch (Exception ex)
			{
				floppyMissionToggle?.Hide();
				if (!reportedError)
				{
					reportedError = true;
					FloppyPlugin.Log.LogError((object)("Could not add the Floppy mission option: " + ex));
				}
			}
		}
	}
	internal sealed class FloppyMissionToggle : MonoBehaviour
	{
		private MissionInfoWindow window;

		private DefaultButton nativeToggle;

		private DefaultButton button;

		private RectTransform nativeRect;

		private RectTransform buttonRect;

		private TextMeshProUGUI label;

		private Image icon;

		private CanvasGroup appearance;

		private Vector2 nativePosition;

		private bool hasNativePosition;

		private bool visible;

		private bool lastEnabled;

		private bool lastCanEdit;

		private bool lastAuthority;

		private int lastLanguage = -1;

		internal bool CanEdit
		{
			get
			{
				if ((Object)(object)FloppyPlugin.Instance != (Object)null && FloppyAvailability.CanEdit)
				{
					if (!((Object)(object)DropPod.Instance == (Object)null))
					{
						return !DropPod.Instance.IsLaunching;
					}
					return true;
				}
				return false;
			}
		}

		internal void Setup(MissionInfoWindow owner, DefaultButton template)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			window = owner;
			nativeToggle = template;
			nativeRect = (RectTransform)((Component)template).transform;
			nativePosition = nativeRect.anchoredPosition;
			hasNativePosition = true;
			if ((Object)(object)button == (Object)null)
			{
				CreateButton(template);
			}
			visible = true;
			PositionControls();
			RefreshState(force: true);
			((Component)button).gameObject.SetActive(true);
		}

		private void CreateButton(DefaultButton template)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			button = Object.Instantiate<DefaultButton>(template, ((Component)template).transform.parent, false);
			((Object)((Component)button).gameObject).name = "FloppyMissionToggle";
			((Component)button).gameObject.SetActive(false);
			buttonRect = (RectTransform)((Component)button).transform;
			((Button)button).OnHoverEnter = new UnityEvent();
			((Button)button).OnHoverExit = new UnityEvent();
			((Button)button).OnClickDown = new UnityEvent();
			((Button)button).OnClickUp = new UnityEvent();
			((Button)button).OnClickUp.AddListener(new UnityAction(OnClick));
			label = ((Component)button).GetComponentInChildren<TextMeshProUGUI>(true);
			ref Image reference = ref icon;
			Graphic secondaryGraphic = button.SecondaryGraphic;
			reference = (Image)(object)((secondaryGraphic is Image) ? secondaryGraphic : null);
			if ((Object)(object)label == (Object)null || (Object)(object)icon == (Object)null || (Object)(object)button.MainGraphic == (Object)null)
			{
				throw new InvalidOperationException("The mission options toggle has an unsupported layout.");
			}
			appearance = ((Component)button).gameObject.AddComponent<CanvasGroup>();
			((Component)button).gameObject.AddComponent<FloppyMissionToggleHint>().Owner = this;
			((Component)button).GetComponent<Graphic>().raycastTarget = true;
		}

		private void PositionControls()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (!visible || (Object)(object)nativeRect == (Object)null || (Object)(object)buttonRect == (Object)null)
			{
				return;
			}
			Transform parent = ((Transform)nativeRect).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			if (!((Object)(object)val == (Object)null))
			{
				Rect rect = val.rect;
				float num = ((Rect)(ref rect)).width * 0.25f;
				buttonRect.anchoredPosition = new Vector2(0f - num, nativePosition.y);
				if (((Component)nativeToggle).gameObject.activeSelf)
				{
					nativeRect.anchoredPosition = new Vector2(num, nativePosition.y);
				}
			}
		}

		internal void RestoreNativeLayout()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (hasNativePosition && (Object)(object)nativeRect != (Object)null)
			{
				nativeRect.anchoredPosition = nativePosition;
			}
			hasNativePosition = false;
		}

		internal void Hide()
		{
			visible = false;
			RestoreNativeLayout();
			if ((Object)(object)button != (Object)null)
			{
				((Component)button).gameObject.SetActive(false);
			}
		}

		private void OnClick()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (visible && ((Behaviour)this).isActiveAndEnabled && !((Object)(object)window == (Object)null) && ((Component)window).gameObject.activeInHierarchy && ((MissionData)(ref window.Mission)).Mission is OuroMission && CanEdit && (int)((Button)button).LastPressButton == 0)
			{
				FloppyAvailability.SetEnabled(!FloppyAvailability.Enabled);
				RefreshState(force: true);
			}
		}

		private void LateUpdate()
		{
			if (visible && !((Object)(object)button == (Object)null))
			{
				if ((Object)(object)FloppyPlugin.Instance == (Object)null)
				{
					Hide();
				}
				else
				{
					RefreshState(force: false);
				}
			}
		}

		private void OnRectTransformDimensionsChange()
		{
			PositionControls();
		}

		private void RefreshState(bool force)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			bool enabled = FloppyAvailability.Enabled;
			bool canEdit = CanEdit;
			bool canEdit2 = FloppyAvailability.CanEdit;
			int languageIndex = TextBlocks.LanguageIndex;
			if (force || lastEnabled != enabled || lastCanEdit != canEdit || lastAuthority != canEdit2 || lastLanguage != languageIndex)
			{
				lastEnabled = enabled;
				lastCanEdit = canEdit;
				lastAuthority = canEdit2;
				lastLanguage = languageIndex;
				((TMP_Text)label).text = (canEdit2 ? "Floppy" : "Floppy · HOST");
				((Button)button).IgnoreEvents = !canEdit;
				appearance.alpha = (canEdit ? 1f : 0.55f);
				icon.sprite = (enabled ? Global.Instance.CheckmarkIcon : Global.Instance.CrossIcon);
				button.SetDefaultColor(enabled ? Global.Instance.RedUIColor : Global.Instance.WhiteUIColor);
				RectOutline val = default(RectOutline);
				float num = (((Component)button).TryGetComponent<RectOutline>(ref val) ? ((OutlineGraphic)val).thickness : 1.5f);
				RectTransform rectTransform = button.MainGraphic.rectTransform;
				Rect rect = ((RectTransform)((Transform)rectTransform).parent).rect;
				float num2 = ((Rect)(ref rect)).width * 0.5f;
				rect = rectTransform.rect;
				float num3 = num2 - ((Rect)(ref rect)).width * 0.5f - num;
				rectTransform.anchoredPosition = new Vector2(enabled ? num3 : (0f - num3), rectTransform.anchoredPosition.y);
				if (((Button)button).Hovering && (Object)(object)HoverInfoDisplay.Instance != (Object)null)
				{
					HoverInfoDisplay.Instance.Refresh();
				}
			}
		}

		private void OnDestroy()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			RestoreNativeLayout();
			if ((Object)(object)button != (Object)null)
			{
				((Button)button).OnClickUp.RemoveListener(new UnityAction(OnClick));
				((Component)button).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)button).gameObject);
			}
		}

		internal static void DisposeAll()
		{
			FloppyMissionToggle[] array = Object.FindObjectsByType<FloppyMissionToggle>((FindObjectsInactive)1);
			foreach (FloppyMissionToggle obj in array)
			{
				obj.Hide();
				Object.Destroy((Object)(object)obj);
			}
		}
	}
	internal sealed class FloppyMissionToggleHint : HoverInfo
	{
		internal FloppyMissionToggle Owner;

		public override string GetInfo(HoverInfoDisplay display)
		{
			if (!FloppyAvailability.CanEdit)
			{
				return "The lobby host chooses whether Floppy appears.";
			}
			if ((Object)(object)Owner == (Object)null || !Owner.CanEdit)
			{
				return "Deployment has already started.";
			}
			return "Replace Ouroboros shops with Floppy. Change this before starting or continuing a run.";
		}

		public override bool GetTitle(out string title, out Color color)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			title = "Floppy";
			color = Global.Instance.WhiteUIColor;
			return true;
		}

		public override bool CanChangeCursor(out CursorData cursor)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			cursor = Global.Instance.GetPointCursor();
			if ((Object)(object)Owner != (Object)null)
			{
				return Owner.CanEdit;
			}
			return false;
		}
	}
	[BepInPlugin("horse.mycopunk.floppy", "Floppy", "0.4.1")]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public sealed class FloppyPlugin : BaseUnityPlugin
	{
		public const string Guid = "horse.mycopunk.floppy";

		internal static FloppyPlugin Instance;

		internal static ManualLogSource Log;

		internal ConfigEntry<bool> Enabled;

		internal ConfigEntry<float> Volume;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Replace Ouroboros shops with Floppy.");
			Volume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 0.6f, new ConfigDescription("Spatial retro PC sound volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			try
			{
				ModelAssets.Load();
				PcAudio.Load();
				harmony = new Harmony("horse.mycopunk.floppy");
				harmony.PatchAll(typeof(FloppyPlugin).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Floppy loaded. Three exchanges per player per shop appearance.");
			}
			catch (Exception ex)
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Floppy could not load; vanilla shops remain available: " + ex));
			}
		}

		private void OnDestroy()
		{
			FloppyMissionToggle.DisposeAll();
			FloppyAvailability.Dispose();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			FloppyInventorySelection.Cancel();
			FloppyStation[] array = Object.FindObjectsByType<FloppyStation>((FindObjectsInactive)1);
			foreach (FloppyStation obj2 in array)
			{
				((Component)obj2).gameObject.SetActive(false);
				obj2.RestoreVanilla();
				Object.Destroy((Object)(object)((Component)obj2).gameObject);
			}
			FloppyDeferredShop.DisposeAll();
			ModelAssets.Dispose();
			PcAudio.Dispose();
			Instance = null;
		}

		private void Update()
		{
			FloppyAvailability.Tick(Time.unscaledTime);
		}
	}
	[HarmonyPatch(typeof(OuroStoreRoom), "Setup")]
	internal static class ReplaceShop
	{
		private static bool Prefix(OuroStoreRoom __instance, OuroObjective objective, OuroItemPositions itemPositions, OuroRoom room, int seed)
		{
			if ((Object)(object)FloppyPlugin.Instance == (Object)null || !ModelAssets.Ready)
			{
				return true;
			}
			FloppyStation floppyStation = ((Component)__instance).GetComponentInChildren<FloppyStation>(true);
			FloppyDeferredShop floppyDeferredShop = ((Component)__instance).GetComponent<FloppyDeferredShop>();
			if (!FloppyAvailability.IsSynchronized)
			{
				if ((Object)(object)floppyStation != (Object)null)
				{
					((Component)floppyStation).gameObject.SetActive(false);
				}
				if ((Object)(object)floppyDeferredShop == (Object)null)
				{
					floppyDeferredShop = ((Component)__instance).gameObject.AddComponent<FloppyDeferredShop>();
				}
				floppyDeferredShop.Defer(__instance, objective, itemPositions, room, seed);
				return false;
			}
			floppyDeferredShop?.Clear();
			if (!FloppyAvailability.Enabled)
			{
				if ((Object)(object)floppyStation != (Object)null)
				{
					((Component)floppyStation).gameObject.SetActive(false);
					floppyStation.RestoreVanilla();
				}
				return true;
			}
			try
			{
				if ((Object)(object)floppyStation == (Object)null)
				{
					floppyStation = ModelAssets.Instantiate(((Component)__instance).transform).AddComponent<FloppyStation>();
				}
				floppyStation.Setup(__instance, objective, itemPositions, room, seed);
				return false;
			}
			catch (Exception ex)
			{
				FloppyPlugin.Log.LogError((object)("Floppy setup failed; restoring vanilla shop: " + ex));
				if ((Object)(object)floppyStation != (Object)null)
				{
					floppyStation.RestoreVanilla();
					Object.Destroy((Object)(object)((Component)floppyStation).gameObject);
				}
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(OuroObjective), "SpawnShop_ClientRpc")]
	internal static class FloppyShopAnnouncement
	{
		private static void Prefix(ref bool playVoiceline)
		{
			if ((Object)(object)FloppyPlugin.Instance != (Object)null && ModelAssets.Ready && FloppyAvailability.IsSynchronized && FloppyAvailability.Enabled)
			{
				playVoiceline = false;
			}
		}
	}
	internal sealed class FloppyShopHint : HoverInfo
	{
		internal FloppyStation Owner;

		private string shownText;

		private UpgradeInstance shownModule;

		private bool shownCanConfirm;

		private InputAction cancelAction;

		internal bool CancelPressed
		{
			get
			{
				if (cancelAction != null)
				{
					return cancelAction.WasPressedThisFrame();
				}
				return false;
			}
		}

		public override bool CenterText => false;

		public override object Context
		{
			get
			{
				if (!((Object)(object)Owner != (Object)null))
				{
					return this;
				}
				return ((object)Owner.SelectedModule) ?? ((object)Owner);
			}
		}

		private void OnEnable()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (cancelAction == null)
			{
				MenuActions menu = PlayerInput.Controls.Menu;
				cancelAction = ((MenuActions)(ref menu)).Cancel.Clone();
			}
			cancelAction.Enable();
		}

		public override bool HasAnchor(out AnchorParams anchor)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			anchor = new AnchorParams
			{
				Pivot = new Vector2(0.5f, 1f),
				Offset = new Vector2(0f, -110f),
				GamepadOnly = false
			};
			return true;
		}

		public override string GetInfo(HoverInfoDisplay display)
		{
			if (!((Object)(object)Owner != (Object)null))
			{
				return "";
			}
			return Owner.HintText;
		}

		public override bool GetTitle(out string title, out Color color)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			title = "Floppy";
			color = Global.Instance.WhiteUIColor;
			return true;
		}

		public override bool GetSubtitle(out string subtitle, out Color color)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			UpgradeInstance val = (((Object)(object)Owner != (Object)null) ? Owner.SelectedModule : null);
			subtitle = ((val != null) ? val.Upgrade.GetInstanceName(val) : null);
			color = ((val != null) ? val.Upgrade.Color : Color.white);
			return val != null;
		}

		public override Color GetOutlineColor(out Material material)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			UpgradeInstance val = (((Object)(object)Owner != (Object)null) ? Owner.SelectedModule : null);
			material = FloppyUiMaterial.Resolve((val != null) ? val.UIMaterial : null);
			if (val == null)
			{
				return Color.white;
			}
			return val.Upgrade.Color;
		}

		public override bool GetPrimaryBinding(out InputAction binding, out string label)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			PlayerActions player = PlayerInput.Controls.Player;
			binding = ((PlayerActions)(ref player)).Interact;
			label = "Exchange";
			if ((Object)(object)Owner != (Object)null)
			{
				return Owner.CanConfirmExchange;
			}
			return false;
		}

		public override bool GetSecondaryBinding(out InputAction binding, out string label)
		{
			binding = cancelAction;
			label = "Cancel";
			if ((Object)(object)Owner != (Object)null && Owner.CanCancelSelection)
			{
				return cancelAction != null;
			}
			return false;
		}

		public override bool HasUnlockAction(out UnlockActionParams data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			data = default(UnlockActionParams);
			if ((Object)(object)Owner == (Object)null || !Owner.CanConfirmExchange)
			{
				return false;
			}
			data.Duration = 0.65f;
			data.Cost = ExchangeRules.Cost(Owner.SelectedModule);
			PlayerActions player = PlayerInput.Controls.Player;
			data.Action = ((PlayerActions)(ref player)).Interact;
			data.UnlockLoop = WwiseEvent.op_Implicit(Global.Instance.UnlockLoop);
			data.OnComplete = Confirm;
			return true;
		}

		private void Confirm()
		{
			if ((Object)(object)Owner != (Object)null && Owner.CanConfirmExchange)
			{
				Owner.Interact(Player.LocalPlayer);
			}
		}

		private void Update()
		{
			HoverInfoDisplay instance = HoverInfoDisplay.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (!((Object)(object)Owner != (Object)null) || !((Object)(object)Highlighter.Instance != (Object)null) || (object)Highlighter.Instance.SelectedTarget != Owner || !Highlighter.Instance.IsSelectedTargetInInteractRange || !PlayerInput.IsPlayerEnabled || PlayerInput.IsMenuEnabled || !PositionAnchor(instance))
			{
				if ((Object)(object)instance.SelectedInfo == (Object)(object)this && ((Component)instance).gameObject.activeSelf)
				{
					instance.Deactivate();
				}
				return;
			}
			string hintText = Owner.HintText;
			UpgradeInstance selectedModule = Owner.SelectedModule;
			bool canConfirmExchange = Owner.CanConfirmExchange;
			if ((Object)(object)instance.SelectedInfo != (Object)(object)this || !((Component)instance).gameObject.activeSelf)
			{
				instance.ShowInfo((HoverInfo)(object)this);
			}
			else if (shownText != hintText || shownModule != selectedModule || shownCanConfirm != canConfirmExchange)
			{
				instance.Refresh();
			}
			shownText = hintText;
			shownModule = selectedModule;
			shownCanConfirm = canConfirmExchange;
		}

		private void LateUpdate()
		{
			HoverInfoDisplay instance = HoverInfoDisplay.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.SelectedInfo != (Object)(object)this) && ((Component)instance).gameObject.activeSelf && (!PlayerInput.IsPlayerEnabled || PlayerInput.IsMenuEnabled || !PositionAnchor(instance)))
			{
				instance.Deactivate();
			}
		}

		private bool PositionAnchor(HoverInfoDisplay display)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)display).GetComponentInParent<Canvas>();
			Camera val = (((Object)(object)componentInParent != (Object)null) ? componentInParent.worldCamera : null);
			if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
			{
				val = PlayerLook.LocalUICamera;
			}
			if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
			{
				return false;
			}
			((Component)this).transform.position = val.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, Mathf.Max(1f, val.nearClipPlane + 1f)));
			return true;
		}

		protected override void OnDisable()
		{
			InputAction obj = cancelAction;
			if (obj != null)
			{
				obj.Disable();
			}
			HoverInfoDisplay instance = HoverInfoDisplay.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.SelectedInfo == (Object)(object)this)
			{
				instance.Deactivate();
			}
			((HoverInfo)this).OnDisable();
		}

		private void OnDestroy()
		{
			InputAction obj = cancelAction;
			if (obj != null)
			{
				obj.Dispose();
			}
		}
	}
	public sealed class FloppyStation : MonoBehaviour, IInteractable, ISelectable
	{
		private readonly FloppyVisitState visits = new FloppyVisitState();

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

		private FloppyVisitState.Visit visit;

		private OuroStoreRoom shop;

		private OuroObjective objective;

		private int seed;

		private Transform tray;

		private Transform carriage;

		private Transform socket;

		private PcSpeaker speaker;

		private Renderer powerLed;

		private Renderer readLed;

		private GameObject preview;

		private FloppyShopHint shopHint;

		private UpgradeInstance pending;

		private bool busy;

		private bool reading;

		private bool powered;

		public bool HoldToInteract => false;

		public bool IsInspectable => false;

		public bool EndInteractOnFocusLoss => false;

		public InputAction InteractBinding
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				PlayerActions player = PlayerInput.Controls.Player;
				return ((PlayerActions)(ref player)).Interact;
			}
		}

		public bool UsesInteractBinding => true;

		public bool EnableInteractableHighlighting
		{
			get
			{
				if (pending == null)
				{
					return CanInteract(Player.LocalPlayer);
				}
				return false;
			}
		}

		public bool DrawWithInteractableMaterial => true;

		public float Health => 1f;

		public float NormalizedHealth => 1f;

		public float LastSelectedTime => 0f;

		public float HoldToInteractDuration => 0.65f;

		public bool ShowHighlightVisual => false;

		public bool EnableHighlighting => visit != null;

		public List<TargetMesh> Meshes => null;

		public string InteractText => "Floppy";

		internal UpgradeInstance SelectedModule => pending;

		internal bool CanConfirmExchange
		{
			get
			{
				if (pending != null)
				{
					return CanInteract(Player.LocalPlayer);
				}
				return false;
			}
		}

		internal string HintText => "Attempts: " + (visit?.Remaining ?? 3) + "/" + 3;

		internal bool CanCancelSelection
		{
			get
			{
				if (pending != null)
				{
					return !busy;
				}
				return false;
			}
		}

		public bool Exists()
		{
			return (Object)(object)this != (Object)null;
		}

		public void EndInteract(Player player)
		{
		}

		internal void Setup(OuroStoreRoom owner, OuroObjective source, OuroItemPositions positions, OuroRoom room, int shopSeed)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0403: Unknown result type (might be due to invalid IL or missing references)
			string key = ((object)((Object)source).GetEntityId()/*cast due to .constrained prefix*/).ToString() + ":" + shopSeed + ":" + (((Object)(object)room != (Object)null) ? ((object)((Object)room).GetEntityId()/*cast due to .constrained prefix*/).ToString() : (((Object)(object)positions != (Object)null) ? ((object)((Object)positions).GetEntityId()/*cast due to .constrained prefix*/).ToString() : "0"));
			if (visits.CanKeep(key, ((Component)this).gameObject.activeInHierarchy, powered, busy))
			{
				return;
			}
			FloppyInventorySelection.Cancel(this);
			((MonoBehaviour)this).StopAllCoroutines();
			if ((Object)(object)speaker != (Object)null)
			{
				PcAudio.Stop(speaker);
			}
			ClearPreview();
			pending = null;
			busy = false;
			reading = false;
			shop = owner;
			objective = source;
			seed = shopSeed;
			visit = visits.Enter(key);
			if ((Object)(object)shopHint == (Object)null)
			{
				GameObject val = new GameObject("Floppy_ShopHint");
				val.transform.SetParent(((Component)this).transform, false);
				val.transform.localPosition = Vector3.up * 0.90110904f;
				shopHint = val.AddComponent<FloppyShopHint>();
				shopHint.Owner = this;
			}
			if ((Object)(object)tray == (Object)null)
			{
				tray = ((Component)this).transform.Find("Tray");
				carriage = ((Component)this).transform.Find("RailCarriage");
				socket = tray.Find("ModuleSocket");
				speaker = ((Component)this).gameObject.AddComponent<PcSpeaker>();
				Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					if (((Object)val2).name == "PowerLED_Mesh")
					{
						powerLed = val2;
					}
					if (((Object)val2).name == "ReadLED_Mesh")
					{
						readLed = val2;
					}
				}
			}
			Vector3 val3 = default(Vector3);
			Quaternion val4 = default(Quaternion);
			if ((Object)(object)room != (Object)null)
			{
				val3 = ((Component)room).transform.position;
				val4 = ((Component)room).transform.rotation;
			}
			else
			{
				if (!((Object)(object)positions != (Object)null) || ((TransformDataArray)(ref positions.Positions)).Length <= 0)
				{
					throw new InvalidOperationException("Shop has no item position.");
				}
				TransformData val5 = ((TransformDataArray)(ref positions.Positions))[0];
				((TransformData)(ref val5)).GetGlobalPositionAndRotation(((Component)positions).transform, ref val3, ref val4);
			}
			RaycastHit val6 = default(RaycastHit);
			if (Physics.Raycast(val3 + Vector3.up * 2f, Vector3.down, ref val6, 6f, 8193, (QueryTriggerInteraction)1))
			{
				Vector3 val7 = Vector3.ProjectOnPlane(val4 * Vector3.forward, ((RaycastHit)(ref val6)).normal);
				if (((Vector3)(ref val7)).sqrMagnitude < 0.0001f)
				{
					val7 = Vector3.ProjectOnPlane(val4 * Vector3.up, ((RaycastHit)(ref val6)).normal);
				}
				val4 = Quaternion.LookRotation(val7, ((RaycastHit)(ref val6)).normal);
				val3 = ((RaycastHit)(ref val6)).point;
			}
			((Component)this).transform.SetPositionAndRotation(val3, val4);
			((Component)this).transform.localScale = Vector3.one;
			HideVanilla(owner);
			((Component)owner).gameObject.SetActive(true);
			((Component)this).gameObject.SetActive(true);
			tray.localPosition = Vector3.zero;
			carriage.localPosition = Vector3.zero;
			object? obj = AccessTools.Field(typeof(OuroStoreRoom), "waypointSprite")?.GetValue(owner);
			Sprite val8 = (Sprite)((obj is Sprite) ? obj : null);
			if ((Object)(object)val8 != (Object)null && (Object)(object)Highlighter.Instance != (Object)null)
			{
				Highlighter.Instance.AddWaypointPing(((Component)owner).transform, val8, new Color(0.2f, 0.85f, 0.62f)).localPosition = ((Component)owner).transform.InverseTransformPoint(val3 + Vector3.up * 1.1263863f);
			}
			((MonoBehaviour)this).StartCoroutine(PowerOn());
		}

		private void HideVanilla(OuroStoreRoom owner)
		{
			string[] array = new string[2] { "shelves", "upgrades" };
			foreach (string text in array)
			{
				if (!(AccessTools.Field(typeof(OuroStoreRoom), text)?.GetValue(owner) is IEnumerable enumerable))
				{
					continue;
				}
				foreach (object item in enumerable)
				{
					object obj = ((item is GameObject) ? item : null);
					if (obj == null)
					{
						object obj2 = ((item is Component) ? item : null);
						obj = ((obj2 != null) ? ((Component)obj2).gameObject : null);
					}
					GameObject val = (GameObject)obj;
					if ((Object)(object)val != (Object)null && val.activeSelf)
					{
						hiddenVanilla.Add(val);
						val.SetActive(false);
					}
				}
			}
		}

		internal void RestoreVanilla()
		{
			foreach (GameObject item in hiddenVanilla)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.SetActive(true);
				}
			}
			hiddenVanilla.Clear();
		}

		private IEnumerator PowerOn()
		{
			busy = true;
			powered = !visit.IsExhausted;
			if (powered)
			{
				Play("power_on");
				yield return (object)new WaitForSeconds(1.6f);
				speaker.StartIdle();
				yield return Slide(0.76969725f);
			}
			busy = false;
		}

		public void Interact(Player player)
		{
			if (!CanInteract(player))
			{
				return;
			}
			if (pending != null)
			{
				if (!ExchangeRules.CanSubmit(pending, out var reason))
				{
					Notice(reason);
					pending = null;
					ClearPreview();
					return;
				}
				if (!PlayerData.Instance.CanAffordCost(ExchangeRules.Cost(pending)))
				{
					Notice("Not enough currency for this exchange.");
					return;
				}
				UpgradeInstance val = ExchangeRules.Prepare(pending, seed + visit.Used * 104729 + pending.InstanceID);
				if (val == null)
				{
					Notice("No other module of this rarity is available for this gear.");
				}
				else
				{
					((MonoBehaviour)this).StartCoroutine(Exchange(pending, val));
				}
			}
			else
			{
				FloppyInventorySelection.Open(this, Select);
			}
		}

		private bool CanInteract(Player player)
		{
			if (!busy && powered && visit != null && !visit.IsExhausted && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.LocalPlayer && player.IsAlive && (Object)(object)objective != (Object)null && !((ObjectiveBase)objective).HasEnded)
			{
				return !objective.ContinuingToNextLevel;
			}
			return false;
		}

		private void Select(UpgradeInstance input)
		{
			if (CanInteract(Player.LocalPlayer))
			{
				if (!ExchangeRules.CanSubmit(input, out var reason))
				{
					Notice(reason);
					return;
				}
				pending = input;
				ShowModule(input);
			}
		}

		private IEnumerator Exchange(UpgradeInstance input, UpgradeInstance output)
		{
			busy = true;
			pending = null;
			yield return (object)new WaitForSeconds(0.3f);
			yield return Slide(0f);
			reading = true;
			Play("disk_read");
			yield return (object)new WaitForSeconds(1.9f);
			reading = false;
			string reason = "Exchange cancelled: the stage has ended.";
			if (CanFinish())
			{
				FloppyExchangeDiagnostics.LogState("before", input, output);
			}
			if (!CanFinish() || !ExchangeRules.Commit(input, output, out reason))
			{
				if (CanFinish())
				{
					FloppyExchangeDiagnostics.LogState("cancelled", input, output);
				}
				Notice(CanFinish() ? reason : "Exchange cancelled: the stage has ended.");
				ClearPreview();
				yield return Slide(0.76969725f);
				busy = false;
				yield break;
			}
			FloppyExchangeDiagnostics.LogState("after", input, output);
			visit.RecordSuccess();
			ShowModule(output);
			Play("complete");
			yield return Slide(0.76969725f);
			Notice("Received: " + output.Upgrade.GetInstanceName(output) + ".");
			yield return (object)new WaitForSeconds(1.8f);
			ClearPreview();
			if (visit.IsExhausted)
			{
				yield return Slide(0f);
				speaker.StopIdle();
				Play("power_off");
				yield return (object)new WaitForSeconds(1.35f);
				powered = false;
			}
			busy = false;
		}

		private bool CanFinish()
		{
			if ((Object)(object)objective != (Object)null && !((ObjectiveBase)objective).HasEnded && !objective.ContinuingToNextLevel && (Object)(object)Player.LocalPlayer != (Object)null)
			{
				return Player.LocalPlayer.IsAlive;
			}
			return false;
		}

		private IEnumerator Slide(float distance)
		{
			Play("tray");
			float start = tray.localPosition.z;
			for (float t = 0f; t < 0.75f; t += Time.deltaTime)
			{
				tray.localPosition = Vector3.forward * Mathf.Lerp(start, distance, Mathf.SmoothStep(0f, 1f, t / 0.75f));
				carriage.localPosition = tray.localPosition * 0.5f;
				yield return null;
			}
			tray.localPosition = Vector3.forward * distance;
			carriage.localPosition = tray.localPosition * 0.5f;
		}

		private void ShowModule(UpgradeInstance module)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			ClearPreview();
			Mesh upgradeEngramMesh = Global.Instance.UpgradeEngramMesh;
			preview = new GameObject("Floppy_ModulePreview");
			preview.transform.SetParent(socket, false);
			preview.transform.localScale = Vector3.one * 0.5f;
			Transform transform = preview.transform;
			Bounds bounds = upgradeEngramMesh.bounds;
			transform.localPosition = -((Bounds)(ref bounds)).center * 0.5f;
			preview.AddComponent<MeshFilter>().sharedMesh = upgradeEngramMesh;
			((Renderer)preview.AddComponent<MeshRenderer>()).sharedMaterial = Global.GetRarity(module.Upgrade.Rarity).collectableMat;
		}

		private void ClearPreview()
		{
			if ((Object)(object)preview != (Object)null)
			{
				Object.Destroy((Object)(object)preview);
			}
			preview = null;
		}

		private void Play(string name)
		{
			speaker.Play(name);
		}

		private void Notice(string text)
		{
			FloppyPlugin.Log.LogDebug((object)text);
		}

		internal void CancelSelection()
		{
			if (CanCancelSelection)
			{
				pending = null;
				ClearPreview();
			}
		}

		private void Update()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)shopHint != (Object)null && shopHint.CancelPressed)
			{
				CancelSelection();
			}
			SetLed(powerLed, (Color)(powered ? new Color(0.19f, 0.84f, 0.39f) : Color.black));
			SetLed(readLed, (Color)((reading && Mathf.FloorToInt(Time.time * 15f) % 3 != 0) ? new Color(1f, 0.4f, 0.045f) : Color.black));
		}

		private static void SetLed(Renderer renderer, Color color)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)renderer == (Object)null))
			{
				MaterialPropertyBlock val = new MaterialPropertyBlock();
				renderer.GetPropertyBlock(val);
				val.SetColor("_EmissionColor", color * 2f);
				val.SetFloat("_Emission", (((Color)(ref color)).maxColorComponent > 0f) ? 2f : 0f);
				val.SetFloat("_UseEmission", (((Color)(ref color)).maxColorComponent > 0f) ? 1f : 0f);
				val.SetColor("_ShadowColor", color);
				val.SetColor("_BaseColor", color);
				val.SetColor("_Color", color);
				renderer.SetPropertyBlock(val);
			}
		}

		private void OnDisable()
		{
			//IL_0026: 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)
			FloppyInventorySelection.Cancel(this);
			((MonoBehaviour)this).StopAllCoroutines();
			ClearPreview();
			if ((Object)(object)tray != (Object)null)
			{
				tray.localPosition = Vector3.zero;
			}
			if ((Object)(object)carriage != (Object)null)
			{
				carriage.localPosition = Vector3.zero;
			}
			pending = null;
			reading = false;
			busy = false;
			powered = false;
			if ((Object)(object)speaker != (Object)null)
			{
				PcAudio.Stop(speaker);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)shop != (Object)null && (Object)(object)Highlighter.Instance != (Object)null)
			{
				Highlighter.Instance.RemovePing(((Component)shop).transform);
			}
		}

		GameObject ISelectable.get_gameObject()
		{
			return ((Component)this).gameObject;
		}

		Transform ISelectable.get_transform()
		{
			return ((Component)this).transform;
		}

		string ISelectable.get_name()
		{
			return ((Object)this).name;
		}
	}
	internal static class FloppyUiMaterial
	{
		private static readonly string[] MaskProperties = new string[6] { "_Stencil", "_StencilOp", "_StencilComp", "_StencilReadMask", "_StencilWriteMask", "_ColorMask" };

		internal static Material Resolve(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return null;
			}
			string[] maskProperties = MaskProperties;
			foreach (string text in maskProperties)
			{
				if (!material.HasProperty(text))
				{
					return null;
				}
			}
			return material;
		}
	}
	internal sealed class FloppyVisitState
	{
		internal sealed class Visit
		{
			internal int Used { get; private set; }

			internal int Remaining => 3 - Used;

			internal bool IsExhausted => Used >= 3;

			internal void RecordSuccess()
			{
				if (IsExhausted)
				{
					throw new InvalidOperationException("Floppy visit has no exchanges remaining.");
				}
				Used++;
			}
		}

		internal const int Limit = 3;

		private readonly Dictionary<string, Visit> visits = new Dictionary<string, Visit>();

		internal string Key { get; private set; }

		internal Visit Current { get; private set; }

		internal bool CanKeep(string key, bool active, bool powered, bool busy)
		{
			if (Key == key && Current != null && active)
			{
				if (!(powered || busy))
				{
					return Current.IsExhausted;
				}
				return true;
			}
			return false;
		}

		internal Visit Enter(string key)
		{
			Key = key;
			if (!visits.TryGetValue(key, out var value))
			{
				visits.Add(key, value = new Visit());
			}
			Current = value;
			return value;
		}
	}
	internal static class ModelAssets
	{
		private sealed class Part
		{
			internal string Assembly;

			internal Mesh Mesh;

			internal int Material;
		}

		private sealed class Surface
		{
			internal string Name;

			internal Color Color;

			internal float Emission;
		}

		private static readonly List<Part> parts = new List<Part>();

		private static readonly List<Surface> surfaces = new List<Surface>();

		private static Texture2D plastic;

		private static Texture2D metal;

		private static string loggedShader;

		internal static bool Ready => parts.Count > 0;

		internal static void Load()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Floppy.Model") ?? throw new InvalidDataException("Embedded Floppy model missing.");
			using BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8);
			if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "FLOPPY01")
			{
				throw new InvalidDataException("Unknown Floppy mesh version.");
			}
			int num = Count(binaryReader, 64);
			for (int i = 0; i < num; i++)
			{
				surfaces.Add(new Surface
				{
					Name = ReadString(binaryReader),
					Color = new Color(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
					Emission = binaryReader.ReadSingle()
				});
			}
			int num2 = Count(binaryReader, 64);
			for (int j = 0; j < num2; j++)
			{
				string text = ReadString(binaryReader);
				int num3 = binaryReader.ReadInt32();
				if (num3 < 0 || num3 >= surfaces.Count)
				{
					throw new InvalidDataException("Bad material index.");
				}
				int num4 = Count(binaryReader, 300000);
				if (num4 % 3 != 0)
				{
					throw new InvalidDataException("Incomplete triangle.");
				}
				Vector3[] array = (Vector3[])(object)new Vector3[num4];
				Vector3[] array2 = (Vector3[])(object)new Vector3[num4];
				Vector2[] array3 = (Vector2[])(object)new Vector2[num4];
				int[] array4 = new int[num4];
				for (int k = 0; k < num4; k++)
				{
					array[k] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array2[k] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array3[k] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array4[k] = k;
				}
				Mesh val = new Mesh
				{
					name = "Floppy_" + text + "_" + j,
					indexFormat = (IndexFormat)(num4 > 65535)
				};
				val.vertices = array;
				val.normals = array2;
				val.uv = array3;
				val.triangles = array4;
				val.RecalculateBounds();
				val.UploadMeshData(true);
				parts.Add(new Part
				{
					Assembly = text,
					Mesh = val,
					Material = num3
				});
			}
			if (stream.Position != stream.Length)
			{
				throw new InvalidDataException("Trailing model data.");
			}
			plastic = LoadTexture("Plastic");
			metal = LoadTexture("Metal");
		}

		private static int Count(BinaryReader reader, int maximum)
		{
			int num = reader.ReadInt32();
			if (num < 0 || num > maximum)
			{
				throw new InvalidDataException("Invalid mesh count.");
			}
			return num;
		}

		private static string ReadString(BinaryReader reader)
		{
			return Encoding.UTF8.GetString(reader.ReadBytes(Count(reader, 1024)));
		}

		internal static GameObject Instantiate(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_045d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0517: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Floppy");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			try
			{
				Transform transform = new GameObject("Tray").transform;
				transform.SetParent(val.transform, false);
				Transform transform2 = new GameObject("RailCarriage").transform;
				transform2.SetParent(val.transform, false);
				((Component)transform).gameObject.layer = 12;
				BoxCollider obj = ((Component)transform).gameObject.AddComponent<BoxCollider>();
				((Collider)obj).isTrigger = true;
				obj.center = ModelMetrics.TrayCenter;
				obj.size = ModelMetrics.TraySize;
				Shader val2 = FindShader("Shader Graphs/PastelObjUV") ?? FindShader("Shader Graphs/Pastel") ?? FindShader("Universal Render Pipeline/Unlit");
				if ((Object)(object)val2 == (Object)null)
				{
					throw new InvalidOperationException("No supported loaded shader found.");
				}
				if (loggedShader != ((Object)val2).name)
				{
					loggedShader = ((Object)val2).name;
					FloppyPlugin.Log.LogInfo((object)("Floppy surfaces: " + ((Object)val2).name + "; embedded Plastic/Metal 512x512; shop module scale 0.5."));
				}
				Material[] array = (Material[])(object)new Material[surfaces.Count];
				for (int i = 0; i < array.Length; i++)
				{
					Surface surface = surfaces[i];
					Material val3 = new Material(val2)
					{
						name = surface.Name
					};
					SetColor(val3, surface.Color);
					if (val3.HasProperty("_ShadowColor"))
					{
						val3.SetColor("_ShadowColor", new Color(surface.Color.r * 0.72f, surface.Color.g * 0.72f, surface.Color.b * 0.72f, 1f));
					}
					bool flag = surface.Name.Contains("Steel");
					Texture2D val4 = (flag ? metal : ((surface.Name.Contains("Ivory") || surface.Name.Contains("Bezel") || surface.Name.Contains("Rubber") || surface.Name.Contains("Badge")) ? plastic : Texture2D.whiteTexture));
					if (val3.HasProperty("_MainTex"))
					{
						val3.SetTexture("_MainTex", (Texture)(object)val4);
					}
					if (val3.HasProperty("_BaseMap"))
					{
						val3.SetTexture("_BaseMap", (Texture)(object)val4);
					}
					if (val3.HasProperty("_SecondaryTex"))
					{
						val3.SetTexture("_SecondaryTex", (Texture)(object)val4);
					}
					if (val3.HasProperty("_MainTexTile"))
					{
						val3.SetFloat("_MainTexTile", 1f);
					}
					if (val3.HasProperty("_SecondaryTexTile"))
					{
						val3.SetFloat("_SecondaryTexTile", 1f);
					}
					if (val3.HasProperty("_MainBlend"))
					{
						val3.SetFloat("_MainBlend", 0f);
					}
					if (val3.HasProperty("_SunColorIntensity"))
					{
						val3.SetFloat("_SunColorIntensity", 0.5f);
					}
					if (val3.HasProperty("_Infection"))
					{
						val3.SetFloat("_Infection", 0f);
					}
					if (val3.HasProperty("_SpecularMap"))
					{
						val3.SetTexture("_SpecularMap", (Texture)(object)Texture2D.blackTexture);
					}
					if (val3.HasProperty("_Smoothness"))
					{
						val3.SetFloat("_Smoothness", 0.22f);
					}
					if (val3.HasProperty("_Metallic"))
					{
						val3.SetFloat("_Metallic", flag ? 0.65f : 0f);
					}
					if (val3.HasProperty("_Emission"))
					{
						val3.SetFloat("_Emission", surface.Emission);
					}
					if (val3.HasProperty("_UseEmission"))
					{
						val3.SetFloat("_UseEmission", (float)((surface.Emission > 0f) ? 1 : 0));
					}
					if (surface.Emission > 0f)
					{
						val3.EnableKeyword("_EMISSION");
						if (val3.HasProperty("_EmissionColor"))
						{
							val3.SetColor("_EmissionColor", surface.Color * surface.Emission);
						}
					}
					array[i] = val3;
				}
				val.AddComponent<ModelMaterialOwner>().Materials = array;
				foreach (Part part in parts)
				{
					GameObject val5 = new GameObject(part.Assembly + "_Mesh");
					val5.transform.SetParent((part.Assembly == "Tray") ? transform : ((part.Assembly == "RailCarriage") ? transform2 : val.transform), false);
					val5.AddComponent<MeshFilter>().sharedMesh = part.Mesh;
					((Renderer)val5.AddComponent<MeshRenderer>()).sharedMaterial = array[part.Material];
				}
				Transform transform3 = new GameObject("ModuleSocket").transform;
				transform3.SetParent(transform, false);
				transform3.localPosition = ModelMetrics.SocketCenter;
				val.layer = 12;
				BoxCollider obj2 = val.AddComponent<BoxCollider>();
				obj2.center = ModelMetrics.CaseCenter;
				obj2.size = ModelMetrics.CaseSize;
				return val;
			}
			catch
			{
				Object.Destroy((Object)(object)val);
				throw;
			}
		}

		internal static void SetColor(Material material, Color color)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (material.HasProperty("_BaseColor"))
			{
				material.SetColor("_BaseColor", color);
			}
			if (material.HasProperty("_Color"))
			{
				material.SetColor("_Color", color);
			}
		}

		private static Shader FindShader(string name)
		{
			Shader val = Shader.Find(name);
			if (!((Object)(object)val != (Object)null) || !val.isSupported)
			{
				return null;
			}
			return val;
		}

		private static Texture2D LoadTexture(string name)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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)
			//IL_00f0: Expected O, but got Unknown
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Floppy.Texture." + name) ?? throw new InvalidDataException("Embedded Floppy surface missing: " + name);
			using BinaryReader binaryReader = new BinaryReader(stream, Encoding.UTF8);
			if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "FLPTEX01")
			{
				throw new InvalidDataException("Unknown Floppy surface format: " + name);
			}
			int num = binaryReader.ReadInt32();
			int num2 = binaryReader.ReadInt32();
			if (num <= 0 || num2 <= 0 || num > 1024 || num2 > 1024 || stream.Length - stream.Position != num * num2 * 3)
			{
				throw new InvalidDataException("Invalid Floppy surface dimensions: " + name);
			}
			byte[] array = binaryReader.ReadBytes(num * num2 * 3);
			Texture2D val = new Texture2D(num, num2, (TextureFormat)3, true, false)
			{
				name = "Floppy_" + name,
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)2,
				anisoLevel = 2
			};
			try
			{
				val.SetPixelData<byte>(array, 0, 0);
				val.Apply(true, true);
				return val;
			}
			catch
			{
				Object.Destroy((Object)(object)val);
				throw;
			}
		}

		internal static void Dispose()
		{
			foreach (Part part in parts)
			{
				if ((Object)(object)part.Mesh != (Object)null)
				{
					Object.Destroy((Object)(object)part.Mesh);
				}
			}
			parts.Clear();
			surfaces.Clear();
			if ((Object)(object)plastic != (Object)null)
			{
				Object.Destroy((Object)(object)plastic);
			}
			if ((Object)(object)metal != (Object)null)
			{
				Object.Destroy((Object)(object)metal);
			}
			plastic = (metal = null);
			loggedShader = null;
		}
	}
	internal sealed class ModelMaterialOwner : MonoBehaviour
	{
		internal Material[] Materials;

		private void OnDestroy()
		{
			if (Materials == null)
			{
				return;
			}
			Material[] materials = Materials;
			foreach (Material val in materials)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
			}
		}
	}
	internal static class ModelMetrics
	{
		internal const float BakedScale = 0.37546209f;

		internal const float ModuleScale = 0.5f;

		internal const float TrayTravel = 0.76969725f;

		internal static readonly Vector3 SocketCenter = new Vector3(0f, 2.59f, 0.37f) * 0.37546209f;

		internal static readonly Vector3 CaseCenter = new Vector3(0f, 2.41f, 0f) * 0.37546209f;

		internal static readonly Vector3 CaseSize = new Vector3(2.45f, 4.82f, 2.8f) * 0.37546209f;

		internal static readonly Vector3 TrayCenter = new Vector3(0f, 2.51f, 1.49f) * 0.37546209f;

		internal static readonly Vector3 TraySize = new Vector3(1.96f, 1.74f, 0.15f) * 0.37546209f;

		internal const float EmitterHeight = 0.90110904f;

		internal const float WaypointHeight = 1.1263863f;
	}
	internal static class PcAudio
	{
		private static byte[] bank;

		private static uint bankId;

		private static bool loaded;

		private static bool warned;

		internal static void Load()
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Floppy.AudioBank") ?? throw new InvalidDataException("Embedded Floppy soundbank missing.");
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			bank = memoryStream.ToArray();
		}

		private unsafe static bool EnsureLoaded()
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Invalid comparison between Unknown and I4
			if (loaded)
			{
				return true;
			}
			if (bank == null || !AkUnitySoundEngine.IsInitialized())
			{
				return false;
			}
			IntPtr hglobal = Marshal.AllocHGlobal(bank.Length + 15);
			try
			{
				IntPtr intPtr = new IntPtr((hglobal.ToInt64() + 15) & -16);
				Marshal.Copy(bank, 0, intPtr, bank.Length);
				AKRESULT val = AkUnitySoundEngine.LoadBankMemoryCopy(intPtr, (uint)bank.Length, ref bankId);
				loaded = (int)val == 1;
				if (!loaded && !warned)
				{
					warned = true;
					FloppyPlugin.Log.LogError((object)("Wwise rejected Floppy soundbank: " + ((object)(*(AKRESULT*)(&val))/*cast due to .constrained prefix*/).ToString()));
				}
				return loaded;
			}
			finally
			{
				Marshal.FreeHGlobal(hglobal);
			}
		}

		internal static uint Post(string phase, GameObject emitter, EventCallback callback, object cookie)
		{
			if (!EnsureLoaded())
			{
				return 0u;
			}
			uint num = AkUnitySoundEngine.PostEvent("Play_Floppy_" + phase, emitter, 1u, callback, cookie);
			if (num == 0 && !warned)
			{
				warned = true;
				FloppyPlugin.Log.LogError((object)("Wwise could not post Floppy event: " + phase));
			}
			if (num != 0)
			{
				SetVolume(num);
			}
			return num;
		}

		internal static void SetVolume(uint id)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (id != 0 && (Object)(object)FloppyPlugin.Instance != (Object)null)
			{
				AkUnitySoundEngine.SetRTPCValueByPlayingID("User_Volume", FloppyPlugin.Instance.Volume.Value, id);
			}
		}

		internal static void Stop(PcSpeaker speaker)
		{
			speaker.StopAll();
		}

		internal static void Dispose()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (loaded && AkUnitySoundEngine.IsInitialized())
			{
				AkUnitySoundEngine.UnloadBank(bankId, IntPtr.Zero);
			}
			loaded = false;
			bank = null;
		}
	}
	internal sealed class PcSpeaker : MonoBehaviour
	{
		private sealed class Playback
		{
			internal volatile uint Id;

			internal volatile bool Ended;
		}

		private readonly ConcurrentDictionary<uint, Playback> playing = new ConcurrentDictionary<uint, Playback>();

		private GameObject emitter;

		private uint idle;

		private float nextVolumeUpdate;

		private EventCallback ended;

		private void EnsureEmitter()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			if (!((Object)(object)emitter != (Object)null))
			{
				emitter = new GameObject("Floppy_Wwise_Emitter");
				emitter.transform.SetParent(((Component)this).transform, false);
				emitter.transform.localPosition = Vector3.up * 0.90110904f;
				emitter.AddComponent<AkGameObj>();
				ended = new EventCallback(OnEventEnded);
			}
		}

		private uint PlayInternal(string phase)
		{
			EnsureEmitter();
			Playback playback = new Playback();
			uint num = (playback.Id = PcAudio.Post(phase, emitter, ended, playback));
			if (num != 0 && !playback.Ended)
			{
				playing.TryAdd(num, playback);
			}
			return num;
		}

		internal void Play(string phase)
		{
			PlayInternal(phase);
		}

		internal void StartIdle()
		{
			StopIdle();
			idle = PlayInternal("idle");
		}

		internal void StopIdle()
		{
			Stop(idle);
			idle = 0u;
		}

		private void Stop(uint id)
		{
			if (id != 0 && playing.TryRemove(id, out var _))
			{
				AkUnitySoundEngine.StopPlayingID(id, 40);
			}
		}

		private void OnEventEnded(object cookie, AkCallbackType type, AkCallbackInfo info)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)type == 1 && cookie is Playback playback)
			{
				playback.Ended = true;
				if (playback.Id != 0)
				{
					playing.TryRemove(playback.Id, out var _);
				}
			}
		}

		internal void StopAll()
		{
			foreach (uint key in playing.Keys)
			{
				Stop(key);
			}
			idle = 0u;
		}

		private void Update()
		{
			if (Time.unscaledTime < nextVolumeUpdate)
			{
				return;
			}
			nextVolumeUpdate = Time.unscaledTime + 0.25f;
			foreach (uint key in playing.Keys)
			{
				PcAudio.SetVolume(key);
			}
		}

		private void OnDisable()
		{
			StopAll();
		}

		private void OnDestroy()
		{
			StopAll();
			if ((Object)(object)emitter != (Object)null)
			{
				Object.Destroy((Object)(object)emitter);
			}
		}
	}
}