Decompiled source of TeleportCarts v0.2.3

TeleportCarts.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Odinplus.Shared.ConfigurationUi;
using Odinplus.Shared.Input;
using Odinplus.Shared.Timing;
using Odinplus.Shared.Unity;
using Odinplus.Shared.YamlEditor;
using ServerSync;
using TMPro;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TeleportCarts")]
[assembly: AssemblyDescription("https://valheim.hexium.gg/mods/OdinPlus/TeleportCarts")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("odinplus")]
[assembly: AssemblyProduct("TeleportCarts")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyFileVersion("0.2.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.3.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace TeleportCarts
{
	internal static class CartArrivalDecision
	{
		public static bool ShouldDeferDetachedHotkey(bool isHotkeyTarget, bool wasAttachedAtDeparture)
		{
			if (isHotkeyTarget)
			{
				return !wasAttachedAtDeparture;
			}
			return false;
		}

		public static bool ShouldExpireDetachedHotkeyAreaWait(bool isDetachedHotkey, float elapsedSeconds, float timeoutSeconds)
		{
			if (isDetachedHotkey)
			{
				return elapsedSeconds >= timeoutSeconds;
			}
			return false;
		}

		public static CartArrivalAction Plan(bool wasAttachedAtDeparture, int attempts, bool hasPlacedCart, bool cartFound, bool verifiedAttached, int maximumAttempts)
		{
			if (!cartFound)
			{
				if (attempts < maximumAttempts)
				{
					return CartArrivalAction.WaitForCart;
				}
				return CartArrivalAction.Timeout;
			}
			if (!wasAttachedAtDeparture)
			{
				if (!hasPlacedCart)
				{
					return CartArrivalAction.PlaceDetachedAndComplete;
				}
				return CartArrivalAction.CompleteDetached;
			}
			if (verifiedAttached)
			{
				return CartArrivalAction.CompleteAttached;
			}
			if (!hasPlacedCart)
			{
				return CartArrivalAction.PlaceAttachedAndRetry;
			}
			return CartArrivalAction.RetryAttach;
		}

		public static CartArrivalAction FinishAttachedRetry(bool verifiedAttached, int attempts, int maximumAttempts)
		{
			if (!verifiedAttached)
			{
				if (attempts < maximumAttempts)
				{
					return CartArrivalAction.RetryAttach;
				}
				return CartArrivalAction.Timeout;
			}
			return CartArrivalAction.CompleteAttached;
		}

		public static bool ShouldMarkPlaced(CartArrivalAction action, bool placementSucceeded)
		{
			bool flag = placementSucceeded;
			if (flag)
			{
				bool flag2 = (uint)(action - 1) <= 1u;
				flag = flag2;
			}
			return flag;
		}

		public static bool ShouldPlaceOwnedUnloadedAttachedCart(bool wasAttachedAtDeparture, bool hasPlacedCart, bool liveCartFound, bool recordFound, bool sourceOwnershipCaptured)
		{
			return wasAttachedAtDeparture && !hasPlacedCart && !liveCartFound && recordFound && sourceOwnershipCaptured;
		}
	}
	internal enum CartArrivalAction
	{
		WaitForCart,
		PlaceDetachedAndComplete,
		PlaceAttachedAndRetry,
		RetryAttach,
		CompleteDetached,
		CompleteAttached,
		Timeout
	}
	public sealed class EffectiveCartPolicy
	{
		public CartServerPolicy ServerPolicy { get; }

		public PlayerCartPreferences PlayerPreferences { get; }

		public float SearchRadius => ServerPolicy.Carts.SearchRadius;

		public float ForwardOffset => ServerPolicy.Placement.ForwardOffset;

		public float ReattachRadius => ServerPolicy.Placement.ReattachRadius;

		private EffectiveCartPolicy(CartServerPolicy serverPolicy, PlayerCartPreferences playerPreferences)
		{
			ServerPolicy = serverPolicy;
			PlayerPreferences = playerPreferences;
		}

		public static EffectiveCartPolicy Create(CartServerPolicy server, PlayerCartPreferences player)
		{
			CartServerPolicyValidator.Validate(server);
			PlayerCartPreferencesValidator.Validate(player);
			return new EffectiveCartPolicy(server, player);
		}

		public bool IsTransitionEnabled(CartTransitionKind kind, bool basementsInstalled)
		{
			if (ServerPolicy.Carts.Enabled && PlayerPreferences.Carts.Enabled && CartTransitionPolicy.IsEnabled(ServerPolicy.Carts.Teleport, kind, basementsInstalled))
			{
				return CartTransitionPolicy.IsEnabled(PlayerPreferences.Carts.Teleport, kind, basementsInstalled);
			}
			return false;
		}
	}
	internal static class CartEnvironmentDecision
	{
		public static bool IsBasement(string? environmentName)
		{
			if (!string.Equals(environmentName, "Basement", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(environmentName, "Undercroft", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}
	}
	internal static class CartPlacementDecision
	{
		public const float TerrainClearanceOffset = 0.4f;

		public static bool UsesNativeTargetWithoutPreOffset()
		{
			return true;
		}

		public static bool UsesNativeTargetHeight(CartTransitionKind transition)
		{
			return transition != CartTransitionKind.Portal;
		}

		public static float DetachedForwardDistance(float configuredForwardOffset, float projectedCartExtent)
		{
			return configuredForwardOffset + Math.Max(0f, projectedCartExtent);
		}
	}
	public sealed class PlayerCartPreferences
	{
		public int SchemaVersion { get; set; } = 1;

		public PlayerCartFeaturePreferences Carts { get; set; } = new PlayerCartFeaturePreferences();

		public static PlayerCartPreferences CreateDefault()
		{
			return new PlayerCartPreferences();
		}
	}
	public sealed class PlayerCartFeaturePreferences
	{
		public bool Enabled { get; set; } = true;

		public PlayerCartTeleportConfig Teleport { get; set; } = new PlayerCartTeleportConfig();
	}
	public sealed class PlayerCartTeleportConfig
	{
		public CartPortalTransportConfig Portals { get; set; } = new CartPortalTransportConfig();

		public CartTransitionToggleConfig Dungeons { get; set; } = new CartTransitionToggleConfig();

		public CartTransitionToggleConfig Basements { get; set; } = new CartTransitionToggleConfig();
	}
	public static class PlayerCartPreferencesValidator
	{
		public static void Validate(PlayerCartPreferences preferences)
		{
			if (preferences == null)
			{
				throw new InvalidDataException("Player cart preferences cannot be null.");
			}
			if (preferences.SchemaVersion != 1)
			{
				throw new InvalidDataException("Only SchemaVersion 1 is supported.");
			}
			if (preferences.Carts == null || preferences.Carts.Teleport == null || preferences.Carts.Teleport.Portals == null || preferences.Carts.Teleport.Dungeons == null || preferences.Carts.Teleport.Basements == null)
			{
				throw new InvalidDataException("Carts and Carts.Teleport sections are required.");
			}
		}
	}
	public static class PlayerCartPreferenceSnapshot
	{
		public static bool TryReplace(PlayerCartPreferences lastValid, string yaml, out PlayerCartPreferences retained, out string error)
		{
			try
			{
				PlayerCartPreferences playerCartPreferences = new <cba6ec40-2546-4a46-9577-18d27987fd9e>DeserializerBuilder().Build().Deserialize<PlayerCartPreferences>(yaml);
				PlayerCartPreferencesValidator.Validate(playerCartPreferences);
				retained = playerCartPreferences;
				error = string.Empty;
				return true;
			}
			catch (Exception ex)
			{
				retained = lastValid;
				error = ex.Message;
				return false;
			}
		}
	}
	public sealed class CartServerPolicy
	{
		public int SchemaVersion { get; set; } = 1;

		public CartFeatureConfig Carts { get; set; } = new CartFeatureConfig();

		public CartPlacementConfig Placement { get; set; } = new CartPlacementConfig();
	}
	public sealed class CartFeatureConfig
	{
		public bool Enabled { get; set; } = true;

		public CartTeleportConfig Teleport { get; set; } = new CartTeleportConfig();

		public float SearchRadius { get; set; } = 10f;
	}
	public sealed class CartTeleportConfig
	{
		public CartPortalTransportConfig Portals { get; set; } = new CartPortalTransportConfig();

		public CartTransitionToggleConfig Dungeons { get; set; } = new CartTransitionToggleConfig();

		public CartTransitionToggleConfig Basements { get; set; } = new CartTransitionToggleConfig();
	}
	public sealed class CartPortalTransportConfig
	{
		public bool Enabled { get; set; } = true;
	}
	public sealed class CartTransitionToggleConfig
	{
		public bool Enabled { get; set; } = true;
	}
	public sealed class CartPlacementConfig
	{
		public float ForwardOffset { get; set; } = 0.8f;

		public float ReattachRadius { get; set; } = 15f;
	}
	public static class CartServerPolicyValidator
	{
		public static void Validate(CartServerPolicy policy)
		{
			if (policy == null)
			{
				throw new InvalidDataException("Cart server policy cannot be null.");
			}
			if (policy.SchemaVersion != 1)
			{
				throw new InvalidDataException("Only SchemaVersion 1 is supported.");
			}
			if (policy.Carts == null || policy.Carts.Teleport == null || policy.Placement == null || policy.Carts.Teleport.Portals == null || policy.Carts.Teleport.Dungeons == null || policy.Carts.Teleport.Basements == null)
			{
				throw new InvalidDataException("Carts, Carts.Teleport, Carts.Teleport.Portals, Carts.Teleport.Dungeons, Carts.Teleport.Basements, and Placement sections are required.");
			}
			if (policy.Carts.SearchRadius <= 0f || policy.Carts.SearchRadius > 100f)
			{
				throw new InvalidDataException("Carts.SearchRadius must be between 0 and 100.");
			}
			if (policy.Placement.ForwardOffset <= 0f || policy.Placement.ForwardOffset > 20f || policy.Placement.ReattachRadius <= 0f || policy.Placement.ReattachRadius > 100f)
			{
				throw new InvalidDataException("Placement.ForwardOffset must be between 0 and 20 and Placement.ReattachRadius must be between 0 and 100.");
			}
		}
	}
	public enum CartTransitionKind
	{
		Portal,
		Dungeon,
		Basement
	}
	internal static class CartTransitionPolicy
	{
		public static bool IsEnabled(CartTeleportConfig config, CartTransitionKind kind, bool basementsInstalled)
		{
			switch (kind)
			{
			default:
				return config.Dungeons.Enabled;
			case CartTransitionKind.Basement:
				if (basementsInstalled)
				{
					return config.Basements.Enabled;
				}
				return false;
			case CartTransitionKind.Portal:
				return config.Portals.Enabled;
			}
		}

		public static bool IsEnabled(PlayerCartTeleportConfig config, CartTransitionKind kind, bool basementsInstalled)
		{
			switch (kind)
			{
			default:
				return config.Dungeons.Enabled;
			case CartTransitionKind.Basement:
				if (basementsInstalled)
				{
					return config.Basements.Enabled;
				}
				return false;
			case CartTransitionKind.Portal:
				return config.Portals.Enabled;
			}
		}
	}
	internal static class CartTransportDecision
	{
		public static bool CanUseUnattachedTarget(bool hasExplicitTarget, bool targetIsAttached, bool targetInSearchRadius)
		{
			return hasExplicitTarget && !targetIsAttached && targetInSearchRadius;
		}
	}
	internal static class CartWorldGate
	{
		public static bool ShouldBlock(bool noPortals, bool noBossPortals, bool bossEventActive)
		{
			if (!noPortals)
			{
				return noBossPortals && bossEventActive;
			}
			return true;
		}
	}
	[BepInPlugin("odinplus.TeleportCarts", "TeleportCarts", "0.2.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class TeleportCartsPlugin : BaseUnityPlugin
	{
		private enum Toggle
		{
			On = 1,
			Off = 0
		}

		private static readonly object UiGate = new object();

		private static bool _uiCommitting;

		private static bool _uiFaulted;

		private NativeConfigTransport? _uiTransport;

		private ModuleConfigurationService? _uiService;

		private string _uiObservedServer = "";

		private string _uiObservedPlayer = "";

		private string _uiObservedCfg = "";

		internal const string Author = "odinplus";

		internal const string ModGuid = "odinplus.TeleportCarts";

		internal const string ModName = "TeleportCarts";

		internal const string ModVersion = "0.2.3";

		private const string ConfigFileName = "odinplus.TeleportCarts.cfg";

		private static readonly ConfigSync Sync = new ConfigSync("odinplus.TeleportCarts")
		{
			DisplayName = "TeleportCarts",
			CurrentVersion = "0.2.3",
			MinimumRequiredVersion = "0.2.3"
		};

		private static readonly CustomSyncedValue<string> Snapshot = new CustomSyncedValue<string>(Sync, "YamlPolicy", string.Empty);

		private static ConfigEntry<Toggle>? _forceServerConfig;

		private static ConfigEntry<bool>? _enableMod;

		private static ConfigEntry<bool>? _enableDiagnostics;

		private static ConfigEntry<KeyboardShortcut>? _teleportCartHotkey;

		private readonly Harmony _harmony = new Harmony("odinplus.TeleportCarts");

		private readonly <cba6ec40-2546-4a46-9577-18d27987fd9e>ISerializer _serializer = new <cba6ec40-2546-4a46-9577-18d27987fd9e>SerializerBuilder().Build();

		private FileSystemWatcher? _serverYamlWatcher;

		private FileSystemWatcher? _playerYamlWatcher;

		private FileSystemWatcher? _configWatcher;

		private string _serverYamlPath;

		private string _playerYamlPath;

		private GameObject? _yamlEditorHost;

		public static readonly ManualLogSource TeleportCartsLogger = Logger.CreateLogSource("TeleportCarts");

		internal static CartServerPolicy ServerPolicy { get; private set; } = new CartServerPolicy();

		internal static PlayerCartPreferences PlayerPreferences { get; private set; } = PlayerCartPreferences.CreateDefault();

		internal static EffectiveCartPolicy Policy { get; private set; } = EffectiveCartPolicy.Create(ServerPolicy, PlayerPreferences);

		internal static ManualLogSource Log { get; private set; } = TeleportCartsLogger;

		internal static bool IsEnabled => _enableMod?.Value ?? false;

		internal static bool DiagnosticsEnabled => _enableDiagnostics?.Value ?? false;

		internal static KeyboardShortcut TeleportCartHotkey => (KeyboardShortcut)(((??)_teleportCartHotkey?.Value) ?? new KeyboardShortcut((KeyCode)304, (KeyCode[])(object)new KeyCode[1] { (KeyCode)99 }));

		internal static bool IsHotkeyConfigured
		{
			get
			{
				//IL_000b: 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_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Invalid comparison between Unknown and I4
				ConfigEntry<KeyboardShortcut>? teleportCartHotkey = _teleportCartHotkey;
				if (teleportCartHotkey == null)
				{
					return true;
				}
				KeyboardShortcut value = teleportCartHotkey.Value;
				return (int)((KeyboardShortcut)(ref value)).MainKey > 0;
			}
		}

		internal static bool BasementsInstalled { get; private set; }

		internal static bool IsBlocked { get; private set; }

		public string HandleUiConfigRequestV1(string request)
		{
			EnsureUi();
			return _uiTransport.Exchange(request);
		}

		private void EnsureUi()
		{
			if (_uiService != null)
			{
				return;
			}
			try
			{
				ObserveUiFiles(reload: false, "Server");
				ObserveUiFiles(reload: false, "Player");
			}
			catch
			{
			}
			_uiService = new ModuleConfigurationService("odinplus.TeleportCarts", ReadUi, UiDefaults, ValidateUi, CommitUi, ReadUiCandidate);
			_uiTransport = new NativeConfigTransport("odinplus.TeleportCarts", delegate(UiConfigRequest r, string caller, bool admin)
			{
				lock (UiGate)
				{
					return _uiService.Handle(r, caller, admin, DateTime.UtcNow);
				}
			}, delegate
			{
				lock (UiGate)
				{
					_uiService.NewSession();
				}
			});
		}

		private void Update()
		{
			EnsureUi();
			_uiTransport.Tick();
		}

		private Dictionary<string, ConfigEntryBase> UiEntries(string scope)
		{
			Dictionary<string, ConfigEntryBase> entries = new Dictionary<string, ConfigEntryBase>();
			if (scope == "Server")
			{
				Add((ConfigEntryBase?)(object)_forceServerConfig);
				Add((ConfigEntryBase?)(object)_enableMod);
			}
			else
			{
				Add((ConfigEntryBase?)(object)_enableDiagnostics);
				Add((ConfigEntryBase?)(object)_teleportCartHotkey);
			}
			return entries;
			void Add(ConfigEntryBase? entry)
			{
				if (entry != null)
				{
					entries[entry.Definition.Section + "/" + entry.Definition.Key] = entry;
				}
			}
		}

		private object UiPolicy(string scope)
		{
			if (!(scope == "Server"))
			{
				return PlayerPreferences;
			}
			return ServerPolicy;
		}

		private object UiDefaultPolicy(string scope)
		{
			if (!(scope == "Server"))
			{
				return PlayerCartPreferences.CreateDefault();
			}
			return new CartServerPolicy();
		}

		private ModuleConfigurationCandidate UiDefaults(string scope)
		{
			return new ModuleConfigurationCandidate
			{
				Yaml = ModuleConfigProtocolV1.SerializePayload(UiDefaultPolicy(scope)),
				Cfg = UiEntries(scope).ToDictionary<KeyValuePair<string, ConfigEntryBase>, string, string>((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => TomlTypeConverter.ConvertToString(x.Value.DefaultValue, x.Value.SettingType))
			};
		}

		private void ObserveUiFiles(bool reload, string scope)
		{
			string path = ((scope == "Server") ? _serverYamlPath : _playerYamlPath);
			string text = (File.Exists(path) ? File.ReadAllText(path) : string.Empty);
			string text2 = (File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) ? File.ReadAllText(((BaseUnityPlugin)this).Config.ConfigFilePath) : string.Empty);
			string text3 = ((scope == "Server") ? _uiObservedServer : _uiObservedPlayer);
			if (scope == "Server")
			{
				_uiObservedServer = text;
			}
			else
			{
				_uiObservedPlayer = text;
			}
			if (reload && text != text3)
			{
				if (scope == "Server")
				{
					ReloadServerYaml();
				}
				else
				{
					ReloadPlayerYaml();
				}
			}
			if (reload && text2 != _uiObservedCfg)
			{
				ReloadBepInExConfig(this, new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath)));
			}
			_uiObservedCfg = text2;
		}

		private ModuleConfigurationCandidate ReadUiCandidate(string scope)
		{
			ObserveUiFiles(reload: true, scope);
			return new ModuleConfigurationCandidate
			{
				Yaml = ModuleConfigProtocolV1.SerializePayload(UiPolicy(scope)),
				Cfg = UiEntries(scope).ToDictionary<KeyValuePair<string, ConfigEntryBase>, string, string>((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => x.Value.GetSerializedValue())
			};
		}

		private ModuleConfigurationView ReadUi(string scope)
		{
			object obj = UiPolicy(scope);
			ModuleConfigurationView moduleConfigurationView = new ModuleConfigurationView
			{
				Version = "0.2.3",
				Candidate = new ModuleConfigurationCandidate
				{
					Yaml = ModuleConfigProtocolV1.SerializePayload(obj),
					Cfg = UiEntries(scope).ToDictionary<KeyValuePair<string, ConfigEntryBase>, string, string>((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => x.Value.GetSerializedValue())
				},
				Descriptors = ConfigurationFields.Describe(obj, UiDefaultPolicy(scope), scope)
			};
			foreach (KeyValuePair<string, ConfigEntryBase> item in UiEntries(scope))
			{
				ConfigEntryBase value = item.Value;
				ConfigurationDescriptor configurationDescriptor = new ConfigurationDescriptor
				{
					StableId = "cfg:" + item.Key,
					Scope = scope,
					Group = value.Definition.Section,
					Label = value.Definition.Key,
					Help = value.Description.Description,
					ValueYaml = value.GetSerializedValue(),
					DefaultYaml = TomlTypeConverter.ConvertToString(value.DefaultValue, value.SettingType),
					Kind = ((value.SettingType == typeof(bool)) ? "Toggle" : ((value.SettingType == typeof(KeyboardShortcut)) ? "KeyboardShortcut" : (value.SettingType.IsEnum ? "Enum" : "Text")))
				};
				if (value.SettingType.IsEnum)
				{
					configurationDescriptor.AllowedValues = Enum.GetNames(value.SettingType).ToList();
				}
				if (value.Description.AcceptableValues is AcceptableValueList<string> val)
				{
					configurationDescriptor.Kind = "Enum";
					configurationDescriptor.AllowedValues = val.AcceptableValues.ToList();
				}
				moduleConfigurationView.Descriptors.Add(configurationDescriptor);
			}
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				moduleConfigurationView.Prefabs = (from x in (from p in ZNetScene.instance.m_prefabs
						where (Object)(object)p != (Object)null && (Object)(object)p.GetComponent<Character>() != (Object)null
						select ((Object)p).name).Distinct()
					orderby x
					select x).Take(2048).ToList();
			}
			string[] array = new string[2] { "com.kpro.TeleportEverything", "zenox.teleporteverything" };
			foreach (string key in array)
			{
				if (Chainloader.PluginInfos.TryGetValue(key, out var value2))
				{
					moduleConfigurationView.CompatibilityWarnings.Add(new CompatibilityWarning
					{
						ModName = value2.Metadata.Name,
						DetectedVersion = value2.Metadata.Version.ToString(),
						Reason = "Overlapping transport rules.",
						SuggestedAction = "Remove it or disable overlapping features, then restart."
					});
				}
			}
			if (!BasementsInstalled)
			{
				moduleConfigurationView.Warnings.Add("Basements is not installed. Basement preferences are retained for future use.");
			}
			foreach (ConfigurationDescriptor item2 in moduleConfigurationView.Descriptors.Where((ConfigurationDescriptor r) => r.Kind == "Number"))
			{
				item2.Minimum = 0.0;
				item2.Maximum = ((item2.StableId == "Placement.ForwardOffset") ? 20 : 100);
				string text = "Enter a number greater than zero; maximum " + item2.Maximum + ".";
				item2.Help = (string.IsNullOrWhiteSpace(item2.Help) ? text : (item2.Help + " " + text));
			}
			if (scope == "Player")
			{
				PlayerDescriptorAvailability.Apply(moduleConfigurationView, IsEnabled, ServerPolicy);
			}
			return moduleConfigurationView;
		}

		private object ParseUi(string scope, string yaml)
		{
			if (scope == "Server")
			{
				CartServerPolicy cartServerPolicy = ModuleConfigProtocolV1.DeserializePayload<CartServerPolicy>(yaml);
				CartServerPolicyValidator.Validate(cartServerPolicy);
				if (ConfigurationFields.HasNonFinite(cartServerPolicy))
				{
					throw new ArgumentException("Numbers must be finite.");
				}
				return cartServerPolicy;
			}
			PlayerCartPreferences playerCartPreferences = ModuleConfigProtocolV1.DeserializePayload<PlayerCartPreferences>(yaml);
			PlayerCartPreferencesValidator.Validate(playerCartPreferences);
			if (ConfigurationFields.HasNonFinite(playerCartPreferences))
			{
				throw new ArgumentException("Numbers must be finite.");
			}
			return playerCartPreferences;
		}

		private string? ValidateUi(string scope, ModuleConfigurationCandidate candidate)
		{
			try
			{
				if (_uiFaulted)
				{
					return "Saving is blocked after a rollback failure. Restart after checking the module log and configuration files.";
				}
				ParseUi(scope, candidate.Yaml);
				Dictionary<string, ConfigEntryBase> entries = UiEntries(scope);
				if (candidate.Cfg == null || candidate.Cfg.Count != entries.Count || candidate.Cfg.Keys.Any((string k) => !entries.ContainsKey(k)))
				{
					return "The complete configuration must include only this scope's supported settings.";
				}
				foreach (KeyValuePair<string, string> item in candidate.Cfg)
				{
					ConfigEntryBase val = entries[item.Key];
					object obj = TomlTypeConverter.ConvertToValue(item.Value, val.SettingType);
					if (val.Description.AcceptableValues != null && !val.Description.AcceptableValues.IsValid(obj))
					{
						return "Invalid value for " + val.Definition.Key + ".";
					}
					if (val.SettingType.IsEnum && !Enum.IsDefined(val.SettingType, obj))
					{
						return "Unsupported option.";
					}
				}
				return null;
			}
			catch (ArgumentException ex)
			{
				return ex.Message;
			}
			catch (InvalidDataException ex2)
			{
				return ex2.Message;
			}
			catch
			{
				return "The draft contains malformed or unsupported configuration values.";
			}
		}

		private void CommitUi(string scope, ModuleConfigurationCandidate candidate)
		{
			object parsed = ParseUi(scope, candidate.Yaml);
			CartServerPolicy oldServer = ServerPolicy;
			PlayerCartPreferences oldPlayer = PlayerPreferences;
			string oldSnapshot = Snapshot.Value;
			Dictionary<string, ConfigEntryBase> entries = UiEntries(scope);
			Dictionary<string, string> oldCfg = entries.ToDictionary<KeyValuePair<string, ConfigEntryBase>, string, string>((KeyValuePair<string, ConfigEntryBase> x) => x.Key, (KeyValuePair<string, ConfigEntryBase> x) => x.Value.GetSerializedValue());
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			_uiCommitting = true;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			try
			{
				AtomicModuleCommit.Execute((scope == "Server") ? _serverYamlPath : _playerYamlPath, ModuleConfigProtocolV1.SerializePayload(parsed), ((BaseUnityPlugin)this).Config.ConfigFilePath, delegate
				{
					foreach (KeyValuePair<string, string> item in candidate.Cfg)
					{
						entries[item.Key].SetSerializedValue(item.Value);
					}
					if (scope == "Server")
					{
						ServerPolicy = (CartServerPolicy)parsed;
					}
					else
					{
						PlayerPreferences = (PlayerCartPreferences)parsed;
					}
					RebuildEffectivePolicy();
				}, delegate
				{
					((BaseUnityPlugin)this).Config.Save();
				}, delegate
				{
					if (scope == "Server")
					{
						Snapshot.AssignLocalValue(ModuleConfigProtocolV1.SerializePayload(ServerPolicy));
					}
				}, delegate
				{
					AtomicModuleCommit.RestoreAll(((IEnumerable<KeyValuePair<string, string>>)oldCfg).Select((Func<KeyValuePair<string, string>, Action>)((KeyValuePair<string, string> pair) => delegate
					{
						entries[pair.Key].SetSerializedValue(pair.Value);
					})).Concat(new Action[2]
					{
						delegate
						{
							ServerPolicy = oldServer;
							PlayerPreferences = oldPlayer;
							RebuildEffectivePolicy();
						},
						delegate
						{
							if (scope == "Server")
							{
								Snapshot.AssignLocalValue(oldSnapshot);
							}
						}
					}));
				}, delegate(Exception error)
				{
					_uiFaulted = true;
					Log.LogError((object)("UI configuration rollback failed: " + error.Message));
				}, (scope == "Server") ? _uiObservedServer : _uiObservedPlayer, _uiObservedCfg);
				try
				{
					ObserveUiFiles(reload: false, scope);
				}
				catch
				{
				}
				Log.LogInfo((object)("UI configuration saved: scope=" + scope + "."));
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
				_uiCommitting = false;
			}
		}

		private void Awake()
		{
			Log = TeleportCartsLogger;
			FindIncompatibleMods();
			BindConfiguration();
			_serverYamlPath = Path.Combine(Paths.ConfigPath, "odinplus.TeleportCarts.server.yml");
			_playerYamlPath = Path.Combine(Paths.ConfigPath, "odinplus.TeleportCarts.yml");
			Snapshot.ValueChanged += ReadSnapshot;
			if (Sync.IsSourceOfTruth)
			{
				ReloadServerYaml();
				SetupServerYamlWatcher();
			}
			ReloadPlayerYaml();
			SetupPlayerYamlWatcher();
			SetupConfigWatcher();
			try
			{
				RegisterYamlEditor();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("YAML editor unavailable; cart transport will continue. " + ex));
			}
			Localizer.Load();
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
		}

		private void Start()
		{
			EnsureUi();
			if (!IsBlocked)
			{
				BasementsInstalled = Chainloader.PluginInfos.ContainsKey("com.rolopogo.Basement");
				((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} loaded. enabled={1}, yamlSource={2}.", "TeleportCarts", IsEnabled, Sync.IsSourceOfTruth));
			}
		}

		private void OnDestroy()
		{
			_uiTransport?.Dispose();
			if (!IsBlocked)
			{
				_serverYamlWatcher?.Dispose();
				_playerYamlWatcher?.Dispose();
				_configWatcher?.Dispose();
				if ((Object)(object)_yamlEditorHost != (Object)null)
				{
					Object.Destroy((Object)(object)_yamlEditorHost);
				}
				Snapshot.ValueChanged -= ReadSnapshot;
				CartTransport.CancelPending();
				_harmony.UnpatchSelf();
				if (!_uiFaulted)
				{
					((BaseUnityPlugin)this).Config.Save();
				}
			}
		}

		private void BindConfiguration()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			try
			{
				_forceServerConfig = BindSynced("General", "Force Server Config", Toggle.On, "When On (default), the server's synchronized TeleportCarts settings are enforced for connected clients.");
				Sync.AddLockingConfigEntry<Toggle>(_forceServerConfig);
				_enableMod = BindSynced("General", "Enable Mod", defaultValue: true, "Master switch for TeleportCarts cart transport.");
				_teleportCartHotkey = BindLocal<KeyboardShortcut>("Controls", "Teleport Nearest Cart Hotkey", new KeyboardShortcut((KeyCode)304, (KeyCode[])(object)new KeyCode[1] { (KeyCode)99 }), "Hotkey to teleport the nearest unattached cart when hovering over a portal or dungeon entrance.");
				YamlEditorButton.Bind(((BaseUnityPlugin)this).Config, "Advanced Configuration", "Teleport Rules");
				_enableDiagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Enable Cart Teleport Diagnostics", false, new ConfigDescription("Writes transition capture, landing position, and reattach details to this machine's log.", (AcceptableValueBase)null, new object[1]
				{
					new Odinplus.Shared.YamlEditor.ConfigurationManagerAttributes
					{
						IsAdvanced = true
					}
				}));
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		private ConfigEntry<T> BindSynced<T>(string group, string key, T defaultValue, string description)
		{
			ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, key, defaultValue, Describe(description, "Server synchronized"));
			Sync.AddConfigEntry<T>(val).SynchronizedConfig = true;
			return val;
		}

		private ConfigEntry<T> BindLocal<T>(string group, string key, T defaultValue, string description)
		{
			return ((BaseUnityPlugin)this).Config.Bind<T>(group, key, defaultValue, Describe(description, "Local only"));
		}

		private static ConfigDescription Describe(string description, string scope)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(description + " [" + scope + "]", (AcceptableValueBase)null, Array.Empty<object>());
		}

		private void SetupServerYamlWatcher()
		{
			_serverYamlWatcher = new FileSystemWatcher(Paths.ConfigPath, Path.GetFileName(_serverYamlPath))
			{
				IncludeSubdirectories = false,
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				EnableRaisingEvents = true
			};
			_serverYamlWatcher.Changed += delegate
			{
				ReloadServerYaml();
			};
			_serverYamlWatcher.Created += delegate
			{
				ReloadServerYaml();
			};
			_serverYamlWatcher.Renamed += delegate
			{
				ReloadServerYaml();
			};
		}

		private void SetupPlayerYamlWatcher()
		{
			_playerYamlWatcher = new FileSystemWatcher(Paths.ConfigPath, Path.GetFileName(_playerYamlPath))
			{
				IncludeSubdirectories = false,
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				EnableRaisingEvents = true
			};
			_playerYamlWatcher.Changed += delegate
			{
				ReloadPlayerYaml();
			};
			_playerYamlWatcher.Created += delegate
			{
				ReloadPlayerYaml();
			};
			_playerYamlWatcher.Renamed += delegate
			{
				ReloadPlayerYaml();
			};
		}

		private void SetupConfigWatcher()
		{
			_configWatcher = new FileSystemWatcher(Paths.ConfigPath, "odinplus.TeleportCarts.cfg")
			{
				IncludeSubdirectories = false,
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
				SynchronizingObject = ThreadingHelper.SynchronizingObject,
				EnableRaisingEvents = true
			};
			_configWatcher.Changed += ReloadBepInExConfig;
			_configWatcher.Created += ReloadBepInExConfig;
			_configWatcher.Renamed += ReloadBepInExConfig;
		}

		private void RegisterYamlEditor()
		{
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			YamlEditorRegistry.Initialize("odinplus.TeleportCarts", "TeleportCarts");
			YamlEditorRegistry.Register(new Odinplus.Shared.YamlEditor.YamlDocument("server", "Server policy (" + Path.GetFileName(_serverYamlPath) + ")", _serverYamlPath, YamlValidation.FromExceptional(delegate(string text)
			{
				CartServerPolicyValidator.Validate(new <cba6ec40-2546-4a46-9577-18d27987fd9e>DeserializerBuilder().Build().Deserialize<CartServerPolicy>(text) ?? throw new InvalidDataException("The document is empty."));
			}), () => Sync.IsSourceOfTruth && !_uiFaulted, () => "only the server host can edit the server policy"));
			YamlEditorRegistry.Register(new Odinplus.Shared.YamlEditor.YamlDocument("player", "Player preferences (" + Path.GetFileName(_playerYamlPath) + ")", _playerYamlPath, YamlValidation.FromTryPattern((string text) => (!PlayerCartPreferenceSnapshot.TryReplace(PlayerPreferences, text, out PlayerCartPreferences _, out string error)) ? error : null), () => !_uiFaulted));
			_yamlEditorHost = new GameObject("TeleportCartsYamlEditor");
			Object.DontDestroyOnLoad((Object)(object)_yamlEditorHost);
			_yamlEditorHost.AddComponent<YamlEditorBehaviour>();
		}

		private void ReloadBepInExConfig(object sender, FileSystemEventArgs eventArgs)
		{
			lock (UiGate)
			{
				if (!_uiCommitting && !_uiFaulted)
				{
					ReloadBepInExConfigCore(sender, eventArgs);
				}
			}
		}

		private void ReloadBepInExConfigCore(object sender, FileSystemEventArgs eventArgs)
		{
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not reload odinplus.TeleportCarts.cfg. Check its entries and format. " + ex.Message));
			}
		}

		private void ReloadServerYaml()
		{
			lock (UiGate)
			{
				if (!_uiCommitting && !_uiFaulted)
				{
					ReloadServerYamlCore();
				}
			}
		}

		private void ReloadServerYamlCore()
		{
			if (!Sync.IsSourceOfTruth)
			{
				return;
			}
			if (!File.Exists(_serverYamlPath))
			{
				File.WriteAllText(_serverYamlPath, DefaultServerYamlTemplate());
			}
			try
			{
				CartServerPolicy cartServerPolicy = new <cba6ec40-2546-4a46-9577-18d27987fd9e>DeserializerBuilder().Build().Deserialize<CartServerPolicy>(File.ReadAllText(_serverYamlPath));
				CartServerPolicyValidator.Validate(cartServerPolicy);
				ServerPolicy = cartServerPolicy;
				RebuildEffectivePolicy();
				Snapshot.AssignLocalValue(_serializer.Serialize(cartServerPolicy));
				LogDiagnostic($"Accepted server YAML: enabled={cartServerPolicy.Carts.Enabled}, searchRadius={cartServerPolicy.Carts.SearchRadius:0.##}, forwardOffset={cartServerPolicy.Placement.ForwardOffset:0.##}.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("TeleportCarts retained the previous valid server YAML: " + ex.Message));
			}
		}

		private void ReloadPlayerYaml()
		{
			lock (UiGate)
			{
				if (!_uiCommitting && !_uiFaulted)
				{
					ReloadPlayerYamlCore();
				}
			}
		}

		private void ReloadPlayerYamlCore()
		{
			if (!File.Exists(_playerYamlPath))
			{
				File.WriteAllText(_playerYamlPath, DefaultPlayerYamlTemplate());
			}
			string yaml = File.ReadAllText(_playerYamlPath);
			if (PlayerCartPreferenceSnapshot.TryReplace(PlayerPreferences, yaml, out PlayerCartPreferences retained, out string error))
			{
				PlayerPreferences = retained;
				RebuildEffectivePolicy();
				LogDiagnostic($"Accepted local player YAML: enabled={retained.Carts.Enabled}.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("TeleportCarts retained the previous valid local player YAML: " + error));
			}
		}

		private static void ReadSnapshot()
		{
			if (Sync.IsSourceOfTruth || string.IsNullOrWhiteSpace(Snapshot.Value))
			{
				return;
			}
			try
			{
				CartServerPolicy cartServerPolicy = new <cba6ec40-2546-4a46-9577-18d27987fd9e>DeserializerBuilder().Build().Deserialize<CartServerPolicy>(Snapshot.Value);
				CartServerPolicyValidator.Validate(cartServerPolicy);
				ServerPolicy = cartServerPolicy;
				RebuildEffectivePolicy();
				LogDiagnostic($"Accepted server YAML snapshot: enabled={cartServerPolicy.Carts.Enabled}, searchRadius={cartServerPolicy.Carts.SearchRadius:0.##}.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Rejected TeleportCarts server snapshot: " + ex.Message));
			}
		}

		private static void RebuildEffectivePolicy()
		{
			Policy = EffectiveCartPolicy.Create(ServerPolicy, PlayerPreferences);
		}

		private void FindIncompatibleMods()
		{
			string[] array = new string[2] { "com.kpro.TeleportEverything", "zenox.teleporteverything" };
			foreach (string text in array)
			{
				if (Chainloader.PluginInfos.TryGetValue(text, out var value))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)($"Incompatible mod detected: {value.Metadata.Name} ({value.Metadata.Version}), GUID: {text}.\n" + "This mod can conflict with TeleportCarts.\nTo avoid issues, please either:\n- Uninstall the detected mod, or\n- Disable the conflicting features in one of the mods."));
				}
			}
		}

		internal static void LogDiagnostic(string message)
		{
			if (DiagnosticsEnabled)
			{
				Log.LogInfo((object)("TeleportCarts: " + message));
			}
		}

		private static string DefaultServerYamlTemplate()
		{
			return "# Server policy. This file is synchronized to clients.\n# The server owns transport availability and placement numbers. A player file can only narrow them.\n# Native ore teleport rules always apply to cart cargo; they are never overridden.\nSchemaVersion: 1\n\nCarts:\n  # Disable cart transport for every player.\n  Enabled: true\n  # Attached-cart detection radius around the teleporting player.\n  SearchRadius: 10\n\n  Teleport:\n    Portals:\n      # Disable cart transport through normal and stone portals.\n      Enabled: true\n    Dungeons:\n      # Covers both dungeon entrances and exits.\n      Enabled: true\n    Basements:\n      # Requires the Basements mod on the server.\n      Enabled: true\n\nPlacement:\n  # Drop the cart this far ahead of the player's arrival point.\n  ForwardOffset: 0.8\n  # Reattach only when the cart is within this distance of the arrived player.\n  ReattachRadius: 15\n";
		}

		private static string DefaultPlayerYamlTemplate()
		{
			return "# Local player preference. This file is never synchronized and can only restrict the server policy.\n# Native ore teleport rules always apply to cart cargo; they are never overridden.\nSchemaVersion: 1\n\nCarts:\n  # Disable cart transport only for this player.\n  Enabled: true\n\n  Teleport:\n    Portals:\n      # Disable cart transport through portals only for this player.\n      Enabled: true\n    Dungeons:\n      # Disable dungeon entrance and exit cart transport only for this player.\n      Enabled: true\n    Basements:\n      # Disable Basements cart transport only for this player.\n      Enabled: true\n";
		}
	}
	internal static class DirectCartTeleportDecision
	{
		public static bool ShouldPrepareUnattachedCart(bool teleportIsDirect, bool isLocalPlayer, bool sourcePortalIsValid, bool sourceDistanceIsValid, bool attachedCartAvailable, bool transitionEnabled)
		{
			return teleportIsDirect && isLocalPlayer && sourcePortalIsValid && sourceDistanceIsValid && !attachedCartAvailable && transitionEnabled;
		}
	}
	internal static class PlayerDescriptorAvailability
	{
		internal static void Apply(ModuleConfigurationView view, bool moduleEnabled, CartServerPolicy server)
		{
			if (!moduleEnabled)
			{
				Disable(view, (ConfigurationDescriptor _) => true, "The cart module is off. Saved preferences are retained.");
				return;
			}
			if (!server.Carts.Enabled)
			{
				Disable(view, (ConfigurationDescriptor _) => true, "Cart transport is off. Saved preferences are retained.");
				return;
			}
			if (!server.Carts.Teleport.Portals.Enabled)
			{
				Disable(view, (ConfigurationDescriptor row) => Under(row, "Carts.Teleport.Portals"), "Portal cart transport is off. Saved preferences are retained.");
			}
			if (!server.Carts.Teleport.Dungeons.Enabled)
			{
				Disable(view, (ConfigurationDescriptor row) => Under(row, "Carts.Teleport.Dungeons"), "Dungeon cart transport is off. Saved preferences are retained.");
			}
			if (!server.Carts.Teleport.Basements.Enabled)
			{
				Disable(view, (ConfigurationDescriptor row) => Under(row, "Carts.Teleport.Basements"), "Basement cart transport is off. Saved preferences are retained.");
			}
		}

		private static bool Under(ConfigurationDescriptor row, string path)
		{
			return row.StableId.StartsWith(path + ".", StringComparison.Ordinal);
		}

		private static void Disable(ModuleConfigurationView view, Func<ConfigurationDescriptor, bool> matches, string reason)
		{
			foreach (ConfigurationDescriptor descriptor in view.Descriptors)
			{
				if (matches(descriptor))
				{
					descriptor.Enabled = false;
					descriptor.DisabledReason = "Disabled by server: " + reason;
				}
			}
		}
	}
	internal static class CartTransportDiagnostics
	{
		public static string Player(Player player)
		{
			return "player=" + SafeName(player) + " playerId=" + SafeId(player);
		}

		public static string Cart(Vagon cart)
		{
			return "cart=" + SafePrefab(cart) + " cartId=" + SafeId(cart);
		}

		public static string Event(Player player, CartTransitionKind transition, string outcome, Vagon? cart = null, bool? attached = null, int? attempt = null, Vector3? position = null)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			return $"cart-transition outcome={outcome} transition={transition} {Player(player)}" + (((Object)(object)cart == (Object)null) ? string.Empty : (" " + Cart(cart))) + (attached.HasValue ? $" attached={attached.Value}" : string.Empty) + (attempt.HasValue ? $" attempt={attempt.Value}" : string.Empty) + (position.HasValue ? (" position=" + Format(position.Value)) : string.Empty);
		}

		public static string Format(Vector3 position)
		{
			//IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			return $"({position.x:0.##},{position.y:0.##},{position.z:0.##})";
		}

		private static string SafeName(Player player)
		{
			try
			{
				return string.IsNullOrWhiteSpace(player.GetPlayerName()) ? "<unknown>" : player.GetPlayerName();
			}
			catch
			{
				return "<unknown>";
			}
		}

		private static string SafePrefab(Vagon cart)
		{
			try
			{
				ZNetView nview = cart.m_nview;
				return ((nview != null) ? nview.GetPrefabName() : null) ?? "<unknown>";
			}
			catch
			{
				return "<unknown>";
			}
		}

		private static string SafeId(Player player)
		{
			//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)
			try
			{
				return ((object)((Character)player).GetZDOID()/*cast due to .constrained prefix*/).ToString();
			}
			catch
			{
				return "<unknown>";
			}
		}

		private static string SafeId(Vagon cart)
		{
			try
			{
				ZNetView nview = cart.m_nview;
				return ((nview == null) ? null : ((object)Unsafe.As<ZDOID, ZDOID>(ref nview.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString()) ?? "<unknown>";
			}
			catch
			{
				return "<unknown>";
			}
		}
	}
	internal static class CartShortcutInput
	{
		private enum TargetPortalPrefixResult
		{
			Unavailable,
			PickerOpened,
			AllowVanilla
		}

		private enum ShortcutTargetKind
		{
			None,
			Portal,
			Dungeon
		}

		private readonly struct ShortcutContext
		{
			public ShortcutTargetKind Kind { get; }

			public Player? Player { get; }

			public Vagon? Cart { get; }

			public TeleportWorld? Portal { get; }

			public Teleport? Dungeon { get; }

			public bool Eligible
			{
				get
				{
					if (Kind != ShortcutTargetKind.None && (Object)(object)Player != (Object)null)
					{
						return (Object)(object)Cart != (Object)null;
					}
					return false;
				}
			}

			public ShortcutContext(ShortcutTargetKind kind, Player? player, Vagon? cart, TeleportWorld? portal, Teleport? dungeon)
			{
				Kind = kind;
				Player = player;
				Cart = cart;
				Portal = portal;
				Dungeon = dungeon;
			}
		}

		private static readonly ShortcutConsumptionState Consumption = new ShortcutConsumptionState();

		private static readonly ShortcutPressGate PressGate = new ShortcutPressGate();

		private static int _armedFrame = -1;

		private static int _executedFrame = -1;

		private static ShortcutContext _armedContext;

		private static Vagon? _targetPortalCart;

		private static FieldInfo? _targetPortalTeleportingField;

		public static bool TrySuppress(string buttonName, ButtonQueryKind kind)
		{
			//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)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_011b: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut teleportCartHotkey = TeleportCartsPlugin.TeleportCartHotkey;
			if ((int)((KeyboardShortcut)(ref teleportCartHotkey)).MainKey == 0)
			{
				Consumption.Reset();
				PressGate.Reset();
				return false;
			}
			int frameCount = Time.frameCount;
			bool keyDown = Input.GetKeyDown(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey);
			bool key = Input.GetKey(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey);
			bool keyUp = Input.GetKeyUp(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey);
			bool flag = kind == ButtonQueryKind.Down && keyDown;
			bool flag2 = Consumption.RequiresInspectionForFrame(frameCount);
			bool isConsuming = Consumption.IsConsuming;
			if (!flag && !isConsuming && !flag2)
			{
				return false;
			}
			if (!ShortcutInputWorkGate.ShouldInspectBindings(flag && !isConsuming && CanStartShortcut(), flag, isConsuming, flag2))
			{
				return false;
			}
			if (!keyDown && !key && !keyUp && isConsuming)
			{
				Consumption.ShouldSuppress(new ShortcutButtonQuery(buttonName, ((object)((KeyboardShortcut)(ref teleportCartHotkey)).MainKey/*cast due to .constrained prefix*/).ToString(), kind, frameCount, contextEligible: false, actionMatchesShortcut: false, mainKeyPressed: false, mainKeyHeld: false, mainKeyReleased: false));
				if (!Consumption.RequiresInspectionForFrame(frameCount))
				{
					return false;
				}
			}
			IReadOnlyList<string> effectiveControlPaths = ZInputShortcutBindings.GetEffectiveControlPaths(GetButtonDef, buttonName);
			IReadOnlyList<string> activeControlPaths = ZInputShortcutBindings.GetActiveControlPaths(GetButtonDef, buttonName);
			bool actionMatchesShortcut = ShortcutBindingMatcher.MatchesKeyboardShortcut(effectiveControlPaths, activeControlPaths, ((object)((KeyboardShortcut)(ref teleportCartHotkey)).MainKey/*cast due to .constrained prefix*/).ToString(), keyDown || key || keyUp, (kind == ButtonQueryKind.Down) ? ModifiersHeld(teleportCartHotkey) : NoModifiersRequired(), kind != ButtonQueryKind.Down);
			ShortcutContext context = ((kind == ButtonQueryKind.Down && ShortcutInputWorkGate.ShouldCaptureContext(actionMatchesShortcut, keyDown, Consumption.IsConsuming)) ? GetContext(frameCount) : default(ShortcutContext));
			bool num = Consumption.ShouldSuppress(new ShortcutButtonQuery(buttonName, ((object)((KeyboardShortcut)(ref teleportCartHotkey)).MainKey/*cast due to .constrained prefix*/).ToString(), kind, frameCount, context.Eligible, actionMatchesShortcut, keyDown, key, keyUp));
			if (num && kind == ButtonQueryKind.Down && PressGate.ShouldStart(keyDown, key) && context.Eligible && _armedFrame != frameCount && _executedFrame != frameCount)
			{
				Arm(frameCount, context);
			}
			return num;
		}

		public static void ProcessPlayerUpdate(Player player)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0061: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_targetPortalCart != (Object)null && !IsTargetPortalMapTeleporting())
			{
				CartTransport.ClearTargetPortalHotkey(_targetPortalCart);
				_targetPortalCart = null;
			}
			int frameCount = Time.frameCount;
			KeyboardShortcut teleportCartHotkey = TeleportCartsPlugin.TeleportCartHotkey;
			if ((int)((KeyboardShortcut)(ref teleportCartHotkey)).MainKey == 0 || !Input.GetKey(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey))
			{
				PressGate.Reset();
			}
			if (_armedFrame != frameCount && _executedFrame != frameCount && IsRawShortcutDown(teleportCartHotkey) && PressGate.ShouldStart(Input.GetKeyDown(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey), Input.GetKey(((KeyboardShortcut)(ref teleportCartHotkey)).MainKey)))
			{
				ShortcutContext context = GetContext(frameCount);
				if (context.Eligible)
				{
					Arm(frameCount, context);
				}
			}
			ExecuteArmed(player);
		}

		private static void ExecuteArmed(Player player)
		{
			int frameCount = Time.frameCount;
			if (_armedFrame != frameCount || (Object)(object)_armedContext.Player != (Object)(object)player || _executedFrame == frameCount)
			{
				return;
			}
			ShortcutContext armedContext = _armedContext;
			_armedFrame = -1;
			_armedContext = default(ShortcutContext);
			_executedFrame = frameCount;
			if (armedContext.Eligible && !((Object)(object)armedContext.Cart == (Object)null))
			{
				if (armedContext.Kind == ShortcutTargetKind.Portal && (Object)(object)armedContext.Portal != (Object)null)
				{
					ExecutePortal(player, armedContext.Cart, armedContext.Portal);
				}
				else if (armedContext.Kind == ShortcutTargetKind.Dungeon && (Object)(object)armedContext.Dungeon != (Object)null)
				{
					ExecuteDungeon(player, armedContext.Cart, armedContext.Dungeon);
				}
			}
		}

		private static void ExecutePortal(Player player, Vagon cart, TeleportWorld portal)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			if (!CartTransport.IsCurrentShortcutTarget(player, cart, portal, null, CartTransitionKind.Portal))
			{
				return;
			}
			bool allowAllItems = portal.m_allowAllItems;
			if (!CartTransport.CartIsTeleportable(cart, allowAllItems))
			{
				ShowCenterMessage("$tcart_items_prevent");
				TeleportCartsPlugin.LogDiagnostic(CartTransportDiagnostics.Event(player, CartTransitionKind.Portal, "hotkey-blocked-cargo", cart, false));
				return;
			}
			if (CartTransport.IsWorldTeleportBlocked())
			{
				ShowCenterMessage("$tcart_blocked_world");
				return;
			}
			if (IsTargetPortalMapTeleporting())
			{
				if (CartTransport.IsCurrentShortcutTarget(player, cart, portal, null, CartTransitionKind.Portal))
				{
					CartTransport.SetTeleportOrigin(((Component)cart).transform.position);
					CartTransport.SetExplicitTargetCart(cart);
					_targetPortalCart = cart;
				}
				return;
			}
			if (InvokeTargetPortalPrefix(player, portal) == TargetPortalPrefixResult.PickerOpened)
			{
				if (CartTransport.IsCurrentShortcutTarget(player, cart, portal, null, CartTransitionKind.Portal))
				{
					CartTransport.SetTeleportOrigin(((Component)cart).transform.position);
					CartTransport.SetExplicitTargetCart(cart);
					_targetPortalCart = cart;
				}
				return;
			}
			Vector3 position = ((Component)portal).transform.position;
			if (!CartTransport.IsPlacementSafe(cart, position, ((Component)portal).transform.rotation, out string failureReason))
			{
				TeleportCartsPlugin.Log.LogWarning((object)(CartTransportDiagnostics.Event(player, CartTransitionKind.Portal, "hotkey-blocked-placement", cart, false) + " reason=" + failureReason));
				ShowCenterMessage("$tcart_blocked_placement");
				TeleportCartsPlugin.LogDiagnostic(CartTransportDiagnostics.Event(player, CartTransitionKind.Portal, "hotkey-blocked-placement", cart, false));
			}
			else if (CartTransport.IsCurrentShortcutTarget(player, cart, portal, null, CartTransitionKind.Portal))
			{
				CartTransport.SetTeleportOrigin(((Component)cart).transform.position);
				CartTransport.SetExplicitTargetCart(cart);
				portal.Teleport(player);
			}
		}

		private static void ExecuteDungeon(Player player, Vagon cart, Teleport dungeon)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			CartTransitionKind dungeonHoverTransitionKind = CartTransport.GetDungeonHoverTransitionKind();
			if (CartTransport.IsCurrentShortcutTarget(player, cart, null, dungeon, dungeonHoverTransitionKind))
			{
				CartTransport.EnterDungeonTransition();
				CartTransport.SetTeleportOrigin(((Component)cart).transform.position);
				CartTransport.SetExplicitTargetCart(cart);
				if (!dungeon.Interact((Humanoid)(object)player, false, false))
				{
					CartTransport.ClearDungeonTransition();
					CartTransport.ClearExplicitTargetCart();
					TeleportCartsPlugin.LogDiagnostic(CartTransportDiagnostics.Event(player, CartTransitionKind.Dungeon, "hotkey-interaction-rejected", cart, false));
				}
				else
				{
					TeleportCartsPlugin.LogDiagnostic(CartTransportDiagnostics.Event(player, CartTransitionKind.Dungeon, "hotkey-interaction-started", cart, false));
				}
			}
		}

		private static ShortcutContext GetContext(int frame)
		{
			return CaptureContext();
		}

		private static ShortcutContext CaptureContext()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !TeleportCartsPlugin.IsEnabled || !TeleportCartsPlugin.IsHotkeyConfigured)
			{
				return default(ShortcutContext);
			}
			CartTransitionKind kind;
			bool flag = CartTransport.TryGetHotkeyTransition(localPlayer, out kind);
			bool transitionEnabled = flag && TeleportCartsPlugin.Policy.IsTransitionEnabled(kind, TeleportCartsPlugin.BasementsInstalled);
			if (!ShortcutInputWorkGate.ShouldDiscoverTransport(playerAlive: true, moduleEnabled: true, hotkeyConfigured: true, transitionEnabled, flag, uiAllowsInput: true) || IsUiBlocking())
			{
				return default(ShortcutContext);
			}
			if (CartTransport.TryGetAttached(localPlayer, TeleportCartsPlugin.Policy, out Vagon _))
			{
				return default(ShortcutContext);
			}
			if (!CartTransport.TryGetClosestUnattached(localPlayer, TeleportCartsPlugin.Policy, out Vagon cart2))
			{
				return default(ShortcutContext);
			}
			GameObject hovering = localPlayer.m_hovering;
			if ((Object)(object)hovering == (Object)null)
			{
				return default(ShortcutContext);
			}
			TeleportWorld componentInParent = hovering.GetComponentInParent<TeleportWorld>();
			if ((Object)(object)componentInParent != (Object)null && componentInParent.TargetFound())
			{
				return new ShortcutContext(ShortcutTargetKind.Portal, localPlayer, cart2, componentInParent, null);
			}
			Teleport componentInParent2 = hovering.GetComponentInParent<Teleport>();
			if (!((Object)(object)componentInParent2 != (Object)null) || !((Object)(object)componentInParent2.m_targetPoint != (Object)null))
			{
				return default(ShortcutContext);
			}
			return new ShortcutContext(ShortcutTargetKind.Dungeon, localPlayer, cart2, null, componentInParent2);
		}

		private static bool CanStartShortcut()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || !TeleportCartsPlugin.IsEnabled || !TeleportCartsPlugin.IsHotkeyConfigured)
			{
				return false;
			}
			if (!CartTransport.TryGetHotkeyTransition(localPlayer, out var kind))
			{
				return false;
			}
			bool transitionEnabled = TeleportCartsPlugin.Policy.IsTransitionEnabled(kind, TeleportCartsPlugin.BasementsInstalled);
			if (ShortcutInputWorkGate.ShouldDiscoverTransport(playerAlive: true, moduleEnabled: true, hotkeyConfigured: true, transitionEnabled, usableHoverTarget: true, uiAllowsInput: true))
			{
				return !IsUiBlocking();
			}
			return false;
		}

		private static object? GetButtonDef(string buttonName)
		{
			if (ZInput.instance == null)
			{
				return null;
			}
			return ZInput.instance.GetButtonDef(buttonName);
		}

		private static bool IsTargetPortalMapTeleporting()
		{
			if ((object)_targetPortalTeleportingField == null)
			{
				_targetPortalTeleportingField = FindTargetPortalTeleportingField();
			}
			object obj = _targetPortalTeleportingField?.GetValue(null);
			if (obj is bool)
			{
				return (bool)obj;
			}
			return false;
		}

		private static TargetPortalPrefixResult InvokeTargetPortalPrefix(Player player, TeleportWorld portal)
		{
			if (!Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.targetportal"))
			{
				return TargetPortalPrefixResult.Unavailable;
			}
			Type? type = FindTargetPortalMapType();
			MethodInfo methodInfo = FindTargetPortalPrefix(type);
			if (type == null || methodInfo == null || !TryGetTargetPortalTriggerContext(player, portal, out TeleportWorldTrigger trigger, out Collider playerCollider))
			{
				return TargetPortalPrefixResult.Unavailable;
			}
			try
			{
				object obj = methodInfo.Invoke(null, new object[2] { trigger, playerCollider });
				if (obj is bool && (bool)obj)
				{
					return TargetPortalPrefixResult.AllowVanilla;
				}
				return IsTargetPortalMapTeleporting() ? TargetPortalPrefixResult.PickerOpened : TargetPortalPrefixResult.Unavailable;
			}
			catch (TargetInvocationException ex)
			{
				TeleportCartsPlugin.Log.LogWarning((object)$"Could not open TargetPortal's picker from the cart hotkey: {ex.InnerException ?? ex}");
				return IsTargetPortalMapTeleporting() ? TargetPortalPrefixResult.PickerOpened : TargetPortalPrefixResult.Unavailable;
			}
		}

		private static Type? FindTargetPortalMapType()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("TargetPortal.Map", throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}

		private static MethodInfo? FindTargetPortalPrefix(Type? mapType)
		{
			if (mapType == null)
			{
				return null;
			}
			Type[] nestedTypes = mapType.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
			foreach (Type type in nestedTypes)
			{
				if (!(type.Name != "OpenMapOnPortalEnter"))
				{
					MethodInfo method = type.GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					ParameterInfo[] array = method?.GetParameters();
					if (method?.ReturnType == typeof(bool) && array != null && array.Length == 2 && array[0].ParameterType == typeof(TeleportWorldTrigger) && array[1].ParameterType == typeof(Collider))
					{
						return method;
					}
				}
			}
			return null;
		}

		private static bool TryGetTargetPortalTriggerContext(Player player, TeleportWorld portal, out TeleportWorldTrigger? trigger, out Collider? playerCollider)
		{
			trigger = null;
			playerCollider = null;
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)portal == (Object)null || !((Component)portal).gameObject.activeInHierarchy)
			{
				return false;
			}
			Collider[] componentsInChildren = ((Component)player).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && val.enabled && ((Component)val).gameObject.activeInHierarchy && (Object)(object)((Component)val).GetComponent<Player>() == (Object)(object)player)
				{
					playerCollider = val;
					break;
				}
			}
			if ((Object)(object)playerCollider == (Object)null)
			{
				return false;
			}
			TeleportWorldTrigger[] componentsInChildren2 = ((Component)portal).GetComponentsInChildren<TeleportWorldTrigger>(true);
			foreach (TeleportWorldTrigger val2 in componentsInChildren2)
			{
				Collider val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Collider>() : null);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null) && val3.enabled && val3.isTrigger && ((Component)val2).gameObject.activeInHierarchy && !((Object)(object)((Component)val2).transform.parent == (Object)null) && !((Object)(object)((Component)val2).GetComponentInParent<TeleportWorld>() != (Object)(object)portal))
				{
					trigger = val2;
					return true;
				}
			}
			return false;
		}

		private static FieldInfo? FindTargetPortalTeleportingField()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				FieldInfo fieldInfo = assemblies[i].GetType("TargetPortal.Map", throwOnError: false)?.GetField("Teleporting", BindingFlags.Static | BindingFlags.Public);
				if (fieldInfo?.FieldType == typeof(bool))
				{
					return fieldInfo;
				}
			}
			return null;
		}

		private static IEnumerable<bool> ModifiersHeld(KeyboardShortcut shortcut)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				yield return Input.GetKey(modifier);
			}
		}

		private static IEnumerable<bool> NoModifiersRequired()
		{
			yield break;
		}

		private static bool IsRawShortcutDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		private static void Arm(int frame, ShortcutContext context)
		{
			_armedFrame = frame;
			_armedContext = context;
		}

		internal static bool IsUiBlocking()
		{
			if (!WrapperUiInput.IsBlocking && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !SingletonBool("InventoryGui", "instance", "IsVisible") && !SingletonBool("Console", "instance", "IsVisible") && !SingletonBool("TextInput", "instance", "IsVisible") && !SingletonBool("TextInput", "instance", "HasFocus"))
			{
				return SingletonBool("Odinplus.Shared.YamlEditor.YamlEditorRegistry", null, "IsOpen");
			}
			return true;
		}

		private static bool SingletonBool(string typeName, string? instanceName, string memberName)
		{
			Type type = typeof(Player).Assembly.GetType(typeName) ?? typeof(ShortcutConsumptionState).Assembly.GetType(typeName);
			if (type == null)
			{
				return false;
			}
			object obj = null;
			if (instanceName != null)
			{
				obj = type.GetProperty(instanceName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null) ?? type.GetField(instanceName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
				if (obj == null)
				{
					return false;
				}
			}
			MethodInfo method = type.GetMethod(memberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method?.ReturnType == typeof(bool))
			{
				return (bool)method.Invoke(obj, null);
			}
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property?.PropertyType == typeof(bool))
			{
				return (bool)property.GetValue(obj);
			}
			FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field?.FieldType == typeof(bool))
			{
				return (bool)field.GetValue(obj);
			}
			return false;
		}

		private static void ShowCenterMessage(string key)
		{
			if ((Object)(object)MessageHud.instance != (Object)null && Localization.instance != null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, Localization.instance.Localize(key), 0, (Sprite)null, false, true);
			}
		}
	}
	internal static class CartTransport
	{
		private readonly struct CartHoverContextKey : IEquatable<CartHoverContextKey>
		{
			private readonly Player _player;

			private readonly object? _session;

			private readonly object _hover;

			private readonly CartTransitionKind _transition;

			private readonly EffectiveCartPolicy _policy;

			public CartHoverContextKey(Player player, object? session, object hover, CartTransitionKind transition, EffectiveCartPolicy policy)
			{
				_player = player;
				_session = session;
				_hover = hover;
				_transition = transition;
				_policy = policy;
			}

			public bool Equals(CartHoverContextKey other)
			{
				if (_player == other._player && _session == other._session && _hover == other._hover && _transition == other._transition)
				{
					return _policy == other._policy;
				}
				return false;
			}
		}

		private static bool _portalTransition;

		private static bool _dungeonTransition;

		private static Vector3 _portalSourcePosition;

		private static float _portalSourceCapturedAt;

		private static bool _hasPortalSource;

		private static bool _directPortalTransition;

		private static ZDOID? _pendingCartId;

		private static bool _pendingCartAttached;

		private static bool _pendingDetachedHotkey;

		private static int _pendingCartAttempts;

		private static bool _pendingCartUnavailableLogged;

		private static bool _pendingCartPlaced;

		private static bool _pendingCartSourceOwnershipCaptured;

		private static CartTransitionKind _pendingCartTransition;

		private static Quaternion _pendingCartRotation;

		private static Vector3 _pendingCartTarget;

		private static Vector3 _pendingCartLocalPosition;

		private static Quaternion _pendingCartLocalRotation;

		private static float _pendingAttachedPlayerPushDistance;

		private static float _pendingStartedAt;

		private static Vagon? _explicitTargetCart;

		private static CartTransitionKind? _dungeonTransitionKind;

		private static readonly TimedContextCache<CartHoverContextKey, bool> HoverAvailability = new TimedContextCache<CartHoverContextKey, bool>(0.2);

		private static Vector3? _teleportOrigin;

		private const float DirectPortalSourceLifetimeSeconds = 30f;

		private const float DirectPortalSourceDistance = 10f;

		private const int MaximumPendingCartAttempts = 30;

		private const float MaximumDetachedHotkeyArrivalWaitSeconds = 30f;

		public static bool HasPendingTransport => _pendingCartId.HasValue;

		public static void ObservePortalEntry(Player player)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				_portalSourcePosition = ((Component)player).transform.position;
				_portalSourceCapturedAt = Time.time;
				_hasPortalSource = true;
				_directPortalTransition = false;
			}
		}

		public static void EnterPortalTransition()
		{
			_portalTransition = true;
			_directPortalTransition = false;
		}

		public static void ExitPortalTransition()
		{
			_portalTransition = false;
			_directPortalTransition = false;
			ClearPortalSource();
		}

		public static void EnterDungeonTransition()
		{
			_dungeonTransition = true;
			_dungeonTransitionKind = ((!IsInBasement()) ? CartTransitionKind.Dungeon : CartTransitionKind.Basement);
		}

		public static void ExitDungeonTransition()
		{
			_dungeonTransition = false;
		}

		public static void ClearDungeonTransition()
		{
			_dungeonTransition = false;
			_dungeonTransitionKind = null;
		}

		public static void SetExplicitTargetCart(Vagon? cart)
		{
			_explicitTargetCart = cart;
		}

		public static void ClearExplicitTargetCart()
		{
			_explicitTargetCart = null;
		}

		public static void ClearTargetPortalHotkey(Vagon cart)
		{
			if ((Object)(object)_explicitTargetCart == (Object)(object)cart)
			{
				_explicitTargetCart = null;
			}
			_teleportOrigin = null;
		}

		public static void PrepareDirectPortalCart(Player player, EffectiveCartPolicy policy)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			_directPortalTransition = _hasPortalSource && Time.time - _portalSourceCapturedAt <= 30f && Vector3.Distance(((Component)player).transform.position, _portalSourcePosition) <= 10f;
		}

		public static void EndDirectPortalCart()
		{
			_directPortalTransition = false;
			ClearPortalSource();
		}

		public static void CancelPending()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			_portalTransition = false;
			_dungeonTransition = false;
			_directPortalTransition = false;
			ClearPortalSource();
			_pendingCartId = null;
			_pendingCartAttached = false;
			_pendingDetachedHotkey = false;
			_pendingCartAttempts = 0;
			_pendingCartUnavailableLogged = false;
			_pendingCartPlaced = false;
			_pendingCartSourceOwnershipCaptured = false;
			_pendingCartTransition = CartTransitionKind.Portal;
			_dungeonTransitionKind = null;
			_pendingCartRotation = default(Quaternion);
			_pendingCartTarget = default(Vector3);
			_pendingCartLocalPosition = default(Vector3);
			_pendingCartLocalRotation = default(Quaternion);
			_pendingAttachedPlayerPushDistance = 0f;
			_pendingStartedAt = 0f;
			_explicitTargetCart = null;
		}

		public static CartTransitionKind ClassifyCurrentTransition(Player player)
		{
			if (_portalTransition)
			{
				return CartTransitionKind.Portal;
			}
			if (_dungeonTransition)
			{
				CartTransitionKind? dungeonTransitionKind = _dungeonTransitionKind;
				if (!dungeonTransitionKind.HasValue)
				{
					if (!IsInBasement())
					{
						return CartTransitionKind.Dungeon;
					}
					return CartTransitionKind.Basement;
				}
				return dungeonTransitionKind.GetValueOrDefault();
			}
			if (_dungeonTransitionKind.HasValue)
			{
				return _dungeonTransitionKind.Value;
			}
			if (!((Character)player).InInterior() && !IsInBasement())
			{
				return CartTransitionKind.Portal;
			}
			return CartTransitionKind.Dungeon;
		}

		public static bool TryGetAttached(Player player, EffectiveCartPolicy policy, out Vagon? cart)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_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)
			cart = null;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			float num = policy.SearchRadius * policy.SearchRadius;
			Vector3 position = ((Component)player).transform.position;
			foreach (Vagon instance in Vagon.m_instances)
			{
				if ((Object)(object)instance != (Object)null)
				{
					Vector3 val = ((Component)instance).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude <= num && instance.IsAttached((Character)(object)player))
					{
						cart = instance;
						break;
					}
				}
			}
			return (Object)(object)cart != (Object)null;
		}

		public static bool TryGetClosestUnattached(Player player, EffectiveCartPolicy policy, out Vagon? cart)
		{
			//IL_0019: 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_0058: 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_005e: 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)
			cart = null;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (policy == null)
			{
				return false;
			}
			Vector3 position = ((Component)player).transform.position;
			float searchRadius = policy.SearchRadius;
			float num = searchRadius * searchRadius;
			float num2 = float.PositiveInfinity;
			Vagon val = null;
			foreach (Vagon instance in Vagon.m_instances)
			{
				if (!((Object)(object)instance == (Object)null))
				{
					Vector3 val2 = ((Component)instance).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > num) && !(sqrMagnitude >= num2) && !instance.IsAttached((Character)(object)player))
					{
						num2 = sqrMagnitude;
						val = instance;
					}
				}
			}
			cart = val;
			return (Object)(object)val != (Object)null;
		}

		public static bool TryGetHotkeyTransition(Player player, out CartTransitionKind kind)
		{
			kind = CartTransitionKind.Portal;
			GameObject hovering = player.m_hovering;
			if ((Object)(object)hovering == (Object)null)
			{
				return false;
			}
			TeleportWorld componentInParent = hovering.GetComponentInParent<TeleportWorld>();
			if ((Object)(object)componentInParent != (Object)null && componentInParent.TargetFound())
			{
				kind = CartTransitionKind.Portal;
				return true;
			}
			Teleport componentInParent2 = hovering.GetComponentInParent<Teleport>();
			if ((Object)(object)componentInParent2 == (Object)null || (Object)(object)componentInParent2.m_targetPoint == (Object)null)
			{
				return false;
			}
			kind = ((!IsInBasement()) ? CartTransitionKind.Dungeon : CartTransitionKind.Basement);
			return true;
		}

		public static CartTransitionKind GetDungeonHoverTransitionKind()
		{
			if (!IsInBasement())
			{
				return CartTransitionKind.Dungeon;
			}
			return CartTransitionKind.Basement;
		}

		public static bool TryGetTransportCart(Player player, EffectiveCartPolicy policy, out Vagon? cart, out bool isAttached)
		{
			//IL_0032: 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)
			if (TryGetAttached(player, policy, out cart))
			{
				isAttached = true;
				return true;
			}
			if ((Object)(object)_explicitTargetCart != (Object)null && CartTransportDecision.CanUseUnattachedTarget(hasExplicitTarget: true, _explicitTargetCart.IsAttached((Character)(object)player), Vector3.Distance(((Component)_explicitTargetCart).transform.position, ((Component)player).transform.position) <= policy.SearchRadius))
			{
				cart = _explicitTargetCart;
				isAttached = false;
				return true;
			}
			isAttached = false;
			cart = null;
			return false;
		}

		public static bool IsExplicitHotkeyCart(Vagon cart)
		{
			return (Object)(object)_explicitTargetCart == (Object)(object)cart;
		}

		public static string AppendHoverHint(string baseText, CartTransitionKind transitionKind, object hoverSource)
		{
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(baseText))
			{
				HoverAvailability.Clear();
				return baseText;
			}
			Player localPlayer = Player.m_localPlayer;
			EffectiveCartPolicy policy = TeleportCartsPlugin.Policy;
			if ((Object)(object)localPlayer == (Object)null || policy == null || !TeleportCartsPlugin.IsEnabled || !TeleportCartsPlugin.IsHotkeyConfigured)
			{
				HoverAvailability.Clear();
				return baseText;
			}
			GameObject hovering = localPlayer.m_hovering;
			TeleportWorld val = ((hovering != null) ? hovering.GetComponentInParent<TeleportWorld>() : null);
			Teleport val2 = ((hovering != null) ? hovering.GetComponentInParent<Teleport>() : null);
			bool flag = ((transitionKind != CartTransitionKind.Portal) ? ((Object)(object)val2 != (Object)null && val2 == hoverSource && (Object)(object)val2.m_targetPoint != (Object)null) : ((Object)(object)val != (Object)null && val == hoverSource && val.TargetFound()));
			if (((Character)localPlayer).IsDead() || !flag || !policy.IsTransitionEnabled(transitionKind, TeleportCartsPlugin.BasementsInstalled) || !ShortcutInputWorkGate.ShouldDiscoverTransport(playerAlive: true, moduleEnabled: true, hotkeyConfigured: true, policy.IsTransitionEnabled(transitionKind, TeleportCartsPlugin.BasementsInstalled), flag, uiAllowsInput: true) || CartShortcutInput.IsUiBlocking())
			{
				HoverAvailability.Clear();
				return baseText;
			}
			CartHoverContextKey key = new CartHoverContextKey(localPlayer, ZNet.instance, hoverSource, transitionKind, policy);
			if (!HoverAvailability.TryGet(key, Time.time, out var value))
			{
				value = !TryGetAttached(localPlayer, policy, out Vagon cart) && TryGetClosestUnattached(localPlayer, policy, out cart);
				HoverAvailability.Store(key, Time.time, value);
			}
			if (!value)
			{
				return baseText;
			}
			string text = FormatHotkey(TeleportCartsPlugin.TeleportCartHotkey);
			string text2 = ((Localization.instance != null) ? Localization.instance.Localize("$tcart_hover_teleport_cart") : "Teleport with nearest cart");
			return baseText + "\n[<color=yellow><b>" + text + "</b></color>] " + text2;
		}

		public static bool IsCurrentShortcutTarget(Player player, Vagon cart, TeleportWorld? portal, Teleport? dungeon, CartTransitionKind transition)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)cart == (Object)null) && !((Character)player).IsDead() && TeleportCartsPlugin.IsEnabled && TeleportCartsPlugin.IsHotkeyConfigured && !CartShortcutInput.IsUiBlocking() && TeleportCartsPlugin.Policy.IsTransitionEnabled(transition, TeleportCartsPlugin.BasementsInstalled) && !cart.IsAttached((Character)(object)player))
			{
				Vector3 val = ((Component)cart).transform.position - ((Component)player).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > TeleportCartsPlugin.Policy.SearchRadius * TeleportCartsPlugin.Policy.SearchRadius))
				{
					GameObject hovering = player.m_hovering;
					if (transition == CartTransitionKind.Portal)
					{
						if ((Object)(object)portal != (Object)null && portal.TargetFound() && (Object)(object)hovering != (Object)null)
						{
							return hovering.GetComponentInParent<TeleportWorld>() == portal;
						}
						return false;
					}
					if ((Object)(object)dungeon != (Object)null && (Object)(object)dungeon.m_targetPoint != (Object)null && (Object)(object)hovering != (Object)null)
					{
						return hovering.GetComponentInParent<Teleport>() == dungeon;
					}
					return false;
				}
			}
			return false;
		}

		internal static string FormatHotkey(KeyboardShortcut shortcut)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ShortcutHoverText.Format(shortcut, (string token) => (Localization.instance == null) ? token : Localization.instance.Localize(token));
		}

		public static bool CartIsTeleportable(Vagon cart, bool allowAllItems)
		{
			Container componentInChildren = ((Component)cart).GetComponentInChildren<Container>();
			if (componentInChildren == null)
			{
				return false;
			}
			Inventory inventory = componentInChildren.m_inventory;
			return ((inventory != null) ? new bool?(inventory.IsTeleportable(allowAllItems)) : ((bool?)null)) == true;
		}

		public static bool IsWorldTeleportBlocked()
		{
			ZoneSystem instance = ZoneSystem.instance;
			RandEventSystem instance2 = RandEventSystem.instance;
			return CartWorldGate.ShouldBlock((Object)(object)instance != (Object)null && instance.GetGlobalKey("noportals"), (Object)(object)instance != (Object)null && instance.GetGlobalKey("nobossportals"), (Object)(object)instance2 != (Object)null && instance2.GetBossEvent() != null);
		}

		public static float GetCartHeight(Vagon cart)
		{
			//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_005e: 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_006d: 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)
			if ((Object)(object)cart == (Object)null)
			{
				return 2f;
			}
			Collider[] componentsInChildren = ((Component)cart).GetComponentsInChildren<Collider>();
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return 2f;
			}
			float num = float.MaxValue;
			float num2 = float.MinValue;
			bool flag = false;
			Collider[] array = componentsInChildren;
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && !val.isTrigger)
				{
					Bounds bounds = val.bounds;
					if (((Bounds)(ref bounds)).min.y < num)
					{
						num = ((Bounds)(ref bounds)).min.y;
					}
					if (((Bounds)(ref bounds)).max.y > num2)
					{
						num2 = ((Bounds)(ref bounds)).max.y;
					}
					flag = true;
				}
			}
			if (!flag)
			{
				return 2f;
			}
			return Mathf.Max(1f, num2 - num);
		}

		public static bool IsPlacementSafe(Vagon cart, Vector3 targetPosition, Quaternion rotation, out string failureReason)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0050: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			failureReason = "";
			if ((Object)(object)cart == (Object)null)
			{
				failureReason = "Cart reference missing.";
				return false;
			}
			if (!HasVerticalClearance(cart, targetPosition, rotation, TeleportCartsPlugin.Policy, out var availableHeight, out var cartHeight, CartTransitionKind.Portal, useDetachedForwardOffset: true))
			{
				failureReason = $"Insufficient vertical clearance at {targetPosition}. Required height: {cartHeight:0.##}m, Available: {availableHeight:0.##}m.";
				return false;
			}
			Vector3 val = targetPosition + rotation * Vector3.forward * GetDetachedForwardOffset(cart, rotation, TeleportCartsPlugin.Policy);
			Quaternion val2 = rotation * Quaternion.Inverse(((Component)cart).transform.rotation);
			Collider[] componentsInChildren = ((Component)cart).GetComponentsInChildren<Collider>();
			foreach (Vagon instance in Vagon.m_instances)
			{
				if ((Object)(object)instance == (Object)(object)cart || (Object)(object)instance == (Object)null)
				{
					continue;
				}
				Collider[] componentsInChildren2 = ((Component)instance).GetComponentsInChildren<Collider>();
				Collider[] array = componentsInChildren;
				foreach (Collider val3 in array)
				{
					if ((Object)(object)val3 == (Object)null || val3.isTrigger)
					{
						continue;
					}
					Vector3 firstPosition = val + val2 * (((Component)val3).transform.position - ((Component)cart).transform.position);
					Quaternion firstRotation = val2 * ((Component)val3).transform.rotation;
					Collider[] array2 = componentsInChildren2;
					foreach (Collider val4 in array2)
					{
						if (!((Object)(object)val4 == (Object)null) && !val4.isTrigger && CollidersOverlapAtPose(val3, firstPosition, firstRotation, val4))
						{
							ZNetView nview = instance.m_nview;
							failureReason = $"Destination is obstructed by another stationary cart ({((nview != null) ? nview.GetZDO() : null)}) at {((Component)instance).transform.position}.";
							return false;
						}
					}
				}
			}
			failureReason = "OK";
			return true;
		}

		private static bool CollidersOverlapAtPose(Collider first, Vector3 firstPosition, Quaternion firstRotation, Collider second)
		{
			//IL_0009: 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)
			//IL_0012: 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_0059: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			float num = default(float);
			if (CanComputePenetration(first))
			{
				return Physics.ComputePenetration(first, firstPosition, firstRotation, second, ((Component)second).transform.position, ((Component)second).transform.rotation, ref val, ref num);
			}
			if (CanComputePenetration(second))
			{
				return Physics.ComputePenetration(second, ((Component)second).transform.position, ((Component)second).transform.rotation, first, firstPosition, firstRotation, ref val, ref num);
			}
			Bounds boundsAtPose = GetBoundsAtPose(first, firstPosition, firstRotation);
			return ((Bounds)(ref boundsAtPose)).Intersects(second.bounds);
		}

		private static bool CanComputePenetration(Collider collider)
		{
			if ((!(collider is BoxCollider) && !(collider is SphereCollider) && !(collider is CapsuleCollider)) || 1 == 0)
			{
				MeshCollider val = (MeshCollider)(object)((collider is MeshCollider) ? collider : null);
				if (val != null)
				{
					return val.convex;
				}
				return false;
			}
			return true;
		}

		private static Bounds GetBoundsAtPose(Collider collider, Vector3 position, Quaternion rotation)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0055: 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_0064: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = collider.bounds;
			Vector3 val = position + rotation * (((Bounds)(ref bounds)).center - ((Component)collider).transform.position);
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			Vector3 val2 = rotation * Vector3.right;
			Vector3 val3 = rotation * Vector3.up;
			Vector3 val4 = rotation * Vector3.forward;
			Vector3 val5 = default(Vector3);
			((Vector3)(ref val5))..ctor(Mathf.Abs(val2.x) * extents.x + Mathf.Abs(val3.x) * extents.y + Mathf.Abs(val4.x) * extents.z, Mathf.Abs(val2.y) * extents.x + Mathf.Abs(val3.y) * extents.y + Mathf.Abs(val4.y) * extents.z, Mathf.Abs(val2.z) * extents.x + Mathf.Abs(val3.z) * extents.y + Mathf.Abs(val4.z) * extents.z);
			return new Bounds(val, val5 * 2f);
		}

		internal static bool HasVerticalClearance(Vagon cart, Vector3 target, Quaternion rotation, EffectiveCartPolicy policy, out float availableHeight, out float cartHeight, CartTransitionKind transition = CartTransitionKind.Portal, bool useDetachedForwardOffset = false)
		{
			//IL_001e: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_00c1: 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)
			cartHeight = GetCartHeight(cart);
			availableHeight = float.MaxValue;
			float num = (useDetachedForwardOffset ? GetDetachedForwardOffset(cart, rotation, policy) : policy.ForwardOffset);
			Vector3 val = target + rotation * Vector3.forward * num;
			float num2 = default(float);
			if (!CartPlacementDecision.UsesNativeTargetHeight(transition) && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(val, ref num2) && Mathf.Abs(num2 - val.y) < 10f)
			{
				val.y = num2 + 0.1f;
			}
			Vector3 val2 = val + Vector3.up * 0.2f;
			int num3 = (((Object)(object)ZoneSystem.instance != (Object)null) ? (ZoneSystem.instance.m_blockRayMask | ZoneSystem.instance.m_solidRayMask) : (-5));
			RaycastHit val3 = default(RaycastHit);
			if (Physics.Raycast(val2, Vector3.up, ref val3, 20f, num3, (QueryTriggerInteraction)1))
			{
				availableHeight = ((RaycastHit)(ref val3)).distance + 0.2f;
				if (availableHeight < cartHeight + 0.15f)
				{
					return false;
				}
			}
			return true;
		}

		public static CartPlacementResult Transport(Vagon cart, Vector3 target, Quaternion rotation, EffectiveCartPolicy policy, CartTransitionKind transition = CartTransitionKind.Portal)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (migh