Decompiled source of Wayfarer v0.5.13

plugins/Wayfarer/Wayfarer.Core.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.5.13.0")]
[assembly: AssemblyInformationalVersion("0.5.13")]
[assembly: AssemblyProduct("Wayfarer.Core")]
[assembly: AssemblyTitle("Wayfarer.Core")]
[assembly: AssemblyVersion("0.5.13.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Wayfarer.Core
{
	public readonly struct DeathPinCandidate
	{
		public readonly float X;

		public readonly float Z;

		public readonly string? Name;

		public readonly bool Saved;

		public readonly bool Death;

		public readonly bool ForeignAuthor;

		public readonly long OwnerId;

		public DeathPinCandidate(float x, float z, string? name, bool saved, bool death, long ownerId, bool foreignAuthor)
		{
			X = x;
			Z = z;
			Name = name;
			Saved = saved;
			Death = death;
			OwnerId = ownerId;
			ForeignAuthor = foreignAuthor;
		}
	}
	public static class DeathPinCleanup
	{
		public const float MatchRadius = 1f;

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		public static int FindUnique(IReadOnlyList<DeathPinCandidate> pins, float originalX, float originalZ, int nativeDay, long localPlayerId)
		{
			if (pins == null || localPlayerId == 0L || nativeDay < 0 || !Finite(originalX) || !Finite(originalZ))
			{
				return -1;
			}
			string b = "$hud_mapday " + nativeDay.ToString(CultureInfo.InvariantCulture);
			int num = -1;
			for (int i = 0; i < pins.Count; i++)
			{
				DeathPinCandidate deathPinCandidate = pins[i];
				if (!deathPinCandidate.Saved || !deathPinCandidate.Death || deathPinCandidate.ForeignAuthor || (deathPinCandidate.OwnerId != 0L && deathPinCandidate.OwnerId != localPlayerId) || !string.Equals(deathPinCandidate.Name, b, StringComparison.Ordinal) || !Finite(deathPinCandidate.X) || !Finite(deathPinCandidate.Z))
				{
					continue;
				}
				double num2 = (double)deathPinCandidate.X - (double)originalX;
				double num3 = (double)deathPinCandidate.Z - (double)originalZ;
				if (!(num2 * num2 + num3 * num3 >= 1.0))
				{
					if (num >= 0)
					{
						return -1;
					}
					num = i;
				}
			}
			return num;
		}
	}
	public enum Category
	{
		Bed,
		Stones,
		Map,
		Boat,
		Grave,
		Player
	}
	public sealed class Destination
	{
		public string Id { get; }

		public Category Category { get; }

		public string LabelKey { get; }

		public long WorldId { get; }

		public bool IsLastKnown { get; set; }

		public string Name { get; set; } = "";

		public float X { get; set; }

		public float Y { get; set; }

		public float Z { get; set; }

		public Destination(string id, Category category, string labelKey, long worldId)
		{
			Id = id;
			Category = category;
			LabelKey = labelKey;
			WorldId = worldId;
		}
	}
	public static class DestinationPolicy
	{
		public static bool SharedPlayer(bool online, bool sharesPosition, bool isLocal)
		{
			if (online && sharesPosition)
			{
				return !isLocal;
			}
			return false;
		}

		public static bool CanSelect(Destination d, long worldId, bool advancedEnabled)
		{
			if (d.WorldId == worldId)
			{
				if (!advancedEnabled && d.Category != Category.Bed && d.Category != Category.Stones)
				{
					return d.Category == Category.Map;
				}
				return true;
			}
			return false;
		}
	}
	public static class LandingPolicy
	{
		public static bool Clear(bool areaReady, float normalY, bool clear, bool water)
		{
			if (areaReady && clear)
			{
				if (!water)
				{
					return normalY >= 0.65f;
				}
				return true;
			}
			return false;
		}

		public static float CorrectHeight(float supplied, float floor, float water)
		{
			return Math.Max(floor, water) + 0.6f;
		}

		public static bool IsValid(float x, float y, float z)
		{
			if (!float.IsNaN(x) && !float.IsNaN(y) && !float.IsNaN(z) && !float.IsInfinity(x) && !float.IsInfinity(y) && !float.IsInfinity(z) && Math.Abs(x) < 12000f)
			{
				return Math.Abs(z) < 12000f;
			}
			return false;
		}
	}
	public sealed class SelectionState
	{
		public bool Armed { get; private set; }

		public bool PickerOpen { get; private set; }

		public bool Advanced { get; private set; }

		public long WorldId { get; private set; }

		public void ChangeWorld(long world)
		{
			if (WorldId != world)
			{
				Close();
				WorldId = world;
			}
		}

		public void Arm()
		{
			Armed = !Armed;
			PickerOpen = false;
		}

		public void Close()
		{
			Armed = false;
			PickerOpen = false;
		}

		public void SetAdvanced(bool enabled)
		{
			Advanced = enabled;
			if (!enabled)
			{
				PickerOpen = false;
			}
		}

		public void SetEnabled(bool enabled)
		{
			if (!enabled)
			{
				Close();
			}
		}

		public void OpenPicker()
		{
			if (Advanced)
			{
				PickerOpen = true;
				Armed = false;
			}
		}
	}
	public sealed class ObservedDestinations
	{
		private long world;

		private readonly Dictionary<string, Destination> entries = new Dictionary<string, Destination>();

		public IReadOnlyCollection<Destination> Items => entries.Values;

		public void ChangeWorld(long id)
		{
			if (world != id)
			{
				entries.Clear();
				world = id;
			}
		}

		public void Put(Destination d)
		{
			if (d.WorldId == world)
			{
				entries[d.Id] = d;
			}
		}
	}
	public static class WayfarerIdentity
	{
		public const string Version = "0.5.13";

		public const string Family = "Mischief";
	}
	public static class ConfigurationKeys
	{
		public const string Enabled = "Enabled";

		public const string Language = "Language";

		public const string CloseMap = "CloseMap";

		public const string Messages = "ShowMessages";

		public const string TombstoneHints = "TombstoneHints";
	}
	public static class ServerConfigurationKeys
	{
		public const string Section = "Server";

		public const string AllowTeleport = "AllowTeleport";

		public const string AllowBed = "AllowBed";
	}
	public static class CheatKeys
	{
		public const string Section = "Cheats";

		public const string Stones = "TeleportToStones";

		public const string Map = "TeleportAnywhere";

		public const string Boat = "TeleportToBoat";

		public const string Grave = "TeleportToGrave";

		public const string Player = "TeleportToPlayer";

		public static string? For(Category category)
		{
			return category switch
			{
				Category.Player => "TeleportToPlayer", 
				Category.Grave => "TeleportToGrave", 
				Category.Boat => "TeleportToBoat", 
				Category.Map => "TeleportAnywhere", 
				Category.Stones => "TeleportToStones", 
				_ => null, 
			};
		}
	}
	public interface IWayfarerNavigation
	{
		NavigationSnapshot Snapshot();
	}
	public sealed class NavigationSnapshot
	{
		public bool WorldReady { get; }

		public bool Advanced { get; }

		public IReadOnlyList<Category> Categories { get; }

		public NavigationSnapshot(bool worldReady, bool advanced, IEnumerable<Category> categories)
		{
			WorldReady = worldReady;
			Advanced = advanced;
			Categories = Array.AsReadOnly(categories.ToArray());
		}
	}
	public sealed class NavigationProvider : IWayfarerNavigation
	{
		private readonly Func<NavigationSnapshot> snapshot;

		public NavigationProvider(Func<NavigationSnapshot> snapshot)
		{
			this.snapshot = snapshot ?? throw new ArgumentNullException("snapshot");
		}

		public NavigationSnapshot Snapshot()
		{
			return snapshot();
		}
	}
	public sealed class ProductPresentation
	{
		public string Title { get; }

		public string Brand { get; }

		public ProductPresentation(string title, string brand)
		{
			Title = title;
			Brand = brand;
		}
	}
	public readonly struct PanelRect
	{
		public float X { get; }

		public float Y { get; }

		public float Width { get; }

		public float Height { get; }

		public float Right => X + Width;

		public float Bottom => Y + Height;

		public PanelRect(float x, float y, float width, float height)
		{
			X = x;
			Y = y;
			Width = width;
			Height = height;
		}
	}
	public enum SlotKind
	{
		Text,
		Button,
		Icon,
		Tab,
		Switch
	}
	public readonly struct PanelSlot
	{
		public string Name { get; }

		public SlotKind Kind { get; }

		public PanelRect Rect { get; }

		public int Row { get; }

		public int Column { get; }

		public int Span { get; }

		public bool Focusable => Row >= 0;

		public PanelSlot(string name, SlotKind kind, PanelRect rect, int row = -1, int column = 0, int span = 1)
		{
			Name = name;
			Kind = kind;
			Rect = rect;
			Row = row;
			Column = column;
			Span = span;
		}

		public IEnumerable<(int X, int Y)> Cells()
		{
			for (int i = 0; i < Span; i++)
			{
				yield return (X: Column + i, Y: Row);
			}
		}
	}
	public sealed class PanelScreen
	{
		public string Id { get; }

		public float Height { get; }

		public int Columns { get; }

		public IReadOnlyList<PanelSlot> Slots { get; }

		public PanelSlot this[string name] => Slots.First((PanelSlot s) => s.Name == name);

		public PanelScreen(string id, float height, int columns, IReadOnlyList<PanelSlot> slots)
		{
			Id = id;
			Height = height;
			Columns = columns;
			Slots = slots;
		}

		public bool Has(string name)
		{
			return Slots.Any((PanelSlot s) => s.Name == name);
		}
	}
	public static class PanelLayout
	{
		public const float Width = 370f;

		public const float Left = 12f;

		public const float Inner = 346f;

		public const float Top = 62f;

		public const float Row = 46f;

		public const float ButtonHeight = 40f;

		public const float MinScale = 0.3f;

		public const float Edge = 24f;

		public const float TabHeight = 26f;

		public const float TabBetween = 6f;

		public const int PageSize = 6;

		public const int PickerColumns = 6;

		public const float DefaultLeft = 0.084f;

		public const float DefaultTop = 0.392f;

		public static readonly string[] MainActions = new string[4] { "Bed", "Stones", "Map", "Advanced" };

		private static PanelSlot[] Header()
		{
			return new PanelSlot[2]
			{
				new PanelSlot("Title", SlotKind.Text, new PanelRect(12f, 4f, 270f, 30f)),
				new PanelSlot("Brand", SlotKind.Text, new PanelRect(12f, 31f, 270f, 20f))
			};
		}

		public static PanelScreen Main(IEnumerable<string> allowed)
		{
			string[] array = MainActions.Where(allowed.Contains<string>).ToArray();
			List<PanelSlot> list = Header().ToList();
			for (int i = 0; i < array.Length; i++)
			{
				list.Add(new PanelSlot(array[i], SlotKind.Button, new PanelRect(12f, 62f + 46f * (float)i, 346f, 40f), i));
			}
			if (array.Length == 0)
			{
				list.Add(new PanelSlot("PolicyDenied", SlotKind.Text, new PanelRect(12f, 62f, 346f, 40f)));
			}
			return new PanelScreen("main", 124f + 46f * (float)Math.Max(0, array.Length - 1), 1, list);
		}

		public static PanelRect Tab(int index, int count)
		{
			if (count <= 0 || index < 0 || index >= count)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			float num = (346f - 6f * (float)(count - 1)) / (float)count;
			return new PanelRect(12f + (float)index * (num + 6f), 62f, num, 26f);
		}

		public static PanelScreen Picker(int categories, int shown)
		{
			if (categories < 1 || categories > 3)
			{
				throw new ArgumentOutOfRangeException("categories");
			}
			if (shown < 0 || shown > 6)
			{
				throw new ArgumentOutOfRangeException("shown");
			}
			List<PanelSlot> list = Header().ToList();
			int num = 6 / categories;
			for (int i = 0; i < categories; i++)
			{
				list.Add(new PanelSlot("Category" + i, SlotKind.Tab, Tab(i, categories), 0, i * num, num));
			}
			list.Add(new PanelSlot("Help", SlotKind.Text, new PanelRect(12f, 96f, 346f, 64f)));
			if (shown == 0)
			{
				list.Add(new PanelSlot("Empty", SlotKind.Text, new PanelRect(12f, 168f, 346f, 48f)));
			}
			for (int j = 0; j < shown; j++)
			{
				list.Add(new PanelSlot("Destination" + j, SlotKind.Button, new PanelRect(12f, 168 + j * 39, 346f, 34f), 1 + j, 0, 6));
			}
			int num2 = 1 + shown;
			list.Add(new PanelSlot("Previous", SlotKind.Button, new PanelRect(12f, 409f, 46f, 30f), num2, 0, 2));
			list.Add(new PanelSlot("Page", SlotKind.Text, new PanelRect(74f, 409f, 100f, 30f)));
			list.Add(new PanelSlot("Next", SlotKind.Button, new PanelRect(180f, 409f, 46f, 30f), num2, 2, 2));
			list.Add(new PanelSlot("Refresh", SlotKind.Button, new PanelRect(232f, 409f, 126f, 30f), num2, 4, 2));
			list.Add(new PanelSlot("Cancel", SlotKind.Button, new PanelRect(12f, 450f, 346f, 40f), num2 + 1, 0, 6));
			return new PanelScreen("picker", 510f, 6, list);
		}

		public static float Scale(float parentWidth, float parentHeight, float height)
		{
			return Math.Max(0.3f, Math.Min(1f, Math.Min((parentHeight - 24f) / height, (parentWidth - 24f) / 370f)));
		}

		public static (float X, float Y) Position(float ratioX, float ratioY, float parentWidth, float parentHeight, float scaledWidth, float scaledHeight)
		{
			return (X: Clamp(ratioX * parentWidth, 0f, Math.Max(0f, parentWidth - scaledWidth)), Y: Clamp(ratioY * parentHeight, 0f, Math.Max(0f, parentHeight - scaledHeight)));
		}

		private static float Clamp(float value, float min, float max)
		{
			if (!(value < min))
			{
				if (!(value > max))
				{
					return value;
				}
				return max;
			}
			return min;
		}

		public static (int Pages, int Page, int Shown) Page(int count, int page)
		{
			int num = Math.Max(1, (count + 6 - 1) / 6);
			int num2 = Math.Max(0, Math.Min(page, num - 1));
			return (Pages: num, Page: num2, Shown: Math.Max(0, Math.Min(6, count - num2 * 6)));
		}
	}
	public sealed class PendingTeleport
	{
		private readonly TeleportActorFacts actor;

		private readonly TeleportRequest request;

		private readonly long generation;

		private readonly double deadline;

		private readonly TeleportTargetFacts departure;

		private bool canceled;

		private bool movement;

		private bool recovered;

		private double recoveryDeadline;

		public PendingTeleport(TeleportActorFacts actor, TeleportRequest request, long generation, double now, float departureX, float departureY, float departureZ)
		{
			this.actor = actor;
			this.request = request;
			this.generation = generation;
			deadline = now + 10.0;
			departure = new TeleportTargetFacts(LandingPolicy.IsValid(departureX, departureY, departureZ), departureX, departureY, departureZ);
		}

		private bool Same(TeleportActorFacts live, long currentGeneration)
		{
			if (currentGeneration == generation && actor.ActorId == live.ActorId && actor.WorldId == live.WorldId && actor.SessionId == live.SessionId)
			{
				return live.Present;
			}
			return false;
		}

		public void Cancel()
		{
			canceled = true;
		}

		public bool TryAccept(TeleportGrant grant, TeleportActorFacts live, long currentGeneration, double now, bool effectiveEnabled)
		{
			if (canceled || movement || !effectiveEnabled || !Same(live, currentGeneration) || !live.Alive || live.Teleporting || !live.CooldownReady || now >= deadline || now >= grant.ExpiresAt || grant.ActorId != actor.ActorId || grant.WorldId != actor.WorldId || grant.SessionId != actor.SessionId || grant.RequestId != request.RequestId || grant.Category != request.Category || grant.DestinationId != request.DestinationId)
			{
				return false;
			}
			movement = true;
			recoveryDeadline = now + 30.0;
			return true;
		}

		public bool TryRecovery(TeleportActorFacts live, long currentGeneration, double now, out TeleportTargetFacts capturedDeparture)
		{
			capturedDeparture = departure;
			if (!movement || recovered || !departure.Valid || now >= recoveryDeadline || !Same(live, currentGeneration) || !live.Alive || live.Teleporting)
			{
				return false;
			}
			recovered = true;
			return true;
		}
	}
	public sealed class PerFrame<T>
	{
		private readonly Func<int> frame;

		private readonly Func<T> compute;

		private int cachedFrame;

		private bool cached;

		private T value;

		public T Value
		{
			get
			{
				int num = frame();
				if (!cached || num != cachedFrame)
				{
					value = compute();
					cachedFrame = num;
					cached = true;
				}
				return value;
			}
		}

		public PerFrame(Func<int> frame, Func<T> compute)
		{
			this.frame = frame ?? throw new ArgumentNullException("frame");
			this.compute = compute ?? throw new ArgumentNullException("compute");
		}
	}
	public sealed class TeleportPolicy
	{
		public IReadOnlyCollection<Category> PlayerCategories { get; }

		public bool AllowTeleport { get; }

		public bool AllowBed { get; }

		public bool AllowStones { get; }

		public bool AllowMap { get; }

		public bool AllowBoat { get; }

		public bool AllowGrave { get; }

		public bool AllowPlayer { get; }

		public TeleportPolicy(bool allowTeleport = true, bool allowBed = true, bool allowStones = false, bool allowMap = false, bool allowBoat = false, bool allowGrave = false, bool allowPlayer = false, IReadOnlyCollection<Category>? playerCategories = null)
		{
			PlayerCategories = (IReadOnlyCollection<Category>)(((object)playerCategories) ?? ((object)Array.Empty<Category>()));
			AllowTeleport = allowTeleport;
			AllowBed = allowBed;
			AllowStones = allowStones;
			AllowMap = allowMap;
			AllowBoat = allowBoat;
			AllowGrave = allowGrave;
			AllowPlayer = allowPlayer;
		}

		public static bool IsCheat(Category category)
		{
			return category != Category.Bed;
		}

		public bool Enables(Category category)
		{
			if (AllowTeleport)
			{
				return category switch
				{
					Category.Player => AllowPlayer, 
					Category.Grave => AllowGrave, 
					Category.Boat => AllowBoat, 
					Category.Map => AllowMap, 
					Category.Stones => AllowStones, 
					Category.Bed => AllowBed, 
					_ => false, 
				};
			}
			return false;
		}

		public bool AllowsCategory(Category category, bool travelCheats)
		{
			return Refusal(category, travelCheats) == null;
		}

		public string? Refusal(Category category, bool travelCheats)
		{
			if (AllowTeleport)
			{
				if (Enables(category))
				{
					if (!IsCheat(category) || travelCheats || PlayerCategories.Contains(category))
					{
						return null;
					}
					return "travelrestricted";
				}
				return "destinationdisabled";
			}
			return "teleportdisabled";
		}
	}
	public static class TeleportRefusals
	{
		public const string TeleportDisabled = "teleportdisabled";

		public const string DestinationDisabled = "destinationdisabled";

		public const string TravelRestricted = "travelrestricted";

		public static readonly IReadOnlyList<string> Codes = Array.AsReadOnly(new string[3] { "teleportdisabled", "destinationdisabled", "travelrestricted" });

		public static bool Is(string? code)
		{
			if (code != null)
			{
				return Codes.Contains<string>(code);
			}
			return false;
		}
	}
	public sealed class TeleportRequest
	{
		public string RequestId { get; }

		public Category Category { get; }

		public string DestinationId { get; }

		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public bool IsLastKnown { get; }

		public TeleportRequest(string request, Category category, string destination, float x, float y, float z, bool isLastKnown = false)
		{
			Text(request);
			Text(destination);
			if (!Enum.IsDefined(typeof(Category), category))
			{
				throw new ArgumentException("Unknown category.");
			}
			RequestId = request;
			Category = category;
			DestinationId = destination;
			X = x;
			Y = y;
			Z = z;
			IsLastKnown = isLastKnown;
		}

		internal static void Text(string value)
		{
			if (string.IsNullOrWhiteSpace(value) || value.Length > 128 || value.IndexOfAny(new char[3] { '\0', '\r', '\n' }) >= 0)
			{
				throw new ArgumentException("Invalid teleport correlation.");
			}
		}
	}
	public sealed class TeleportActorFacts
	{
		public string ActorId { get; }

		public long WorldId { get; }

		public string SessionId { get; }

		public bool TravelCheats { get; }

		public bool Present { get; }

		public bool Alive { get; }

		public bool Teleporting { get; }

		public bool CooldownReady { get; }

		public TeleportActorFacts(string actor, long world, string session, bool travelCheats, bool present, bool alive, bool teleporting, bool cooldownReady)
		{
			TeleportRequest.Text(actor);
			TeleportRequest.Text(session);
			ActorId = actor;
			WorldId = world;
			SessionId = session;
			TravelCheats = travelCheats;
			Present = present;
			Alive = alive;
			Teleporting = teleporting;
			CooldownReady = cooldownReady;
		}
	}
	public sealed class TeleportTargetFacts
	{
		public bool Valid { get; }

		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public TeleportTargetFacts(bool valid, float x, float y, float z)
		{
			Valid = valid;
			X = x;
			Y = y;
			Z = z;
		}
	}
	public sealed class AuthorizationDecision
	{
		public bool Allowed { get; }

		public string Code { get; }

		public TeleportTargetFacts Target { get; }

		internal AuthorizationDecision(bool allowed, string code, TeleportTargetFacts target)
		{
			Allowed = allowed;
			Code = code;
			Target = target;
		}
	}
	public static class TeleportAuthorization
	{
		public static bool Advanced(Category category)
		{
			if (category != Category.Boat && category != Category.Grave)
			{
				return category == Category.Player;
			}
			return true;
		}

		public static AuthorizationDecision Evaluate(TeleportPolicy policy, TeleportActorFacts actor, TeleportRequest request, TeleportTargetFacts target)
		{
			string text = policy.Refusal(request.Category, actor.TravelCheats) ?? ((!actor.Present || actor.WorldId == 0L) ? "unavailable" : ((!actor.Alive) ? "dead" : ((actor.Teleporting || !actor.CooldownReady) ? "busy" : ((!LandingPolicy.IsValid(request.X, request.Y, request.Z) || !target.Valid || !LandingPolicy.IsValid(target.X, target.Y, target.Z)) ? "unavailable" : "success"))));
			return new AuthorizationDecision(text == "success", text, target);
		}
	}
	public sealed class TeleportGrant
	{
		public string ActorId { get; }

		public long WorldId { get; }

		public string SessionId { get; }

		public string RequestId { get; }

		public string GrantId { get; }

		public Category Category { get; }

		public string DestinationId { get; }

		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public double ExpiresAt { get; }

		public TeleportGrant(string actor, long world, string session, string request, string grant, Category category, string destination, float x, float y, float z, double expires)
		{
			TeleportRequest.Text(actor);
			TeleportRequest.Text(session);
			TeleportRequest.Text(request);
			TeleportRequest.Text(grant);
			TeleportRequest.Text(destination);
			if (world == 0L || !Enum.IsDefined(typeof(Category), category) || !LandingPolicy.IsValid(x, y, z) || double.IsNaN(expires) || double.IsInfinity(expires))
			{
				throw new ArgumentException("Invalid grant.");
			}
			ActorId = actor;
			WorldId = world;
			SessionId = session;
			RequestId = request;
			GrantId = grant;
			Category = category;
			DestinationId = destination;
			X = x;
			Y = y;
			Z = z;
			ExpiresAt = expires;
		}
	}
	public sealed class TeleportCompletion
	{
		public string RequestId { get; }

		public string GrantId { get; }

		public bool Accepted { get; }

		public TeleportCompletion(string request, string grant, bool accepted)
		{
			TeleportRequest.Text(request);
			TeleportRequest.Text(grant);
			RequestId = request;
			GrantId = grant;
			Accepted = accepted;
		}
	}
	public sealed class TeleportGrantLedger
	{
		private sealed class Entry
		{
			internal TeleportGrant Grant;

			internal bool Consumed;

			internal bool Completed;
		}

		private readonly Dictionary<(string, long, string, string), Entry> entries = new Dictionary<(string, long, string, string), Entry>();

		private static (string, long, string, string) Key(TeleportGrant grant)
		{
			return (grant.ActorId, grant.WorldId, grant.SessionId, grant.RequestId);
		}

		public TeleportGrant? Issue(TeleportActorFacts actor, TeleportRequest request, AuthorizationDecision decision, double now)
		{
			(string, long, string, string) key = (actor.ActorId, actor.WorldId, actor.SessionId, request.RequestId);
			if (!decision.Allowed || entries.ContainsKey(key) || entries.Count >= 4096 || entries.Values.Any((Entry e) => e.Grant.ActorId == actor.ActorId && !e.Completed && now < e.Grant.ExpiresAt))
			{
				return null;
			}
			TeleportTargetFacts target = decision.Target;
			TeleportGrant teleportGrant = new TeleportGrant(actor.ActorId, actor.WorldId, actor.SessionId, request.RequestId, Guid.NewGuid().ToString("N"), request.Category, request.DestinationId, target.X, target.Y, target.Z, now + 10.0);
			entries.Add(key, new Entry
			{
				Grant = teleportGrant
			});
			return teleportGrant;
		}

		public bool TrackVerifiedGrant(TeleportGrant grant)
		{
			(string, long, string, string) key = Key(grant);
			if (entries.ContainsKey(key) || entries.Count >= 4096)
			{
				return false;
			}
			entries.Add(key, new Entry
			{
				Grant = grant
			});
			return true;
		}

		public bool TryConsume(TeleportGrant grant, TeleportActorFacts liveActor, double now)
		{
			if (liveActor.ActorId != grant.ActorId || liveActor.WorldId != grant.WorldId || liveActor.SessionId != grant.SessionId || !liveActor.Present || !liveActor.Alive || liveActor.Teleporting || !liveActor.CooldownReady || now >= grant.ExpiresAt)
			{
				return false;
			}
			if (!entries.TryGetValue(Key(grant), out Entry value) || value.Consumed || value.Completed || value.Grant.GrantId != grant.GrantId || value.Grant.Category != grant.Category || value.Grant.DestinationId != grant.DestinationId || value.Grant.X != grant.X || value.Grant.Y != grant.Y || value.Grant.Z != grant.Z)
			{
				return false;
			}
			value.Consumed = true;
			return true;
		}

		public bool Complete(TeleportActorFacts actor, string request, string? grantId = null)
		{
			if (!entries.TryGetValue((actor.ActorId, actor.WorldId, actor.SessionId, request), out Entry value) || (grantId != null && value.Grant.GrantId != grantId))
			{
				return false;
			}
			value.Completed = true;
			return true;
		}

		public void Reset()
		{
			entries.Clear();
		}
	}
	public sealed class TombstoneNote
	{
		public string Cause { get; }

		public string Killer { get; }

		public int Day { get; }

		public TombstoneNote(string cause, string killer, int day)
		{
			Cause = cause ?? "";
			Killer = killer ?? "";
			Day = Math.Max(0, day);
		}
	}
	public static class TombstoneHints
	{
		public const bool DefaultEnabled = true;

		public const string SourceGuid = "JevMods.BetterTombstoneHints";

		public const string SourceName = "BetterTombstoneHints";

		public const string ModuleId = "tombstone_hints";

		public const string CauseField = "JevMods_Cause";

		public const string KillerField = "JevMods_Killer";

		public const string DayField = "JevMods_Day";

		public const int MaxName = 64;

		public const string Died = "died";

		public const string Slain = "slain";

		public const string SlainBy = "slain_by";

		public const string SlainByCreature = "slain_by_creature";

		private static readonly Dictionary<string, string> byHitType = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			{ "Fall", "fall" },
			{ "Drowning", "drowning" },
			{ "Burning", "burning" },
			{ "Freezing", "freezing" },
			{ "Poisoned", "poisoned" },
			{ "Water", "water" },
			{ "Smoke", "smoke" },
			{ "EdgeOfWorld", "edge_of_world" },
			{ "Impact", "impact" },
			{ "Cart", "cart" },
			{ "Tree", "tree" },
			{ "Self", "self" },
			{ "Structural", "structural" },
			{ "Turret", "turret" },
			{ "Boat", "boat" },
			{ "Stalagtite", "stalactite" },
			{ "Catapult", "catapult" },
			{ "CinderFire", "cinder_fire" },
			{ "AshlandsOcean", "ashlands_ocean" },
			{ "AshlandsLava", "ashlands_lava" },
			{ "Incinerator", "incinerator" },
			{ "DrawBridge", "drawbridge" }
		};

		public static readonly IReadOnlyList<string> Causes = Array.AsReadOnly(new string[4] { "slain_by_creature", "slain_by", "slain", "died" }.Concat(byHitType.Values).ToArray());

		private static readonly Dictionary<string, string> nativeByCause = byHitType.ToDictionary<KeyValuePair<string, string>, string, string>((KeyValuePair<string, string> p) => p.Value, (KeyValuePair<string, string> p) => "$stat_DeathBy" + p.Key, StringComparer.Ordinal);

		public static string Key(string cause)
		{
			return "tomb_" + cause;
		}

		public static string NativeKey(string cause)
		{
			switch (cause)
			{
			case "slain_by_creature":
			case "slain_by":
			case "slain":
				return "$stat_DeathByEnemyHit";
			case "ashlands_lava":
				return "$stat_DeathByBurning";
			default:
			{
				if (nativeByCause.TryGetValue(cause, out string value))
				{
					return value;
				}
				goto case null;
			}
			case null:
				return "";
			}
		}

		public static string ForHitType(string hitType)
		{
			if (hitType == null || !byHitType.TryGetValue(hitType, out string value))
			{
				return "died";
			}
			return value;
		}

		public static TombstoneNote Death(string? hitType, object? attacker, bool attackerIsPlayer, bool attackerIsBoss, string attackerName, int day)
		{
			if (hitType == null)
			{
				return new TombstoneNote("died", "", day);
			}
			if (hitType == "EnemyHit" || hitType == "PlayerHit")
			{
				if (attacker == null)
				{
					return new TombstoneNote("slain", "", day);
				}
				return new TombstoneNote((attackerIsPlayer || attackerIsBoss) ? "slain_by" : "slain_by_creature", Clean(attackerName), day);
			}
			return new TombstoneNote(ForHitType(hitType), "", day);
		}

		public static string Render(TombstoneNote note, Func<string, string> localize, string dayText)
		{
			string text = NativeKey(Causes.Contains(note.Cause) ? note.Cause : "died");
			string text2 = ((text.Length == 0) ? "" : Clean(localize(text), 256));
			if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal))
			{
				text2 = "";
			}
			string text3 = Clean(localize(Clean(note.Killer)));
			if (text3.Length > 0)
			{
				text2 = ((text2.Length == 0) ? text3 : (text2 + ": " + text3));
			}
			string text4 = Clean(dayText);
			if (text4.Length != 0)
			{
				if (text2.Length != 0)
				{
					return text2 + ", " + text4;
				}
				return text4;
			}
			return text2;
		}

		public static string Insert(string hoverText, string note)
		{
			if (hoverText.Length == 0 || note.Length == 0)
			{
				return hoverText;
			}
			int num = hoverText.IndexOf('\n');
			if (num >= 0)
			{
				return hoverText.Insert(num, "\n" + note);
			}
			return hoverText + "\n" + note;
		}

		public static bool StepsAside(IEnumerable<string> installedGuids)
		{
			return installedGuids.Contains<string>("JevMods.BetterTombstoneHints", StringComparer.Ordinal);
		}

		private static string Clean(string? value, int max = 64)
		{
			if (string.IsNullOrEmpty(value))
			{
				return "";
			}
			string text = new string(value.Where((char c) => c != '<' && c != '>' && c != '\r' && c != '\n').ToArray()).Trim();
			if (text.Length <= max)
			{
				return text;
			}
			return text.Substring(0, max);
		}
	}
	public static class WayfarerLanguages
	{
		public static readonly string[] Languages = new string[7] { "English", "Spanish", "Chinese", "Russian", "French", "German", "Korean" };

		public static string[] Settings => new string[1] { "Auto" }.Concat(Languages).ToArray();

		public static string Normalize(string language)
		{
			if (language.IndexOf("Chinese", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return "Chinese";
			}
			return Languages.FirstOrDefault((string l) => string.Equals(l, language, StringComparison.OrdinalIgnoreCase)) ?? "English";
		}

		public static string NameKey(string setting)
		{
			return "language_" + (string.Equals(setting, "Auto", StringComparison.OrdinalIgnoreCase) ? "auto" : Normalize(setting).ToLowerInvariant());
		}
	}
}

