Decompiled source of SLTCore v0.2.0

Mods/SLTCore.Fusion.dll

Decompiled a week ago
using System;
using System.Buffers.Binary;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using LabFusion.Entities;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.SDK.Modules;
using MelonLoader;
using Microsoft.CodeAnalysis;
using SLTCore.Core;
using SLTCore.Fusion;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(FusionBridgeMod), "SLTCore Fusion Bridge", "0.2.0", "CraftyDev", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "SLTCore", "LabFusion" })]
[assembly: AssemblyVersion("0.2.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SLTCore.Fusion
{
	public sealed class FusionBridgeMod : MelonMod
	{
		private SLTFusionTransport? _transport;

		public override void OnInitializeMelon()
		{
			try
			{
				ModuleMessageManager.RegisterHandler<SLTFusionMessage>();
				_transport = new SLTFusionTransport();
				SLTFusionMessage.Transport = _transport;
				if (SLTAPI.Service != null)
				{
					SLTAPI.Service.AttachTransport((ISLTTransport)(object)_transport);
				}
				else
				{
					SLTAPI.Available += Attach;
				}
				((MelonBase)this).LoggerInstance.Msg("SLTCore Fusion transport registered. Built against Fusion 1.14.3; multiplayer headset tests are still required.");
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("Fusion API mismatch; navigation will remain disabled in multiplayer: " + ex.Message);
			}
		}

		private void Attach(SLTService service)
		{
			if (_transport != null)
			{
				service.AttachTransport((ISLTTransport)(object)_transport);
			}
		}

		public override void OnUpdate()
		{
			_transport?.Drain();
		}

		public override void OnDeinitializeMelon()
		{
			SLTAPI.Available -= Attach;
			SLTFusionMessage.Transport = null;
		}
	}
	public static class FusionAgentAuthority
	{
		public static bool CanDrive(NetworkEntity? entity)
		{
			if (!NetworkInfo.HasServer)
			{
				return true;
			}
			if (NetworkInfo.IsHost && entity != null && entity.IsRegistered && !entity.IsDestroyed)
			{
				return entity.IsOwner;
			}
			return false;
		}

		public static string AgentId(NetworkEntity entity, string sharedSpawnToken)
		{
			if (entity == null || !entity.IsRegistered || string.IsNullOrWhiteSpace(sharedSpawnToken) || sharedSpawnToken.Length > 48)
			{
				throw new ArgumentException("A registered entity and a shared per-spawn token are required");
			}
			return "fusion:" + entity.ID + ":" + sharedSpawnToken;
		}
	}
	public sealed class SLTBlob : INetSerializable
	{
		public byte[] Bytes = Array.Empty<byte>();

		public int? GetSize()
		{
			return 4 + Bytes.Length;
		}

		public void Serialize(INetSerializer serializer)
		{
			serializer.SerializeValue(ref Bytes);
		}
	}
	public sealed class SLTFusionMessage : ModuleMessageHandler
	{
		internal static SLTFusionTransport? Transport;

		protected override bool OnPreRelayMessage(ReceivedMessage received)
		{
			//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_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			MessageRoute route = ((ReceivedMessage)(ref received)).Route;
			if ((int)((MessageRoute)(ref route)).Type != 1 || !Unwrap(((ReceivedMessage)(ref received)).Bytes, out byte[] bytes))
			{
				return false;
			}
			SLTPacket val = default(SLTPacket);
			if (WireCodec.TryDecode(bytes, ref val))
			{
				return (int)val.Kind == 1;
			}
			return false;
		}

		protected override void OnHandleMessage(ReceivedMessage received)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			SLTFusionTransport transport = Transport;
			if (transport == null || !Unwrap(((ReceivedMessage)(ref received)).Bytes, out byte[] bytes))
			{
				return;
			}
			bool flag = ((ReceivedMessage)(ref received)).Sender == 0;
			if (NetworkInfo.IsHost)
			{
				int num;
				if (((ReceivedMessage)(ref received)).IsServerHandled)
				{
					MessageRoute route = ((ReceivedMessage)(ref received)).Route;
					num = (((int)((MessageRoute)(ref route)).Type != 1) ? 1 : 0);
				}
				else
				{
					num = 1;
				}
				if (((uint)num | (flag ? 1u : 0u)) != 0 || !((ReceivedMessage)(ref received)).Sender.HasValue)
				{
					return;
				}
			}
			else if (!flag || ((ReceivedMessage)(ref received)).IsServerHandled)
			{
				return;
			}
			transport.Queue(bytes, flag, ((ReceivedMessage)(ref received)).Sender);
		}

		internal static bool Unwrap(byte[] source, out byte[] bytes)
		{
			bytes = Array.Empty<byte>();
			if (source == null || source.Length < 4 || source.Length > 16388)
			{
				return false;
			}
			int num = BinaryPrimitives.ReadInt32BigEndian(source.AsSpan(0, 4));
			if (num < 0 || num != source.Length - 4 || num > 16384)
			{
				return false;
			}
			bytes = source.AsSpan(4, num).ToArray();
			return true;
		}
	}
	internal sealed class SLTFusionTransport : ISLTTransport
	{
		private readonly ConcurrentQueue<(byte[] bytes, bool host, byte? sender)> _incoming = new ConcurrentQueue<(byte[], bool, byte?)>();

		private int _queued;

		public AuthorityMode Mode
		{
			get
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					return (AuthorityMode)(NetworkInfo.HasServer ? (NetworkInfo.IsHost ? 1 : 2) : 0);
				}
				catch
				{
					return (AuthorityMode)3;
				}
			}
		}

		public string Description => "Fusion ModuleMessage API; LabFusion " + typeof(NetworkInfo).Assembly.GetName().Version;

		public event Action<byte[], bool, byte?>? Received;

		internal void Queue(byte[] bytes, bool host, byte? sender)
		{
			if (Interlocked.Increment(ref _queued) > 64)
			{
				Interlocked.Decrement(ref _queued);
			}
			else
			{
				_incoming.Enqueue((bytes, host, sender));
			}
		}

		internal void Drain()
		{
			int num = 0;
			(byte[], bool, byte?) result;
			while (num++ < 16 && _incoming.TryDequeue(out result))
			{
				Interlocked.Decrement(ref _queued);
				this.Received?.Invoke(result.Item1, result.Item2, result.Item3);
			}
		}

		public void Broadcast(byte[] bytes)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkInfo.IsHost && bytes.Length <= 16384)
			{
				MessageRelay.RelayModule<SLTFusionMessage, SLTBlob>(new SLTBlob
				{
					Bytes = bytes
				}, CommonMessageRoutes.ReliableToClients);
			}
		}

		public void SendToHost(byte[] bytes)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkInfo.IsClient && bytes.Length <= 16384)
			{
				MessageRelay.RelayModule<SLTFusionMessage, SLTBlob>(new SLTBlob
				{
					Bytes = bytes
				}, CommonMessageRoutes.ReliableToServer);
			}
		}

		public void SendToPeer(byte peer, byte[] bytes)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkInfo.IsHost && peer != 0 && bytes.Length <= 16384)
			{
				MessageRelay.RelayModule<SLTFusionMessage, SLTBlob>(new SLTBlob
				{
					Bytes = bytes
				}, new MessageRoute(peer, (NetworkChannel)0));
			}
		}
	}
}

