Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of TeleportCarts v0.2.3
TeleportCarts.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
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