plugins/Wayfarer/Wayfarer.dll

Decompiled 16 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraPotions.Meadworks.Crucible;
using ExtraPotions.Meadworks.Crucible.UI;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using Wayfarer.Core;
using Wayfarer.CrucibleIntegration;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.5.13.0")]
[assembly: AssemblyInformationalVersion("0.5.13")]
[assembly: AssemblyProduct("Wayfarer")]
[assembly: AssemblyTitle("Wayfarer")]
[assembly: AssemblyVersion("0.5.13.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Wayfarer
{
	internal sealed class DestinationCatalog
	{
		private readonly Plugin plugin;

		private readonly ObservedDestinations boats = new ObservedDestinations();

		private readonly Dictionary<string, Ship> liveBoats = new Dictionary<string, Ship>();

		internal DestinationCatalog(Plugin plugin)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			this.plugin = plugin;
		}

		private static Vector3 Position(Destination d)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(d.X, d.Y, d.Z);
		}

		private Destination Make(string id, Category c, string key, Vector3 pos, string name = "")
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_002e: 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_0043: Expected O, but got Unknown
			return new Destination(id, c, key, plugin.World)
			{
				X = pos.x,
				Y = pos.y,
				Z = pos.z,
				Name = name
			};
		}

		internal unsafe void Observe()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			boats.ChangeWorld(plugin.World);
			liveBoats.Clear();
			if (plugin.World == 0L)
			{
				return;
			}
			foreach (Destination item in boats.Items)
			{
				item.IsLastKnown = true;
			}
			foreach (IMonoUpdater instance in Ship.Instances)
			{
				Ship val = (Ship)(object)((instance is Ship) ? instance : null);
				if (val != null)
				{
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					if (Object.op_Implicit((Object)(object)component) && component.IsValid())
					{
						ZDOID uid = component.GetZDO().m_uid;
						string text = "boat:" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
						Destination val2 = Make(text, (Category)3, "boat", ((Component)val).transform.position, ((Object)val).name.Replace("(Clone)", ""));
						boats.Put(val2);
						liveBoats[text] = val;
					}
				}
			}
		}

		internal unsafe List<Destination> List(Category category)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Invalid comparison between Unknown and I4
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			if (!plugin.CanUse(category) || plugin.World == 0L)
			{
				return new List<Destination>();
			}
			if ((int)category == 3)
			{
				Observe();
				return boats.Items.OrderBy((Destination d) => d.Id).ToList();
			}
			List<Destination> list = new List<Destination>();
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if ((int)category == 4)
			{
				if (val != null && val.HaveDeathPoint())
				{
					list.Add(Make("death", category, "death", val.GetDeathPoint()));
				}
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					TombStone[] array = Object.FindObjectsByType<TombStone>((FindObjectsSortMode)0);
					foreach (TombStone val2 in array)
					{
						ZNetView component = ((Component)val2).GetComponent<ZNetView>();
						if (Object.op_Implicit((Object)(object)component) && component.IsValid() && AccessTools.Method(typeof(TombStone), "GetOwner", (Type[])null, (Type[])null)?.Invoke(val2, null) is long num2 && num2 == Player.m_localPlayer.GetPlayerID())
						{
							ZDOID uid = component.GetZDO().m_uid;
							list.Add(Make("grave:" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString(), category, "grave", ((Component)val2).transform.position));
						}
					}
				}
			}
			else if ((int)category == 5 && Object.op_Implicit((Object)(object)ZNet.instance))
			{
				ZNetView val3 = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Component)Player.m_localPlayer).GetComponent<ZNetView>() : null);
				string text = ((Object.op_Implicit((Object)(object)val3) && val3.IsValid()) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref val3.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString() : "");
				foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
				{
					bool publicPosition = player.m_publicPosition;
					ZDOID uid = player.m_characterID;
					if (DestinationPolicy.SharedPlayer(true, publicPosition, ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() == text) && LandingPolicy.IsValid(player.m_position.x, player.m_position.y, player.m_position.z))
					{
						uid = player.m_characterID;
						list.Add(Make("player:" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString(), category, "player", player.m_position, player.m_name));
					}
				}
			}
			return (from d in list
				orderby d.Name, d.Id
				select d).ToList();
		}

		internal bool TryResolve(string id, out Destination? d, out string error)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: 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)
			d = null;
			error = "unavailable";
			if (plugin.World == 0L)
			{
				return false;
			}
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (id == "bed")
			{
				error = "nobed";
				if (val == null || !val.HaveCustomSpawnPoint())
				{
					return false;
				}
				d = Make(id, (Category)0, "bed", val.GetCustomSpawnPoint());
			}
			else if (id == "stones")
			{
				error = "nostones";
				string text = ((string)AccessTools.Field(typeof(Game), "m_StartLocation")?.GetValue(Game.instance)) ?? "StartTemple";
				Vector3 pos = default(Vector3);
				if (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || !ZoneSystem.instance.GetLocationIcon(text, ref pos))
				{
					return false;
				}
				d = Make(id, (Category)1, "stones", pos);
			}
			else
			{
				if (!plugin.CanAdvanced)
				{
					return false;
				}
				Category category = (Category)(id.StartsWith("boat:") ? 3 : (id.StartsWith("player:") ? 5 : 4));
				d = ((IEnumerable<Destination>)List(category)).FirstOrDefault((Func<Destination, bool>)((Destination item) => item.Id == id));
				if (d == null)
				{
					return false;
				}
			}
			if (!plugin.CanUse(d.Category))
			{
				error = plugin.Refusal(d.Category);
				return false;
			}
			if (LandingPolicy.IsValid(d.X, d.Y, d.Z))
			{
				return DestinationPolicy.CanSelect(d, plugin.World, plugin.CanAdvanced);
			}
			return false;
		}
	}
	internal sealed class MapUi
	{
		private static readonly Color Ink = new Color(0.92f, 0.88f, 0.76f);

		private static readonly Category[] EveryCategory = (Category[])Enum.GetValues(typeof(Category));

		private readonly Plugin p;

		private RectTransform? root;

		private string signature = "";

		private string screen = "main";

		private Category category = (Category)3;

		private int page;

		private long lastWorld;

		private bool inputsReady;

		private string heldScreen = "";

		private Category heldCategory;

		private int heldPage;

		private string heldLanguage = "";

		private bool heldEnabled;

		private bool heldArmed;

		private bool heldTeleport;

		private int heldMask;

		private readonly Dictionary<GridCell, Selectable> focusables = new Dictionary<GridCell, Selectable>();

		private GridNavigator? navigator;

		private GridCell? focus;

		private Category[] Categories
		{
			get
			{
				Category[] array = new Category[3];
				RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
				return ((IEnumerable<Category>)(object)array).Where(p.CanUse).ToArray();
			}
		}

		internal MapUi(Plugin plugin)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			p = plugin;
		}

		internal void Destroy()
		{
			focusables.Clear();
			navigator = null;
			if (Object.op_Implicit((Object)(object)root))
			{
				Object.Destroy((Object)(object)((Component)root).gameObject);
			}
			root = null;
			signature = "";
		}

		internal void Refresh()
		{
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			if (p.World != lastWorld)
			{
				lastWorld = p.World;
				Destroy();
				screen = "main";
				page = 0;
				focus = null;
			}
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.m_largeRoot) || !instance.m_largeRoot.activeSelf || p.World == 0L)
			{
				p.State.Close();
				if (Object.op_Implicit((Object)(object)root))
				{
					((Component)root).gameObject.SetActive(false);
				}
				screen = "main";
				signature = "";
				focus = null;
				return;
			}
			if (PortalPickerOpen(instance))
			{
				p.State.Close();
				if (Object.op_Implicit((Object)(object)root))
				{
					((Component)root).gameObject.SetActive(false);
				}
				return;
			}
			if (screen == "picker" && !p.State.PickerOpen)
			{
				screen = "main";
			}
			string language = p.Language;
			bool value = p.Options.Enabled.Value;
			bool armed = p.State.Armed;
			bool canTeleport = p.CanTeleport;
			int num = 0;
			for (int i = 0; i < EveryCategory.Length; i++)
			{
				if (p.CanUse(EveryCategory[i]))
				{
					num |= 1 << i;
				}
			}
			string text = screen;
			Category val = category;
			int num2 = page;
			bool flag = inputsReady && text == heldScreen && val == heldCategory && num2 == heldPage && language == heldLanguage && value == heldEnabled && armed == heldArmed && canTeleport == heldTeleport && num == heldMask;
			if (Object.op_Implicit((Object)(object)root) && signature.Length > 0 && flag)
			{
				((Component)root).gameObject.SetActive(true);
			}
			else
			{
				string text2 = string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}", text, val, num2, language, value, armed, canTeleport, string.Join(",", EveryCategory.Where(p.CanUse)));
				if (!Object.op_Implicit((Object)(object)root) || signature != text2)
				{
					Build(instance);
					signature = text2;
				}
				else
				{
					((Component)root).gameObject.SetActive(true);
				}
				inputsReady = true;
				heldScreen = text;
				heldCategory = val;
				heldPage = num2;
				heldLanguage = language;
				heldEnabled = value;
				heldArmed = armed;
				heldTeleport = canTeleport;
				heldMask = num;
			}
			Pad();
		}

		internal static bool PortalPickerOpen(Minimap map)
		{
			if (!Object.op_Implicit((Object)(object)map) || !Object.op_Implicit((Object)(object)map.m_mapImageLarge))
			{
				return false;
			}
			Transform parent = ((Transform)((Graphic)map.m_mapImageLarge).rectTransform).parent;
			Transform val = (Object.op_Implicit((Object)(object)parent) ? parent.Find("Threshold.Destinations") : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				return ((Component)val).gameObject.activeInHierarchy;
			}
			return false;
		}

		private void Build(Minimap map)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			Destroy();
			PanelScreen val = (PanelScreen)((screen == "picker") ? ((object)PickerLayout()) : ((object)MainLayout()));
			if (val == null)
			{
				Build(map);
				return;
			}
			root = KitPanel.Create(map.m_largeRoot.transform, "WayfarerPanel", new Vector2(370f, val.Height), false);
			if (Object.op_Implicit((Object)(object)root))
			{
				KitForged.SidePlate(root);
				RectTransform? obj = root;
				RectTransform? obj2 = root;
				RectTransform? obj3 = root;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0f, 1f);
				obj3.pivot = val2;
				Vector2 anchorMin = (obj2.anchorMax = val2);
				obj.anchorMin = anchorMin;
				RectTransform val4 = (RectTransform)((Transform)root).parent;
				RectTransform? obj4 = root;
				Vector3 one = Vector3.one;
				Rect rect = val4.rect;
				float width = ((Rect)(ref rect)).width;
				rect = val4.rect;
				((Transform)obj4).localScale = one * PanelLayout.Scale(width, ((Rect)(ref rect)).height, val.Height);
				Position(root, 0.084f, 0.392f);
				TMP_Text val5 = Text(val, "Title", p.Presentation.Title, 19f);
				if ((Object)(object)KitCanvas.Heading != (Object)null)
				{
					val5.font = KitCanvas.Heading;
				}
				Text(val, "Brand", p.Presentation.Brand, 12f);
				if (screen == "picker")
				{
					Picker(val);
				}
				else
				{
					Main(val);
				}
				RestoreFocus();
			}
		}

		private PanelScreen MainLayout()
		{
			List<string> list = new List<string>();
			if (p.CanUse((Category)0))
			{
				list.Add("Bed");
			}
			if (p.CanUse((Category)1))
			{
				list.Add("Stones");
			}
			if (p.CanUse((Category)2))
			{
				list.Add("Map");
			}
			if (p.CanAdvanced)
			{
				list.Add("Advanced");
			}
			return PanelLayout.Main((IEnumerable<string>)list);
		}

		private PanelScreen? PickerLayout()
		{
			//IL_0035: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			Category[] categories = Categories;
			if (categories.Length == 0)
			{
				p.State.Close();
				screen = "main";
				signature = "";
				return null;
			}
			if (!categories.Contains(category))
			{
				category = categories[0];
				page = 0;
			}
			(int, int, int) tuple = PanelLayout.Page(p.Catalog.List(category).Count, page);
			page = tuple.Item2;
			return PanelLayout.Picker(categories.Length, tuple.Item3);
		}

		private void Main(PanelScreen layout)
		{
			if (layout.Has("Bed"))
			{
				Button(layout, "Bed", p.T("bed"), delegate
				{
					p.Teleports.TryTeleport("bed");
				});
			}
			if (layout.Has("Stones"))
			{
				Button(layout, "Stones", p.T("stones"), delegate
				{
					p.Teleports.TryTeleport("stones");
				});
			}
			if (layout.Has("Map"))
			{
				Button(layout, "Map", p.T(p.State.Armed ? "armed" : "anywhere"), delegate
				{
					p.State.Arm();
					if (p.State.Armed)
					{
						p.Report("pick");
					}
				});
			}
			if (layout.Has("Advanced"))
			{
				Button(layout, "Advanced", p.T("destinations"), delegate
				{
					p.State.OpenPicker();
					screen = "picker";
					page = 0;
				});
			}
			if (layout.Has("PolicyDenied"))
			{
				Text(layout, "PolicyDenied", p.T("teleportdisabled"), 16f);
			}
		}

		private unsafe void Picker(PanelScreen layout)
		{
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Invalid comparison between Unknown and I4
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Invalid comparison between Unknown and I4
			Category[] categories = Categories;
			List<KitTab> list = ((IEnumerable<Category>)categories).Select((Func<Category, KitTab>)((Category c) => new KitTab
			{
				Id = ((object)(*(Category*)(&c))/*cast due to .constrained prefix*/).ToString(),
				Caption = p.T(((object)(*(Category*)(&c))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant()),
				Click = Guard(delegate
				{
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					category = c;
					page = 0;
					signature = "";
				})
			})).ToList();
			List<Button> list2 = KitTabs.Place(root, (IList<KitTab>)list, ((object)Unsafe.As<Category, Category>(ref category)/*cast due to .constrained prefix*/).ToString(), 12f, 62f, 346f);
			for (int num = 0; num < list2.Count && num < categories.Length; num++)
			{
				Focus(layout["Category" + num], (Selectable)(object)list2[num]);
				KitTooltip.Set(((Component)list2[num]).gameObject, p.T(((object)Unsafe.As<Category, Category>(ref categories[num])/*cast due to .constrained prefix*/).ToString().ToLowerInvariant()), p.T(((int)categories[num] == 3) ? "boathelp" : (((int)categories[num] == 4) ? "deathhelp" : "playerhelp")));
			}
			Text(layout, "Help", p.T(((int)category == 3) ? "boathelp" : (((int)category == 4) ? "deathhelp" : "playerhelp")), 14f);
			List<Destination> list3 = p.Catalog.List(category);
			(int Pages, int Page, int Shown) paging = PanelLayout.Page(list3.Count, page);
			if (layout.Has("Empty"))
			{
				Text(layout, "Empty", p.T("none"), 16f);
			}
			for (int num2 = 0; num2 < paging.Shown; num2++)
			{
				int num3 = paging.Page * 6 + num2;
				Destination d = list3[num3];
				string text = p.T(d.LabelKey) + (string.IsNullOrEmpty(d.Name) ? "" : (" · " + d.Name)) + (d.IsLastKnown ? (" · " + p.T("lastknown")) : "");
				if ((int)d.Category == 4 && d.Id != "death")
				{
					text = text + " · " + (num3 + 1);
				}
				Button val = Button(layout, "Destination" + num2, text, delegate
				{
					p.Teleports.TryTeleport(d.Id);
				});
				if (Object.op_Implicit((Object)(object)val))
				{
					KitTooltip.Set(((Component)val).gameObject, p.T(((object)Unsafe.As<Category, Category>(ref category)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant()), text + "\n" + p.T("destination_help"));
				}
			}
			Button(layout, "Previous", "‹", delegate
			{
				page = Mathf.Max(0, page - 1);
				signature = "";
			});
			Text(layout, "Page", $"{paging.Page + 1} / {paging.Pages}", 16f).alignment = (TextAlignmentOptions)514;
			Button(layout, "Next", "›", delegate
			{
				page = Mathf.Min(paging.Pages - 1, page + 1);
				signature = "";
			});
			Button(layout, "Refresh", p.T("refresh"), delegate
			{
				signature = "";
			});
			Button(layout, "Cancel", p.T("cancel"), delegate
			{
				p.State.Close();
				screen = "main";
				signature = "";
			});
		}

		private static Vector2 At(PanelRect rect)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(((PanelRect)(ref rect)).X, 0f - ((PanelRect)(ref rect)).Y);
		}

		private static void Place(RectTransform rect, PanelRect at)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rect.pivot = val;
			Vector2 anchorMin = (rect.anchorMax = val);
			rect.anchorMin = anchorMin;
			rect.anchoredPosition = At(at);
			rect.sizeDelta = new Vector2(((PanelRect)(ref at)).Width, ((PanelRect)(ref at)).Height);
		}

		private Action Guard(Action action)
		{
			return delegate
			{
				try
				{
					action();
				}
				catch (Exception error)
				{
					p.Error(error);
				}
			};
		}

		private TMP_Text Text(PanelScreen layout, string name, string words, float size)
		{
			//IL_000a: 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_004f: 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)
			TMP_Text obj = KitCanvas.Text((Transform)(object)root, name, words, size, Ink, (TextAlignmentOptions)4097, true);
			obj.enableAutoSizing = true;
			obj.fontSizeMin = Mathf.Min(12f, size);
			obj.fontSizeMax = size;
			obj.overflowMode = (TextOverflowModes)3;
			RectTransform rectTransform = obj.rectTransform;
			PanelSlot val = layout[name];
			Place(rectTransform, ((PanelSlot)(ref val)).Rect);
			return obj;
		}

		private Button? Button(PanelScreen layout, string name, string caption, Action action)
		{
			//IL_0002: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			PanelSlot slot = layout[name];
			RectTransform? obj = root;
			Action action2 = Guard(action);
			Vector2 val = At(((PanelSlot)(ref slot)).Rect);
			PanelRect rect = ((PanelSlot)(ref slot)).Rect;
			float width = ((PanelRect)(ref rect)).Width;
			rect = ((PanelSlot)(ref slot)).Rect;
			Button val2 = KitButton.Create(obj, name, caption, action2, val, new Vector2(width, ((PanelRect)(ref rect)).Height));
			if (Object.op_Implicit((Object)(object)val2))
			{
				Focus(slot, (Selectable)(object)val2);
				KitTooltip.Set(((Component)val2).gameObject, caption, ButtonHelp(name));
			}
			return val2;
		}

		private string ButtonHelp(string name)
		{
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Invalid comparison between Unknown and I4
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Invalid comparison between Unknown and I4
			switch (name)
			{
			case "Bed":
			case "Stones":
				return p.T("usagehelp");
			case "Map":
				return p.T("pick") + "\n" + p.T("usagehelp");
			case "Advanced":
				return p.T("cheathelp");
			case "Previous":
				return p.T("previous_help");
			case "Next":
				return p.T("next_help");
			case "Refresh":
				return p.T(((int)category == 3) ? "boathelp" : (((int)category == 4) ? "deathhelp" : "playerhelp"));
			case "Cancel":
				return p.T("back_help");
			default:
				return p.T("destination_help");
			}
		}

		private void Focus(PanelSlot slot, Selectable control)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (!((PanelSlot)(ref slot)).Focusable)
			{
				return;
			}
			foreach (var (num, num2) in ((PanelSlot)(ref slot)).Cells())
			{
				focusables[new GridCell(num, num2)] = control;
			}
			navigator = null;
		}

		private bool Usable(GridCell cell)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (focusables.TryGetValue(cell, out Selectable value) && Object.op_Implicit((Object)(object)value) && ((Component)value).gameObject.activeInHierarchy)
			{
				return value.IsInteractable();
			}
			return false;
		}

		private GridNavigator? Navigator()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_009d: Expected O, but got Unknown
			if (navigator != null || focusables.Count == 0)
			{
				return navigator;
			}
			int num = focusables.Keys.Max((GridCell c) => ((GridCell)(ref c)).X) + 1;
			int num2 = focusables.Keys.Max((GridCell c) => ((GridCell)(ref c)).Y) + 1;
			GridNavigator val = new GridNavigator(num, num2, (Func<GridCell, bool>)Usable, (Func<GridCell, GridCell>)null, false);
			GridNavigator result = val;
			navigator = val;
			return result;
		}

		private void RestoreFocus()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (focus.HasValue)
			{
				if (!focusables.ContainsKey(focus.Value))
				{
					GridNavigator val = Navigator();
					focus = ((val == null) ? ((GridCell?)null) : KitPad.Start(val));
				}
				Select();
			}
		}

		private void Select()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (focus.HasValue && (Object)(object)EventSystem.current != (Object)null && focusables.TryGetValue(focus.Value, out Selectable value) && Object.op_Implicit((Object)(object)value))
			{
				EventSystem.current.SetSelectedGameObject(((Component)value).gameObject);
			}
		}

		private void Pad()
		{
			//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_0040: Invalid comparison between Unknown and I4
			//IL_0045: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			//IL_00bc: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)root) || !((Component)root).gameObject.activeInHierarchy || !MeadworksInput.GamepadActive)
			{
				return;
			}
			foreach (PadButton item in KitPad.Polled)
			{
				if ((int)item == 1 || !MeadworksInput.PadDown(item))
				{
					continue;
				}
				if ((int)KitPad.ActionOf(item) == 2)
				{
					if (focus.HasValue && Usable(focus.Value))
					{
						MeadworksInput.PadConsume(item);
						Selectable obj = focusables[focus.Value];
						Button val = (Button)(object)((obj is Button) ? obj : null);
						if (val != null)
						{
							((UnityEvent)val.onClick).Invoke();
						}
					}
				}
				else
				{
					GridNavigator val2 = Navigator();
					if (val2 != null)
					{
						MeadworksInput.PadConsume(item);
						focus = (focus.HasValue ? new GridCell?(KitPad.Next(val2, focus.Value, item)) : KitPad.Start(val2));
						Select();
					}
				}
				break;
			}
		}

		internal static void Position(RectTransform panel, float x, float y)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = ((RectTransform)((Transform)panel).parent).rect;
			Vector2 size = ((Rect)(ref rect)).size;
			Vector2 val = Vector2.Scale(panel.sizeDelta, new Vector2(((Transform)panel).localScale.x, ((Transform)panel).localScale.y));
			(float, float) tuple = PanelLayout.Position(x, y, size.x, size.y, val.x, val.y);
			panel.anchoredPosition = new Vector2(tuple.Item1, 0f - tuple.Item2);
		}
	}
	[BepInPlugin("com.meadworks.wayfarer", "Wayfarer", "0.5.13")]
	[BepInDependency("com.meadworks.crucible", "0.3.32")]
	[BepInDependency("com.meadworks.crucible.ui", "0.3.21")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "com.meadworks.wayfarer";

		internal static Plugin? Instance;

		internal Settings Options;

		internal readonly SelectionState State = new SelectionState();

		internal DestinationCatalog Catalog;

		internal TeleportService Teleports;

		internal MapUi? Ui;

		private MeadworksLog? log;

		private Harmony? harmony;

		private float nextScan;

		private float nextError;

		private ProductRegistration? registration;

		private CrucibleServices? integration;

		internal ProductPresentation Presentation = new ProductPresentation("Wayfarer", "Meadworks");

		internal CrucibleServices Integration => integration;

		internal bool CanTeleport
		{
			get
			{
				if (Options != null && Options.Enabled.Value && integration != null && integration.Session.AuthorityReady)
				{
					return integration.EffectivePolicy.AllowTeleport;
				}
				return false;
			}
		}

		internal bool CanAdvanced
		{
			get
			{
				if (!CanUse((Category)3) && !CanUse((Category)4))
				{
					return CanUse((Category)5);
				}
				return true;
			}
		}

		internal long World
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.GetWorld() == null)
				{
					return 0L;
				}
				return ZNet.instance.GetWorldUID();
			}
		}

		internal string Language
		{
			get
			{
				if (!(Options.Language.Value != "Auto"))
				{
					return MeadworksTranslations.GameLanguage();
				}
				return WayfarerLanguages.Normalize(Options.Language.Value);
			}
		}

		internal bool CanUse(Category category)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (CanTeleport)
			{
				return integration.EffectivePolicy.AllowsCategory(category, integration.TravelCheats);
			}
			return false;
		}

		internal string Refusal(Category category)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			object obj;
			if (integration != null && integration.Session.AuthorityReady)
			{
				obj = integration.EffectivePolicy.Refusal(category, integration.TravelCheats);
				if (obj == null)
				{
					return "unavailable";
				}
			}
			else
			{
				obj = "authorityunavailable";
			}
			return (string)obj;
		}

		internal string TeleportRefusal()
		{
			if (integration != null && integration.Session.AuthorityReady)
			{
				return "teleportdisabled";
			}
			return "authorityunavailable";
		}

		internal void Refuse(Category category)
		{
			//IL_0044: 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_001b: 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)
			if (integration == null || !TeleportPolicy.IsCheat(category) || !integration.EffectivePolicy.Enables(category) || MeadworksMischief.TryUse("com.meadworks.wayfarer", "Cheats." + CheatKeys.For(category), (MischiefCategory)4, (string)null))
			{
				Report(Refusal(category));
			}
		}

		internal string T(string key)
		{
			return integration?.Text(key, Language) ?? key;
		}

		private void Awake()
		{
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			log = MeadworksLog.For(((BaseUnityPlugin)this).Logger, "Wayfarer");
			try
			{
				if (!Plugin.IsReady)
				{
					throw new InvalidOperationException("Required Crucible is not ready");
				}
				MeadworksConfig.EnsureSchema(((BaseUnityPlugin)this).Config, 1, (IReadOnlyList<MigrationStep>)null);
				registration = Plugin.Services.Register(MeadworksIntegration.Metadata());
				integration = new CrucibleServices(registration, ((BaseUnityPlugin)this).Info.Metadata, ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, Navigation);
			}
			catch (Exception ex)
			{
				integration?.Dispose();
				integration = null;
				ProductRegistration? obj = registration;
				if (obj != null)
				{
					obj.Dispose();
				}
				registration = null;
				((Behaviour)this).enabled = false;
				log.Error((object)("Wayfarer initialization rejected: " + ex.GetType().Name + ": " + ex.Message));
				return;
			}
			Options = new Settings(((BaseUnityPlugin)this).Config, integration);
			if (!MeadworksHeadless.AllowsUi)
			{
				InfoMessage("Wayfarer server policy and authority handlers ready");
				return;
			}
			Instance = this;
			Catalog = new DestinationCatalog(this);
			Teleports = new TeleportService(this);
			Ui = new MapUi(this);
			harmony = new Harmony("com.meadworks.wayfarer");
			harmony.PatchAll(typeof(Plugin).Assembly);
			InfoMessage("Wayfarer 0.5.13 | ExtraPotions | expDARE | Crucible API 0.1 ready");
		}

		private NavigationSnapshot Navigation()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			return new NavigationSnapshot(integration != null && integration.Session.AuthorityReady, CanAdvanced, Enum.GetValues(typeof(Category)).Cast<Category>().Where(CanUse));
		}

		private void InfoMessage(string message)
		{
			MeadworksLog? obj = log;
			if (obj != null)
			{
				obj.Info(message);
			}
		}

		private void LogError(object error)
		{
			MeadworksLog? obj = log;
			if (obj != null)
			{
				obj.Error(error);
			}
		}

		private void Update()
		{
			if (Options == null || !MeadworksHeadless.AllowsUi)
			{
				return;
			}
			try
			{
				State.ChangeWorld(World);
				State.SetAdvanced(CanAdvanced);
				State.SetEnabled(CanTeleport);
				if (State.Armed && !CanUse((Category)2))
				{
					State.Close();
				}
				Teleports?.UpdateLanding();
				integration?.Update();
				if (Time.unscaledTime >= nextScan)
				{
					Catalog.Observe();
					nextScan = Time.unscaledTime + 2f;
				}
				Ui?.Refresh();
			}
			catch (Exception error)
			{
				if (Time.unscaledTime >= nextError)
				{
					LogError(error);
					nextError = Time.unscaledTime + 10f;
				}
			}
		}

		internal void Report(string key)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (Options.ShowMessages.Value)
			{
				string text = T(key);
				if ((int)MeadworksHeadless.Channel == 0 && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false, true);
				}
				else
				{
					InfoMessage(text);
				}
			}
		}

		internal void Error(Exception error)
		{
			LogError(error);
			Report("error");
		}

		private void OnDestroy()
		{
			Teleports?.Dispose();
			Ui?.Destroy();
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			integration?.Dispose();
			ProductRegistration? obj2 = registration;
			if (obj2 != null)
			{
				obj2.Dispose();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
	internal static class MapPatches
	{
		private static bool Prefix(Minimap __instance)
		{
			//IL_00c0: 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_00bc: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance == (Object)null || !instance.Options.Enabled.Value || !instance.State.Armed || MapUi.PortalPickerOpen(__instance) || instance.Teleports == null)
			{
				return true;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					instance.Report("unavailable");
					return false;
				}
				Type type = AccessTools.TypeByName("ZInput");
				object obj = ((type == null) ? null : AccessTools.Property(type, "pointerPosition")?.GetValue(null));
				Vector3 position = (Vector3)methodInfo.Invoke(__instance, new object[1] { (obj is Vector3 val) ? val : Input.mousePosition });
				instance.Teleports.ToMap(position);
			}
			catch (Exception error)
			{
				instance.Error(error);
			}
			return false;
		}
	}
	internal sealed class Settings
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<bool> CloseMap;

		public readonly ConfigEntry<bool> ShowMessages;

		public readonly ConfigEntry<bool> TombstoneHints;

		public readonly ConfigEntry<string> Language;

		private readonly CrucibleServices integration;

		private ConfigEntry<T> Bind<T>(ConfigFile config, string section, string key, T value, string description)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return Bind(config, section, key, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private ConfigEntry<T> Bind<T>(ConfigFile config, string section, string key, T value, ConfigDescription description)
		{
			return integration.Bind(config, section, key, value, description);
		}

		public Settings(ConfigFile config, CrucibleServices integration)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			this.integration = integration;
			Enabled = Bind(config, "General", "Enabled", value: true, "Master switch for Wayfarer travel and tombstone hints on this client.");
			Language = Bind(config, "General", "Language", "Auto", new ConfigDescription("Auto follows the game. Other supported languages fall back to English.", (AcceptableValueBase)(object)new AcceptableValueList<string>(WayfarerLanguages.Settings), Array.Empty<object>()));
			CloseMap = Bind(config, "General", "CloseMap", value: true, new ConfigDescription("Close the map after a teleport is accepted.", (AcceptableValueBase)null, new object[1] { (object)new ConfigDependency((Func<bool>)(() => Enabled.Value), (Func<string>)(() => "Requires General: Enabled."), (Func<bool>)null) }));
			ShowMessages = Bind(config, "General", "ShowMessages", value: true, new ConfigDescription("Show translated screen messages.", (AcceptableValueBase)null, new object[1] { (object)new ConfigDependency((Func<bool>)(() => Enabled.Value), (Func<string>)(() => "Requires General: Enabled."), (Func<bool>)null) }));
			TombstoneHints = Bind(config, "General", "TombstoneHints", value: true, new ConfigDescription("Client-side: show the cause of death and the day on tombstones in your game language (adapted from BetterTombstoneHints, MIT). Steps aside while BetterTombstoneHints is installed.", (AcceptableValueBase)null, new object[1] { (object)new ConfigDependency((Func<bool>)(() => Enabled.Value), (Func<string>)(() => "Requires General: Enabled."), (Func<bool>)null) }));
		}
	}
	internal sealed class TeleportService
	{
		private readonly Plugin p;

		private Vector3? pending;

		private Vector3? recovery;

		private long pendingWorld;

		private float expires;

		private long generation = -1L;

		private Task<OperationResult<TeleportGrant>>? authorization;

		private CancellationTokenSource? cancellation;

		private PendingTeleport? lifecycle;

		private TeleportRequest? request;

		private readonly TeleportGrantLedger grants = new TeleportGrantLedger();

		internal bool AwaitingAuthorization => authorization != null;

		internal TeleportService(Plugin plugin)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			p = plugin;
		}

		internal void ToMap(Vector3 position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			position.y = 30f;
			Start(position, (Category)2, "map", lastKnown: false);
		}

		internal void TryTeleport(string id)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Invalid comparison between Unknown and I4
			//IL_0083: 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)
			if (!p.CanTeleport)
			{
				p.Report(p.TeleportRefusal());
				return;
			}
			if (!p.Catalog.TryResolve(id, out Destination d, out string error) || d == null)
			{
				p.Report(error);
				return;
			}
			Vector3 target = default(Vector3);
			((Vector3)(ref target))..ctor(d.X, d.Y, d.Z);
			if ((int)d.Category == 2 || (int)d.Category == 1)
			{
				target.y = 30f;
			}
			Start(target, d.Category, d.Id, d.IsLastKnown);
		}

		private TeleportActorFacts? Actor()
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			SessionSnapshot session = p.Integration.Session;
			if (!Object.op_Implicit((Object)(object)localPlayer) || p.World == 0L || !session.AuthorityReady || session.WorldId != p.World)
			{
				return null;
			}
			ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner())
			{
				return null;
			}
			float num = (float)(AccessTools.Field(typeof(Player), "m_teleportCooldown")?.GetValue(localPlayer) ?? ((object)0f));
			return new TeleportActorFacts(localPlayer.GetPlayerID().ToString(CultureInfo.InvariantCulture), p.World, session.SessionId, session.IsAdmin, true, !((Character)localPlayer).IsDead(), ((Character)localPlayer).IsTeleporting(), num >= 2f);
		}

		private void Start(Vector3 target, Category category, string destination, bool lastKnown)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			if (!p.CanUse(category))
			{
				p.Refuse(category);
				return;
			}
			if (authorization != null || pending.HasValue || recovery.HasValue)
			{
				p.Report("busy");
				return;
			}
			if (!LandingPolicy.IsValid(target.x, target.y, target.z))
			{
				p.Report("unsafe");
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				p.Report("unavailable");
				return;
			}
			if (((Character)localPlayer).IsDead())
			{
				p.Report("dead");
				return;
			}
			if (((Character)localPlayer).IsTeleporting())
			{
				p.Report("busy");
				return;
			}
			TeleportActorFacts val = Actor();
			if (val == null)
			{
				p.Report("unavailable");
				return;
			}
			if (!val.CooldownReady)
			{
				p.Report("rejected");
				return;
			}
			SessionSnapshot session = p.Integration.Session;
			generation = session.Generation;
			Vector3 position = ((Component)localPlayer).transform.position;
			request = new TeleportRequest(Guid.NewGuid().ToString("N"), category, destination, target.x, target.y, target.z, lastKnown);
			lifecycle = new PendingTeleport(val, request, generation, p.Integration.MonotonicTime, position.x, position.y, position.z);
			cancellation = new CancellationTokenSource();
			authorization = p.Integration.AuthorizeAsync(request, cancellation.Token);
			p.Report("authorizing");
		}

		private void CancelAuthorization()
		{
			cancellation?.Cancel();
			PendingTeleport? obj = lifecycle;
			if (obj != null)
			{
				obj.Cancel();
			}
			authorization = null;
			cancellation?.Dispose();
			cancellation = null;
			request = null;
		}

		internal void Dispose()
		{
			CancelAuthorization();
			pending = null;
			recovery = null;
			grants.Reset();
		}

		private void Acknowledge(TeleportGrant grant, bool accepted)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			p.Integration.CompleteAsync(new TeleportCompletion(grant.RequestId, grant.GrantId, accepted), CancellationToken.None);
		}

		private void PumpAuthorization()
		{
			//IL_00b3: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Invalid comparison between Unknown and I4
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Invalid comparison between Unknown and I4
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Invalid comparison between Unknown and I4
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Invalid comparison between Unknown and I4
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: Unknown result type (might be due to invalid IL or missing references)
			SessionSnapshot session = p.Integration.Session;
			if (generation != session.Generation)
			{
				CancelAuthorization();
				pending = null;
				recovery = null;
				lifecycle = null;
				grants.Reset();
				generation = session.Generation;
			}
			else
			{
				if (authorization == null)
				{
					return;
				}
				if (!p.CanTeleport || (request != null && !p.CanUse(request.Category)))
				{
					string key = ((request != null) ? p.Refusal(request.Category) : p.TeleportRefusal());
					CancelAuthorization();
					p.Report(key);
				}
				else
				{
					if (!authorization.IsCompleted)
					{
						return;
					}
					Task<OperationResult<TeleportGrant>> task = authorization;
					authorization = null;
					cancellation?.Dispose();
					cancellation = null;
					if (task.IsFaulted || task.IsCanceled)
					{
						PendingTeleport? obj = lifecycle;
						if (obj != null)
						{
							obj.Cancel();
						}
						p.Report("authorityunavailable");
						return;
					}
					OperationResult<TeleportGrant> result = task.Result;
					if ((int)result.State != 2 || result.Reply == null)
					{
						PendingTeleport? obj2 = lifecycle;
						if (obj2 != null)
						{
							obj2.Cancel();
						}
						p.Report((TeleportRefusals.Is(result.Code) || result.Code == "dead" || result.Code == "busy") ? result.Code : "authorityunavailable");
						return;
					}
					TeleportGrant reply = result.Reply;
					TeleportActorFacts val = Actor();
					Player localPlayer = Player.m_localPlayer;
					if (val == null || request == null || lifecycle == null || !Object.op_Implicit((Object)(object)localPlayer))
					{
						Acknowledge(reply, accepted: false);
						return;
					}
					if ((int)reply.Category != 2 && !p.Catalog.TryResolve(reply.DestinationId, out Destination _, out string _))
					{
						lifecycle.Cancel();
						Acknowledge(reply, accepted: false);
						p.Report("unavailable");
						return;
					}
					Vector3 landing = default(Vector3);
					((Vector3)(ref landing))..ctor(reply.X, reply.Y, reply.Z);
					if (((int)reply.Category == 3 || (int)reply.Category == 5) && !LandingResolver.TryResolve(landing, out landing))
					{
						lifecycle.Cancel();
						Acknowledge(reply, accepted: false);
						p.Report("unsafe");
						return;
					}
					if (!grants.TrackVerifiedGrant(reply) || !grants.TryConsume(reply, val, p.Integration.MonotonicTime) || !lifecycle.TryAccept(reply, val, session.Generation, p.Integration.MonotonicTime, p.CanUse(reply.Category)))
					{
						Acknowledge(reply, accepted: false);
						p.Report("rejected");
						return;
					}
					bool flag = ((Character)localPlayer).TeleportTo(landing, ((Component)localPlayer).transform.rotation, true);
					Acknowledge(reply, flag);
					if (!flag)
					{
						lifecycle.Cancel();
						p.Report("rejected");
						return;
					}
					pending = landing;
					pendingWorld = p.World;
					expires = Time.unscaledTime + 30f;
					p.State.Close();
					p.Report("success");
					if (p.Options.CloseMap.Value && Object.op_Implicit((Object)(object)Minimap.instance))
					{
						Minimap.instance.SetMapMode((MapMode)1);
					}
				}
			}
		}

		internal void UpdateLanding()
		{
			//IL_016b: 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)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			PumpAuthorization();
			if (recovery.HasValue)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!Object.op_Implicit((Object)(object)localPlayer) || p.World != pendingWorld || Time.unscaledTime > expires)
				{
					recovery = null;
					return;
				}
				TeleportActorFacts val = Actor();
				TeleportTargetFacts val2 = default(TeleportTargetFacts);
				if (val != null && val.Alive && !val.Teleporting && val.CooldownReady && lifecycle != null && lifecycle.TryRecovery(val, p.Integration.Session.Generation, p.Integration.MonotonicTime, ref val2))
				{
					((Character)localPlayer).TeleportTo(new Vector3(val2.X, val2.Y, val2.Z), ((Component)localPlayer).transform.rotation, true);
					recovery = null;
					p.Report("unsafe");
				}
			}
			else
			{
				if (!pending.HasValue)
				{
					return;
				}
				Player localPlayer2 = Player.m_localPlayer;
				if (!Object.op_Implicit((Object)(object)localPlayer2) || p.World != pendingWorld || Time.unscaledTime > expires)
				{
					pending = null;
				}
				else
				{
					if (((Character)localPlayer2).IsTeleporting())
					{
						return;
					}
					Vector3 landing = pending.Value;
					pending = null;
					if (((Character)localPlayer2).IsDead() || Vector2.Distance(new Vector2(landing.x, landing.z), new Vector2(((Component)localPlayer2).transform.position.x, ((Component)localPlayer2).transform.position.z)) > 2f || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !ZNetScene.instance.IsAreaReady(landing))
					{
						return;
					}
					int mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
					RaycastHit val3 = default(RaycastHit);
					if (!Physics.Raycast(landing + Vector3.up * 2f, Vector3.down, ref val3, 2000f, mask, (QueryTriggerInteraction)1) && !Physics.Raycast(landing + Vector3.up * 1000f, Vector3.down, ref val3, 2000f, mask, (QueryTriggerInteraction)1))
					{
						Recover();
						return;
					}
					landing.y = LandingPolicy.CorrectHeight(landing.y, ((RaycastHit)(ref val3)).point.y, 30f);
					if (!LandingResolver.Clear(landing, ((RaycastHit)(ref val3)).normal.y) && !LandingResolver.TryResolve(landing, out landing))
					{
						Recover();
						return;
					}
					((Component)localPlayer2).transform.position = landing;
					Rigidbody component = ((Component)localPlayer2).GetComponent<Rigidbody>();
					if (Object.op_Implicit((Object)(object)component))
					{
						component.position = landing;
						component.linearVelocity = Vector3.zero;
					}
					AccessTools.Field(typeof(Character), "m_maxAirAltitude")?.SetValue(localPlayer2, landing.y);
				}
			}
		}

		private void Recover()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			recovery = Vector3.zero;
			expires = Time.unscaledTime + 30f;
			p.Report("unsafe");
		}
	}
	internal static class LandingResolver
	{
		internal static bool Clear(Vector3 pos, float normalY)
		{
			//IL_002d: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			CapsuleCollider val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Component)localPlayer).GetComponent<CapsuleCollider>() : null);
			Vector3 val2 = (Object.op_Implicit((Object)(object)localPlayer) ? ((Component)localPlayer).transform.lossyScale : Vector3.one);
			float num = (Object.op_Implicit((Object)(object)val) ? (val.radius * Mathf.Max(val2.x, val2.z)) : 0.4f);
			float num2 = (Object.op_Implicit((Object)(object)val) ? Mathf.Max(val.height * val2.y, num * 2f) : 1.8f);
			Vector3 val3 = pos + (Object.op_Implicit((Object)(object)val) ? Vector3.Scale(val.center, val2) : (Vector3.up * 0.9f));
			Vector3 val4 = Vector3.up * (num2 * 0.5f - num);
			int mask = LayerMask.GetMask(new string[8] { "Default", "static_solid", "Default_small", "piece", "terrain", "character", "character_net", "character_ghost" });
			bool flag = false;
			Collider[] array = Physics.OverlapCapsule(val3 - val4, val3 + val4, num, mask, (QueryTriggerInteraction)1);
			foreach (Collider val5 in array)
			{
				if (!Object.op_Implicit((Object)(object)localPlayer) || !((Component)val5).transform.IsChildOf(((Component)localPlayer).transform))
				{
					flag = true;
					break;
				}
			}
			return LandingPolicy.Clear(Object.op_Implicit((Object)(object)ZNetScene.instance) && ZNetScene.instance.IsAreaReady(pos), normalY, !flag, pos.y <= 30.61f);
		}

		internal static bool TryResolve(Vector3 target, out Vector3 landing)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b5: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			landing = target;
			if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || !ZNetScene.instance.IsAreaReady(target))
			{
				return false;
			}
			int mask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
			float[] array = new float[2] { 5f, 8f };
			RaycastHit val2 = default(RaycastHit);
			foreach (float num in array)
			{
				for (int j = 0; j < 8; j++)
				{
					float num2 = (float)j * MathF.PI / 4f;
					Vector3 val = target + new Vector3(Mathf.Cos(num2) * num, 0f, Mathf.Sin(num2) * num);
					if (Physics.Raycast(val + Vector3.up * 80f, Vector3.down, ref val2, 180f, mask, (QueryTriggerInteraction)1) && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Ship>()))
					{
						val.y = Mathf.Max(((RaycastHit)(ref val2)).point.y, 30f) + 0.6f;
						if (Clear(val, ((RaycastHit)(ref val2)).normal.y))
						{
							landing = val;
							return true;
						}
					}
				}
			}
			return false;
		}
	}
	internal static class TombstoneHintsFeature
	{
		private static readonly int causeKey = StringExtensionMethods.GetStableHashCode("JevMods_Cause");

		private static readonly int killerKey = StringExtensionMethods.GetStableHashCode("JevMods_Killer");

		private static readonly int dayKey = StringExtensionMethods.GetStableHashCode("JevMods_Day");

		private static readonly FieldRef<TombStone, ZNetView> nview = AccessTools.FieldRefAccess<TombStone, ZNetView>("m_nview");

		private static readonly FieldRef<Character, HitData> lastHit = AccessTools.FieldRefAccess<Character, HitData>("m_lastHit");

		private static readonly MethodInfo? currentDay = AccessTools.Method(typeof(EnvMan), "GetCurrentDay", (Type[])null, (Type[])null);

		private static bool? steppedAside;

		private static bool SteppedAside(Plugin p)
		{
			if (!steppedAside.HasValue)
			{
				steppedAside = TombstoneHints.StepsAside((IEnumerable<string>)Chainloader.PluginInfos.Keys);
				if (steppedAside.Value)
				{
					p.Integration.ReportStepAside("tombstone_hints", "JevMods.BetterTombstoneHints", "BetterTombstoneHints");
				}
			}
			return steppedAside.Value;
		}

		internal static bool Active()
		{
			Plugin instance = Plugin.Instance;
			if ((Object)(object)instance != (Object)null && instance.Options != null && instance.Options.Enabled.Value && instance.Options.TombstoneHints.Value)
			{
				return !SteppedAside(instance);
			}
			return false;
		}

		internal static bool HasZdo(TombStone tombstone)
		{
			ZNetView val = nview.Invoke(tombstone);
			if ((Object)(object)val != (Object)null)
			{
				return val.IsValid();
			}
			return false;
		}

		private static string Localize(string text)
		{
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}

		internal static void Write(TombStone tombstone)
		{
			ZNetView val = nview.Invoke(tombstone);
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)EnvMan.instance == (Object)null))
			{
				int num = ((currentDay?.Invoke(EnvMan.instance, null) is int num2) ? num2 : 0);
				HitData val2 = lastHit.Invoke((Character)(object)localPlayer);
				Character val3 = ((val2 != null) ? val2.GetAttacker() : null);
				Player val4 = (Player)(object)((val3 is Player) ? val3 : null);
				string text = ((val4 != null) ? val4.GetPlayerName() : (((Object)(object)val3 != (Object)null) ? val3.m_name : ""));
				TombstoneNote val5 = TombstoneHints.Death(((object)Unsafe.As<HitType, HitType>(ref val2?.m_hitType)/*cast due to .constrained prefix*/).ToString(), (object)val3, val3 is Player, (Object)(object)val3 != (Object)null && val3.IsBoss(), text, num);
				ZDO zDO = val.GetZDO();
				zDO.Set(causeKey, val5.Cause);
				zDO.Set(killerKey, val5.Killer);
				zDO.Set(dayKey, val5.Day, false);
			}
		}

		internal static string? Read(TombStone tombstone)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			ZNetView val = nview.Invoke(tombstone);
			if ((Object)(object)Plugin.Instance == (Object)null || (Object)(object)val == (Object)null || !val.IsValid())
			{
				return null;
			}
			ZDO zDO = val.GetZDO();
			string text = zDO.GetString(causeKey, "");
			if (text.Length == 0)
			{
				return null;
			}
			TombstoneNote val2 = new TombstoneNote(text, zDO.GetString(killerKey, ""), zDO.GetInt(dayKey, 0));
			string text2 = ((Localization.instance != null) ? Localization.instance.Localize("$msg_newday", new string[1] { val2.Day.ToString(CultureInfo.InvariantCulture) }) : "");
			return TombstoneHints.Render(val2, (Func<string, string>)Localize, text2);
		}
	}
	internal sealed class TombstoneNameplate : MonoBehaviour
	{
		private TombStone? tombstone;

		private TextWrappingModes wrapping;

		private float next;

		private bool shown;

		internal void Initialize(TombStone owner)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			tombstone = owner;
			wrapping = owner.m_worldText.textWrappingMode;
		}

		private void Update()
		{
			if ((Object)(object)tombstone == (Object)null || Time.time < next)
			{
				return;
			}
			next = Time.time + 0.5f;
			try
			{
				string text = (TombstoneHintsFeature.Active() ? TombstoneHintsFeature.Read(tombstone) : null);
				if (text == null)
				{
					if (shown)
					{
						Restore();
						shown = false;
					}
					return;
				}
				tombstone.m_worldText.textWrappingMode = (TextWrappingModes)0;
				if (Readable())
				{
					Show(tombstone.GetOwnerName() + "\n" + text);
					shown = true;
				}
			}
			catch (Exception error)
			{
				((Behaviour)this).enabled = false;
				Plugin.Instance?.Error(error);
			}
		}

		private bool Readable()
		{
			if ((Object)(object)tombstone != (Object)null)
			{
				return TombstoneHintsFeature.HasZdo(tombstone);
			}
			return false;
		}

		private void OnDestroy()
		{
			if (shown && Readable())
			{
				Restore();
			}
		}

		private void Restore()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)tombstone == (Object)null))
			{
				tombstone.m_worldText.textWrappingMode = wrapping;
				if (Readable())
				{
					Show(tombstone.GetOwnerName());
				}
			}
		}

		private void Show(string text)
		{
			if ((Object)(object)tombstone != (Object)null && tombstone.m_worldText.text != text)
			{
				tombstone.m_worldText.text = text;
			}
		}
	}
	[HarmonyPatch]
	internal static class TombstonePatches
	{
		[HarmonyPatch(typeof(TombStone), "Setup")]
		[HarmonyPostfix]
		private static void Setup(TombStone __instance)
		{
			try
			{
				if (TombstoneHintsFeature.Active())
				{
					TombstoneHintsFeature.Write(__instance);
				}
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
			}
		}

		[HarmonyPatch(typeof(TombStone), "Start")]
		[HarmonyPostfix]
		private static void Start(TombStone __instance)
		{
			try
			{
				if ((Object)(object)Plugin.Instance != (Object)null && (Object)(object)((Component)__instance).GetComponent<TombstoneNameplate>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<TombstoneNameplate>().Initialize(__instance);
				}
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
			}
		}

		[HarmonyPatch(typeof(TombStone), "GetHoverText")]
		[HarmonyPostfix]
		private static void GetHoverText(TombStone __instance, ref string __result)
		{
			try
			{
				if (__result.Length != 0 && TombstoneHintsFeature.Active())
				{
					string text = TombstoneHintsFeature.Read(__instance);
					if (text != null)
					{
						__result = TombstoneHints.Insert(__result, text);
					}
				}
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
			}
		}
	}
	internal static class TombstonePinCleanup
	{
		internal sealed class Retrieval
		{
			internal TombStone Tomb;

			internal Container Container;

			internal Inventory Inventory;

			internal Player Player;

			internal Game Game;

			internal Minimap Map;

			internal ZDO Zdo;

			internal long World;

			internal long PlayerId;

			internal long Generation;

			internal long Ticks;

			internal Vector3 Original;

			internal int Day;

			internal bool PinMetadata;
		}

		private static readonly FieldRef<TombStone, ZNetView> tombView = AccessTools.FieldRefAccess<TombStone, ZNetView>("m_nview");

		private static readonly FieldRef<InventoryGui, Container> currentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

		private static readonly FieldRef<InventoryGui, Inventory> dragInventory = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory");

		private static readonly FieldRef<InventoryGui, GameObject> dragObject = AccessTools.FieldRefAccess<InventoryGui, GameObject>("m_dragGo");

		private static readonly FieldRef<Minimap, List<PinData>> mapPins = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

		private static readonly MethodInfo? getDay = AccessTools.Method(typeof(EnvMan), "GetDay", new Type[1] { typeof(double) }, (Type[])null);

		private static int removed;

		private static string lastResult = "idle";

		private static bool Enabled
		{
			get
			{
				Plugin? instance = Plugin.Instance;
				if (instance == null)
				{
					return false;
				}
				return instance.Options?.Enabled.Value == true;
			}
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static Retrieval? Capture(TombStone tomb, bool requireItems)
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)tomb) || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)Game.instance) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.GetWorld() == null || ZNet.instance.IsDedicated())
			{
				return null;
			}
			Player localPlayer = Player.m_localPlayer;
			Game instance = Game.instance;
			PlayerProfile playerProfile = instance.GetPlayerProfile();
			ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>();
			ZNetView val = tombView.Invoke(tomb);
			Container component2 = ((Component)tomb).GetComponent<Container>();
			long worldUID = ZNet.instance.GetWorldUID();
			long playerID = localPlayer.GetPlayerID();
			if (((Character)localPlayer).IsDead() || playerID == 0L || playerProfile == null || playerProfile.GetPlayerID() != playerID || worldUID == 0L || !Plugin.Session.AuthorityReady || Plugin.Session.WorldId != worldUID || !Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !Object.op_Implicit((Object)(object)val) || !val.IsValid() || !val.IsOwner() || !Object.op_Implicit((Object)(object)component2))
			{
				return null;
			}
			ZDO zDO = val.GetZDO();
			Inventory inventory = component2.GetInventory();
			if (zDO == null || zDO.GetLong(ZDOVars.s_owner, 0L) != playerID || inventory == null || (requireItems && inventory.NrOfItems() == 0))
			{
				return null;
			}
			long num = zDO.GetLong(ZDOVars.s_timeOfDeath, 0L);
			Vector3 val2 = default(Vector3);
			int day = -1;
			bool pinMetadata = false;
			if (Object.op_Implicit((Object)(object)EnvMan.instance) && num > 0 && num <= DateTime.MaxValue.Ticks && zDO.GetVec3(ZDOVars.s_spawnPoint, ref val2) && Finite(val2.x) && Finite(val2.y) && Finite(val2.z) && getDay != null)
			{
				pinMetadata = getDay.Invoke(EnvMan.instance, new object[1] { (double)num / 10000000.0 }) is int num2 && (day = num2) >= 0;
			}
			return new Retrieval
			{
				Tomb = tomb,
				Container = component2,
				Inventory = inventory,
				Player = localPlayer,
				Game = instance,
				Map = Minimap.instance,
				Zdo = zDO,
				World = worldUID,
				PlayerId = playerID,
				Generation = Plugin.Session.Generation,
				Ticks = num,
				Original = val2,
				Day = day,
				PinMetadata = pinMetadata
			};
		}

		internal static Retrieval? FromTakeAll(TombStone tomb)
		{
			try
			{
				return Capture(tomb, requireItems: false);
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
				return null;
			}
		}

		internal static Retrieval? FromGui(InventoryGui gui, InventoryGrid? grid = null, ItemData? item = null, Modifier? modifier = null)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			try
			{
				Container val = currentContainer.Invoke(gui);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return null;
				}
				TombStone component = ((Component)val).GetComponent<TombStone>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					return null;
				}
				Retrieval retrieval = Capture(component, requireItems: true);
				if (retrieval == null || retrieval.Container != val)
				{
					return null;
				}
				if ((Object)(object)grid == (Object)null)
				{
					return retrieval;
				}
				Inventory inventory = grid.GetInventory();
				if (Object.op_Implicit((Object)(object)dragObject.Invoke(gui)))
				{
					return (dragInventory.Invoke(gui) == retrieval.Inventory && inventory == ((Humanoid)retrieval.Player).GetInventory()) ? retrieval : null;
				}
				return ((int)modifier.GetValueOrDefault() == 2 && item != null && inventory == retrieval.Inventory) ? retrieval : null;
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
				return null;
			}
		}

		internal static void Complete(Retrieval? capture, bool original)
		{
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Invalid comparison between Unknown and I4
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			if (capture == null || !original)
			{
				return;
			}
			try
			{
				Retrieval retrieval = Capture(capture.Tomb, requireItems: false);
				if (retrieval == null || retrieval.Player != capture.Player || retrieval.Game != capture.Game || retrieval.Container != capture.Container || retrieval.Inventory != capture.Inventory || retrieval.Zdo != capture.Zdo || retrieval.World != capture.World || retrieval.PlayerId != capture.PlayerId || retrieval.Generation != capture.Generation || retrieval.Ticks != capture.Ticks)
				{
					lastResult = "scope-changed";
					return;
				}
				if (retrieval.Inventory.NrOfItems() != 0)
				{
					lastResult = "items-remain";
					return;
				}
				NotifyFoodRetrieved(retrieval);
				if (!Enabled || !Object.op_Implicit((Object)(object)retrieval.Map) || retrieval.Map != capture.Map || !retrieval.PinMetadata || !capture.PinMetadata || retrieval.Day != capture.Day || !((Vector3)(ref retrieval.Original)).Equals(capture.Original))
				{
					lastResult = "pin-unavailable";
					return;
				}
				PinData[] array = mapPins.Invoke(retrieval.Map).ToArray();
				List<DeathPinCandidate> list = new List<DeathPinCandidate>(array.Length);
				PinData[] array2 = array;
				foreach (PinData val in array2)
				{
					bool flag = ((PlatformUserID)(ref val.m_author)).IsValid && (PlatformManager.DistributionPlatform == null || val.m_author != ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID);
					list.Add(new DeathPinCandidate(val.m_pos.x, val.m_pos.z, val.m_name, val.m_save, (int)val.m_type == 4, val.m_ownerID, flag));
				}
				int num = DeathPinCleanup.FindUnique((IReadOnlyList<DeathPinCandidate>)list, retrieval.Original.x, retrieval.Original.z, retrieval.Day, retrieval.PlayerId);
				if (num < 0)
				{
					lastResult = "no-unique-pin";
					return;
				}
				PinData val2 = array[num];
				if (!mapPins.Invoke(retrieval.Map).Contains(val2))
				{
					lastResult = "pin-changed";
					return;
				}
				retrieval.Map.RemovePin(val2);
				removed++;
				lastResult = "removed";
			}
			catch (Exception error)
			{
				lastResult = "error";
				Plugin.Instance?.Error(error);
			}
		}

		private static void NotifyFoodRetrieved(Retrieval now)
		{
			try
			{
				CapabilityRegistry capabilities = Plugin.Services.Capabilities;
				IReadOnlyList<CapabilityMetadata> readOnlyList = capabilities.Providers("meadworks.larder.food.retrieved");
				Action<long, long, string> action = default(Action<long, long, string>);
				if (readOnlyList.Count == 1 && readOnlyList[0].Owner == "com.meadworks.larder" && capabilities.TryResolve<Action<long, long, string>>("meadworks.larder.food.retrieved", new Version(1, 0), ref action))
				{
					action(now.World, now.PlayerId, ((object)Unsafe.As<ZDOID, ZDOID>(ref now.Zdo.m_uid)/*cast due to .constrained prefix*/).ToString());
				}
			}
			catch (Exception error)
			{
				Plugin.Instance?.Error(error);
			}
		}

		internal static object Status()
		{
			return new
			{
				enabled = Enabled,
				removed = removed,
				lastResult = lastResult
			};
		}
	}
	[HarmonyPatch(typeof(TombStone), "OnTakeAllSuccess")]
	internal static class TombstonePinTakeAllPatch
	{
		[HarmonyPrefix]
		private static void Before(TombStone __instance, out TombstonePinCleanup.Retrieval? __state)
		{
			__state = TombstonePinCleanup.FromTakeAll(__instance);
		}

		[HarmonyPostfix]
		private static void After(TombstonePinCleanup.Retrieval? __state, bool __runOriginal)
		{
			TombstonePinCleanup.Complete(__state, __runOriginal);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnTakeAll")]
	internal static class TombstonePinGuiTakeAllPatch
	{
		[HarmonyPrefix]
		private static void Before(InventoryGui __instance, out TombstonePinCleanup.Retrieval? __state)
		{
			__state = TombstonePinCleanup.FromGui(__instance);
		}

		[HarmonyPostfix]
		private static void After(TombstonePinCleanup.Retrieval? __state, bool __runOriginal)
		{
			TombstonePinCleanup.Complete(__state, __runOriginal);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
	internal static class TombstonePinGuiTransferPatch
	{
		[HarmonyPrefix]
		private static void Before(InventoryGui __instance, InventoryGrid grid, ItemData item, Modifier mod, out TombstonePinCleanup.Retrieval? __state)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			__state = TombstonePinCleanup.FromGui(__instance, grid, item, mod);
		}

		[HarmonyPostfix]
		private static void After(TombstonePinCleanup.Retrieval? __state, bool __runOriginal)
		{
			TombstonePinCleanup.Complete(__state, __runOriginal);
		}
	}
}
namespace Wayfarer.Core
{
	public static class MeadworksIntegration
	{
		public static ProductMetadata Metadata()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			return new ProductMetadata("com.meadworks.wayfarer", "Wayfarer", new Version("0.5.13"), new Version(0, 1), new Version(0, 1), (MultiplayerPolicy)2, "Mischief");
		}

		public static UiDescriptor Ui()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			return new UiDescriptor("Wayfarer", "Meadworks", "M");
		}
	}
}
namespace Wayfarer.CrucibleIntegration
{
	public sealed class CrucibleServices : IDisposable
	{
		private readonly ProductRegistration registration;