Mods/SLTCore.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.Json;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using MelonLoader;
using Microsoft.CodeAnalysis;
using SLTCore;
using SLTCore.Core;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(SLTMod), "SLTCore", "0.2.0", "CraftyDev", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyVersion("0.2.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SLTCore
{
	public interface ISLTAgent
	{
		string Id { get; }

		V3 Feet { get; }

		AgentProfile Profile { get; }

		Transform Root { get; }

		bool HasMovementAuthority { get; }

		void OnNavigation(PathResult result);

		void OnReplicatedNavigation(PathResult result)
		{
		}

		void OnMapChanged(long revision)
		{
		}

		void OnAuthorityChanged(bool authoritative)
		{
		}
	}
	public interface ISLTTransport
	{
		AuthorityMode Mode { get; }

		string Description { get; }

		event Action<byte[], bool, byte?> Received;

		void Broadcast(byte[] bytes);

		void SendToHost(byte[] bytes);

		void SendToPeer(byte peer, byte[] bytes);
	}
	public static class SLTAPI
	{
		public const string Version = "0.2.0";

		public const string FullName = "Sentry Logic Track Core";

		public static SLTService? Service { get; internal set; }

		public static bool Ready => Service != null;

		public static event Action<SLTService>? Available;

		internal static void Announce(SLTService service)
		{
			Service = service;
			if (SLTAPI.Available == null)
			{
				return;
			}
			Delegate[] invocationList = SLTAPI.Available.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action<SLTService> action = (Action<SLTService>)invocationList[i];
				try
				{
					action(service);
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("SLTCore consumer startup failed: " + ex.Message);
				}
			}
		}
	}
	public sealed class SLTService
	{
		private sealed class Registration : IDisposable
		{
			private readonly SLTService _service;

			public readonly List<int> Ignored = new List<int>();

			public ISLTAgent Agent { get; }

			public Registration(SLTService service, ISLTAgent agent)
			{
				_service = service;
				Agent = agent;
			}

			public void Dispose()
			{
				_service.Unregister(this);
			}
		}

		private sealed class Pending
		{
			public PathRequest Request;

			public SearchJob Job;

			public Action<PathResult> Callback;
		}

		private readonly int _thread = Environment.CurrentManagedThreadId;

		private readonly SLTConfig _config;

		private readonly Instance _log;

		private readonly string _directory;

		private readonly WorldMap _map;

		private readonly QueryBudget _budget = new QueryBudget();

		private readonly ObstacleTracker _obstacles;

		private readonly UnityWorld _world;

		private readonly MapScheduler _mapping;

		private readonly Dictionary<string, Registration> _agents = new Dictionary<string, Registration>(StringComparer.Ordinal);

		private readonly List<Pending> _requests = new List<Pending>();

		private readonly Queue<OpeningScan> _openingJobs = new Queue<OpeningScan>();

		private readonly List<OpeningResult> _openings = new List<OpeningResult>();

		private readonly List<V3> _foci = new List<V3>();

		private readonly Dictionary<string, (V3 center, double expires)> _interests = new Dictionary<string, (V3, double)>(StringComparer.Ordinal);

		private readonly Dictionary<string, PathResult> _published = new Dictionary<string, PathResult>(StringComparer.Ordinal);

		private readonly Queue<(byte[] bytes, byte? peer)> _outgoing = new Queue<(byte[], byte?)>();

		private readonly Dictionary<byte, double> _helloRates = new Dictionary<byte, double>();

		private readonly ReplicaGate _replica = new ReplicaGate();

		private ISLTTransport? _transport;

		private readonly AuthorityProbe _authority = new AuthorityProbe();

		private AuthorityMode _mode = (AuthorityMode)3;

		private Guid _session = Guid.NewGuid();

		private uint _sequence;

		private long _requestId;

		private int _jobCursor;

		private int _focusCursor;

		private double _nextFocus;

		private double _nextObstacle;

		private double _nextDiagnostic;

		private double _nextHello;

		private double _nextSurvey;

		private double _nextEvict;

		private double _nextNetworkWindow;

		private long _lastAnnouncedRevision;

		private int _networkBytes;

		private int _slowFrames;

		private int _saturations;

		private double _frameAverage;

		private double _nextInvalidate;

		private string _scene = "startup";

		private double _now;

		private readonly List<int> _localRigIgnored = new List<int>();

		private Transform? _lastLocalRig;

		public AuthorityMode Authority => _mode;

		public bool IsAuthoritative
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Invalid comparison between Unknown and I4
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Invalid comparison between Unknown and I4
				AuthorityMode mode = _mode;
				return (int)mode == 1 || (int)mode == 0;
			}
		}

		public long Revision => _map.Revision;

		public int MappedSurfaces => _map.NodeCount;

		public int PendingColumns => _mapping.Pending;

		public event Action<long>? MapChanged;

		public event Action<ObstacleInfo>? ObstacleChanged;

		public event Action<OpeningResult>? OpeningObserved;

		public event Action<PathResult>? ReplicatedRoute;

		public SLTService(SLTConfig config, Instance log, string directory)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			_config = config;
			_log = log;
			_directory = directory;
			_map = new WorldMap(config.CellSize, config.BandHeight);
			_obstacles = new ObstacleTracker(config.MaxTrackedObstacles);
			_world = new UnityWorld(config, _budget, _obstacles);
			_mapping = new MapScheduler(_map, config);
			_obstacles.Dirty += InvalidateRegion;
			_obstacles.Changed += delegate(ObstacleInfo info)
			{
				Safely(delegate
				{
					this.ObstacleChanged?.Invoke(info);
				});
			};
			_budget.Reset(config.PhysicsQueriesPerFrame);
		}

		private void CheckThread()
		{
			if (Environment.CurrentManagedThreadId != _thread)
			{
				throw new InvalidOperationException("SLTCore APIs must be called on the Unity main thread");
			}
		}

		public IDisposable RegisterAgent(ISLTAgent agent)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (agent != null && !string.IsNullOrWhiteSpace(agent.Id) && agent.Id.Length <= 96 && agent.Profile.IsValid)
			{
				V3 feet = agent.Feet;
				if (((V3)(ref feet)).IsFinite)
				{
					if (_agents.ContainsKey(agent.Id))
					{
						throw new InvalidOperationException("Agent ID is already registered: " + agent.Id);
					}
					if (_agents.Count >= _config.MaxRegisteredAgents)
					{
						throw new InvalidOperationException("Agent registration limit reached");
					}
					Registration registration = new Registration(this, agent);
					if (Object.op_Implicit((Object)(object)agent.Root))
					{
						foreach (Collider componentsInChild in ((Component)agent.Root).GetComponentsInChildren<Collider>(true))
						{
							if (Object.op_Implicit((Object)(object)componentsInChild))
							{
								registration.Ignored.Add(((Object)componentsInChild).GetInstanceID());
								_obstacles.Ignore(componentsInChild, ignored: true);
							}
						}
					}
					_agents.Add(agent.Id, registration);
					_mapping.Endpoint(agent.Feet);
					Safely(delegate
					{
						agent.OnAuthorityChanged(IsAuthoritative && agent.HasMovementAuthority);
					});
					return registration;
				}
			}
			throw new ArgumentException("Agent requires a stable ID, valid profile, and feet position");
		}

		private void Unregister(Registration registration)
		{
			CheckThread();
			if (!_agents.TryGetValue(registration.Agent.Id, out Registration value) || value != registration)
			{
				return;
			}
			CancelAgent(registration.Agent.Id);
			foreach (int item in registration.Ignored)
			{
				_obstacles.IgnoreId(item, ignored: false);
			}
			_agents.Remove(registration.Agent.Id);
			_published.Remove(registration.Agent.Id);
		}

		public long RequestPath(string agentId, V3 start, NavigationTarget target, AgentProfile profile, Action<PathResult> callback, bool allowPartial = false)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			V3 goal = default(V3);
			if (target == null || !target.TryGetPosition(ref goal))
			{
				long id = ++_requestId;
				if (!string.IsNullOrWhiteSpace(agentId))
				{
					CancelAgent(agentId);
				}
				Safely(delegate
				{
					//IL_002e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Expected O, but got Unknown
					callback(new PathResult(id, agentId ?? "", (PathStatus)12, Revision, (IReadOnlyList<Waypoint>)null, "The AI mod's chosen destination is unavailable"));
				});
				return id;
			}
			return RequestPath(agentId, start, goal, profile, callback, allowPartial);
		}

		public long RequestPath(string agentId, V3 start, V3 goal, AgentProfile profile, Action<PathResult> callback, bool allowPartial = false)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			long id = ++_requestId;
			PathRequest val = new PathRequest
			{
				RequestId = id,
				AgentId = agentId,
				Start = start,
				Goal = goal,
				Profile = profile,
				AllowPartial = allowPartial
			};
			if (!val.IsValid)
			{
				Safely(delegate
				{
					//IL_002d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0037: Expected O, but got Unknown
					callback(new PathResult(id, agentId ?? "", (PathStatus)4, Revision, (IReadOnlyList<Waypoint>)null, ""));
				});
				return id;
			}
			if (!IsAuthoritative)
			{
				Safely(delegate
				{
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					//IL_002f: Expected O, but got Unknown
					callback(new PathResult(id, agentId, (PathStatus)9, Revision, (IReadOnlyList<Waypoint>)null, "Only the authority plans executable routes"));
				});
				return id;
			}
			if (!_agents.TryGetValue(agentId, out Registration value) || !value.Agent.HasMovementAuthority)
			{
				Safely(delegate
				{
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					//IL_002f: Expected O, but got Unknown
					callback(new PathResult(id, agentId, (PathStatus)9, Revision, (IReadOnlyList<Waypoint>)null, "Register the NPC and verify its ownership first"));
				});
				return id;
			}
			CancelAgent(agentId);
			if (_requests.Count >= _config.MaxQueuedPaths)
			{
				Safely(delegate
				{
					//IL_0025: Unknown result type (might be due to invalid IL or missing references)
					//IL_002f: Expected O, but got Unknown
					callback(new PathResult(id, agentId, (PathStatus)10, Revision, (IReadOnlyList<Waypoint>)null, ""));
				});
				return id;
			}
			PathRequest val2 = val.Copy();
			_requests.Add(new Pending
			{
				Request = val2,
				Job = new SearchJob(_map, (IWorldQuery)(object)_world, val2, _now, _config.MaxSearchVisits),
				Callback = callback
			});
			_mapping.Endpoint(start);
			_mapping.Endpoint(goal);
			return id;
		}

		public void CancelAgent(string agentId)
		{
			CheckThread();
			Pending[] array = _requests.Where((Pending r) => r.Request.AgentId == agentId).ToArray();
			foreach (Pending pending in array)
			{
				_requests.Remove(pending);
				pending.Job.Cancel();
				Safely(delegate
				{
					pending.Callback(pending.Job.Result);
				});
			}
		}

		public LinkCheck ValidateNextSegment(V3 feet, Waypoint next, AgentProfile profile)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_004c: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (!IsAuthoritative)
			{
				return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
			}
			MoveKind kind = ((Waypoint)(ref next)).Kind;
			if ((int)kind == 4 || (int)kind == 5 || (int)kind == 6 || (int)kind == 7)
			{
				return new LinkCheck((LinkState)0, ((Waypoint)(ref next)).Kind, 0f);
			}
			return _world.CheckTraversal(feet, ((Waypoint)(ref next)).Feet, profile);
		}

		public void RegisterTraversalLink(TraversalLink link)
		{
			CheckThread();
			_map.AddLink(link);
		}

		public void SetInterestPoint(string id, V3 center, float lifetimeSeconds = 15f)
		{
			//IL_0080: 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)
			CheckThread();
			if (string.IsNullOrWhiteSpace(id) || id.Length > 96 || !((V3)(ref center)).IsFinite || ((V3)(ref center)).Length > 50000f || !float.IsFinite(lifetimeSeconds) || lifetimeSeconds < 1f || lifetimeSeconds > 60f)
			{
				throw new ArgumentException("Invalid interest point");
			}
			if (_interests.Count >= 8 && !_interests.ContainsKey(id))
			{
				throw new InvalidOperationException("Interest point limit reached");
			}
			_interests[id] = (center, _now + (double)lifetimeSeconds);
			_mapping.Focus(center);
			_nextFocus = 0.0;
		}

		public void RemoveInterestPoint(string id)
		{
			CheckThread();
			_interests.Remove(id);
			_nextFocus = 0.0;
		}

		public void RemoveTraversalLink(string id)
		{
			CheckThread();
			_map.RemoveLink(id);
		}

		public void RegisterObstacle(Collider collider, string stableId, ObstacleKind kind, bool confirmedBreakable = false)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			_obstacles.Register(collider, stableId, kind, confirmedBreakable);
		}

		public void UnregisterObstacle(string stableId)
		{
			CheckThread();
			_obstacles.Unregister(stableId);
		}

		public IReadOnlyList<ObstacleInfo> GetObstacles(V3 center, float radius = 12f)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (!((V3)(ref center)).IsFinite || !float.IsFinite(radius) || radius < 0f || radius > 50f)
			{
				throw new ArgumentException("Invalid query");
			}
			return _obstacles.Nearby(center, radius);
		}

		public IReadOnlyList<OpeningResult> GetOpenings(V3 center, float radius = 12f)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			return _openings.Where((OpeningResult o) => _now - o.ObservedAt < (double)_config.MaxMapAgeSeconds && V3.Distance(o.Center, center) <= radius).ToArray();
		}

		public void ProbeOpening(V3 center, V3 normal, Action<OpeningResult> callback, float width = 3f, float height = 3f, float depth = 1f, float resolution = 0.15f)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			if (!IsAuthoritative)
			{
				throw new InvalidOperationException("Opening measurements run on the authority");
			}
			if (_openingJobs.Count >= 8)
			{
				throw new InvalidOperationException("Opening probe queue is full");
			}
			_openingJobs.Enqueue(new OpeningScan(center, normal, width, height, depth, resolution, callback));
		}

		public void NotifyWorldChanged(Bounds bounds)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			CheckThread();
			V3 val = ((Bounds)(ref bounds)).center.SLT();
			if (((V3)(ref val)).IsFinite)
			{
				val = ((Bounds)(ref bounds)).size.SLT();
				if (((V3)(ref val)).IsFinite)
				{
					Vector3 size = ((Bounds)(ref bounds)).size;
					if (!(((Vector3)(ref size)).sqrMagnitude > 10000f))
					{
						InvalidateRegion(bounds);
						return;
					}
				}
			}
			throw new ArgumentException("Dirty bounds must be finite and local (size length <= 100 m)");
		}

		private void InvalidateRegion(Bounds bounds)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			_mapping.Dirty(bounds);
			foreach (OpeningScan openingJob in _openingJobs)
			{
				openingJob.Invalidate(bounds);
			}
			_openings.RemoveAll(delegate(OpeningResult opening)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				Bounds val = bounds;
				((Bounds)(ref val)).Expand(MathF.Max(opening.Width, opening.Height));
				return ((Bounds)(ref val)).Contains(opening.Center.Unity());
			});
		}

		public V3 GetCrowdSeparation(string agentId, float range = 1.2f)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (!_agents.TryGetValue(agentId, out Registration value) || !float.IsFinite(range) || range <= 0f || range > 5f)
			{
				return default(V3);
			}
			V3 val = default(V3);
			foreach (Registration value2 in _agents.Values)
			{
				if (value2 != value)
				{
					V3 val2 = value.Agent.Feet - value2.Agent.Feet;
					float horizontalLength = ((V3)(ref val2)).HorizontalLength;
					if (horizontalLength > 0.001f && horizontalLength < range && MathF.Abs(val2.Y) < 0.7f)
					{
						val += new V3(val2.X, 0f, val2.Z) / horizontalLength * (1f - horizontalLength / range);
					}
				}
			}
			if (!(((V3)(ref val)).Length > 1f))
			{
				return val;
			}
			return ((V3)(ref val)).Normalized;
		}

		public bool? HasLineOfSight(V3 from, V3 to)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			if (!((V3)(ref from)).IsFinite || !((V3)(ref to)).IsFinite || V3.Distance(from, to) > 100f)
			{
				return false;
			}
			if (!_budget.Take(1))
			{
				return null;
			}
			V3 v = to - from;
			RaycastHit nearest;
			return ((V3)(ref v)).Length < 0.001f || !_world.Ray(from.Unity(), v.Unity() / ((V3)(ref v)).Length, ((V3)(ref v)).Length, out nearest);
		}

		public void AttachTransport(ISLTTransport transport)
		{
			CheckThread();
			if (_transport != null)
			{
				_transport.Received -= Receive;
			}
			_transport = transport;
			_transport.Received += Receive;
			_nextHello = 0.0;
			_log.Msg("Replication transport attached: " + transport.Description);
		}

		public void SceneChanged(string scene)
		{
			CheckThread();
			_scene = ((scene.Length <= 128) ? scene : scene.Substring(0, 128));
			ResetNavigation(clearAgents: true);
			_nextFocus = 0.0;
			_nextHello = 0.0;
		}

		private void ResetNavigation(bool clearAgents)
		{
			Pending[] array = _requests.ToArray();
			_requests.Clear();
			_map.Clear();
			_mapping.Clear();
			_openingJobs.Clear();
			_openings.Clear();
			_foci.Clear();
			_interests.Clear();
			_published.Clear();
			_outgoing.Clear();
			_helloRates.Clear();
			_session = Guid.NewGuid();
			_sequence = 0u;
			_replica.Reset(_scene);
			_lastAnnouncedRevision = Revision;
			Pending[] array2 = array;
			foreach (Pending p in array2)
			{
				Safely(delegate
				{
					//IL_003e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0048: Expected O, but got Unknown
					p.Callback(new PathResult(p.Request.RequestId, p.Request.AgentId, (PathStatus)9, Revision, (IReadOnlyList<Waypoint>)null, "Scene or authority changed"));
				});
			}
			if (clearAgents)
			{
				_agents.Clear();
				_obstacles.Clear();
				_localRigIgnored.Clear();
				_lastLocalRig = null;
			}
		}

		public unsafe void Tick()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0053: Invalid comparison between Unknown and I4
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0741: Unknown result type (might be due to invalid IL or missing references)
			//IL_0747: Invalid comparison between Unknown and I4
			//IL_061e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0623: Unknown result type (might be due to invalid IL or missing references)
			//IL_074a: Unknown result type (might be due to invalid IL or missing references)
			//IL_074f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0771: Expected O, but got Unknown
			//IL_0637: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0378: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			CheckThread();
			_now = Time.realtimeSinceStartupAsDouble;
			_obstacles.Now = _now;
			AuthorityMode val = _transport?.Mode ?? _authority.Read(_now);
			if (_transport == null && ((int)val == 1 || (int)val == 2))
			{
				val = (AuthorityMode)3;
			}
			if (_mode != val)
			{
				_mode = val;
				ResetNavigation(clearAgents: false);
				_log.Msg("Navigation authority: " + ((object)(*(AuthorityMode*)(&val))/*cast due to .constrained prefix*/).ToString());
				Registration[] array = _agents.Values.ToArray();
				foreach (Registration reg in array)
				{
					Safely(delegate
					{
						reg.Agent.OnAuthorityChanged(IsAuthoritative && reg.Agent.HasMovementAuthority);
					});
				}
			}
			if (!_config.Enabled)
			{
				return;
			}
			double num = _config.FrameBudgetMilliseconds * ((Time.unscaledDeltaTime > 0.022f) ? 0.55 : 1.0);
			Stopwatch stopwatch = Stopwatch.StartNew();
			_budget.Reset(_config.PhysicsQueriesPerFrame);
			RefreshLocalRigIgnore();
			if (IsAuthoritative)
			{
				V3 feet;
				if (_now >= _nextFocus)
				{
					_nextFocus = _now + 2.0;
					_foci.Clear();
					Registration[] array2 = _agents.Values.ToArray();
					int num2;
					for (num2 = 0; num2 < array2.Length; num2++)
					{
						if (_foci.Count >= 7)
						{
							break;
						}
						Registration reg2 = array2[(_focusCursor + num2) % array2.Length];
						if (Object.op_Implicit((Object)(object)reg2.Agent.Root))
						{
							feet = reg2.Agent.Feet;
							if (((V3)(ref feet)).IsFinite && !_foci.Any((V3 f) => V3.Distance(f, reg2.Agent.Feet) < 2f))
							{
								_foci.Add(reg2.Agent.Feet);
							}
						}
					}
					if (array2.Length != 0)
					{
						_focusCursor = (_focusCursor + Math.Max(1, num2)) % array2.Length;
					}
					string[] array3 = (from p in _interests
						where p.Value.expires <= _now
						select p.Key).ToArray();
					foreach (string key in array3)
					{
						_interests.Remove(key);
					}
					foreach (var value in _interests.Values)
					{
						_foci.Add(value.center);
					}
					Camera main = Camera.main;
					if (Object.op_Implicit((Object)(object)main))
					{
						_foci.Add((((Component)main).transform.position - Vector3.up * 1.5f).SLT());
					}
					foreach (V3 focus in _foci)
					{
						_mapping.Focus(focus);
					}
				}
				if (_now >= _nextObstacle)
				{
					_nextObstacle = _now + 0.25;
					_obstacles.Tick();
				}
				_budget.SetLimit(_config.ScanQueriesPerFrame);
				_mapping.Tick(_world, _now, num * 0.45);
				_budget.SetLimit(_config.PhysicsQueriesPerFrame - _config.MovementQueryReserve);
				TickPaths(stopwatch, num * 0.85);
				if (_openingJobs.TryPeek(out OpeningScan opening) && stopwatch.Elapsed.TotalMilliseconds < num && opening.Step(_world, _now, Math.Max(0.02, num - stopwatch.Elapsed.TotalMilliseconds)))
				{
					_openingJobs.Dequeue();
					OpeningResult result = opening.Result;
					if (result.Found)
					{
						if (_openings.Count >= 128)
						{
							_openings.RemoveAt(0);
						}
						_openings.Add(result);
					}
					Safely(delegate
					{
						opening.Callback(result);
					});
					Safely(delegate
					{
						this.OpeningObserved?.Invoke(result);
					});
				}
				if (_now >= _nextSurvey && _openingJobs.Count < 2 && _foci.Count > 0 && stopwatch.Elapsed.TotalMilliseconds < num)
				{
					_nextSurvey = _now + 2.0;
					Survey(_foci[(int)_now % _foci.Count]);
				}
				if (_now >= _nextEvict)
				{
					_nextEvict = _now + 5.0;
					List<V3> list = new List<V3>(_foci);
					foreach (Registration value2 in _agents.Values)
					{
						if (Object.op_Implicit((Object)(object)value2.Agent.Root))
						{
							feet = value2.Agent.Feet;
							if (((V3)(ref feet)).IsFinite)
							{
								list.Add(value2.Agent.Feet);
							}
						}
					}
					_map.Evict(_now, (double)_config.MaxMapAgeSeconds, (IReadOnlyList<V3>)list, _config.ScanRadius + 8f, _config.MaxColumns);
				}
				if (Revision != _lastAnnouncedRevision && _now >= _nextInvalidate)
				{
					_nextInvalidate = _now + 0.5;
					_lastAnnouncedRevision = Revision;
					Safely(delegate
					{
						this.MapChanged?.Invoke(Revision);
					});
					Registration[] array = _agents.Values.ToArray();
					foreach (Registration reg3 in array)
					{
						Safely(delegate
						{
							reg3.Agent.OnMapChanged(Revision);
						});
					}
					if ((int)_mode == 1)
					{
						EnqueuePacket(new SLTPacket
						{
							Kind = (PacketKind)4,
							Revision = Revision
						});
					}
				}
			}
			_budget.SetLimit(_config.PhysicsQueriesPerFrame);
			TickNetwork();
			double totalMilliseconds = stopwatch.Elapsed.TotalMilliseconds;
			_frameAverage = ((_frameAverage == 0.0) ? totalMilliseconds : (_frameAverage * 0.97 + totalMilliseconds * 0.03));
			if (totalMilliseconds > num * 2.0)
			{
				_slowFrames++;
			}
			if (_budget.Saturated)
			{
				_saturations++;
			}
			if (_config.WriteDiagnostics && _now >= _nextDiagnostic)
			{
				_nextDiagnostic = _now + 15.0;
				WriteDiagnostics();
			}
		}

		private void TickPaths(Stopwatch clock, double limit)
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Invalid comparison between Unknown and I4
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: 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_01bb: Expected O, but got Unknown
			int num = 0;
			while (_requests.Count > 0 && num < _config.MaxConcurrentPaths && clock.Elapsed.TotalMilliseconds < limit)
			{
				_jobCursor %= _requests.Count;
				Pending pending = _requests[_jobCursor];
				num++;
				if (!_agents.TryGetValue(pending.Request.AgentId, out Registration agent) || !agent.Agent.HasMovementAuthority)
				{
					_requests.RemoveAt(_jobCursor);
					Safely(delegate
					{
						//IL_003e: Unknown result type (might be due to invalid IL or missing references)
						//IL_0048: Expected O, but got Unknown
						pending.Callback(new PathResult(pending.Request.RequestId, pending.Request.AgentId, (PathStatus)9, Revision, (IReadOnlyList<Waypoint>)null, ""));
					});
					continue;
				}
				pending.Job.Step(_now, (double)_config.MaxMapAgeSeconds, 8, Math.Min(0.25, Math.Max(0.02, limit - clock.Elapsed.TotalMilliseconds)));
				if (!pending.Job.Done)
				{
					_jobCursor++;
					continue;
				}
				_requests.RemoveAt(_jobCursor);
				PathResult result = pending.Job.Result;
				_published[result.AgentId] = result;
				Safely(delegate
				{
					pending.Callback(result);
				});
				Safely(delegate
				{
					agent.Agent.OnNavigation(result);
				});
				if ((int)_mode == 1)
				{
					EnqueuePacket(new SLTPacket
					{
						Kind = (PacketKind)3,
						Route = result,
						Revision = Revision
					});
				}
			}
			if (_requests.Count > 0)
			{
				_jobCursor = (_jobCursor + 1) % _requests.Count;
			}
		}

		private void RefreshLocalRigIgnore()
		{
			Camera main = Camera.main;
			if (!Object.op_Implicit((Object)(object)main))
			{
				return;
			}
			RigManager componentInParent = ((Component)main).GetComponentInParent<RigManager>();
			if (!Object.op_Implicit((Object)(object)componentInParent) || (Object)(object)_lastLocalRig == (Object)(object)((Component)componentInParent).transform)
			{
				return;
			}
			foreach (int item in _localRigIgnored)
			{
				_obstacles.IgnoreId(item, ignored: false);
			}
			_localRigIgnored.Clear();
			_lastLocalRig = ((Component)componentInParent).transform;
			foreach (Collider componentsInChild in ((Component)componentInParent).GetComponentsInChildren<Collider>(true))
			{
				if (Object.op_Implicit((Object)(object)componentsInChild))
				{
					_localRigIgnored.Add(((Object)componentsInChild).GetInstanceID());
					_obstacles.Ignore(componentsInChild, ignored: true);
				}
			}
		}

		private void Survey(V3 feet)
		{
			//IL_0010: 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)
			//IL_0016: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_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_00cc: 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_00d7: 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_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: 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_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: 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_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			if (!_budget.Take(16))
			{
				return;
			}
			Vector3 val = feet.Unity();
			Vector3[] array = (Vector3[])(object)new Vector3[4]
			{
				Vector3.forward,
				Vector3.right,
				Vector3.back,
				Vector3.left
			};
			RaycastHit nearest2;
			foreach (Vector3 val2 in array)
			{
				RaycastHit nearest;
				bool flag = _world.Ray(val + Vector3.up * 0.35f, val2, 3f, out nearest);
				bool num = _world.Ray(val + Vector3.up * 1.35f, val2, 3f, out nearest2);
				RaycastHit nearest3;
				bool flag2 = _world.Ray(val + Vector3.up * 2.5f, val2, 3f, out nearest3);
				if (!num && ((flag && Object.op_Implicit((Object)(object)((RaycastHit)(ref nearest)).collider)) || (flag2 && Object.op_Implicit((Object)(object)((RaycastHit)(ref nearest3)).collider))))
				{
					RaycastHit val3 = ((flag && Object.op_Implicit((Object)(object)((RaycastHit)(ref nearest)).collider)) ? nearest : nearest3);
					Vector3 v = val + val2 * ((RaycastHit)(ref val3)).distance + Vector3.up * 1.35f;
					ProbeOpening(v.SLT(), ((RaycastHit)(ref val3)).normal.SLT(), delegate
					{
					}, 3f, 3f, 0.6f);
					return;
				}
				Vector3 val4 = val + val2 * 1.1f;
				if (!_world.Support(val4, 0.3f, 2f, 65f, out nearest2))
				{
					ProbeOpening(val4.SLT(), Vector3.up.SLT(), delegate
					{
					}, 3f, 3f, 0.4f);
					return;
				}
			}
			if (_world.Ray(val + Vector3.up * 0.4f, Vector3.up, 5f, out var nearest4) && Object.op_Implicit((Object)(object)((RaycastHit)(ref nearest4)).collider))
			{
				Vector3 val5 = val + Vector3.right;
				if (!_world.Ray(val5 + Vector3.up * 0.4f, Vector3.up, 5f, out nearest2))
				{
					ProbeOpening(new V3(val5.x, ((RaycastHit)(ref nearest4)).point.y, val5.z), Vector3.down.SLT(), delegate
					{
					}, 3f, 3f, 0.6f);
				}
			}
		}

		private void TickNetwork()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			if (_transport == null)
			{
				return;
			}
			AuthorityMode mode = _mode;
			if ((int)mode == 0 || (int)mode == 3)
			{
				return;
			}
			if (_now >= _nextHello)
			{
				_nextHello = _now + 3.0;
				if ((int)_mode == 1)
				{
					EnqueuePacket(new SLTPacket
					{
						Kind = (PacketKind)2,
						Revision = Revision
					});
				}
				else
				{
					_transport.SendToHost(WireCodec.Encode(new SLTPacket
					{
						Kind = (PacketKind)1,
						Scene = _scene
					}));
				}
			}
			if (_now >= _nextNetworkWindow)
			{
				_nextNetworkWindow = _now + 1.0;
				_networkBytes = 0;
			}
			(byte[], byte?) result;
			while (_outgoing.TryPeek(out result) && _networkBytes + result.Item1.Length <= _config.MaxNetworkBytesPerSecond)
			{
				_outgoing.Dequeue();
				_networkBytes += result.Item1.Length;
				if (result.Item2.HasValue)
				{
					_transport.SendToPeer(result.Item2.Value, result.Item1);
				}
				else
				{
					_transport.Broadcast(result.Item1);
				}
			}
		}

		private void EnqueuePacket(SLTPacket packet, byte? target = null)
		{
			packet.Scene = _scene;
			packet.Session = _session;
			packet.Sequence = ++_sequence;
			if (_outgoing.Count >= 64)
			{
				_outgoing.Dequeue();
			}
			try
			{
				_outgoing.Enqueue((WireCodec.Encode(packet), target));
			}
			catch (ArgumentException ex)
			{
				_log.Warning("Replication payload rejected: " + ex.Message);
			}
		}

		private void Receive(byte[] bytes, bool fromHost, byte? sender)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Invalid comparison between Unknown and I4
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Invalid comparison between Unknown and I4
			//IL_00a6: 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_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00e0: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			CheckThread();
			SLTPacket packet = default(SLTPacket);
			if (!WireCodec.TryDecode(bytes, ref packet) || packet.Scene != _scene)
			{
				return;
			}
			if ((int)_mode == 1 && (int)packet.Kind == 1 && sender.HasValue)
			{
				if (_helloRates.TryGetValue(sender.Value, out var value) && _now - value < 2.0)
				{
					return;
				}
				_helloRates[sender.Value] = _now;
				EnqueuePacket(new SLTPacket
				{
					Kind = (PacketKind)2,
					Revision = Revision
				}, sender);
				{
					foreach (PathResult value2 in _published.Values)
					{
						EnqueuePacket(new SLTPacket
						{
							Kind = (PacketKind)3,
							Route = value2,
							Revision = Revision
						}, sender);
					}
					return;
				}
			}
			if ((int)_mode != 2 || !_replica.Accept(packet, fromHost))
			{
				return;
			}
			if ((int)packet.Kind == 3 && packet.Route != null)
			{
				PathResult route = packet.Route;
				if (_agents.TryGetValue(route.AgentId, out Registration agent))
				{
					Safely(delegate
					{
						agent.Agent.OnReplicatedNavigation(route);
					});
				}
				Safely(delegate
				{
					this.ReplicatedRoute?.Invoke(route);
				});
			}
			else if ((int)packet.Kind == 4)
			{
				Safely(delegate
				{
					this.MapChanged?.Invoke(packet.Revision);
				});
			}
		}

		private void Safely(Action callback)
		{
			try
			{
				callback();
			}
			catch (Exception ex)
			{
				_log.Warning("Consumer callback failed: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		public void WriteDiagnostics()
		{
			//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)
			CheckThread();
			try
			{
				var value = new
				{
					version = "0.2.0",
					releaseStatus = "Compiled preview; headset verification required",
					gameVersion = Application.version,
					unityVersion = Application.unityVersion,
					platform = ((object)Application.platform/*cast due to .constrained prefix*/).ToString(),
					scene = _scene,
					authority = ((object)Unsafe.As<AuthorityMode, AuthorityMode>(ref _mode)/*cast due to .constrained prefix*/).ToString(),
					transport = (_transport?.Description ?? "None"),
					runtime = RuntimeInformation.FrameworkDescription,
					architecture = RuntimeInformation.ProcessArchitecture.ToString(),
					bonelibRequired = false,
					assemblies = (from a in (from a in AppDomain.CurrentDomain.GetAssemblies()
							select a.GetName()).Where(delegate(AssemblyName a)
						{
							string name = a.Name;
							int num;
							switch (name)
							{
							default:
								num = ((!(name == "SLTCore.Fusion")) ? 1 : 0);
								break;
							case "MelonLoader":
							case "LabFusion":
							case "BoneLib":
							case "SLTCore":
								num = 0;
								break;
							}
							return num == 0;
						})
						group a by a.Name).ToDictionary((IGrouping<string, AssemblyName> g) => g.Key, (IGrouping<string, AssemblyName> g) => string.Join(", ", g.Select((AssemblyName a) => a.Version?.ToString()).Distinct())),
					mappedSurfaces = _map.NodeCount,
					columns = _map.ColumnCount,
					queuedColumns = _mapping.Pending,
					pendingPaths = _requests.Count,
					registeredAgents = _agents.Count,
					trackedObstacles = _obstacles.Count,
					openingProbes = _openingJobs.Count,
					observedOpenings = _openings.Count,
					mapRevision = Revision,
					meanFrameWorkMs = _frameAverage,
					budgetOverruns = _slowFrames,
					saturatedPhysicsBuffers = _saturations,
					physicsQueryReservationsLastFrame = _budget.Used
				};
				File.WriteAllText(Path.Combine(_directory, "diagnostics.json"), JsonSerializer.Serialize(value, SLTConfig.Json));
			}
			catch (Exception ex)
			{
				_log.Warning("Could not write diagnostics: " + ex.Message);
			}
		}

		internal void Shutdown()
		{
			ResetNavigation(clearAgents: true);
			if (_transport != null)
			{
				_transport.Received -= Receive;
			}
		}
	}
	internal sealed class AuthorityProbe
	{
		private double _next;

		private AuthorityMode _cached;

		public AuthorityMode Read(double now)
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_0096: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			if (now < _next)
			{
				return _cached;
			}
			_next = now + 0.5;
			try
			{
				Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "LabFusion");
				if (assembly == null)
				{
					AuthorityMode result = (AuthorityMode)0;
					_cached = (AuthorityMode)0;
					return result;
				}
				Type type = assembly.GetType("LabFusion.Network.NetworkInfo");
				AuthorityMode result2;
				if (type == null)
				{
					result2 = (AuthorityMode)3;
					_cached = (AuthorityMode)3;
					return result2;
				}
				object obj = Read("HasServer");
				if (!(obj is bool))
				{
					result2 = (AuthorityMode)3;
					_cached = (AuthorityMode)3;
					return result2;
				}
				if (!(bool)obj)
				{
					result2 = (AuthorityMode)0;
					_cached = (AuthorityMode)0;
					return result2;
				}
				if (!((Read("IsHost") ?? Read("IsServer")) is bool flag))
				{
					result2 = (AuthorityMode)3;
					_cached = (AuthorityMode)3;
					return result2;
				}
				int num = (flag ? 1 : 2);
				result2 = (AuthorityMode)num;
				_cached = (AuthorityMode)num;
				return result2;
				object? Read(string name)
				{
					object obj3 = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
					if (obj3 == null)
					{
						FieldInfo? field = type.GetField(name, BindingFlags.Static | BindingFlags.Public);
						if ((object)field == null)
						{
							return null;
						}
						obj3 = field.GetValue(null);
					}
					return obj3;
				}
			}
			catch
			{
				AuthorityMode result2 = (AuthorityMode)3;
				_cached = (AuthorityMode)3;
				return result2;
			}
		}
	}
	internal static class UnityConvert
	{
		public static Vector3 Unity(this V3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(v.X, v.Y, v.Z);
		}

		public static V3 SLT(this Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new V3(v.x, v.y, v.z);
		}
	}
	internal sealed class UnityWorld : IWorldQuery
	{
		internal readonly SLTConfig Config;

		internal readonly QueryBudget Budget;

		internal readonly ObstacleTracker Obstacles;

		private readonly Il2CppStructArray<RaycastHit> _hits = new Il2CppStructArray<RaycastHit>(48L);

		private readonly Il2CppReferenceArray<Collider> _overlaps = new Il2CppReferenceArray<Collider>(48L);

		internal const float Skin = 0.045f;

		public UnityWorld(SLTConfig config, QueryBudget budget, ObstacleTracker obstacles)
		{
			Config = config;
			Budget = budget;
			Obstacles = obstacles;
		}

		internal bool Ignored(Collider c)
		{
			if (Object.op_Implicit((Object)(object)c) && c.enabled && !c.isTrigger)
			{
				return Obstacles.IsIgnored(c);
			}
			return true;
		}

		internal bool Ray(Vector3 from, Vector3 direction, float distance, out RaycastHit nearest, int? mask = null)
		{
			//IL_0002: 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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			nearest = default(RaycastHit);
			int num = Physics.RaycastNonAlloc(from, direction, _hits, distance, mask ?? Config.CollisionMask, (QueryTriggerInteraction)1);
			if (num == ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length)
			{
				Budget.Saturated = true;
				return true;
			}
			float num2 = float.MaxValue;
			bool result = false;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				if (!Ignored(((RaycastHit)(ref val)).collider))
				{
					Obstacles.Observe(((RaycastHit)(ref val)).collider);
					if (((RaycastHit)(ref val)).distance < num2)
					{
						nearest = val;
						num2 = ((RaycastHit)(ref val)).distance;
						result = true;
					}
				}
			}
			return result;
		}

		internal bool BodyClear(Vector3 feet, float radius, float height, float lift = 0f)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//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_0030: 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)
			float num = radius + 0.045f + lift;
			float num2 = MathF.Max(num, height - radius + lift);
			int num3 = Physics.OverlapCapsuleNonAlloc(feet + Vector3.up * num, feet + Vector3.up * num2, radius, _overlaps, Config.CollisionMask, (QueryTriggerInteraction)1);
			if (num3 == ((Il2CppArrayBase<Collider>)(object)_overlaps).Length)
			{
				Budget.Saturated = true;
				return false;
			}
			bool result = true;
			for (int i = 0; i < num3; i++)
			{
				Collider c = ((Il2CppArrayBase<Collider>)(object)_overlaps)[i];
				if (!Ignored(c))
				{
					Obstacles.Observe(c);
					result = false;
				}
			}
			return result;
		}

		private bool Sweep(Vector3 feet, Vector3 destination, float radius, float height, float lift)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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)
			Vector3 val = destination - feet;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.001f)
			{
				return true;
			}
			float num = radius + 0.045f + lift;
			float num2 = MathF.Max(num, height - radius + lift);
			int num3 = Physics.CapsuleCastNonAlloc(feet + Vector3.up * num, feet + Vector3.up * num2, radius, val / magnitude, _hits, magnitude, Config.CollisionMask, (QueryTriggerInteraction)1);
			if (num3 == ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length)
			{
				Budget.Saturated = true;
				return false;
			}
			for (int i = 0; i < num3; i++)
			{
				RaycastHit val2 = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				if (!Ignored(((RaycastHit)(ref val2)).collider))
				{
					Obstacles.Observe(((RaycastHit)(ref val2)).collider);
					return false;
				}
			}
			return true;
		}

		internal bool Support(Vector3 p, float above, float below, float slope, out RaycastHit hit)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (Ray(p + Vector3.up * above, Vector3.down, above + below, out hit, Config.FloorMask) && Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider) && ((RaycastHit)(ref hit)).normal.y >= MathF.Cos(slope * (float)Math.PI / 180f))
			{
				if (!Config.AllowDynamicFloors && Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider.attachedRigidbody))
				{
					return ((RaycastHit)(ref hit)).collider.attachedRigidbody.isKinematic;
				}
				return true;
			}
			return false;
		}

		public LinkCheck CheckTraversal(V3 from, V3 to, AgentProfile p)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0063: 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_00ab: 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_00b1: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: 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_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: 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_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Invalid comparison between Unknown and I4
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			if (!p.IsValid || !((V3)(ref from)).IsFinite || !((V3)(ref to)).IsFinite)
			{
				return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
			}
			V3 val = to - from;
			float horizontalLength = ((V3)(ref val)).HorizontalLength;
			if (horizontalLength > 2.5f || MathF.Abs(val.Y) > MathF.Max(p.MaxDrop, 2f))
			{
				return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
			}
			int num = Math.Max(1, (int)MathF.Ceiling(horizontalLength / MathF.Min(0.18f, p.Radius)));
			int count = (num + 1) * 3 + 7;
			if (!Budget.Take(count))
			{
				return new LinkCheck((LinkState)2, (MoveKind)0, 0f);
			}
			Vector3 val2 = from.Unity();
			Vector3 val3 = to.Unity();
			float lift = p.Radius * 0.35f;
			bool num2 = BodyClear(val2, p.Radius, p.Height, lift) && BodyClear(val3, p.Radius, p.Height, lift);
			bool flag = !num2;
			float height = (num2 ? p.Height : p.CrouchHeight);
			if (flag && (!p.CanCrouch || !BodyClear(val2, p.Radius, height, lift) || !BodyClear(val3, p.Radius, height, lift)))
			{
				return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
			}
			float y = val.Y;
			MoveKind val4 = (MoveKind)(flag ? 1 : 0);
			bool num3 = y > 0.06f && y <= p.StepHeight + 0.01f;
			bool flag2 = y < -0.06f && 0f - y <= p.MaxDrop + 0.01f;
			Vector3 val5 = val2;
			Vector3 val6 = val3;
			if (num3)
			{
				val5 += Vector3.up * y;
				if (!Sweep(val2, val5, p.Radius, height, lift) || !BodyClear(val5, p.Radius, height, lift))
				{
					return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
				}
				if (!flag)
				{
					val4 = (MoveKind)2;
				}
			}
			else if (flag2)
			{
				val6 += Vector3.up * (0f - y);
				if (!Sweep(val6, val3, p.Radius, height, lift) || !BodyClear(val6, p.Radius, height, lift))
				{
					return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
				}
				if (!flag)
				{
					val4 = (MoveKind)3;
				}
			}
			if (!Sweep(val5, val6, p.Radius, height, lift))
			{
				return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
			}
			Vector3 val7 = (Vector3)((horizontalLength > 0.001f) ? (new Vector3((0f - val.Z) / horizontalLength, 0f, val.X / horizontalLength) * p.Radius * 0.75f) : new Vector3(p.Radius * 0.75f, 0f, 0f));
			float? num4 = null;
			for (int i = 0; i <= num; i++)
			{
				Vector3 val8 = Vector3.Lerp(val2, val3, (float)i / (float)num);
				float above = p.StepHeight + 0.12f;
				float below = MathF.Max(0.18f, flag2 ? (0f - y + 0.05f) : 0.18f);
				if (!Support(val8, above, below, p.MaxSlopeDegrees, out var hit) || !Support(val8 + val7, above, below, p.MaxSlopeDegrees, out var hit2) || !Support(val8 - val7, above, below, p.MaxSlopeDegrees, out hit2))
				{
					return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
				}
				if (num4.HasValue)
				{
					float num5 = ((RaycastHit)(ref hit)).point.y - num4.Value;
					if (num5 > p.StepHeight + 0.025f || 0f - num5 > p.MaxDrop + 0.025f)
					{
						return new LinkCheck((LinkState)0, (MoveKind)0, 0f);
					}
				}
				num4 = ((RaycastHit)(ref hit)).point.y;
			}
			return new LinkCheck((LinkState)1, val4, (flag ? 0.18f : 0f) + (((int)val4 == 3) ? 0.35f : 0f));
		}

		internal RaycastHit[] ColumnHits(ColumnKey key, WorldMap map, out bool overflow)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = map.ColumnCenter(key).Unity();
			val.y = (float)(((ColumnKey)(ref key)).Band + 1) * map.BandHeight + 0.02f;
			int num = Physics.RaycastNonAlloc(val, Vector3.down, _hits, map.BandHeight + 0.04f, Config.FloorMask, (QueryTriggerInteraction)1);
			overflow = num == ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length;
			if (overflow)
			{
				Budget.Saturated = true;
				return Array.Empty<RaycastHit>();
			}
			List<RaycastHit> list = new List<RaycastHit>(num);
			for (int i = 0; i < num; i++)
			{
				RaycastHit item = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				if (!Ignored(((RaycastHit)(ref item)).collider) && !(((RaycastHit)(ref item)).normal.y < 0.42f) && !(map.ColumnAt(((RaycastHit)(ref item)).point.SLT()) != key))
				{
					Obstacles.Observe(((RaycastHit)(ref item)).collider);
					list.Add(item);
				}
			}
			list.Sort((RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).point.y.CompareTo(((RaycastHit)(ref b)).point.y));
			return list.ToArray();
		}

		internal Surface? SurfaceAt(RaycastHit hit, WorldMap map)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: 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_016f: 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_0177: 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: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider))
			{
				return null;
			}
			Vector3 point = ((RaycastHit)(ref hit)).point;
			Rigidbody attachedRigidbody = ((RaycastHit)(ref hit)).collider.attachedRigidbody;
			bool flag = Object.op_Implicit((Object)(object)attachedRigidbody) && !attachedRigidbody.isKinematic;
			if (flag && !Config.AllowDynamicFloors)
			{
				return null;
			}
			float minimumMappedRadius = Config.MinimumMappedRadius;
			if (!BodyClear(point, minimumMappedRadius, Config.MinimumMappedHeight, minimumMappedRadius * 0.35f))
			{
				return null;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[4]
			{
				Vector3.right * minimumMappedRadius,
				Vector3.left * minimumMappedRadius,
				Vector3.forward * minimumMappedRadius,
				Vector3.back * minimumMappedRadius
			};
			foreach (Vector3 val in array)
			{
				if (!Support(point + val, 0.25f, 0.2f, 65f, out var _))
				{
					return null;
				}
			}
			float num = Config.MaxMeasuredHeadroom;
			if (Ray(point + Vector3.up * 0.025f, Vector3.up, num, out var nearest))
			{
				if (!Object.op_Implicit((Object)(object)((RaycastHit)(ref nearest)).collider))
				{
					return null;
				}
				num = ((RaycastHit)(ref nearest)).distance + 0.025f;
			}
			return new Surface(map.KeyAt(point.SLT()), point.SLT(), ((RaycastHit)(ref hit)).normal.y, num, flag);
		}

		internal bool OpeningPixelFree(Vector3 point, Vector3 normal, float radius, float depth)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = point - normal * depth * 0.5f;
			int num = Physics.OverlapSphereNonAlloc(val, radius, _overlaps, Config.CollisionMask, (QueryTriggerInteraction)1);
			if (num == ((Il2CppArrayBase<Collider>)(object)_overlaps).Length)
			{
				Budget.Saturated = true;
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				if (!Ignored(((Il2CppArrayBase<Collider>)(object)_overlaps)[i]))
				{
					return false;
				}
			}
			num = Physics.SphereCastNonAlloc(val, radius, normal, _hits, depth, Config.CollisionMask, (QueryTriggerInteraction)1);
			if (num == ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length)
			{
				Budget.Saturated = true;
				return false;
			}
			for (int j = 0; j < num; j++)
			{
				RaycastHit val2 = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[j];
				if (!Ignored(((RaycastHit)(ref val2)).collider))
				{
					ObstacleTracker obstacles = Obstacles;
					val2 = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[j];
					obstacles.Observe(((RaycastHit)(ref val2)).collider);
					return false;
				}
			}
			return true;
		}
	}
	internal sealed class ColumnScan
	{
		private readonly ColumnKey _key;

		private RaycastHit[]? _hits;

		private int _index;

		private readonly List<Surface> _surfaces = new List<Surface>();

		public ColumnScan(ColumnKey key)
		{
			//IL_0012: 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)
			_key = key;
		}

		public bool Step(UnityWorld world, WorldMap map, double now)
		{
			//IL_0093: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			if (_hits == null)
			{
				if (!world.Budget.Take(1))
				{
					return false;
				}
				_hits = world.ColumnHits(_key, map, out var _);
			}
			while (_index < _hits.Length && _surfaces.Count < 24)
			{
				if (!world.Budget.Take(6))
				{
					return false;
				}
				Surface val = world.SurfaceAt(_hits[_index++], map);
				if (val != null)
				{
					_surfaces.Add(val);
				}
			}
			map.Replace(_key, _surfaces, now);
			return true;
		}
	}
	public sealed class ObstacleInfo
	{
		public string Id { get; internal set; } = "";

		public V3 Center { get; internal set; }

		public V3 Size { get; internal set; }

		public ObstacleKind Kind { get; internal set; }

		public bool ConfirmedBreakable { get; internal set; }

		public bool IsActive { get; internal set; }

		public double ObservedAt { get; internal set; }
	}
	internal sealed class ObstacleTracker
	{
		private sealed class Entry
		{
			public Collider Collider;

			public ObstacleInfo Info = new ObstacleInfo();

			public Bounds Last;

			public Quaternion Rotation;

			public double LastSeen;

			public bool Persistent;
		}

		private readonly Dictionary<int, Entry> _tracked = new Dictionary<int, Entry>();

		private readonly Dictionary<int, double> _checked = new Dictionary<int, double>();

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

		private readonly int _limit;

		private int _cursor;

		public double Now { get; set; }

		public int Count => _tracked.Count;

		public event Action<Bounds>? Dirty;

		public event Action<ObstacleInfo>? Changed;

		public ObstacleTracker(int limit)
		{
			_limit = limit;
		}

		public bool IsIgnored(Collider c)
		{
			if (Object.op_Implicit((Object)(object)c))
			{
				return _ignored.ContainsKey(((Object)c).GetInstanceID());
			}
			return false;
		}

		public void Ignore(Collider c, bool ignored)
		{
			if (Object.op_Implicit((Object)(object)c))
			{
				IgnoreId(((Object)c).GetInstanceID(), ignored);
			}
		}

		public void IgnoreId(int id, bool ignored)
		{
			_ignored.TryGetValue(id, out var value);
			if (ignored)
			{
				_ignored[id] = value + 1;
				_tracked.Remove(id);
			}
			else if (value <= 1)
			{
				_ignored.Remove(id);
			}
			else
			{
				_ignored[id] = value - 1;
			}
		}

		public void Observe(Collider c)
		{
			if (!Object.op_Implicit((Object)(object)c) || IsIgnored(c))
			{
				return;
			}
			int instanceID = ((Object)c).GetInstanceID();
			double value2;
			if (_tracked.TryGetValue(instanceID, out Entry value))
			{
				value.LastSeen = Now;
			}
			else if (_tracked.Count < _limit && (!_checked.TryGetValue(instanceID, out value2) || !(Now - value2 < 5.0)))
			{
				if (_checked.Count >= _limit * 4)
				{
					_checked.Clear();
				}
				_checked[instanceID] = Now;
				bool num = Object.op_Implicit((Object)(object)c.attachedRigidbody);
				ObjectDestructible componentInParent = ((Component)c).GetComponentInParent<ObjectDestructible>();
				if (num || Object.op_Implicit((Object)(object)componentInParent))
				{
					Track(c, "local:" + instanceID, (ObstacleKind)((!Object.op_Implicit((Object)(object)componentInParent)) ? 1 : 3), Object.op_Implicit((Object)(object)componentInParent));
				}
			}
		}

		public void Register(Collider collider, string stableId, ObstacleKind kind, bool confirmedBreakable)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)collider) || string.IsNullOrWhiteSpace(stableId) || stableId.Length > 96)
			{
				throw new ArgumentException("Invalid obstacle registration");
			}
			if (_tracked.Count >= _limit && !_tracked.ContainsKey(((Object)collider).GetInstanceID()))
			{
				throw new InvalidOperationException("Obstacle registration limit reached");
			}
			Track(collider, stableId, kind, confirmedBreakable);
			_tracked[((Object)collider).GetInstanceID()].Persistent = true;
		}

		private void Track(Collider c, string id, ObstacleKind kind, bool confirmed)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			if (_tracked.Count < _limit || _tracked.ContainsKey(((Object)c).GetInstanceID()))
			{
				Bounds bounds = c.bounds;
				_tracked[((Object)c).GetInstanceID()] = new Entry
				{
					Collider = c,
					Last = bounds,
					Rotation = ((Component)c).transform.rotation,
					LastSeen = Now,
					Info = new ObstacleInfo
					{
						Id = id,
						Center = ((Bounds)(ref bounds)).center.SLT(),
						Size = ((Bounds)(ref bounds)).size.SLT(),
						Kind = kind,
						ConfirmedBreakable = confirmed,
						IsActive = (c.enabled && ((Component)c).gameObject.activeInHierarchy),
						ObservedAt = Now
					}
				};
			}
		}

		public void Tick(int max = 32)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_0127: 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_00e8: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			int[] array = _tracked.Keys.ToArray();
			if (array.Length == 0)
			{
				return;
			}
			int num2 = _cursor % array.Length;
			int num3 = 0;
			while (num3 < array.Length && num < max)
			{
				int key = array[(num2 + num3) % array.Length];
				Entry entry = _tracked[key];
				Collider collider = entry.Collider;
				bool flag = Object.op_Implicit((Object)(object)collider) && collider.enabled && ((Component)collider).gameObject.activeInHierarchy;
				Bounds val = (flag ? collider.bounds : entry.Last);
				Vector3 val2 = ((Bounds)(ref val)).center - ((Bounds)(ref entry.Last)).center;
				int num4;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0009f))
				{
					val2 = ((Bounds)(ref val)).size - ((Bounds)(ref entry.Last)).size;
					if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0009f))
					{
						num4 = ((flag && Quaternion.Angle(((Component)collider).transform.rotation, entry.Rotation) > 2f) ? 1 : 0);
						goto IL_00ff;
					}
				}
				num4 = 1;
				goto IL_00ff;
				IL_00ff:
				bool flag2 = (byte)num4 != 0;
				if (flag != entry.Info.IsActive || flag2)
				{
					Bounds last = entry.Last;
					((Bounds)(ref last)).Encapsulate(val);
					((Bounds)(ref last)).Expand(0.75f);
					this.Dirty?.Invoke(last);
					entry.Last = val;
					entry.Info.Center = ((Bounds)(ref val)).center.SLT();
					entry.Info.Size = ((Bounds)(ref val)).size.SLT();
					entry.Info.IsActive = flag;
					entry.Info.ObservedAt = Now;
					if (flag)
					{
						entry.Rotation = ((Component)collider).transform.rotation;
					}
					this.Changed?.Invoke(entry.Info);
				}
				if (!Object.op_Implicit((Object)(object)collider) || (Now - entry.LastSeen > 45.0 && !entry.Persistent))
				{
					_tracked.Remove(key);
				}
				num3++;
				num++;
			}
			_cursor = num2 + num;
		}

		public void Unregister(string stableId)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			KeyValuePair<int, Entry>[] array = _tracked.Where<KeyValuePair<int, Entry>>((KeyValuePair<int, Entry> p) => p.Value.Info.Id == stableId).ToArray();
			for (int num = 0; num < array.Length; num++)
			{
				KeyValuePair<int, Entry> keyValuePair = array[num];
				this.Dirty?.Invoke(keyValuePair.Value.Last);
				_tracked.Remove(keyValuePair.Key);
			}
		}

		public IReadOnlyList<ObstacleInfo> Nearby(V3 center, float radius)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return (from e in _tracked.Values
				where V3.Distance(e.Info.Center, center) <= radius
				select new ObstacleInfo
				{
					Id = e.Info.Id,
					Center = e.Info.Center,
					Size = e.Info.Size,
					Kind = e.Info.Kind,
					ConfirmedBreakable = e.Info.ConfirmedBreakable,
					IsActive = e.Info.IsActive,
					ObservedAt = e.Info.ObservedAt
				}).ToArray();
		}

		public void Clear()
		{
			_tracked.Clear();
			_checked.Clear();
			_ignored.Clear();
			_cursor = 0;
		}
	}
	public sealed class SLTConfig
	{
		internal static readonly JsonSerializerOptions Json = new JsonSerializerOptions
		{
			WriteIndented = true,
			PropertyNameCaseInsensitive = true
		};

		public bool Enabled { get; set; } = true;

		public float CellSize { get; set; } = 0.5f;

		public float ScanRadius { get; set; } = 8f;

		public float BandHeight { get; set; } = 6f;

		public float RescanSeconds { get; set; } = 10f;

		public float MaxMapAgeSeconds { get; set; } = 30f;

		public double FrameBudgetMilliseconds { get; set; } = 1.2;

		public int PhysicsQueriesPerFrame { get; set; } = 128;

		public int ScanQueriesPerFrame { get; set; } = 48;

		public int MovementQueryReserve { get; set; } = 48;

		public int MaxColumns { get; set; } = 7000;

		public int MaxTrackedObstacles { get; set; } = 512;

		public int MaxRegisteredAgents { get; set; } = 32;

		public int MaxConcurrentPaths { get; set; } = 4;

		public int MaxQueuedPaths { get; set; } = 48;

		public int MaxSearchVisits { get; set; } = 4096;

		public int CollisionMask { get; set; } = -5;

		public int FloorMask { get; set; } = -5;

		public bool AllowDynamicFloors { get; set; }

		public float MinimumMappedRadius { get; set; } = 0.15f;

		public float MinimumMappedHeight { get; set; } = 0.45f;

		public float MaxMeasuredHeadroom { get; set; } = 4f;

		public int MaxNetworkBytesPerSecond { get; set; } = 24576;

		public bool WriteDiagnostics { get; set; } = true;

		public void Clamp()
		{
			CellSize = F(CellSize, 0.3f, 1.2f, 0.5f);
			ScanRadius = F(ScanRadius, 3f, 16f, 8f);
			BandHeight = F(BandHeight, 3f, 10f, 6f);
			RescanSeconds = F(RescanSeconds, 3f, 60f, 10f);
			MaxMapAgeSeconds = F(MaxMapAgeSeconds, RescanSeconds + 5f, 120f, 30f);
			FrameBudgetMilliseconds = (double.IsFinite(FrameBudgetMilliseconds) ? Math.Clamp(FrameBudgetMilliseconds, 0.2, 3.0) : 1.2);
			PhysicsQueriesPerFrame = Math.Clamp(PhysicsQueriesPerFrame, 32, 384);
			MovementQueryReserve = Math.Clamp(MovementQueryReserve, 8, PhysicsQueriesPerFrame / 2);
			ScanQueriesPerFrame = Math.Clamp(ScanQueriesPerFrame, 8, PhysicsQueriesPerFrame - MovementQueryReserve - 8);
			MaxColumns = Math.Clamp(MaxColumns, 500, 20000);
			MaxTrackedObstacles = Math.Clamp(MaxTrackedObstacles, 32, 2048);
			MaxRegisteredAgents = Math.Clamp(MaxRegisteredAgents, 1, 64);
			MaxConcurrentPaths = Math.Clamp(MaxConcurrentPaths, 1, 8);
			MaxQueuedPaths = Math.Clamp(MaxQueuedPaths, 1, 128);
			MaxSearchVisits = Math.Clamp(MaxSearchVisits, 128, 16000);
			MinimumMappedRadius = F(MinimumMappedRadius, 0.1f, 0.3f, 0.15f);
			MinimumMappedHeight = F(MinimumMappedHeight, MinimumMappedRadius * 2f, 0.9f, 0.45f);
			MaxMeasuredHeadroom = F(MaxMeasuredHeadroom, 2f, 6f, 4f);
			MaxNetworkBytesPerSecond = Math.Clamp(MaxNetworkBytesPerSecond, 4096, 65536);
			static float F(float v, float min, float max, float fallback)
			{
				if (!float.IsFinite(v))
				{
					return fallback;
				}
				return Math.Clamp(v, min, max);
			}
		}

		public static SLTConfig Load(string path, Instance log)
		{
			SLTConfig sLTConfig;
			try
			{
				sLTConfig = (File.Exists(path) ? (JsonSerializer.Deserialize<SLTConfig>(File.ReadAllText(path), Json) ?? new SLTConfig()) : new SLTConfig());
			}
			catch (Exception ex)
			{
				log.Warning("Config could not be read; using defaults: " + ex.Message);
				sLTConfig = new SLTConfig();
			}
			sLTConfig.Clamp();
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			File.WriteAllText(path, JsonSerializer.Serialize(sLTConfig, Json));
			return sLTConfig;
		}
	}
	internal sealed class QueryBudget
	{
		public int Used { get; private set; }

		public int Limit { get; private set; }

		public bool Saturated { get; set; }

		public void Reset(int limit)
		{
			Used = 0;
			Limit = limit;
			Saturated = false;
		}

		public void SetLimit(int limit)
		{
			Limit = limit;
		}

		public bool Take(int count)
		{
			if (Used + count > Limit)
			{
				return false;
			}
			Used += count;
			return true;
		}
	}
	public sealed class SLTMod : MelonMod
	{
		public override void OnInitializeMelon()
		{
			string text = Path.Combine(MelonUtils.UserDataDirectory, "SLTCore");
			Directory.CreateDirectory(text);
			SLTAPI.Announce(new SLTService(SLTConfig.Load(Path.Combine(text, "config.json"), ((MelonBase)this).LoggerInstance), ((MelonBase)this).LoggerInstance, text));
			((MelonBase)this).LoggerInstance.Msg("SLTCore 0.2.0 preview loaded. Navigation framework; NPC integration is required. BoneLib is optional.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			SLTAPI.Service?.SceneChanged(sceneName);
		}

		public override void OnUpdate()
		{
			SLTAPI.Service?.Tick();
		}

		public override void OnDeinitializeMelon()
		{
			SLTAPI.Service?.Shutdown();
			SLTAPI.Service = null;
		}
	}
	public static class NavigationTargets
	{
		public static NavigationTarget TrackTransform(Transform target, V3 worldOffset = default(V3))
		{
			//IL_000d: 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)
			if (!((V3)(ref worldOffset)).IsFinite)
			{
				throw new ArgumentException("Offset must be finite", "worldOffset");
			}
			return NavigationTarget.Resolve((Func<V3?>)(() => (!Object.op_Implicit((Object)(object)target)) ? ((V3?)null) : new V3?(target.position.SLT() + worldOffset)));
		}
	}
	internal sealed class MapScheduler
	{
		private readonly WorldMap _map;

		private readonly SLTConfig _config;

		private readonly Queue<ColumnKey> _urgent = new Queue<ColumnKey>();

		private readonly HashSet<ColumnKey> _urgentSet = new HashSet<ColumnKey>();

		private readonly Queue<ColumnKey> _normal = new Queue<ColumnKey>();

		private readonly HashSet<ColumnKey> _normalSet = new HashSet<ColumnKey>();

		private readonly List<IEnumerator<ColumnKey>> _areas = new List<IEnumerator<ColumnKey>>();

		private ColumnScan? _active;

		private ColumnKey _activeKey;

		private int _areaCursor;

		public int Pending => _urgentSet.Count + _normalSet.Count;

		public MapScheduler(WorldMap map, SLTConfig config)
		{
			_map = map;
			_config = config;
		}

		public void Focus(V3 p)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing refe

UserLibs/SLTCore.Core.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace SLTCore.Core
{
	public abstract class NavigationTarget
	{
		private sealed class FixedTarget : NavigationTarget
		{
			private readonly V3 _position;

			public FixedTarget(V3 position)
			{
				_position = position;
			}

			public override bool TryGetPosition(out V3 feetPosition)
			{
				feetPosition = _position;
				return true;
			}
		}

		private sealed class ResolvedTarget : NavigationTarget
		{
			private readonly Func<V3?> _resolver;

			public ResolvedTarget(Func<V3?> resolver)
			{
				_resolver = resolver;
			}

			public override bool TryGetPosition(out V3 feetPosition)
			{
				feetPosition = default(V3);
				try
				{
					V3? v = _resolver();
					if (!v.HasValue || !Usable(v.Value))
					{
						return false;
					}
					feetPosition = v.Value;
					return true;
				}
				catch
				{
					return false;
				}
			}
		}

		public abstract bool TryGetPosition(out V3 feetPosition);

		public static NavigationTarget At(V3 feetPosition)
		{
			if (!Usable(feetPosition))
			{
				throw new ArgumentException("A finite destination within world limits is required", "feetPosition");
			}
			return new FixedTarget(feetPosition);
		}

		public static NavigationTarget Resolve(Func<V3?> resolver)
		{
			if (resolver == null)
			{
				throw new ArgumentNullException("resolver");
			}
			return new ResolvedTarget(resolver);
		}

		private static bool Usable(V3 p)
		{
			if (p.IsFinite)
			{
				return p.Length < 50000f;
			}
			return false;
		}
	}
	public enum PacketKind : byte
	{
		SessionRequest = 1,
		Session,
		Route,
		Invalidate
	}
	public sealed class SLTPacket
	{
		public PacketKind Kind { get; set; }

		public Guid Session { get; set; }

		public uint Sequence { get; set; }

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

		public long Revision { get; set; }

		public PathResult? Route { get; set; }
	}
	public static class WireCodec
	{
		public const ushort Protocol = 1;

		public const int MaxPacketBytes = 16384;

		public const int MaxWaypoints = 512;

		private const uint Magic = 1129598035u;

		private static readonly UTF8Encoding Utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);

		public static byte[] Encode(SLTPacket p)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Utf8, leaveOpen: true);
			binaryWriter.Write(1129598035u);
			binaryWriter.Write((ushort)1);
			binaryWriter.Write((byte)p.Kind);
			binaryWriter.Write(p.Session.ToByteArray());
			binaryWriter.Write(p.Sequence);
			Text(binaryWriter, p.Scene, 128);
			binaryWriter.Write(p.Revision);
			if (p.Kind == PacketKind.Route)
			{
				PathResult pathResult = p.Route ?? throw new ArgumentException("Missing route");
				if (pathResult.Points.Count > 512)
				{
					throw new ArgumentException("Route too long");
				}
				binaryWriter.Write(pathResult.RequestId);
				Text(binaryWriter, pathResult.AgentId, 96);
				binaryWriter.Write((byte)pathResult.Status);
				binaryWriter.Write(pathResult.Revision);
				Text(binaryWriter, pathResult.Reason, 192);
				binaryWriter.Write((ushort)pathResult.Points.Count);
				foreach (Waypoint point in pathResult.Points)
				{
					if (!point.Feet.IsFinite || point.Feet.Length > 50000f || !Enum.IsDefined(typeof(MoveKind), point.Kind))
					{
						throw new ArgumentException("Invalid waypoint");
					}
					binaryWriter.Write(point.Feet.X);
					binaryWriter.Write(point.Feet.Y);
					binaryWriter.Write(point.Feet.Z);
					binaryWriter.Write((byte)point.Kind);
					Text(binaryWriter, point.ActionId, 96);
				}
			}
			if (memoryStream.Length > 16384)
			{
				throw new ArgumentException("Packet exceeds limit");
			}
			return memoryStream.ToArray();
		}

		public static bool TryDecode(byte[] bytes, out SLTPacket packet)
		{
			packet = new SLTPacket();
			if (bytes == null || bytes.Length < 35 || bytes.Length > 16384)
			{
				return false;
			}
			try
			{
				using MemoryStream memoryStream = new MemoryStream(bytes, writable: false);
				using BinaryReader binaryReader = new BinaryReader(memoryStream, Utf8);
				if (binaryReader.ReadUInt32() != 1129598035 || binaryReader.ReadUInt16() != 1)
				{
					return false;
				}
				PacketKind packetKind = (PacketKind)binaryReader.ReadByte();
				if (!Enum.IsDefined(typeof(PacketKind), packetKind))
				{
					return false;
				}
				byte[] array = binaryReader.ReadBytes(16);
				if (array.Length != 16)
				{
					return false;
				}
				Guid session = new Guid(array);
				uint sequence = binaryReader.ReadUInt32();
				string scene = Text(binaryReader, 128);
				long revision = binaryReader.ReadInt64();
				SLTPacket sLTPacket = new SLTPacket
				{
					Kind = packetKind,
					Session = session,
					Sequence = sequence,
					Scene = scene,
					Revision = revision
				};
				if (packetKind == PacketKind.Route)
				{
					long num = binaryReader.ReadInt64();
					string text = Text(binaryReader, 96);
					PathStatus pathStatus = (PathStatus)binaryReader.ReadByte();
					long revision2 = binaryReader.ReadInt64();
					string reason = Text(binaryReader, 192);
					int num2 = binaryReader.ReadUInt16();
					if (!Enum.IsDefined(typeof(PathStatus), pathStatus) || num < 1 || string.IsNullOrWhiteSpace(text) || num2 > 512 || num2 * 15 > memoryStream.Length - memoryStream.Position)
					{
						return false;
					}
					List<Waypoint> list = new List<Waypoint>(num2);
					for (int i = 0; i < num2; i++)
					{
						V3 feet = new V3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
						MoveKind moveKind = (MoveKind)binaryReader.ReadByte();
						string actionId = Text(binaryReader, 96);
						if (!feet.IsFinite || feet.Length > 50000f || !Enum.IsDefined(typeof(MoveKind), moveKind))
						{
							return false;
						}
						list.Add(new Waypoint(feet, moveKind, actionId));
					}
					if ((pathStatus == PathStatus.Complete || pathStatus == PathStatus.Partial) && num2 == 0)
					{
						return false;
					}
					sLTPacket.Route = new PathResult(num, text, pathStatus, revision2, list, reason);
				}
				if (memoryStream.Position != memoryStream.Length)
				{
					return false;
				}
				packet = sLTPacket;
				return true;
			}
			catch (Exception ex) when (ex is IOException || ex is ArgumentException || ex is OverflowException)
			{
				return false;
			}
		}

		private static void Text(BinaryWriter writer, string text, int max)
		{
			byte[] bytes = Utf8.GetBytes(text);
			if (text.Length > max || bytes.Length > max * 4)
			{
				throw new ArgumentException("Text exceeds protocol limit");
			}
			writer.Write((ushort)bytes.Length);
			writer.Write(bytes);
		}

		private static string Text(BinaryReader reader, int max)
		{
			int num = reader.ReadUInt16();
			if (num > max * 4)
			{
				throw new InvalidDataException("Text exceeds protocol limit");
			}
			byte[] array = reader.ReadBytes(num);
			if (array.Length != num)
			{
				throw new EndOfStreamException();
			}
			string text = Utf8.GetString(array);
			if (text.Length > max)
			{
				throw new InvalidDataException();
			}
			return text;
		}
	}
	public sealed class ReplicaGate
	{
		private readonly Dictionary<string, uint> _last = new Dictionary<string, uint>(StringComparer.Ordinal);

		private uint? _lastInvalidate;

		public Guid Session { get; private set; }

		public string Scene { get; private set; } = "";

		public void Reset(string scene)
		{
			Scene = scene;
			Session = Guid.Empty;
			_last.Clear();
			_lastInvalidate = null;
		}

		public bool Accept(SLTPacket packet, bool fromHost)
		{
			if (!fromHost || packet.Scene != Scene || packet.Session == Guid.Empty)
			{
				return false;
			}
			if (packet.Kind == PacketKind.Session)
			{
				if (Session != packet.Session)
				{
					Session = packet.Session;
					_last.Clear();
					_lastInvalidate = null;
				}
				return true;
			}
			if (packet.Session != Session || Session == Guid.Empty)
			{
				return false;
			}
			if (packet.Kind == PacketKind.Invalidate)
			{
				if (_lastInvalidate.HasValue && (int)(packet.Sequence - _lastInvalidate.Value) <= 0)
				{
					return false;
				}
				_lastInvalidate = packet.Sequence;
				return true;
			}
			if (packet.Kind != PacketKind.Route || packet.Route == null)
			{
				return false;
			}
			string agentId = packet.Route.AgentId;
			if (_last.TryGetValue(agentId, out var value) && (int)(packet.Sequence - value) <= 0)
			{
				return false;
			}
			if (_last.Count >= 64 && !_last.ContainsKey(agentId))
			{
				return false;
			}
			_last[agentId] = packet.Sequence;
			return true;
		}
	}
	public readonly struct V3 : IEquatable<V3>
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public bool IsFinite
		{
			get
			{
				if (float.IsFinite(X) && float.IsFinite(Y))
				{
					return float.IsFinite(Z);
				}
				return false;
			}
		}

		public float Length => MathF.Sqrt(X * X + Y * Y + Z * Z);

		public float HorizontalLength => MathF.Sqrt(X * X + Z * Z);

		public V3 Normalized
		{
			get
			{
				if (!(Length > 1E-05f))
				{
					return default(V3);
				}
				return this / Length;
			}
		}

		public V3(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public static V3 operator +(V3 a, V3 b)
		{
			return new V3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
		}

		public static V3 operator -(V3 a, V3 b)
		{
			return new V3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
		}

		public static V3 operator *(V3 a, float b)
		{
			return new V3(a.X * b, a.Y * b, a.Z * b);
		}

		public static V3 operator /(V3 a, float b)
		{
			return new V3(a.X / b, a.Y / b, a.Z / b);
		}

		public static float Distance(V3 a, V3 b)
		{
			return (a - b).Length;
		}

		public bool Equals(V3 b)
		{
			if (X.Equals(b.X) && Y.Equals(b.Y))
			{
				return Z.Equals(b.Z);
			}
			return false;
		}

		public override bool Equals(object? o)
		{
			if (o is V3 b)
			{
				return Equals(b);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(X, Y, Z);
		}

		public override string ToString()
		{
			return $"({X:0.00}, {Y:0.00}, {Z:0.00})";
		}
	}
	public readonly record struct ColumnKey(int X, int Z, int Band);
	public readonly record struct NodeKey(int X, int Y, int Z);
	public enum MoveKind : byte
	{
		Walk,
		Crouch,
		Step,
		Drop,
		Jump,
		Climb,
		Break,
		Custom
	}
	public enum LinkState : byte
	{
		Blocked,
		Clear,
		Deferred
	}
	public enum PathStatus : byte
	{
		Complete,
		Partial,
		NoPath,
		AwaitingMap,
		InvalidRequest,
		Cancelled,
		TimedOut,
		MapChanged,
		TooComplex,
		AuthorityUnavailable,
		Busy,
		TooLong,
		TargetUnavailable
	}
	public enum OpeningKind : byte
	{
		Wall,
		Floor,
		Ceiling
	}
	public enum ObstacleKind : byte
	{
		Solid,
		Movable,
		BreakableCandidate,
		ConfirmedBreakable,
		Door,
		Glass
	}
	public enum AuthorityMode : byte
	{
		SinglePlayer,
		Host,
		Client,
		Unknown
	}
	public sealed class AgentProfile
	{
		public float Radius { get; set; } = 0.28f;

		public float Height { get; set; } = 1.75f;

		public float CrouchHeight { get; set; } = 1.05f;

		public float StepHeight { get; set; } = 0.3f;

		public float MaxSlopeDegrees { get; set; } = 42f;

		public float MaxDrop { get; set; } = 0.4f;

		public bool CanCrouch { get; set; } = true;

		public bool CanBreak { get; set; }

		public bool CanJump { get; set; }

		public bool CanClimb { get; set; }

		public float ExtraCost { get; set; }

		public bool IsValid
		{
			get
			{
				if (float.IsFinite(Radius) && Radius >= 0.1f && Radius <= 2f && float.IsFinite(Height) && Height >= Radius * 2f && Height <= 5f && float.IsFinite(CrouchHeight) && CrouchHeight >= Radius * 2f && CrouchHeight <= Height && float.IsFinite(StepHeight) && StepHeight >= 0f && StepHeight <= 1f && float.IsFinite(MaxSlopeDegrees) && MaxSlopeDegrees >= 0f && MaxSlopeDegrees <= 65f && float.IsFinite(MaxDrop) && MaxDrop >= 0f && MaxDrop <= 4f && float.IsFinite(ExtraCost) && ExtraCost >= 0f)
				{
					return ExtraCost <= 100f;
				}
				return false;
			}
		}

		public AgentProfile Copy()
		{
			return (AgentProfile)MemberwiseClone();
		}

		public bool Allows(MoveKind kind)
		{
			return kind switch
			{
				MoveKind.Crouch => CanCrouch, 
				MoveKind.Break => CanBreak, 
				MoveKind.Jump => CanJump, 
				MoveKind.Climb => CanClimb, 
				MoveKind.Custom => false, 
				_ => true, 
			};
		}
	}
	public sealed class Surface
	{
		public NodeKey Key { get; }

		public V3 Feet { get; }

		public float NormalY { get; }

		public float Headroom { get; }

		public bool Dynamic { get; }

		public Surface(NodeKey key, V3 feet, float normalY, float headroom, bool dynamic = false)
		{
			Key = key;
			Feet = feet;
			NormalY = normalY;
			Headroom = headroom;
			Dynamic = dynamic;
		}

		public bool Fits(AgentProfile p)
		{
			if (NormalY >= MathF.Cos(p.MaxSlopeDegrees * (float)Math.PI / 180f))
			{
				return Headroom + 0.01f >= (p.CanCrouch ? p.CrouchHeight : p.Height);
			}
			return false;
		}

		internal bool Equivalent(Surface other)
		{
			if (Key == other.Key && V3.Distance(Feet, other.Feet) < 0.01f && MathF.Abs(Headroom - other.Headroom) < 0.03f && MathF.Abs(NormalY - other.NormalY) < 0.02f)
			{
				return Dynamic == other.Dynamic;
			}
			return false;
		}
	}
	public readonly record struct Waypoint(V3 Feet, MoveKind Kind = MoveKind.Walk, string ActionId = "");
	public sealed class PathResult
	{
		public long RequestId { get; }

		public string AgentId { get; }

		public PathStatus Status { get; }

		public long Revision { get; }

		public IReadOnlyList<Waypoint> Points { get; }

		public string Reason { get; }

		public bool CanExecute
		{
			get
			{
				if (Status != PathStatus.Complete)
				{
					return Status == PathStatus.Partial;
				}
				return true;
			}
		}

		public PathResult(long requestId, string agentId, PathStatus status, long revision, IReadOnlyList<Waypoint>? points = null, string reason = "")
		{
			RequestId = requestId;
			AgentId = agentId;
			Status = status;
			Revision = revision;
			IReadOnlyList<Waypoint> readOnlyList2;
			if (points != null)
			{
				IReadOnlyList<Waypoint> readOnlyList = new List<Waypoint>(points).AsReadOnly();
				readOnlyList2 = readOnlyList;
			}
			else
			{
				IReadOnlyList<Waypoint> readOnlyList = Array.Empty<Waypoint>();
				readOnlyList2 = readOnlyList;
			}
			Points = readOnlyList2;
			Reason = reason;
		}
	}
	public sealed class PathRequest
	{
		public long RequestId { get; set; }

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

		public V3 Start { get; set; }

		public V3 Goal { get; set; }

		public AgentProfile Profile { get; set; } = new AgentProfile();

		public bool AllowPartial { get; set; }

		public bool IsValid
		{
			get
			{
				if (RequestId > 0 && !string.IsNullOrWhiteSpace(AgentId) && AgentId.Length <= 96 && Start.IsFinite && Goal.IsFinite && Start.Length < 50000f && Goal.Length < 50000f && V3.Distance(Start, Goal) <= 150f && Profile != null)
				{
					return Profile.IsValid;
				}
				return false;
			}
		}

		public PathRequest Copy()
		{
			return new PathRequest
			{
				RequestId = RequestId,
				AgentId = AgentId,
				Start = Start,
				Goal = Goal,
				Profile = (Profile?.Copy() ?? new AgentProfile
				{
					Radius = float.NaN
				}),
				AllowPartial = AllowPartial
			};
		}
	}
	public sealed class TraversalLink
	{
		public string Id { get; }

		public V3 From { get; }

		public V3 To { get; }

		public MoveKind Kind { get; }

		public float Width { get; }

		public float Height { get; }

		public float Cost { get; }

		public bool Bidirectional { get; }

		public TraversalLink(string id, V3 from, V3 to, MoveKind kind, float width, float height, float extraCost = 3f, bool bidirectional = false)
		{
			if (string.IsNullOrWhiteSpace(id) || id.Length > 96 || !from.IsFinite || !to.IsFinite || !float.IsFinite(width) || !float.IsFinite(height) || width <= 0f || height <= 0f || !float.IsFinite(extraCost) || extraCost < 0f)
			{
				throw new ArgumentException("Invalid traversal link");
			}
			Id = id;
			From = from;
			To = to;
			Kind = kind;
			Width = width;
			Height = height;
			Cost = V3.Distance(from, to) + extraCost;
			Bidirectional = bidirectional;
		}
	}
	public readonly record struct LinkCheck(LinkState State, MoveKind Kind = MoveKind.Walk, float ExtraCost = 0f);
	public interface IWorldQuery
	{
		LinkCheck CheckTraversal(V3 from, V3 to, AgentProfile profile);
	}
	public sealed class OpeningResult
	{
		public V3 Center { get; init; }

		public V3 Normal { get; init; }

		public float Width { get; init; }

		public float Height { get; init; }

		public float Resolution { get; init; }

		public OpeningKind Kind { get; init; }

		public bool Found { get; init; }

		public bool Truncated { get; init; }

		public bool Invalidated { get; init; }

		public double ObservedAt { get; init; }

		public bool Fits(AgentProfile p)
		{
			if (Found && Width >= p.Radius * 2f)
			{
				return Height >= ((Kind != OpeningKind.Wall) ? (p.Radius * 2f) : (p.CanCrouch ? p.CrouchHeight : p.Height));
			}
			return false;
		}
	}
	public sealed class SearchJob
	{
		private readonly WorldMap _map;

		private readonly IWorldQuery _world;

		private readonly PathRequest _request;

		private readonly PriorityQueue<NodeKey, float> _open = new PriorityQueue<NodeKey, float>();

		private readonly Dictionary<NodeKey, float> _g = new Dictionary<NodeKey, float>();

		private readonly Dictionary<NodeKey, (NodeKey parent, MoveKind kind, string action)> _parents = new Dictionary<NodeKey, (NodeKey, MoveKind, string)>();

		private readonly HashSet<NodeKey> _closed = new HashSet<NodeKey>();

		private Surface? _start;

		private Surface? _goal;

		private Surface? _current;

		private Surface? _closest;

		private List<(Surface node, MoveKind? special, string id, float cost)>? _neighbors;

		private int _neighborIndex;

		private long _revision;

		private int _restarts;

		private readonly int _maxVisits;

		private readonly double _created;

		private double _now;

		private double _maxAge;

		public PathResult? Result { get; private set; }

		public bool Done => Result != null;

		public int Visited => _closed.Count;

		public SearchJob(WorldMap map, IWorldQuery world, PathRequest request, double now, int maxVisits = 4096)
		{
			_map = map;
			_world = world;
			_request = request.Copy();
			_maxVisits = maxVisits;
			_created = now;
			if (!_request.IsValid)
			{
				Finish(PathStatus.InvalidRequest, "Invalid request or profile");
			}
		}

		public void Cancel()
		{
			if (!Done)
			{
				Finish(PathStatus.Cancelled, "Superseded or cancelled");
			}
		}

		public void Step(double now, double maxAge, int maxQueries, double maxMilliseconds)
		{
			if (Done)
			{
				return;
			}
			_now = now;
			_maxAge = maxAge;
			if (now - _created > 12.0)
			{
				Finish(PathStatus.TimedOut, "Mapping or search deadline exceeded");
				return;
			}
			if (_start == null)
			{
				_start = _map.Nearest(_request.Start, _request.Profile, now, maxAge);
				_goal = _map.Nearest(_request.Goal, _request.Profile, now, maxAge);
				if (_start == null || _goal == null)
				{
					_start = null;
					return;
				}
				_revision = _map.Revision;
				_g[_start.Key] = 0f;
				_open.Enqueue(_start.Key, Heuristic(_start));
				_closest = _start;
				LinkCheck linkCheck = _world.CheckTraversal(_request.Start, _start.Feet, _request.Profile);
				LinkCheck linkCheck2 = _world.CheckTraversal(_goal.Feet, _request.Goal, _request.Profile);
				if (linkCheck.State == LinkState.Deferred || linkCheck2.State == LinkState.Deferred)
				{
					Restart();
					return;
				}
				if (linkCheck.State != LinkState.Clear || linkCheck2.State != LinkState.Clear)
				{
					Finish(PathStatus.NoPath, "Endpoint connector blocked");
					return;
				}
			}
			if (!_map.TryGet(_start.Key, out Surface node) || !_map.TryGet(_goal.Key, out Surface node2) || !node.Fits(_request.Profile) || !node2.Fits(_request.Profile) || (_current != null && !_map.TryGet(_current.Key, out Surface _)))
			{
				if (++_restarts > 128)
				{
					Finish(PathStatus.MapChanged, "Geometry changed throughout search");
				}
				else
				{
					Restart();
				}
				return;
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			int num = 0;
			while (num < maxQueries && stopwatch.Elapsed.TotalMilliseconds < maxMilliseconds)
			{
				if (_current == null)
				{
					NodeKey element = default(NodeKey);
					bool flag = false;
					float priority;
					while (_open.TryDequeue(out element, out priority))
					{
						if (!_closed.Contains(element))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						if (_revision != _map.Revision && ++_restarts <= 128)
						{
							Restart();
						}
						else
						{
							CompleteOrPartial(PathStatus.NoPath, "No connected route in the observed area");
						}
						break;
					}
					if (!_map.TryGet(element, out _current))
					{
						Restart();
						break;
					}
					if (!_map.IsFresh(_current, now, maxAge))
					{
						Finish(PathStatus.MapChanged, "Surface observations expired");
						break;
					}
					if (_current.Key == _goal.Key)
					{
						MakePath(_current, PathStatus.Complete);
						break;
					}
					_closed.Add(element);
					if (_closed.Count >= _maxVisits)
					{
						CompleteOrPartial(PathStatus.TooComplex, "Search visit limit reached");
						break;
					}
					if (Heuristic(_current) < Heuristic(_closest))
					{
						_closest = _current;
					}
					_neighbors = new List<(Surface, MoveKind?, string, float)>();
					_neighborIndex = 0;
					foreach (Surface item in _map.Neighbors(_current, _request.Profile, now, maxAge))
					{
						_neighbors.Add((item, null, "", 0f));
					}
					foreach (TraversalLink value2 in _map.Links.Values)
					{
						if (!_request.Profile.Allows(value2.Kind) || value2.Width < _request.Profile.Radius * 2f || value2.Height < (_request.Profile.CanCrouch ? _request.Profile.CrouchHeight : _request.Profile.Height))
						{
							continue;
						}
						bool flag2 = V3.Distance(_current.Feet, value2.From) <= _map.CellSize * 0.8f;
						bool flag3 = value2.Bidirectional && V3.Distance(_current.Feet, value2.To) <= _map.CellSize * 0.8f;
						if (flag2 || flag3)
						{
							Surface surface = _map.Nearest(flag2 ? value2.To : value2.From, _request.Profile, now, maxAge, _map.CellSize * 0.8f, 0.25f);
							if (surface != null)
							{
								_neighbors.Add((surface, value2.Kind, value2.Id, value2.Cost));
							}
						}
					}
				}
				if (_neighborIndex >= _neighbors.Count)
				{
					_current = null;
					continue;
				}
				(Surface, MoveKind?, string, float) tuple = _neighbors[_neighborIndex];
				if (!_map.TryGet(tuple.Item1.Key, out Surface node4) || !node4.Fits(_request.Profile))
				{
					_neighborIndex++;
					continue;
				}
				tuple.Item1 = node4;
				if (_closed.Contains(tuple.Item1.Key))
				{
					_neighborIndex++;
					continue;
				}
				LinkCheck linkCheck3;
				if (tuple.Item2.HasValue)
				{
					linkCheck3 = new LinkCheck(LinkState.Clear, tuple.Item2.Value);
				}
				else
				{
					linkCheck3 = _world.CheckTraversal(_current.Feet, tuple.Item1.Feet, _request.Profile);
					num++;
				}
				if (linkCheck3.State == LinkState.Deferred)
				{
					break;
				}
				_neighborIndex++;
				if (linkCheck3.State == LinkState.Clear)
				{
					float num2 = MathF.Max(V3.Distance(_current.Feet, tuple.Item1.Feet), tuple.Item4) + MathF.Max(0f, linkCheck3.ExtraCost) + _request.Profile.ExtraCost;
					float num3 = _g[_current.Key] + num2;
					if (!_g.TryGetValue(tuple.Item1.Key, out var value) || !(num3 >= value))
					{
						_g[tuple.Item1.Key] = num3;
						_parents[tuple.Item1.Key] = (_current.Key, linkCheck3.Kind, tuple.Item3);
						_open.Enqueue(tuple.Item1.Key, num3 + Heuristic(tuple.Item1));
					}
				}
			}
		}

		private float Heuristic(Surface node)
		{
			return V3.Distance(node.Feet, _goal.Feet);
		}

		private void Restart()
		{
			_start = (_goal = (_current = (_closest = null)));
			_neighbors = null;
			_open.Clear();
			_g.Clear();
			_parents.Clear();
			_closed.Clear();
		}

		private void CompleteOrPartial(PathStatus failure, string reason)
		{
			if (_request.AllowPartial && _closest != null && _start != null && _closest.Key != _start.Key)
			{
				MakePath(_closest, PathStatus.Partial);
			}
			else
			{
				Finish(failure, reason);
			}
		}

		private void MakePath(Surface end, PathStatus status)
		{
			List<Waypoint> list = new List<Waypoint>();
			NodeKey key = end.Key;
			int num = 0;
			(NodeKey, MoveKind, string) value;
			while (_parents.TryGetValue(key, out value))
			{
				if (++num > 512)
				{
					Finish(PathStatus.TooLong, "Route exceeds 512 waypoints; request a nearer goal");
					return;
				}
				if (!_map.TryGet(key, out Surface node) || !node.Fits(_request.Profile) || !_map.IsFresh(node, _now, _maxAge) || (value.Item3.Length > 0 && !_map.Links.ContainsKey(value.Item3)))
				{
					if (++_restarts <= 128)
					{
						Restart();
					}
					else
					{
						Finish(PathStatus.MapChanged, "Route repeatedly changed");
					}
					return;
				}
				list.Add(new Waypoint(node.Feet, value.Item2, value.Item3));
				(key, _, _) = value;
			}
			list.Add(new Waypoint(_start.Feet));
			list.Reverse();
			if (V3.Distance(_request.Start, list[0].Feet) > 0.03f)
			{
				list.Insert(0, new Waypoint(_request.Start));
			}
			if (status == PathStatus.Complete)
			{
				if (V3.Distance(list[list.Count - 1].Feet, _request.Goal) > 0.03f)
				{
					list.Add(new Waypoint(_request.Goal));
				}
			}
			if (list.Count > 512)
			{
				Finish(PathStatus.TooLong, "Route exceeds wire waypoint limit");
			}
			else
			{
				Result = new PathResult(_request.RequestId, _request.AgentId, status, _map.Revision, list);
			}
		}

		private void Finish(PathStatus status, string reason)
		{
			Result = new PathResult(_request.RequestId, _request.AgentId, status, _map.Revision, null, reason);
		}
	}
	public readonly record struct GridRectangle(int Left, int Bottom, int Right, int Top)
	{
		public int Width => Right - Left + 1;

		public int Height => Top - Bottom + 1;
	}
	public static class OpeningMath
	{
		public static GridRectangle? Measure(bool[,] free, int seedX, int seedY)
		{
			int length = free.GetLength(0);
			int length2 = free.GetLength(1);
			if (seedX < 0 || seedY < 0 || seedX >= length || seedY >= length2 || !free[seedX, seedY])
			{
				return null;
			}
			GridRectangle value = new GridRectangle(seedX, seedY, seedX, seedY);
			for (int num = seedY; num >= 0; num--)
			{
				int num2 = 0;
				int num3 = length - 1;
				for (int i = num; i < length2 && free[seedX, i]; i++)
				{
					int num4 = seedX;
					int j = seedX;
					while (num4 > 0 && free[num4 - 1, i])
					{
						num4--;
					}
					for (; j + 1 < length && free[j + 1, i]; j++)
					{
					}
					num2 = Math.Max(num2, num4);
					num3 = Math.Min(num3, j);
					if (i >= seedY && (num3 - num2 + 1) * (i - num + 1) > value.Width * value.Height)
					{
						value = new GridRectangle(num2, num, num3, i);
					}
				}
			}
			return value;
		}
	}
	public sealed class WorldMap
	{
		private sealed class Column
		{
			public List<Surface> Nodes = new List<Surface>();

			public double ObservedAt;
		}

		private readonly Dictionary<ColumnKey, Column> _columns = new Dictionary<ColumnKey, Column>();

		private readonly Dictionary<NodeKey, Surface> _nodes = new Dictionary<NodeKey, Surface>();

		private readonly Dictionary<(int, int), List<Surface>> _horizontal = new Dictionary<(int, int), List<Surface>>();

		public Dictionary<string, TraversalLink> Links { get; } = new Dictionary<string, TraversalLink>(StringComparer.Ordinal);

		public float CellSize { get; }

		public float BandHeight { get; }

		public long Revision { get; private set; }

		public int NodeCount => _nodes.Count;

		public int ColumnCount => _columns.Count;

		public WorldMap(float cellSize = 0.5f, float bandHeight = 6f)
		{
			if (cellSize < 0.2f || cellSize > 2f || bandHeight < 2f || !float.IsFinite(cellSize) || !float.IsFinite(bandHeight))
			{
				throw new ArgumentOutOfRangeException("cellSize");
			}
			CellSize = cellSize;
			BandHeight = bandHeight;
		}

		public ColumnKey ColumnAt(V3 p)
		{
			return new ColumnKey((int)MathF.Floor(p.X / CellSize), (int)MathF.Floor(p.Z / CellSize), (int)MathF.Floor(p.Y / BandHeight));
		}

		public NodeKey KeyAt(V3 p)
		{
			return new NodeKey((int)MathF.Floor(p.X / CellSize), (int)MathF.Round(p.Y / 0.04f), (int)MathF.Floor(p.Z / CellSize));
		}

		public V3 ColumnCenter(ColumnKey c)
		{
			return new V3(((float)c.X + 0.5f) * CellSize, (float)c.Band * BandHeight, ((float)c.Z + 0.5f) * CellSize);
		}

		public bool TryGet(NodeKey key, out Surface node)
		{
			return _nodes.TryGetValue(key, out node);
		}

		public double LastScanned(ColumnKey key)
		{
			if (!_columns.TryGetValue(key, out Column value))
			{
				return double.NegativeInfinity;
			}
			return value.ObservedAt;
		}

		public void Replace(ColumnKey key, List<Surface> nodes, double observedAt)
		{
			if (!double.IsFinite(observedAt))
			{
				throw new ArgumentOutOfRangeException("observedAt");
			}
			if (nodes.Count > 24 || nodes.Any((Surface n) => !n.Feet.IsFinite || n.Headroom < 0f || !float.IsFinite(n.Headroom) || n.Key != KeyAt(n.Feet) || ColumnAt(n.Feet) != key))
			{
				throw new ArgumentException("Invalid column surfaces");
			}
			nodes = (from n in nodes
				group n by n.Key into g
				select g.First() into n
				orderby n.Feet.Y
				select n).ToList();
			if (_columns.TryGetValue(key, out Column value) && value.Nodes.Count == nodes.Count && value.Nodes.Zip(nodes).All(((Surface First, Surface Second) pair) => pair.First.Equivalent(pair.Second)))
			{
				value.ObservedAt = observedAt;
				return;
			}
			if (value != null)
			{
				RemoveNodes(key, value.Nodes);
			}
			_columns[key] = new Column
			{
				Nodes = nodes,
				ObservedAt = observedAt
			};
			if (!_horizontal.TryGetValue((key.X, key.Z), out List<Surface> value2))
			{
				value2 = (_horizontal[(key.X, key.Z)] = new List<Surface>());
			}
			foreach (Surface node in nodes)
			{
				_nodes[node.Key] = node;
				value2.Add(node);
			}
			Revision++;
		}

		private void RemoveNodes(ColumnKey key, List<Surface> nodes)
		{
			foreach (Surface node in nodes)
			{
				_nodes.Remove(node.Key);
			}
			if (!_horizontal.TryGetValue((key.X, key.Z), out List<Surface> value))
			{
				return;
			}
			value.RemoveAll((Surface n) => nodes.Exists((Surface old) => old.Key == n.Key));
			if (value.Count == 0)
			{
				_horizontal.Remove((key.X, key.Z));
			}
		}

		public bool IsFresh(Surface node, double now, double maxAge)
		{
			return now - LastScanned(ColumnAt(node.Feet)) <= maxAge;
		}

		public Surface? Nearest(V3 point, AgentProfile profile, double now, double maxAge, float horizontal = 0.9f, float vertical = 0.8f)
		{
			Surface result = null;
			float num = float.MaxValue;
			ColumnKey columnKey = ColumnAt(point);
			int num2 = (int)MathF.Ceiling(horizontal / CellSize);
			for (int i = columnKey.X - num2; i <= columnKey.X + num2; i++)
			{
				for (int j = columnKey.Z - num2; j <= columnKey.Z + num2; j++)
				{
					if (!_horizontal.TryGetValue((i, j), out List<Surface> value))
					{
						continue;
					}
					foreach (Surface item in value)
					{
						V3 v = item.Feet - point;
						if (!(v.HorizontalLength > horizontal) && !(MathF.Abs(v.Y) > vertical) && item.Fits(profile) && IsFresh(item, now, maxAge))
						{
							float length = v.Length;
							if (length < num)
							{
								result = item;
								num = length;
							}
						}
					}
				}
			}
			return result;
		}

		public List<Surface> Neighbors(Surface node, AgentProfile profile, double now, double maxAge)
		{
			List<Surface> list = new List<Surface>(12);
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if ((i == 0 && j == 0) || !_horizontal.TryGetValue((node.Key.X + i, node.Key.Z + j), out List<Surface> value))
					{
						continue;
					}
					foreach (Surface item in value)
					{
						float num = item.Feet.Y - node.Feet.Y;
						float horizontalLength = (item.Feet - node.Feet).HorizontalLength;
						float y = MathF.Tan(profile.MaxSlopeDegrees * (float)Math.PI / 180f) * horizontalLength;
						if (!(num > MathF.Max(profile.StepHeight, y) + 0.03f) && !(num < 0f - MathF.Max(profile.MaxDrop, y) - 0.03f) && item.Fits(profile) && IsFresh(item, now, maxAge))
						{
							list.Add(item);
						}
					}
				}
			}
			return list;
		}

		public void AddLink(TraversalLink link)
		{
			if (Links.Count >= 512 && !Links.ContainsKey(link.Id))
			{
				throw new InvalidOperationException("Traversal link limit reached");
			}
			Links[link.Id] = link;
			Revision++;
		}

		public bool RemoveLink(string id)
		{
			bool num = Links.Remove(id);
			if (num)
			{
				Revision++;
			}
			return num;
		}

		public int Evict(double now, double maxAge, IReadOnlyList<V3> foci, float radius, int hardColumnLimit)
		{
			List<ColumnKey> list = new List<ColumnKey>();
			foreach (KeyValuePair<ColumnKey, Column> column in _columns)
			{
				V3 p = ColumnCenter(column.Key);
				if (!foci.Any((V3 f) => (new V3(p.X, f.Y, p.Z) - f).Length <= radius && MathF.Abs(p.Y - f.Y) <= BandHeight * 2f) || now - column.Value.ObservedAt > maxAge)
				{
					list.Add(column.Key);
				}
			}
			foreach (ColumnKey item in list)
			{
				RemoveNodes(item, _columns[item].Nodes);
				_columns.Remove(item);
			}
			if (_columns.Count > hardColumnLimit)
			{
				ColumnKey[] array = (from keyValuePair in _columns.OrderBy<KeyValuePair<ColumnKey, Column>, double>((KeyValuePair<ColumnKey, Column> keyValuePair) => keyValuePair.Value.ObservedAt).Take(_columns.Count - hardColumnLimit)
					select keyValuePair.Key).ToArray();
				foreach (ColumnKey columnKey in array)
				{
					RemoveNodes(columnKey, _columns[columnKey].Nodes);
					_columns.Remove(columnKey);
					list.Add(columnKey);
				}
			}
			if (list.Count != 0)
			{
				Revision++;
			}
			return list.Count;
		}

		public void Clear()
		{
			_columns.Clear();
			_nodes.Clear();
			_horizontal.Clear();
			Links.Clear();
			Revision++;
		}
	}
}