		private MeadworksTranslations? localization;

		private readonly MeadworksLog log;

		private TeleportAuthorityAdapter? authority;

		private ConfigEntry<bool> allowTeleport;

		private ConfigEntry<bool> allowBed;

		private ConfigEntry<bool> stones;

		private ConfigEntry<bool> map;

		private ConfigEntry<bool> boat;

		private ConfigEntry<bool> grave;

		private ConfigEntry<bool> player;

		private readonly PerFrame<bool> travelCheats;

		private static readonly string ProductId = MeadworksIntegration.Metadata().Id;

		public SessionSnapshot Session => Plugin.Session;

		public TeleportPolicy EffectivePolicy => new TeleportPolicy(allowTeleport.Value, allowBed.Value, stones.Value, map.Value, boat.Value, grave.Value, player.Value, PlayerCategories());

		public bool TravelCheats => travelCheats.Value;

		public double MonotonicTime => SessionIntegration.Now;

		private IReadOnlyCollection<Category> PlayerCategories()
		{
			List<Category> list = new List<Category>();
			if (MeadworksMischief.PlayersMay((ConfigEntryBase)(object)stones))
			{
				list.Add((Category)1);
			}
			if (MeadworksMischief.PlayersMay((ConfigEntryBase)(object)map))
			{
				list.Add((Category)2);
			}
			if (MeadworksMischief.PlayersMay((ConfigEntryBase)(object)boat))
			{
				list.Add((Category)3);
			}
			if (MeadworksMischief.PlayersMay((ConfigEntryBase)(object)grave))
			{
				list.Add((Category)4);
			}
			if (MeadworksMischief.PlayersMay((ConfigEntryBase)(object)player))
			{
				list.Add((Category)5);
			}
			return list;
		}

		public CrucibleServices(ProductRegistration registration, BepInPlugin metadata, ConfigFile config, ManualLogSource logger, Func<NavigationSnapshot> navigation)
		{
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			this.registration = registration;
			travelCheats = new PerFrame<bool>((Func<int>)(() => Time.frameCount), (Func<bool>)(() => MeadworksMischief.Decide(ProductId, (MischiefCategory)4).Allowed));
			log = MeadworksLog.For(logger, "Wayfarer");
			try
			{
				allowTeleport = Bind(config, "Server", "AllowTeleport", defaultValue: true, "Master switch for every Wayfarer destination on this server.", (ConfigScope)1);
				allowBed = Bind(config, "Server", "AllowBed", defaultValue: true, "Allow Bed teleport for every player.", (ConfigScope)1);
				stones = MeadworksConfig.BindCheat<bool>(config, "Cheats", "TeleportToStones", false, "Travel cheat: teleport to discovered Sacrificial Stones. Admins only on a server unless the admin lets players use it.", (MischiefCategory)4, (AcceptableValueBase)null);
				map = MeadworksConfig.BindCheat<bool>(config, "Cheats", "TeleportAnywhere", false, "Travel cheat: teleport to any clicked map point. Admins only on a server unless the admin lets players use it.", (MischiefCategory)4, (AcceptableValueBase)null);
				boat = MeadworksConfig.BindCheat<bool>(config, "Cheats", "TeleportToBoat", false, "Travel cheat: teleport to a seen boat. Admins only on a server unless the admin lets players use it.", (MischiefCategory)4, (AcceptableValueBase)null);
				grave = MeadworksConfig.BindCheat<bool>(config, "Cheats", "TeleportToGrave", false, "Travel cheat: teleport to your own grave. Admins only on a server unless the admin lets players use it.", (MischiefCategory)4, (AcceptableValueBase)null);
				player = MeadworksConfig.BindCheat<bool>(config, "Cheats", "TeleportToPlayer", false, "Travel cheat: teleport to a player who shares their map position. Admins only on a server unless the admin lets players use it.", (MischiefCategory)4, (AcceptableValueBase)null);
				authority = new TeleportAuthorityAdapter(registration, () => EffectivePolicy);
				if (MeadworksHeadless.AllowsUi)
				{
					registration.AddUi(MeadworksIntegration.Ui());
				}
				NavigationProvider val = new NavigationProvider(navigation);
				registration.AddCapability<IWayfarerNavigation>("meadworks.navigation", new Version(1, 0), (IWayfarerNavigation)(object)val);
				registration.AddCapability<IWayfarerNavigation>("meadworks.mischief", new Version(1, 0), (IWayfarerNavigation)(object)val);
				if (MeadworksHeadless.AllowsUi)
				{
					localization = MeadworksTranslations.Register(metadata, new ProductTranslations("wayfarer", EmbeddedCatalog()), (string)null, logger);
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public ConfigEntry<T> Bind<T>(ConfigFile config, string section, string key, T defaultValue, ConfigDescription description)
		{
			return MeadworksConfig.Bind<T>(config, section, key, defaultValue, description);
		}

		public ConfigEntry<T> Bind<T>(ConfigFile config, string section, string key, T defaultValue, string description, ConfigScope scope)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return MeadworksConfig.Bind<T>(config, section, key, defaultValue, description, scope, (AcceptableValueBase)null);
		}

		public Task<OperationResult<TeleportGrant>> AuthorizeAsync(TeleportRequest request, CancellationToken cancellation)
		{
			return Plugin.RequestClient.InvokeAsync<TeleportRequest, TeleportGrant>("meadworks.wayfarer.teleport.authorize", request, cancellation);
		}

		public Task<OperationResult<bool>> CompleteAsync(TeleportCompletion completion, CancellationToken cancellation)
		{
			return Plugin.RequestClient.InvokeAsync<TeleportCompletion, bool>("meadworks.wayfarer.teleport.complete", completion, cancellation);
		}

		private static IReadOnlyDictionary<string, string> EmbeddedCatalog()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			Assembly assembly = typeof(CrucibleServices).Assembly;
			foreach (string item in MeadworksLanguages.Supported)
			{
				using Stream stream = assembly.GetManifestResourceStream("Wayfarer.localization." + item + ".json");
				if (stream != null)
				{
					using StreamReader streamReader = new StreamReader(stream);
					dictionary.Add(item, streamReader.ReadToEnd());
				}
			}
			return dictionary;
		}

		public string Text(string key, string language)
		{
			MeadworksTranslations? obj = localization;
			return ((obj != null) ? obj.Translations.Text(key, language) : null) ?? key;
		}

		public void Update()
		{
			MeadworksTranslations? obj = localization;
			if (obj != null)
			{
				obj.Update();
			}
		}

		public void ReportStepAside(string moduleId, string sourceGuid, string sourceName)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			MeadworksStepAside.ReportModule(ProductId, moduleId, new SourceMod(sourceGuid, sourceName), "wayfarer", (string)null);
		}

		public void Info(string message)
		{
			log.Info(message);
		}

		public void Error(object error)
		{
			log.Error(error);
		}

		public void Dispose()
		{
			authority?.Dispose();
			MeadworksTranslations? obj = localization;
			if (obj != null)
			{
				obj.Dispose();
			}
			authority = null;
			localization = null;
		}
	}
	internal static class SessionIntegration
	{
		internal const string Authorize = "meadworks.wayfarer.teleport.authorize";

		internal const string Complete = "meadworks.wayfarer.teleport.complete";

		private static readonly Stopwatch clock = Stopwatch.StartNew();

		internal static double Now => clock.Elapsed.TotalSeconds;

		internal static byte[] Write(Action<BinaryWriter> write)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), leaveOpen: true);
			write(binaryWriter);
			binaryWriter.Flush();
			if (memoryStream.Length > 16384)
			{
				throw new InvalidDataException();
			}
			return memoryStream.ToArray();
		}

		internal static T Read<T>(byte[] bytes, Func<BinaryReader, T> read)
		{
			if (bytes.Length > 16384)
			{
				throw new InvalidDataException();
			}
			using MemoryStream memoryStream = new MemoryStream(bytes, writable: false);
			using BinaryReader arg = new BinaryReader(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true));
			T result = read(arg);
			if (memoryStream.Position != memoryStream.Length)
			{
				throw new InvalidDataException();
			}
			return result;
		}

		internal static string Text(BinaryReader reader)
		{
			string text = reader.ReadString();
			if (string.IsNullOrWhiteSpace(text) || text.Length > 128 || text.IndexOfAny(new char[3] { '\0', '\r', '\n' }) >= 0)
			{
				throw new InvalidDataException();
			}
			return text;
		}
	}
	internal sealed class TeleportCodec : IOperationCodec<TeleportRequest, TeleportGrant>
	{
		public byte[] EncodeRequest(TeleportRequest r)
		{
			return SessionIntegration.Write(delegate(BinaryWriter w)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Expected I4, but got Unknown
				w.Write(r.RequestId);
				w.Write((int)r.Category);
				w.Write(r.DestinationId);
				w.Write(r.X);
				w.Write(r.Y);
				w.Write(r.Z);
				w.Write(r.IsLastKnown);
			});
		}

		public TeleportRequest DecodeRequest(byte[] bytes)
		{
			return SessionIntegration.Read(bytes, (Func<BinaryReader, TeleportRequest>)((BinaryReader r) => new TeleportRequest(SessionIntegration.Text(r), (Category)r.ReadInt32(), SessionIntegration.Text(r), r.ReadSingle(), r.ReadSingle(), r.ReadSingle(), r.ReadBoolean())));
		}

		public byte[] EncodeReply(TeleportGrant g)
		{
			return SessionIntegration.Write(delegate(BinaryWriter w)
			{
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected I4, but got Unknown
				w.Write(g.ActorId);
				w.Write(g.WorldId);
				w.Write(g.SessionId);
				w.Write(g.RequestId);
				w.Write(g.GrantId);
				w.Write((int)g.Category);
				w.Write(g.DestinationId);
				w.Write(g.X);
				w.Write(g.Y);
				w.Write(g.Z);
				w.Write(Math.Max(0.0, Math.Min(10.0, g.ExpiresAt - SessionIntegration.Now)));
			});
		}

		public TeleportGrant DecodeReply(byte[] bytes)
		{
			return SessionIntegration.Read(bytes, (Func<BinaryReader, TeleportGrant>)delegate(BinaryReader r)
			{
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a0: Expected O, but got Unknown
				string text = SessionIntegration.Text(r);
				long num = r.ReadInt64();
				string text2 = SessionIntegration.Text(r);
				string text3 = SessionIntegration.Text(r);
				string text4 = SessionIntegration.Text(r);
				Category val = (Category)r.ReadInt32();
				string text5 = SessionIntegration.Text(r);
				float num2 = r.ReadSingle();
				float num3 = r.ReadSingle();
				float num4 = r.ReadSingle();
				double num5 = r.ReadDouble();
				if (double.IsNaN(num5) || double.IsInfinity(num5) || num5 < 0.0 || num5 > 10.0)
				{
					throw new InvalidDataException();
				}
				return new TeleportGrant(text, num, text2, text3, text4, val, text5, num2, num3, num4, SessionIntegration.Now + num5);
			});
		}
	}
	internal sealed class CompletionCodec : IOperationCodec<TeleportCompletion, bool>
	{
		public byte[] EncodeRequest(TeleportCompletion c)
		{
			return SessionIntegration.Write(delegate(BinaryWriter w)
			{
				w.Write(c.RequestId);
				w.Write(c.GrantId);
				w.Write(c.Accepted);
			});
		}

		public TeleportCompletion DecodeRequest(byte[] bytes)
		{
			return SessionIntegration.Read(bytes, (Func<BinaryReader, TeleportCompletion>)(