Decompiled source of OCDheim v0.2.0

plugins/UniTask.dll

Decompiled a day ago
#define UNITY_EDITOR
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks.CompilerServices;
using Cysharp.Threading.Tasks.Internal;
using Cysharp.Threading.Tasks.Triggers;
using Microsoft.CodeAnalysis;
using Unity.Jobs;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.LowLevel;
using UnityEngine.Networking;
using UnityEngine.ParticleSystemJobs;
using UnityEngine.PlayerLoop;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("UniTask.Linq")]
[assembly: InternalsVisibleTo("UniTask.Addressables")]
[assembly: InternalsVisibleTo("UniTask.DOTween")]
[assembly: InternalsVisibleTo("UniTask.TextMeshPro")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	internal sealed class AsyncMethodBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public AsyncMethodBuilderAttribute(Type builderType)
		{
			BuilderType = builderType;
		}
	}
}
namespace Cysharp.Threading.Tasks
{
	public class AsyncLazy
	{
		private static Action<object> continuation = SetCompletionSource;

		private Func<UniTask> taskFactory;

		private UniTaskCompletionSource completionSource;

		private UniTask.Awaiter awaiter;

		private object syncLock;

		private bool initialized;

		public UniTask Task
		{
			get
			{
				EnsureInitialized();
				return completionSource.Task;
			}
		}

		public AsyncLazy(Func<UniTask> taskFactory)
		{
			this.taskFactory = taskFactory;
			completionSource = new UniTaskCompletionSource();
			syncLock = new object();
			initialized = false;
		}

		internal AsyncLazy(UniTask task)
		{
			taskFactory = null;
			completionSource = new UniTaskCompletionSource();
			syncLock = null;
			initialized = true;
			UniTask.Awaiter awaiter = task.GetAwaiter();
			if (awaiter.IsCompleted)
			{
				SetCompletionSource(in awaiter);
				return;
			}
			this.awaiter = awaiter;
			awaiter.SourceOnCompleted(continuation, this);
		}

		public UniTask.Awaiter GetAwaiter()
		{
			return Task.GetAwaiter();
		}

		private void EnsureInitialized()
		{
			if (!Volatile.Read(ref initialized))
			{
				EnsureInitializedCore();
			}
		}

		private void EnsureInitializedCore()
		{
			lock (syncLock)
			{
				if (Volatile.Read(ref initialized))
				{
					return;
				}
				Func<UniTask> func = Interlocked.Exchange(ref taskFactory, null);
				if (func != null)
				{
					UniTask.Awaiter awaiter = func().GetAwaiter();
					if (awaiter.IsCompleted)
					{
						SetCompletionSource(in awaiter);
					}
					else
					{
						this.awaiter = awaiter;
						awaiter.SourceOnCompleted(continuation, this);
					}
					Volatile.Write(ref initialized, value: true);
				}
			}
		}

		private void SetCompletionSource(in UniTask.Awaiter awaiter)
		{
			try
			{
				awaiter.GetResult();
				completionSource.TrySetResult();
			}
			catch (Exception exception)
			{
				completionSource.TrySetException(exception);
			}
		}

		private static void SetCompletionSource(object state)
		{
			AsyncLazy asyncLazy = (AsyncLazy)state;
			try
			{
				asyncLazy.awaiter.GetResult();
				asyncLazy.completionSource.TrySetResult();
			}
			catch (Exception exception)
			{
				asyncLazy.completionSource.TrySetException(exception);
			}
			finally
			{
				asyncLazy.awaiter = default(UniTask.Awaiter);
			}
		}
	}
	public class AsyncLazy<T>
	{
		private static Action<object> continuation = SetCompletionSource;

		private Func<UniTask<T>> taskFactory;

		private UniTaskCompletionSource<T> completionSource;

		private UniTask<T>.Awaiter awaiter;

		private object syncLock;

		private bool initialized;

		public UniTask<T> Task
		{
			get
			{
				EnsureInitialized();
				return completionSource.Task;
			}
		}

		public AsyncLazy(Func<UniTask<T>> taskFactory)
		{
			this.taskFactory = taskFactory;
			completionSource = new UniTaskCompletionSource<T>();
			syncLock = new object();
			initialized = false;
		}

		internal AsyncLazy(UniTask<T> task)
		{
			taskFactory = null;
			completionSource = new UniTaskCompletionSource<T>();
			syncLock = null;
			initialized = true;
			UniTask<T>.Awaiter awaiter = task.GetAwaiter();
			if (awaiter.IsCompleted)
			{
				SetCompletionSource(in awaiter);
				return;
			}
			this.awaiter = awaiter;
			awaiter.SourceOnCompleted(continuation, this);
		}

		public UniTask<T>.Awaiter GetAwaiter()
		{
			return Task.GetAwaiter();
		}

		private void EnsureInitialized()
		{
			if (!Volatile.Read(ref initialized))
			{
				EnsureInitializedCore();
			}
		}

		private void EnsureInitializedCore()
		{
			lock (syncLock)
			{
				if (Volatile.Read(ref initialized))
				{
					return;
				}
				Func<UniTask<T>> func = Interlocked.Exchange(ref taskFactory, null);
				if (func != null)
				{
					UniTask<T>.Awaiter awaiter = func().GetAwaiter();
					if (awaiter.IsCompleted)
					{
						SetCompletionSource(in awaiter);
					}
					else
					{
						this.awaiter = awaiter;
						awaiter.SourceOnCompleted(continuation, this);
					}
					Volatile.Write(ref initialized, value: true);
				}
			}
		}

		private void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
		{
			try
			{
				T result = awaiter.GetResult();
				completionSource.TrySetResult(result);
			}
			catch (Exception exception)
			{
				completionSource.TrySetException(exception);
			}
		}

		private static void SetCompletionSource(object state)
		{
			AsyncLazy<T> asyncLazy = (AsyncLazy<T>)state;
			try
			{
				T result = asyncLazy.awaiter.GetResult();
				asyncLazy.completionSource.TrySetResult(result);
			}
			catch (Exception exception)
			{
				asyncLazy.completionSource.TrySetException(exception);
			}
			finally
			{
				asyncLazy.awaiter = default(UniTask<T>.Awaiter);
			}
		}
	}
	public interface IReadOnlyAsyncReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
	{
		T Value { get; }

		IUniTaskAsyncEnumerable<T> WithoutCurrent();

		UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public interface IAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>
	{
		new T Value { get; set; }
	}
	[Serializable]
	public class AsyncReactiveProperty<T> : IAsyncReactiveProperty<T>, IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>, IDisposable
	{
		private sealed class WaitAsyncSource : IUniTaskSource<T>, IUniTaskSource, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
		{
			private static Action<object> cancellationCallback;

			private static TaskPool<WaitAsyncSource> pool;

			private WaitAsyncSource nextNode;

			private AsyncReactiveProperty<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<T> core;

			ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			static WaitAsyncSource()
			{
				cancellationCallback = CancellationCallback;
				TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
			}

			private WaitAsyncSource()
			{
			}

			public static IUniTaskSource<T> Create(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new WaitAsyncSource();
				}
				result.parent = parent;
				result.cancellationToken = cancellationToken;
				if (cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
				}
				result.parent.triggerEvent.Add(result);
				TaskTracker.TrackActiveTask(result, 3);
				token = result.core.Version;
				return result;
			}

			private bool TryReturn()
			{
				TaskTracker.RemoveTracking(this);
				core.Reset();
				cancellationTokenRegistration.Dispose();
				cancellationTokenRegistration = default(CancellationTokenRegistration);
				parent.triggerEvent.Remove(this);
				parent = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static void CancellationCallback(object state)
			{
				WaitAsyncSource obj = (WaitAsyncSource)state;
				obj.OnCanceled(obj.cancellationToken);
			}

			public T GetResult(short token)
			{
				try
				{
					return core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				core.TrySetCanceled(cancellationToken);
			}

			public void OnCompleted()
			{
				core.TrySetCanceled(CancellationToken.None);
			}

			public void OnError(Exception ex)
			{
				core.TrySetException(ex);
			}

			public void OnNext(T value)
			{
				core.TrySetResult(value);
			}
		}

		private sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
		{
			private readonly AsyncReactiveProperty<T> parent;

			public WithoutCurrentEnumerable(AsyncReactiveProperty<T> parent)
			{
				this.parent = parent;
			}

			public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new Enumerator(parent, cancellationToken, publishCurrentValue: false);
			}
		}

		private sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable, ITriggerHandler<T>
		{
			private static Action<object> cancellationCallback = CancellationCallback;

			private readonly AsyncReactiveProperty<T> parent;

			private readonly CancellationToken cancellationToken;

			private readonly CancellationTokenRegistration cancellationTokenRegistration;

			private T value;

			private bool isDisposed;

			private bool firstCall;

			public T Current => value;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			public Enumerator(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
			{
				this.parent = parent;
				this.cancellationToken = cancellationToken;
				firstCall = publishCurrentValue;
				parent.triggerEvent.Add(this);
				TaskTracker.TrackActiveTask(this, 3);
				if (cancellationToken.CanBeCanceled)
				{
					cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
				}
			}

			public UniTask<bool> MoveNextAsync()
			{
				if (firstCall)
				{
					firstCall = false;
					value = parent.Value;
					return CompletedTasks.True;
				}
				completionSource.Reset();
				return new UniTask<bool>(this, completionSource.Version);
			}

			public UniTask DisposeAsync()
			{
				if (!isDisposed)
				{
					isDisposed = true;
					TaskTracker.RemoveTracking(this);
					completionSource.TrySetCanceled(cancellationToken);
					parent.triggerEvent.Remove(this);
				}
				return default(UniTask);
			}

			public void OnNext(T value)
			{
				this.value = value;
				completionSource.TrySetResult(result: true);
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				DisposeAsync().Forget();
			}

			public void OnCompleted()
			{
				completionSource.TrySetResult(result: false);
			}

			public void OnError(Exception ex)
			{
				completionSource.TrySetException(ex);
			}

			private static void CancellationCallback(object state)
			{
				((Enumerator)state).DisposeAsync().Forget();
			}
		}

		private TriggerEvent<T> triggerEvent;

		[SerializeField]
		private T latestValue;

		private static bool isValueType;

		public T Value
		{
			get
			{
				return latestValue;
			}
			set
			{
				latestValue = value;
				triggerEvent.SetResult(value);
			}
		}

		public AsyncReactiveProperty(T value)
		{
			latestValue = value;
			triggerEvent = default(TriggerEvent<T>);
		}

		public IUniTaskAsyncEnumerable<T> WithoutCurrent()
		{
			return new WithoutCurrentEnumerable(this);
		}

		public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
		{
			return new Enumerator(this, cancellationToken, publishCurrentValue: true);
		}

		public void Dispose()
		{
			triggerEvent.SetCompleted();
		}

		public static implicit operator T(AsyncReactiveProperty<T> value)
		{
			return value.Value;
		}

		public override string ToString()
		{
			if (isValueType)
			{
				return latestValue.ToString();
			}
			return latestValue?.ToString();
		}

		public UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			short token;
			return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out token), token);
		}

		static AsyncReactiveProperty()
		{
			isValueType = typeof(T).IsValueType;
		}
	}
	public class ReadOnlyAsyncReactiveProperty<T> : IReadOnlyAsyncReactiveProperty<T>, IUniTaskAsyncEnumerable<T>, IDisposable
	{
		private sealed class WaitAsyncSource : IUniTaskSource<T>, IUniTaskSource, ITriggerHandler<T>, ITaskPoolNode<WaitAsyncSource>
		{
			private static Action<object> cancellationCallback;

			private static TaskPool<WaitAsyncSource> pool;

			private WaitAsyncSource nextNode;

			private ReadOnlyAsyncReactiveProperty<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<T> core;

			ref WaitAsyncSource ITaskPoolNode<WaitAsyncSource>.NextNode => ref nextNode;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			static WaitAsyncSource()
			{
				cancellationCallback = CancellationCallback;
				TaskPool.RegisterSizeGetter(typeof(WaitAsyncSource), () => pool.Size);
			}

			private WaitAsyncSource()
			{
			}

			public static IUniTaskSource<T> Create(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new WaitAsyncSource();
				}
				result.parent = parent;
				result.cancellationToken = cancellationToken;
				if (cancellationToken.CanBeCanceled)
				{
					result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, result);
				}
				result.parent.triggerEvent.Add(result);
				TaskTracker.TrackActiveTask(result, 3);
				token = result.core.Version;
				return result;
			}

			private bool TryReturn()
			{
				TaskTracker.RemoveTracking(this);
				core.Reset();
				cancellationTokenRegistration.Dispose();
				cancellationTokenRegistration = default(CancellationTokenRegistration);
				parent.triggerEvent.Remove(this);
				parent = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static void CancellationCallback(object state)
			{
				WaitAsyncSource obj = (WaitAsyncSource)state;
				obj.OnCanceled(obj.cancellationToken);
			}

			public T GetResult(short token)
			{
				try
				{
					return core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			void IUniTaskSource.GetResult(short token)
			{
				GetResult(token);
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				core.TrySetCanceled(cancellationToken);
			}

			public void OnCompleted()
			{
				core.TrySetCanceled(CancellationToken.None);
			}

			public void OnError(Exception ex)
			{
				core.TrySetException(ex);
			}

			public void OnNext(T value)
			{
				core.TrySetResult(value);
			}
		}

		private sealed class WithoutCurrentEnumerable : IUniTaskAsyncEnumerable<T>
		{
			private readonly ReadOnlyAsyncReactiveProperty<T> parent;

			public WithoutCurrentEnumerable(ReadOnlyAsyncReactiveProperty<T> parent)
			{
				this.parent = parent;
			}

			public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new Enumerator(parent, cancellationToken, publishCurrentValue: false);
			}
		}

		private sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable, ITriggerHandler<T>
		{
			private static Action<object> cancellationCallback = CancellationCallback;

			private readonly ReadOnlyAsyncReactiveProperty<T> parent;

			private readonly CancellationToken cancellationToken;

			private readonly CancellationTokenRegistration cancellationTokenRegistration;

			private T value;

			private bool isDisposed;

			private bool firstCall;

			public T Current => value;

			ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }

			ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }

			public Enumerator(ReadOnlyAsyncReactiveProperty<T> parent, CancellationToken cancellationToken, bool publishCurrentValue)
			{
				this.parent = parent;
				this.cancellationToken = cancellationToken;
				firstCall = publishCurrentValue;
				parent.triggerEvent.Add(this);
				TaskTracker.TrackActiveTask(this, 3);
				if (cancellationToken.CanBeCanceled)
				{
					cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
				}
			}

			public UniTask<bool> MoveNextAsync()
			{
				if (firstCall)
				{
					firstCall = false;
					value = parent.Value;
					return CompletedTasks.True;
				}
				completionSource.Reset();
				return new UniTask<bool>(this, completionSource.Version);
			}

			public UniTask DisposeAsync()
			{
				if (!isDisposed)
				{
					isDisposed = true;
					TaskTracker.RemoveTracking(this);
					completionSource.TrySetCanceled(cancellationToken);
					parent.triggerEvent.Remove(this);
				}
				return default(UniTask);
			}

			public void OnNext(T value)
			{
				this.value = value;
				completionSource.TrySetResult(result: true);
			}

			public void OnCanceled(CancellationToken cancellationToken)
			{
				DisposeAsync().Forget();
			}

			public void OnCompleted()
			{
				completionSource.TrySetResult(result: false);
			}

			public void OnError(Exception ex)
			{
				completionSource.TrySetException(ex);
			}

			private static void CancellationCallback(object state)
			{
				((Enumerator)state).DisposeAsync().Forget();
			}
		}

		private TriggerEvent<T> triggerEvent;

		private T latestValue;

		private IUniTaskAsyncEnumerator<T> enumerator;

		private static bool isValueType;

		public T Value => latestValue;

		public ReadOnlyAsyncReactiveProperty(T initialValue, IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			latestValue = initialValue;
			ConsumeEnumerator(source, cancellationToken).Forget();
		}

		public ReadOnlyAsyncReactiveProperty(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			ConsumeEnumerator(source, cancellationToken).Forget();
		}

		private async UniTaskVoid ConsumeEnumerator(IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			enumerator = source.GetAsyncEnumerator(cancellationToken);
			try
			{
				while (await enumerator.MoveNextAsync())
				{
					T result = (latestValue = enumerator.Current);
					triggerEvent.SetResult(result);
				}
			}
			finally
			{
				await enumerator.DisposeAsync();
				enumerator = null;
			}
		}

		public IUniTaskAsyncEnumerable<T> WithoutCurrent()
		{
			return new WithoutCurrentEnumerable(this);
		}

		public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
		{
			return new Enumerator(this, cancellationToken, publishCurrentValue: true);
		}

		public void Dispose()
		{
			if (enumerator != null)
			{
				enumerator.DisposeAsync().Forget();
			}
			triggerEvent.SetCompleted();
		}

		public static implicit operator T(ReadOnlyAsyncReactiveProperty<T> value)
		{
			return value.Value;
		}

		public override string ToString()
		{
			if (isValueType)
			{
				return latestValue.ToString();
			}
			return latestValue?.ToString();
		}

		public UniTask<T> WaitAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			short token;
			return new UniTask<T>(WaitAsyncSource.Create(this, cancellationToken, out token), token);
		}

		static ReadOnlyAsyncReactiveProperty()
		{
			isValueType = typeof(T).IsValueType;
		}
	}
	public static class StateExtensions
	{
		public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			return new ReadOnlyAsyncReactiveProperty<T>(source, cancellationToken);
		}

		public static ReadOnlyAsyncReactiveProperty<T> ToReadOnlyAsyncReactiveProperty<T>(this IUniTaskAsyncEnumerable<T> source, T initialValue, CancellationToken cancellationToken)
		{
			return new ReadOnlyAsyncReactiveProperty<T>(initialValue, source, cancellationToken);
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public readonly struct AsyncUnit : IEquatable<AsyncUnit>
	{
		public static readonly AsyncUnit Default;

		public override int GetHashCode()
		{
			return 0;
		}

		public bool Equals(AsyncUnit other)
		{
			return true;
		}

		public override string ToString()
		{
			return "()";
		}
	}
	public class CancellationTokenEqualityComparer : IEqualityComparer<CancellationToken>
	{
		public static readonly IEqualityComparer<CancellationToken> Default = new CancellationTokenEqualityComparer();

		public bool Equals(CancellationToken x, CancellationToken y)
		{
			return x.Equals(y);
		}

		public int GetHashCode(CancellationToken obj)
		{
			return obj.GetHashCode();
		}
	}
	public static class CancellationTokenExtensions
	{
		private static readonly Action<object> cancellationTokenCallback = Callback;

		private static readonly Action<object> disposeCallback = DisposeCallback;

		public static CancellationToken ToCancellationToken(this UniTask task)
		{
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			ToCancellationTokenCore(task, cancellationTokenSource).Forget();
			return cancellationTokenSource.Token;
		}

		public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken)
		{
			if (linkToken.IsCancellationRequested)
			{
				return linkToken;
			}
			if (!linkToken.CanBeCanceled)
			{
				return task.ToCancellationToken();
			}
			CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { linkToken });
			ToCancellationTokenCore(task, cancellationTokenSource).Forget();
			return cancellationTokenSource.Token;
		}

		public static CancellationToken ToCancellationToken<T>(this UniTask<T> task)
		{
			return task.AsUniTask().ToCancellationToken();
		}

		public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken)
		{
			return task.AsUniTask().ToCancellationToken(linkToken);
		}

		private static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts)
		{
			try
			{
				await task;
			}
			catch (Exception ex)
			{
				UniTaskScheduler.PublishUnobservedTaskException(ex);
			}
			cts.Cancel();
			cts.Dispose();
		}

		public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken)
		{
			if (cancellationToken.IsCancellationRequested)
			{
				return (UniTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration));
			}
			UniTaskCompletionSource uniTaskCompletionSource = new UniTaskCompletionSource();
			return (uniTaskCompletionSource.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, uniTaskCompletionSource));
		}

		private static void Callback(object state)
		{
			((UniTaskCompletionSource)state).TrySetResult();
		}

		public static CancellationTokenAwaitable WaitUntilCanceled(this CancellationToken cancellationToken)
		{
			return new CancellationTokenAwaitable(cancellationToken);
		}

		public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback)
		{
			bool flag = false;
			if (!ExecutionContext.IsFlowSuppressed())
			{
				ExecutionContext.SuppressFlow();
				flag = true;
			}
			try
			{
				return cancellationToken.Register(callback, useSynchronizationContext: false);
			}
			finally
			{
				if (flag)
				{
					ExecutionContext.RestoreFlow();
				}
			}
		}

		public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action<object> callback, object state)
		{
			bool flag = false;
			if (!ExecutionContext.IsFlowSuppressed())
			{
				ExecutionContext.SuppressFlow();
				flag = true;
			}
			try
			{
				return cancellationToken.Register(callback, state, useSynchronizationContext: false);
			}
			finally
			{
				if (flag)
				{
					ExecutionContext.RestoreFlow();
				}
			}
		}

		public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken)
		{
			return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable);
		}

		private static void DisposeCallback(object state)
		{
			((IDisposable)state).Dispose();
		}
	}
	public struct CancellationTokenAwaitable
	{
		public struct Awaiter : ICriticalNotifyCompletion, INotifyCompletion
		{
			private CancellationToken cancellationToken;

			public bool IsCompleted
			{
				get
				{
					if (cancellationToken.CanBeCanceled)
					{
						return cancellationToken.IsCancellationRequested;
					}
					return true;
				}
			}

			public Awaiter(CancellationToken cancellationToken)
			{
				this.cancellationToken = cancellationToken;
			}

			public void GetResult()
			{
			}

			public void OnCompleted(Action continuation)
			{
				UnsafeOnCompleted(continuation);
			}

			public void UnsafeOnCompleted(Action continuation)
			{
				cancellationToken.RegisterWithoutCaptureExecutionContext(continuation);
			}
		}

		private CancellationToken cancellationToken;

		public CancellationTokenAwaitable(CancellationToken cancellationToken)
		{
			this.cancellationToken = cancellationToken;
		}

		public Awaiter GetAwaiter()
		{
			return new Awaiter(cancellationToken);
		}
	}
	public static class CancellationTokenSourceExtensions
	{
		private static readonly Action<object> CancelCancellationTokenSourceStateDelegate = CancelCancellationTokenSourceState;

		private static void CancelCancellationTokenSourceState(object state)
		{
			((CancellationTokenSource)state).Cancel();
		}

		public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			return cts.CancelAfterSlim(TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming);
		}

		public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			return PlayerLoopTimer.StartNew(delayTimeSpan, periodic: false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts);
		}

		public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Component component)
		{
			cts.RegisterRaiseCancelOnDestroy(component.gameObject);
		}

		public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, GameObject gameObject)
		{
			gameObject.GetAsyncDestroyTrigger().CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts);
		}
	}
	public static class Channel
	{
		public static Channel<T> CreateSingleConsumerUnbounded<T>()
		{
			return new SingleConsumerUnboundedChannel<T>();
		}
	}
	public abstract class Channel<TWrite, TRead>
	{
		public ChannelReader<TRead> Reader { get; protected set; }

		public ChannelWriter<TWrite> Writer { get; protected set; }

		public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel)
		{
			return channel.Reader;
		}

		public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel)
		{
			return channel.Writer;
		}
	}
	public abstract class Channel<T> : Channel<T, T>
	{
	}
	public abstract class ChannelReader<T>
	{
		public abstract UniTask Completion { get; }

		public abstract bool TryRead(out T item);

		public abstract UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken));

		public virtual UniTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (TryRead(out var item))
			{
				return UniTask.FromResult(item);
			}
			return ReadAsyncCore(cancellationToken);
		}

		private async UniTask<T> ReadAsyncCore(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (await WaitToReadAsync(cancellationToken) && TryRead(out var item))
			{
				return item;
			}
			throw new ChannelClosedException();
		}

		public abstract IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken));
	}
	public abstract class ChannelWriter<T>
	{
		public abstract bool TryWrite(T item);

		public abstract bool TryComplete(Exception error = null);

		public void Complete(Exception error = null)
		{
			if (!TryComplete(error))
			{
				throw new ChannelClosedException();
			}
		}
	}
	public class ChannelClosedException : InvalidOperationException
	{
		public ChannelClosedException()
			: base("Channel is already closed.")
		{
		}

		public ChannelClosedException(string message)
			: base(message)
		{
		}

		public ChannelClosedException(Exception innerException)
			: base("Channel is already closed", innerException)
		{
		}

		public ChannelClosedException(string message, Exception innerException)
			: base(message, innerException)
		{
		}
	}
	internal class SingleConsumerUnboundedChannel<T> : Channel<T>
	{
		private sealed class SingleConsumerUnboundedChannelWriter : ChannelWriter<T>
		{
			private readonly SingleConsumerUnboundedChannel<T> parent;

			public SingleConsumerUnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent)
			{
				this.parent = parent;
			}

			public override bool TryWrite(T item)
			{
				bool isWaiting;
				lock (parent.items)
				{
					if (parent.closed)
					{
						return false;
					}
					parent.items.Enqueue(item);
					isWaiting = parent.readerSource.isWaiting;
				}
				if (isWaiting)
				{
					parent.readerSource.SingalContinuation();
				}
				return true;
			}

			public override bool TryComplete(Exception error = null)
			{
				lock (parent.items)
				{
					if (parent.closed)
					{
						return false;
					}
					parent.closed = true;
					bool isWaiting = parent.readerSource.isWaiting;
					if (parent.items.Count == 0)
					{
						if (error == null)
						{
							if (parent.completedTaskSource != null)
							{
								parent.completedTaskSource.TrySetResult();
							}
							else
							{
								parent.completedTask = UniTask.CompletedTask;
							}
						}
						else if (parent.completedTaskSource != null)
						{
							parent.completedTaskSource.TrySetException(error);
						}
						else
						{
							parent.completedTask = UniTask.FromException(error);
						}
						if (isWaiting)
						{
							parent.readerSource.SingalCompleted(error);
						}
					}
					parent.completionError = error;
				}
				return true;
			}
		}

		private sealed class SingleConsumerUnboundedChannelReader : ChannelReader<T>, IUniTaskSource<bool>, IUniTaskSource
		{
			private sealed class ReadAllAsyncEnumerable : IUniTaskAsyncEnumerable<T>, IUniTaskAsyncEnumerator<T>, IUniTaskAsyncDisposable
			{
				private readonly Action<object> CancellationCallback1Delegate = CancellationCallback1;

				private readonly Action<object> CancellationCallback2Delegate = CancellationCallback2;

				private readonly SingleConsumerUnboundedChannelReader parent;

				private CancellationToken cancellationToken1;

				private CancellationToken cancellationToken2;

				private CancellationTokenRegistration cancellationTokenRegistration1;

				private CancellationTokenRegistration cancellationTokenRegistration2;

				private T current;

				private bool cacheValue;

				private bool running;

				public T Current
				{
					get
					{
						if (cacheValue)
						{
							return current;
						}
						parent.TryRead(out current);
						return current;
					}
				}

				public ReadAllAsyncEnumerable(SingleConsumerUnboundedChannelReader parent, CancellationToken cancellationToken)
				{
					this.parent = parent;
					cancellationToken1 = cancellationToken;
				}

				public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken))
				{
					if (running)
					{
						throw new InvalidOperationException("Enumerator is already running, does not allow call GetAsyncEnumerator twice.");
					}
					if (cancellationToken1 != cancellationToken)
					{
						cancellationToken2 = cancellationToken;
					}
					if (cancellationToken1.CanBeCanceled)
					{
						cancellationTokenRegistration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
					}
					if (cancellationToken2.CanBeCanceled)
					{
						cancellationTokenRegistration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
					}
					running = true;
					return this;
				}

				public UniTask<bool> MoveNextAsync()
				{
					cacheValue = false;
					return parent.WaitToReadAsync(CancellationToken.None);
				}

				public UniTask DisposeAsync()
				{
					cancellationTokenRegistration1.Dispose();
					cancellationTokenRegistration2.Dispose();
					return default(UniTask);
				}

				private static void CancellationCallback1(object state)
				{
					ReadAllAsyncEnumerable readAllAsyncEnumerable = (ReadAllAsyncEnumerable)state;
					readAllAsyncEnumerable.parent.SingalCancellation(readAllAsyncEnumerable.cancellationToken1);
				}

				private static void CancellationCallback2(object state)
				{
					ReadAllAsyncEnumerable readAllAsyncEnumerable = (ReadAllAsyncEnumerable)state;
					readAllAsyncEnumerable.parent.SingalCancellation(readAllAsyncEnumerable.cancellationToken2);
				}
			}

			private readonly Action<object> CancellationCallbackDelegate = CancellationCallback;

			private readonly SingleConsumerUnboundedChannel<T> parent;

			private CancellationToken cancellationToken;

			private CancellationTokenRegistration cancellationTokenRegistration;

			private UniTaskCompletionSourceCore<bool> core;

			internal bool isWaiting;

			public override UniTask Completion
			{
				get
				{
					if (parent.completedTaskSource != null)
					{
						return parent.completedTaskSource.Task;
					}
					if (parent.closed)
					{
						return parent.completedTask;
					}
					parent.completedTaskSource = new UniTaskCompletionSource();
					return parent.completedTaskSource.Task;
				}
			}

			public SingleConsumerUnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
			{
				this.parent = parent;
				TaskTracker.TrackActiveTask(this, 4);
			}

			public override bool TryRead(out T item)
			{
				lock (parent.items)
				{
					if (parent.items.Count == 0)
					{
						item = default(T);
						return false;
					}
					item = parent.items.Dequeue();
					if (parent.closed && parent.items.Count == 0)
					{
						if (parent.completionError != null)
						{
							if (parent.completedTaskSource != null)
							{
								parent.completedTaskSource.TrySetException(parent.completionError);
							}
							else
							{
								parent.completedTask = UniTask.FromException(parent.completionError);
							}
						}
						else if (parent.completedTaskSource != null)
						{
							parent.completedTaskSource.TrySetResult();
						}
						else
						{
							parent.completedTask = UniTask.CompletedTask;
						}
					}
				}
				return true;
			}

			public override UniTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return UniTask.FromCanceled<bool>(cancellationToken);
				}
				lock (parent.items)
				{
					if (parent.items.Count != 0)
					{
						return CompletedTasks.True;
					}
					if (parent.closed)
					{
						if (parent.completionError == null)
						{
							return CompletedTasks.False;
						}
						return UniTask.FromException<bool>(parent.completionError);
					}
					cancellationTokenRegistration.Dispose();
					core.Reset();
					isWaiting = true;
					this.cancellationToken = cancellationToken;
					if (this.cancellationToken.CanBeCanceled)
					{
						cancellationTokenRegistration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
					}
					return new UniTask<bool>(this, core.Version);
				}
			}

			public void SingalContinuation()
			{
				core.TrySetResult(result: true);
			}

			public void SingalCancellation(CancellationToken cancellationToken)
			{
				TaskTracker.RemoveTracking(this);
				core.TrySetCanceled(cancellationToken);
			}

			public void SingalCompleted(Exception error)
			{
				if (error != null)
				{
					TaskTracker.RemoveTracking(this);
					core.TrySetException(error);
				}
				else
				{
					TaskTracker.RemoveTracking(this);
					core.TrySetResult(result: false);
				}
			}

			public override IUniTaskAsyncEnumerable<T> ReadAllAsync(CancellationToken cancellationToken = default(CancellationToken))
			{
				return new ReadAllAsyncEnumerable(this, cancellationToken);
			}

			bool IUniTaskSource<bool>.GetResult(short token)
			{
				return core.GetResult(token);
			}

			void IUniTaskSource.GetResult(short token)
			{
				core.GetResult(token);
			}

			UniTaskStatus IUniTaskSource.GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			UniTaskStatus IUniTaskSource.UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			private static void CancellationCallback(object state)
			{
				SingleConsumerUnboundedChannelReader obj = (SingleConsumerUnboundedChannelReader)state;
				obj.SingalCancellation(obj.cancellationToken);
			}
		}

		private readonly Queue<T> items;

		private readonly SingleConsumerUnboundedChannelReader readerSource;

		private UniTaskCompletionSource completedTaskSource;

		private UniTask completedTask;

		private Exception completionError;

		private bool closed;

		public SingleConsumerUnboundedChannel()
		{
			items = new Queue<T>();
			base.Writer = new SingleConsumerUnboundedChannelWriter(this);
			readerSource = new SingleConsumerUnboundedChannelReader(this);
			base.Reader = readerSource;
		}
	}
	public static class EnumerableAsyncExtensions
	{
		public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, UniTask> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, UniTask<TR>> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask> Select<T>(this IEnumerable<T> source, Func<T, int, UniTask> selector)
		{
			return Enumerable.Select(source, selector);
		}

		public static IEnumerable<UniTask<TR>> Select<T, TR>(this IEnumerable<T> source, Func<T, int, UniTask<TR>> selector)
		{
			return Enumerable.Select(source, selector);
		}
	}
	public static class EnumeratorAsyncExtensions
	{
		private sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
		{
			private static TaskPool<EnumeratorPromise> pool;

			private EnumeratorPromise nextNode;

			private IEnumerator innerEnumerator;

			private CancellationToken cancellationToken;

			private int initialFrame;

			private bool loopRunning;

			private bool calledGetResult;

			private UniTaskCompletionSourceCore<object> core;

			private static readonly FieldInfo waitForSeconds_Seconds;

			public ref EnumeratorPromise NextNode => ref nextNode;

			static EnumeratorPromise()
			{
				waitForSeconds_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
				TaskPool.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
			}

			private EnumeratorPromise()
			{
			}

			public static IUniTaskSource Create(IEnumerator innerEnumerator, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new EnumeratorPromise();
				}
				TaskTracker.TrackActiveTask(result, 3);
				result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
				result.cancellationToken = cancellationToken;
				result.loopRunning = true;
				result.calledGetResult = false;
				result.initialFrame = -1;
				token = result.core.Version;
				if (result.MoveNext())
				{
					PlayerLoopHelper.AddAction(timing, result);
				}
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					calledGetResult = true;
					core.GetResult(token);
				}
				finally
				{
					if (!loopRunning)
					{
						TryReturn();
					}
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public bool MoveNext()
			{
				if (calledGetResult)
				{
					loopRunning = false;
					TryReturn();
					return false;
				}
				if (innerEnumerator == null)
				{
					return false;
				}
				if (cancellationToken.IsCancellationRequested)
				{
					loopRunning = false;
					core.TrySetCanceled(cancellationToken);
					return false;
				}
				if (initialFrame == -1)
				{
					if (PlayerLoopHelper.IsMainThread)
					{
						initialFrame = Time.frameCount;
					}
				}
				else if (initialFrame == Time.frameCount)
				{
					return true;
				}
				try
				{
					if (innerEnumerator.MoveNext())
					{
						return true;
					}
				}
				catch (Exception error)
				{
					loopRunning = false;
					core.TrySetException(error);
					return false;
				}
				loopRunning = false;
				core.TrySetResult(null);
				return false;
			}

			private bool TryReturn()
			{
				TaskTracker.RemoveTracking(this);
				core.Reset();
				innerEnumerator = null;
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}

			private static IEnumerator ConsumeEnumerator(IEnumerator enumerator)
			{
				while (enumerator.MoveNext())
				{
					object current = enumerator.Current;
					if (current == null)
					{
						yield return null;
						continue;
					}
					CustomYieldInstruction cyi = (CustomYieldInstruction)((current is CustomYieldInstruction) ? current : null);
					if (cyi != null)
					{
						while (cyi.keepWaiting)
						{
							yield return null;
						}
						continue;
					}
					if (current is YieldInstruction)
					{
						IEnumerator innerCoroutine2 = null;
						AsyncOperation val = (AsyncOperation)((current is AsyncOperation) ? current : null);
						if (val == null)
						{
							WaitForSeconds val2 = (WaitForSeconds)((current is WaitForSeconds) ? current : null);
							if (val2 != null)
							{
								innerCoroutine2 = UnwrapWaitForSeconds(val2);
							}
						}
						else
						{
							innerCoroutine2 = UnwrapWaitAsyncOperation(val);
						}
						if (innerCoroutine2 != null)
						{
							while (innerCoroutine2.MoveNext())
							{
								yield return null;
							}
							continue;
						}
					}
					else if (current is IEnumerator enumerator2)
					{
						IEnumerator innerCoroutine2 = ConsumeEnumerator(enumerator2);
						while (innerCoroutine2.MoveNext())
						{
							yield return null;
						}
						continue;
					}
					Debug.LogWarning((object)("yield " + current.GetType().Name + " is not supported on await IEnumerator or IEnumerator.ToUniTask(), please use ToUniTask(MonoBehaviour coroutineRunner) instead."));
					yield return null;
				}
			}

			private static IEnumerator UnwrapWaitForSeconds(WaitForSeconds waitForSeconds)
			{
				float second = (float)waitForSeconds_Seconds.GetValue(waitForSeconds);
				float elapsed = 0f;
				do
				{
					yield return null;
					elapsed += Time.deltaTime;
				}
				while (!(elapsed >= second));
			}

			private static IEnumerator UnwrapWaitAsyncOperation(AsyncOperation asyncOperation)
			{
				while (!asyncOperation.isDone)
				{
					yield return null;
				}
			}
		}

		public static UniTask.Awaiter GetAwaiter<T>(this T enumerator) where T : IEnumerator
		{
			object obj = enumerator;
			Error.ThrowArgumentNullException((IEnumerator)obj, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create((IEnumerator)obj, PlayerLoopTiming.Update, CancellationToken.None, out token), token).GetAwaiter();
		}

		public static UniTask WithCancellation(this IEnumerator enumerator, CancellationToken cancellationToken)
		{
			Error.ThrowArgumentNullException(enumerator, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create(enumerator, PlayerLoopTiming.Update, cancellationToken, out token), token);
		}

		public static UniTask ToUniTask(this IEnumerator enumerator, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
		{
			Error.ThrowArgumentNullException(enumerator, "enumerator");
			short token;
			return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out token), token);
		}

		public static UniTask ToUniTask(this IEnumerator enumerator, MonoBehaviour coroutineRunner)
		{
			AutoResetUniTaskCompletionSource autoResetUniTaskCompletionSource = AutoResetUniTaskCompletionSource.Create();
			coroutineRunner.StartCoroutine(Core(enumerator, coroutineRunner, autoResetUniTaskCompletionSource));
			return autoResetUniTaskCompletionSource.Task;
		}

		private static IEnumerator Core(IEnumerator inner, MonoBehaviour coroutineRunner, AutoResetUniTaskCompletionSource source)
		{
			yield return coroutineRunner.StartCoroutine(inner);
			source.TrySetResult();
		}
	}
	public static class ExceptionExtensions
	{
		public static bool IsOperationCanceledException(this Exception exception)
		{
			return exception is OperationCanceledException;
		}
	}
	public interface IUniTaskAsyncEnumerable<out T>
	{
		IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default(CancellationToken));
	}
	public interface IUniTaskAsyncEnumerator<out T> : IUniTaskAsyncDisposable
	{
		T Current { get; }

		UniTask<bool> MoveNextAsync();
	}
	public interface IUniTaskAsyncDisposable
	{
		UniTask DisposeAsync();
	}
	public interface IUniTaskOrderedAsyncEnumerable<TElement> : IUniTaskAsyncEnumerable<TElement>
	{
		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);

		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);

		IUniTaskOrderedAsyncEnumerable<TElement> CreateOrderedEnumerable<TKey>(Func<TElement, CancellationToken, UniTask<TKey>> keySelector, IComparer<TKey> comparer, bool descending);
	}
	public interface IConnectableUniTaskAsyncEnumerable<out T> : IUniTaskAsyncEnumerable<T>
	{
		IDisposable Connect();
	}
	public static class UniTaskAsyncEnumerableExtensions
	{
		public static UniTaskCancelableAsyncEnumerable<T> WithCancellation<T>(this IUniTaskAsyncEnumerable<T> source, CancellationToken cancellationToken)
		{
			return new UniTaskCancelableAsyncEnumerable<T>(source, cancellationToken);
		}
	}
	[StructLayout(LayoutKind.Auto)]
	public readonly struct UniTaskCancelableAsyncEnumerable<T>
	{
		[StructLayout(LayoutKind.Auto)]
		public readonly struct Enumerator
		{
			private readonly IUniTaskAsyncEnumerator<T> enumerator;

			public T Current => enumerator.Current;

			internal Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
			{
				this.enumerator = enumerator;
			}

			public UniTask<bool> MoveNextAsync()
			{
				return enumerator.MoveNextAsync();
			}

			public UniTask DisposeAsync()
			{
				return enumerator.DisposeAsync();
			}
		}

		private readonly IUniTaskAsyncEnumerable<T> enumerable;

		private readonly CancellationToken cancellationToken;

		internal UniTaskCancelableAsyncEnumerable(IUniTaskAsyncEnumerable<T> enumerable, CancellationToken cancellationToken)
		{
			this.enumerable = enumerable;
			this.cancellationToken = cancellationToken;
		}

		public Enumerator GetAsyncEnumerator()
		{
			return new Enumerator(enumerable.GetAsyncEnumerator(cancellationToken));
		}
	}
	public enum UniTaskStatus
	{
		Pending,
		Succeeded,
		Faulted,
		Canceled
	}
	public interface IUniTaskSource
	{
		UniTaskStatus GetStatus(short token);

		void OnCompleted(Action<object> continuation, object state, short token);

		void GetResult(short token);

		UniTaskStatus UnsafeGetStatus();
	}
	public interface IUniTaskSource<out T> : IUniTaskSource
	{
		new T GetResult(short token);
	}
	public static class UniTaskStatusExtensions
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCompleted(this UniTaskStatus status)
		{
			return status != UniTaskStatus.Pending;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCompletedSuccessfully(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Succeeded;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsCanceled(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Canceled;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsFaulted(this UniTaskStatus status)
		{
			return status == UniTaskStatus.Faulted;
		}
	}
	public static class TaskTracker
	{
		public static class EditorEnableState
		{
			private static bool enableAutoReload;

			private static bool enableTracking;

			private static bool enableStackTrace;

			public static bool EnableAutoReload
			{
				get
				{
					return enableAutoReload;
				}
				set
				{
					enableAutoReload = value;
					EditorPrefs.SetBool("UniTaskTrackerWindow_EnableAutoReloadKey", value);
				}
			}

			public static bool EnableTracking
			{
				get
				{
					return enableTracking;
				}
				set
				{
					enableTracking = value;
					EditorPrefs.SetBool("UniTaskTrackerWindow_EnableTrackingKey", value);
				}
			}

			public static bool EnableStackTrace
			{
				get
				{
					return enableStackTrace;
				}
				set
				{
					enableStackTrace = value;
					EditorPrefs.SetBool("UniTaskTrackerWindow_EnableStackTraceKey", value);
				}
			}
		}

		private static int trackingId = 0;

		public const string EnableAutoReloadKey = "UniTaskTrackerWindow_EnableAutoReloadKey";

		public const string EnableTrackingKey = "UniTaskTrackerWindow_EnableTrackingKey";

		public const string EnableStackTraceKey = "UniTaskTrackerWindow_EnableStackTraceKey";

		private static List<KeyValuePair<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)>> listPool = new List<KeyValuePair<IUniTaskSource, (string, int, DateTime, string)>>();

		private static readonly WeakDictionary<IUniTaskSource, (string formattedType, int trackingId, DateTime addTime, string stackTrace)> tracking = new WeakDictionary<IUniTaskSource, (string, int, DateTime, string)>();

		private static bool dirty;

		[Conditional("UNITY_EDITOR")]
		public static void TrackActiveTask(IUniTaskSource task, int skipFrame)
		{
			dirty = true;
			if (EditorEnableState.EnableTracking)
			{
				string item = (EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, fNeedFileInfo: true).CleanupAsyncStackTrace() : "");
				string item2;
				if (EditorEnableState.EnableStackTrace)
				{
					StringBuilder stringBuilder = new StringBuilder();
					TypeBeautify(task.GetType(), stringBuilder);
					item2 = stringBuilder.ToString();
				}
				else
				{
					item2 = task.GetType().Name;
				}
				tracking.TryAdd(task, (item2, Interlocked.Increment(ref trackingId), DateTime.UtcNow, item));
			}
		}

		[Conditional("UNITY_EDITOR")]
		public static void RemoveTracking(IUniTaskSource task)
		{
			dirty = true;
			if (EditorEnableState.EnableTracking)
			{
				tracking.TryRemove(task);
			}
		}

		public static bool CheckAndResetDirty()
		{
			bool result = dirty;
			dirty = false;
			return result;
		}

		public static void ForEachActiveTask(Action<int, string, UniTaskStatus, DateTime, string> action)
		{
			lock (listPool)
			{
				int num = tracking.ToList(ref listPool, clear: false);
				try
				{
					for (int i = 0; i < num; i++)
					{
						action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
						listPool[i] = default(KeyValuePair<IUniTaskSource, (string, int, DateTime, string)>);
					}
				}
				catch
				{
					listPool.Clear();
					throw;
				}
			}
		}

		private static void TypeBeautify(Type type, StringBuilder sb)
		{
			if (type.IsNested)
			{
				sb.Append(type.DeclaringType.Name.ToString());
				sb.Append(".");
			}
			if (type.IsGenericType)
			{
				int num = type.Name.IndexOf("`");
				if (num != -1)
				{
					sb.Append(type.Name.Substring(0, num));
				}
				else
				{
					sb.Append(type.Name);
				}
				sb.Append("<");
				bool flag = true;
				Type[] genericArguments = type.GetGenericArguments();
				foreach (Type type2 in genericArguments)
				{
					if (!flag)
					{
						sb.Append(", ");
					}
					flag = false;
					TypeBeautify(type2, sb);
				}
				sb.Append(">");
			}
			else
			{
				sb.Append(type.Name);
			}
		}
	}
	public abstract class MoveNextSource : IUniTaskSource<bool>, IUniTaskSource
	{
		protected UniTaskCompletionSourceCore<bool> completionSource;

		public bool GetResult(short token)
		{
			return completionSource.GetResult(token);
		}

		public UniTaskStatus GetStatus(short token)
		{
			return completionSource.GetStatus(token);
		}

		public void OnCompleted(Action<object> continuation, object state, short token)
		{
			completionSource.OnCompleted(continuation, state, token);
		}

		public UniTaskStatus UnsafeGetStatus()
		{
			return completionSource.UnsafeGetStatus();
		}

		void IUniTaskSource.GetResult(short token)
		{
			completionSource.GetResult(token);
		}

		protected bool TryGetResult<T>(UniTask<T>.Awaiter awaiter, out T result)
		{
			try
			{
				result = awaiter.GetResult();
				return true;
			}
			catch (Exception error)
			{
				completionSource.TrySetException(error);
				result = default(T);
				return false;
			}
		}

		protected bool TryGetResult(UniTask.Awaiter awaiter)
		{
			try
			{
				awaiter.GetResult();
				return true;
			}
			catch (Exception error)
			{
				completionSource.TrySetException(error);
				return false;
			}
		}
	}
	public static class UniTaskLoopRunners
	{
		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldInitialization
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldEarlyUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldFixedUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPreUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPreLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldPostLateUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerYieldTimeUpdate
		{
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct UniTaskLoopRunnerLastYieldTimeUpdate
		{
		}
	}
	public enum PlayerLoopTiming
	{
		Initialization,
		LastInitialization,
		EarlyUpdate,
		LastEarlyUpdate,
		FixedUpdate,
		LastFixedUpdate,
		PreUpdate,
		LastPreUpdate,
		Update,
		LastUpdate,
		PreLateUpdate,
		LastPreLateUpdate,
		PostLateUpdate,
		LastPostLateUpdate,
		TimeUpdate,
		LastTimeUpdate
	}
	[Flags]
	public enum InjectPlayerLoopTimings
	{
		All = 0xFFFF,
		Standard = 0x7555,
		Minimum = 0x2110,
		Initialization = 1,
		LastInitialization = 2,
		EarlyUpdate = 4,
		LastEarlyUpdate = 8,
		FixedUpdate = 0x10,
		LastFixedUpdate = 0x20,
		PreUpdate = 0x40,
		LastPreUpdate = 0x80,
		Update = 0x100,
		LastUpdate = 0x200,
		PreLateUpdate = 0x400,
		LastPreLateUpdate = 0x800,
		PostLateUpdate = 0x1000,
		LastPostLateUpdate = 0x2000,
		TimeUpdate = 0x4000,
		LastTimeUpdate = 0x8000
	}
	public interface IPlayerLoopItem
	{
		bool MoveNext();
	}
	public static class PlayerLoopHelper
	{
		private static readonly ContinuationQueue ThrowMarkerContinuationQueue = new ContinuationQueue(PlayerLoopTiming.Initialization);

		private static readonly PlayerLoopRunner ThrowMarkerPlayerLoopRunner = new PlayerLoopRunner(PlayerLoopTiming.Initialization);

		private static int mainThreadId;

		private static string applicationDataPath;

		private static SynchronizationContext unitySynchronizationContext;

		private static ContinuationQueue[] yielders;

		private static PlayerLoopRunner[] runners;

		public static SynchronizationContext UnitySynchronizationContext => unitySynchronizationContext;

		public static int MainThreadId => mainThreadId;

		internal static string ApplicationDataPath => applicationDataPath;

		public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;

		internal static bool IsEditorApplicationQuitting { get; private set; }

		private static PlayerLoopSystem[] InsertRunner(PlayerLoopSystem loopSystem, bool injectOnFirst, Type loopRunnerYieldType, ContinuationQueue cq, Type loopRunnerType, PlayerLoopRunner runner)
		{
			//IL_0028: 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_004e: Expected O, but got Unknown
			//IL_004e: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_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_00b5: 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)
			EditorApplication.playModeStateChanged += delegate(PlayModeStateChange state)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Invalid comparison between Unknown and I4
				if ((int)state == 0 || (int)state == 1)
				{
					IsEditorApplicationQuitting = true;
					if (runner != null)
					{
						runner.Run();
						runner.Clear();
					}
					if (cq != null)
					{
						cq.Run();
						cq.Clear();
					}
					IsEditorApplicationQuitting = false;
				}
			};
			PlayerLoopSystem val = default(PlayerLoopSystem);
			val.type = loopRunnerYieldType;
			val.updateDelegate = new UpdateFunction(cq.Run);
			PlayerLoopSystem val2 = val;
			val = default(PlayerLoopSystem);
			val.type = loopRunnerType;
			val.updateDelegate = new UpdateFunction(runner.Run);
			PlayerLoopSystem val3 = val;
			PlayerLoopSystem[] array = RemoveRunner(loopSystem, loopRunnerYieldType, loopRunnerType);
			PlayerLoopSystem[] array2 = (PlayerLoopSystem[])(object)new PlayerLoopSystem[array.Length + 2];
			Array.Copy(array, 0, array2, injectOnFirst ? 2 : 0, array.Length);
			if (injectOnFirst)
			{
				array2[0] = val2;
				array2[1] = val3;
			}
			else
			{
				array2[^2] = val2;
				array2[^1] = val3;
			}
			return array2;
		}

		private static PlayerLoopSystem[] RemoveRunner(PlayerLoopSystem loopSystem, Type loopRunnerYieldType, Type loopRunnerType)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			return loopSystem.subSystemList.Where((PlayerLoopSystem ls) => ls.type != loopRunnerYieldType && ls.type != loopRunnerType).ToArray();
		}

		private static PlayerLoopSystem[] InsertUniTaskSynchronizationContext(PlayerLoopSystem loopSystem)
		{
			//IL_0002: 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_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem val = default(PlayerLoopSystem);
			val.type = typeof(UniTaskSynchronizationContext);
			val.updateDelegate = new UpdateFunction(UniTaskSynchronizationContext.Run);
			PlayerLoopSystem item = val;
			List<PlayerLoopSystem> list = new List<PlayerLoopSystem>(loopSystem.subSystemList.Where((PlayerLoopSystem ls) => ls.type != typeof(UniTaskSynchronizationContext)).ToArray());
			int num = list.FindIndex((PlayerLoopSystem x) => x.type.Name == "ScriptRunDelayedTasks");
			if (num == -1)
			{
				num = list.FindIndex((PlayerLoopSystem x) => x.type.Name == "UniTaskLoopRunnerUpdate");
			}
			list.Insert(num + 1, item);
			return list.ToArray();
		}

		[RuntimeInitializeOnLoadMethod(/*Could not decode attribute arguments.*/)]
		private static void Init()
		{
			//IL_002f: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			unitySynchronizationContext = SynchronizationContext.Current;
			mainThreadId = Thread.CurrentThread.ManagedThreadId;
			try
			{
				applicationDataPath = Application.dataPath;
			}
			catch
			{
			}
			if ((EditorSettings.enterPlayModeOptionsEnabled && ((Enum)EditorSettings.enterPlayModeOptions).HasFlag((Enum)(object)(EnterPlayModeOptions)1)) || runners == null)
			{
				PlayerLoopSystem playerLoop = PlayerLoop.GetCurrentPlayerLoop();
				Initialize(ref playerLoop);
			}
		}

		[InitializeOnLoadMethod]
		private static void InitOnEditor()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Init();
			EditorApplication.update = (CallbackFunction)Delegate.Combine((Delegate?)(object)EditorApplication.update, (Delegate?)new CallbackFunction(ForceEditorPlayerLoopUpdate));
		}

		private static void ForceEditorPlayerLoopUpdate()
		{
			if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
			{
				return;
			}
			if (yielders != null)
			{
				ContinuationQueue[] array = yielders;
				for (int i = 0; i < array.Length; i++)
				{
					array[i]?.Run();
				}
			}
			if (runners != null)
			{
				PlayerLoopRunner[] array2 = runners;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i]?.Run();
				}
			}
			UniTaskSynchronizationContext.Run();
		}

		private static int FindLoopSystemIndex(PlayerLoopSystem[] playerLoopList, Type systemType)
		{
			for (int i = 0; i < playerLoopList.Length; i++)
			{
				if (playerLoopList[i].type == systemType)
				{
					return i;
				}
			}
			throw new Exception("Target PlayerLoopSystem does not found. Type:" + systemType.FullName);
		}

		private static void InsertLoop(PlayerLoopSystem[] copyList, InjectPlayerLoopTimings injectTimings, Type loopType, InjectPlayerLoopTimings targetTimings, int index, bool injectOnFirst, Type loopRunnerYieldType, Type loopRunnerType, PlayerLoopTiming playerLoopTiming)
		{
			//IL_005a: 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)
			int num = FindLoopSystemIndex(copyList, loopType);
			if ((injectTimings & targetTimings) == targetTimings)
			{
				copyList[num].subSystemList = InsertRunner(copyList[num], injectOnFirst, loopRunnerYieldType, yielders[index] = new ContinuationQueue(playerLoopTiming), loopRunnerType, runners[index] = new PlayerLoopRunner(playerLoopTiming));
			}
			else
			{
				copyList[num].subSystemList = RemoveRunner(copyList[num], loopRunnerYieldType, loopRunnerType);
			}
		}

		public static void Initialize(ref PlayerLoopSystem playerLoop, InjectPlayerLoopTimings injectTimings = InjectPlayerLoopTimings.All)
		{
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			yielders = new ContinuationQueue[16];
			runners = new PlayerLoopRunner[16];
			PlayerLoopSystem[] array = playerLoop.subSystemList.ToArray();
			InsertLoop(array, injectTimings, typeof(Initialization), InjectPlayerLoopTimings.Initialization, 0, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization), PlayerLoopTiming.Initialization);
			InsertLoop(array, injectTimings, typeof(Initialization), InjectPlayerLoopTimings.LastInitialization, 1, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldInitialization), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastInitialization), PlayerLoopTiming.LastInitialization);
			InsertLoop(array, injectTimings, typeof(EarlyUpdate), InjectPlayerLoopTimings.EarlyUpdate, 2, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerEarlyUpdate), PlayerLoopTiming.EarlyUpdate);
			InsertLoop(array, injectTimings, typeof(EarlyUpdate), InjectPlayerLoopTimings.LastEarlyUpdate, 3, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldEarlyUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastEarlyUpdate), PlayerLoopTiming.LastEarlyUpdate);
			InsertLoop(array, injectTimings, typeof(FixedUpdate), InjectPlayerLoopTimings.FixedUpdate, 4, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerFixedUpdate), PlayerLoopTiming.FixedUpdate);
			InsertLoop(array, injectTimings, typeof(FixedUpdate), InjectPlayerLoopTimings.LastFixedUpdate, 5, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldFixedUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastFixedUpdate), PlayerLoopTiming.LastFixedUpdate);
			InsertLoop(array, injectTimings, typeof(PreUpdate), InjectPlayerLoopTimings.PreUpdate, 6, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreUpdate), PlayerLoopTiming.PreUpdate);
			InsertLoop(array, injectTimings, typeof(PreUpdate), InjectPlayerLoopTimings.LastPreUpdate, 7, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreUpdate), PlayerLoopTiming.LastPreUpdate);
			InsertLoop(array, injectTimings, typeof(Update), InjectPlayerLoopTimings.Update, 8, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerUpdate), PlayerLoopTiming.Update);
			InsertLoop(array, injectTimings, typeof(Update), InjectPlayerLoopTimings.LastUpdate, 9, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastUpdate), PlayerLoopTiming.LastUpdate);
			InsertLoop(array, injectTimings, typeof(PreLateUpdate), InjectPlayerLoopTimings.PreLateUpdate, 10, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPreLateUpdate), PlayerLoopTiming.PreLateUpdate);
			InsertLoop(array, injectTimings, typeof(PreLateUpdate), InjectPlayerLoopTimings.LastPreLateUpdate, 11, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPreLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPreLateUpdate), PlayerLoopTiming.LastPreLateUpdate);
			InsertLoop(array, injectTimings, typeof(PostLateUpdate), InjectPlayerLoopTimings.PostLateUpdate, 12, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerPostLateUpdate), PlayerLoopTiming.PostLateUpdate);
			InsertLoop(array, injectTimings, typeof(PostLateUpdate), InjectPlayerLoopTimings.LastPostLateUpdate, 13, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldPostLateUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastPostLateUpdate), PlayerLoopTiming.LastPostLateUpdate);
			InsertLoop(array, injectTimings, typeof(TimeUpdate), InjectPlayerLoopTimings.TimeUpdate, 14, injectOnFirst: true, typeof(UniTaskLoopRunners.UniTaskLoopRunnerYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerTimeUpdate), PlayerLoopTiming.TimeUpdate);
			InsertLoop(array, injectTimings, typeof(TimeUpdate), InjectPlayerLoopTimings.LastTimeUpdate, 15, injectOnFirst: false, typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastYieldTimeUpdate), typeof(UniTaskLoopRunners.UniTaskLoopRunnerLastTimeUpdate), PlayerLoopTiming.LastTimeUpdate);
			int num = FindLoopSystemIndex(array, typeof(Update));
			array[num].subSystemList = InsertUniTaskSynchronizationContext(array[num]);
			playerLoop.subSystemList = array;
			PlayerLoop.SetPlayerLoop(playerLoop);
		}

		public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action)
		{
			PlayerLoopRunner obj = runners[(int)timing];
			if (obj == null)
			{
				ThrowInvalidLoopTiming(timing);
			}
			obj.AddAction(action);
		}

		private static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming)
		{
			throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming);
		}

		public static void AddContinuation(PlayerLoopTiming timing, Action continuation)
		{
			ContinuationQueue obj = yielders[(int)timing];
			if (obj == null)
			{
				ThrowInvalidLoopTiming(timing);
			}
			obj.Enqueue(continuation);
		}

		public static void DumpCurrentPlayerLoop()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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)
			PlayerLoopSystem currentPlayerLoop = PlayerLoop.GetCurrentPlayerLoop();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("PlayerLoop List");
			PlayerLoopSystem[] subSystemList = currentPlayerLoop.subSystemList;
			for (int i = 0; i < subSystemList.Length; i++)
			{
				PlayerLoopSystem val = subSystemList[i];
				stringBuilder.AppendFormat("------{0}------", val.type.Name);
				stringBuilder.AppendLine();
				if (val.subSystemList == null)
				{
					stringBuilder.AppendFormat("{0} has no subsystems!", ((object)(PlayerLoopSystem)(ref val)).ToString());
					stringBuilder.AppendLine();
					continue;
				}
				PlayerLoopSystem[] subSystemList2 = val.subSystemList;
				foreach (PlayerLoopSystem val2 in subSystemList2)
				{
					stringBuilder.AppendFormat("{0}", val2.type.Name);
					stringBuilder.AppendLine();
					if (val2.subSystemList != null)
					{
						Debug.LogWarning((object)("More Subsystem:" + val2.subSystemList.Length));
					}
				}
			}
			Debug.Log((object)stringBuilder.ToString());
		}

		public static bool IsInjectedUniTaskPlayerLoop()
		{
			//IL_0000: 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_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			PlayerLoopSystem[] subSystemList = PlayerLoop.GetCurrentPlayerLoop().subSystemList;
			foreach (PlayerLoopSystem val in subSystemList)
			{
				if (val.subSystemList == null)
				{
					continue;
				}
				PlayerLoopSystem[] subSystemList2 = val.subSystemList;
				for (int j = 0; j < subSystemList2.Length; j++)
				{
					if (subSystemList2[j].type == typeof(UniTaskLoopRunners.UniTaskLoopRunnerInitialization))
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem
	{
		private readonly CancellationToken cancellationToken;

		private readonly Action<object> timerCallback;

		private readonly object state;

		private readonly PlayerLoopTiming playerLoopTiming;

		private readonly bool periodic;

		private bool isRunning;

		private bool tryStop;

		private bool isDisposed;

		protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			this.periodic = periodic;
			this.playerLoopTiming = playerLoopTiming;
			this.cancellationToken = cancellationToken;
			this.timerCallback = timerCallback;
			this.state = state;
		}

		public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			if (PlayerLoopHelper.IsMainThread && !EditorApplication.isPlaying)
			{
				delayType = DelayType.Realtime;
			}
			return delayType switch
			{
				DelayType.UnscaledDeltaTime => new IgnoreTimeScalePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
				DelayType.Realtime => new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
				_ => new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state), 
			};
		}

		public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
		{
			PlayerLoopTimer playerLoopTimer = Create(interval, periodic, delayType, playerLoopTiming, cancellationToken, timerCallback, state);
			playerLoopTimer.Restart();
			return playerLoopTimer;
		}

		public void Restart()
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			ResetCore(null);
			if (!isRunning)
			{
				isRunning = true;
				PlayerLoopHelper.AddAction(playerLoopTiming, this);
			}
			tryStop = false;
		}

		public void Restart(TimeSpan interval)
		{
			if (isDisposed)
			{
				throw new ObjectDisposedException(null);
			}
			ResetCore(interval);
			if (!isRunning)
			{
				isRunning = true;
				PlayerLoopHelper.AddAction(playerLoopTiming, this);
			}
			tryStop = false;
		}

		public void Stop()
		{
			tryStop = true;
		}

		protected abstract void ResetCore(TimeSpan? newInterval);

		public void Dispose()
		{
			isDisposed = true;
		}

		bool IPlayerLoopItem.MoveNext()
		{
			if (isDisposed)
			{
				isRunning = false;
				return false;
			}
			if (tryStop)
			{
				isRunning = false;
				return false;
			}
			CancellationToken cancellationToken = this.cancellationToken;
			if (cancellationToken.IsCancellationRequested)
			{
				isRunning = false;
				return false;
			}
			if (!MoveNextCore())
			{
				timerCallback(state);
				if (periodic)
				{
					ResetCore(null);
					return true;
				}
				isRunning = false;
				return false;
			}
			return true;
		}

		protected abstract bool MoveNextCore();
	}
	internal sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer
	{
		private int initialFrame;

		private float elapsed;

		private float interval;

		public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (elapsed == 0f && initialFrame == Time.frameCount)
			{
				return true;
			}
			elapsed += Time.deltaTime;
			if (elapsed >= interval)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			elapsed = 0f;
			initialFrame = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
			if (interval.HasValue)
			{
				this.interval = (float)interval.Value.TotalSeconds;
			}
		}
	}
	internal sealed class IgnoreTimeScalePlayerLoopTimer : PlayerLoopTimer
	{
		private int initialFrame;

		private float elapsed;

		private float interval;

		public IgnoreTimeScalePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (elapsed == 0f && initialFrame == Time.frameCount)
			{
				return true;
			}
			elapsed += Time.unscaledDeltaTime;
			if (elapsed >= interval)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			elapsed = 0f;
			initialFrame = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
			if (interval.HasValue)
			{
				this.interval = (float)interval.Value.TotalSeconds;
			}
		}
	}
	internal sealed class RealtimePlayerLoopTimer : PlayerLoopTimer
	{
		private ValueStopwatch stopwatch;

		private long intervalTicks;

		public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
			: base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
		{
			ResetCore(interval);
		}

		protected override bool MoveNextCore()
		{
			if (stopwatch.ElapsedTicks >= intervalTicks)
			{
				return false;
			}
			return true;
		}

		protected override void ResetCore(TimeSpan? interval)
		{
			stopwatch = ValueStopwatch.StartNew();
			if (interval.HasValue)
			{
				intervalTicks = interval.Value.Ticks;
			}
		}
	}
	public static class Progress
	{
		private sealed class NullProgress<T> : IProgress<T>
		{
			public static readonly IProgress<T> Instance = new NullProgress<T>();

			private NullProgress()
			{
			}

			public void Report(T value)
			{
			}
		}

		private sealed class AnonymousProgress<T> : IProgress<T>
		{
			private readonly Action<T> action;

			public AnonymousProgress(Action<T> action)
			{
				this.action = action;
			}

			public void Report(T value)
			{
				action(value);
			}
		}

		private sealed class OnlyValueChangedProgress<T> : IProgress<T>
		{
			private readonly Action<T> action;

			private readonly IEqualityComparer<T> comparer;

			private bool isFirstCall;

			private T latestValue;

			public OnlyValueChangedProgress(Action<T> action, IEqualityComparer<T> comparer)
			{
				this.action = action;
				this.comparer = comparer;
				isFirstCall = true;
			}

			public void Report(T value)
			{
				if (isFirstCall)
				{
					isFirstCall = false;
				}
				else if (comparer.Equals(value, latestValue))
				{
					return;
				}
				latestValue = value;
				action(value);
			}
		}

		public static IProgress<T> Create<T>(Action<T> handler)
		{
			if (handler == null)
			{
				return NullProgress<T>.Instance;
			}
			return new AnonymousProgress<T>(handler);
		}

		public static IProgress<T> CreateOnlyValueChanged<T>(Action<T> handler, IEqualityComparer<T> comparer = null)
		{
			if (handler == null)
			{
				return NullProgress<T>.Instance;
			}
			return new OnlyValueChangedProgress<T>(handler, comparer ?? UnityEqualityComparer.GetDefault<T>());
		}
	}
	public static class TaskPool
	{
		internal static int MaxPoolSize;

		private static Dictionary<Type, Func<int>> sizes;

		static TaskPool()
		{
			sizes = new Dictionary<Type, Func<int>>();
			try
			{
				string environmentVariable = Environment.GetEnvironmentVariable("UNITASK_MAX_POOLSIZE");
				if (environmentVariable != null && int.TryParse(environmentVariable, out var result))
				{
					MaxPoolSize = result;
					return;
				}
			}
			catch
			{
			}
			MaxPoolSize = int.MaxValue;
		}

		public static void SetMaxPoolSize(int maxPoolSize)
		{
			MaxPoolSize = maxPoolSize;
		}

		public static IEnumerable<(Type, int)> GetCacheSizeInfo()
		{
			lock (sizes)
			{
				foreach (KeyValuePair<Type, Func<int>> size in sizes)
				{
					yield return (size.Key, size.Value());
				}
			}
		}

		public static void RegisterSizeGetter(Type type, Func<int> getSize)
		{
			lock (sizes)
			{
				sizes[type] = getSize;
			}
		}
	}
	public interface ITaskPoolNode<T>
	{
		ref T NextNode { get; }
	}
	[StructLayout(LayoutKind.Auto)]
	public struct TaskPool<T> where T : class, ITaskPoolNode<T>
	{
		private int gate;

		private int size;

		private T root;

		public int Size => size;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool TryPop(out T result)
		{
			if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
			{
				T val = root;
				if (val != null)
				{
					ref T nextNode = ref val.NextNode;
					root = nextNode;
					nextNode = null;
					size--;
					result = val;
					Volatile.Write(ref gate, 0);
					return true;
				}
				Volatile.Write(ref gate, 0);
			}
			result = null;
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool TryPush(T item)
		{
			if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
			{
				if (size < TaskPool.MaxPoolSize)
				{
					item.NextNode = root;
					root = item;
					size++;
					Volatile.Write(ref gate, 0);
					return true;
				}
				Volatile.Write(ref gate, 0);
			}
			return false;
		}
	}
	public sealed class TimeoutController : IDisposable
	{
		private static readonly Action<object> CancelCancellationTokenSourceStateDelegate = CancelCancellationTokenSourceState;

		private CancellationTokenSource timeoutSource;

		private CancellationTokenSource linkedSource;

		private PlayerLoopTimer timer;

		private bool isDisposed;

		private readonly DelayType delayType;

		private readonly PlayerLoopTiming delayTiming;

		private readonly CancellationTokenSource originalLinkCancellationTokenSource;

		private static void CancelCancellationTokenSourceState(object state)
		{
			((CancellationTokenSource)state).Cancel();
		}

		public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			timeoutSource = new CancellationTokenSource();
			originalLinkCancellationTokenSource = null;
			linkedSource = null;
			this.delayType = delayType;
			this.delayTiming = delayTiming;
		}

		public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update)
		{
			timeoutSource = new CancellationTokenSource();
			originalLinkCancellationTokenSource = linkCancellationTokenSource;
			linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token);
			this.delayType = delayType;
			this.delayTiming = delayTiming;
		}

		public CancellationToken Timeout(int millisecondsTimeout)
		{
			return Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout));
		}

		public CancellationToken Timeout(TimeSpan timeout)
		{
			if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested)
			{
				return originalLinkCancellationTokenSource.Token;
			}
			if (timeoutSource.IsCancellationRequested)
			{
				timeoutSource.Dispose();
				timeoutSource = new CancellationTokenSource();
				if (linkedSource != null)
				{
					linkedSource.Cancel();
					linkedSource.Dispose();
					linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token);
				}
				timer?.Dispose();
				timer = null;
			}
			CancellationToken token = ((linkedSource != null) ? linkedSource : timeoutSource).Token;
			if (timer == null)
			{
				timer = PlayerLoopTimer.StartNew(timeout, periodic: false, delayType, delayTiming, token, CancelCancellationTokenSourceStateDelegate, timeoutSource);
			}
			else
			{
				timer.Restart(timeout);
			}
			return token;
		}

		public bool IsTimeout()
		{
			return timeoutSource.IsCancellationRequested;
		}

		public void Reset()
		{
			timer?.Stop();
		}

		public void Dispose()
		{
			if (isDisposed)
			{
				return;
			}
			try
			{
				timer?.Dispose();
				timeoutSource.Cancel();
				timeoutSource.Dispose();
				if (linkedSource != null)
				{
					linkedSource.Cancel();
					linkedSource.Dispose();
				}
			}
			finally
			{
				isDisposed = true;
			}
		}
	}
	public interface ITriggerHandler<T>
	{
		ITriggerHandler<T> Prev { get; set; }

		ITriggerHandler<T> Next { get; set; }

		void OnNext(T value);

		void OnError(Exception ex);

		void OnCompleted();

		void OnCanceled(CancellationToken cancellationToken);
	}
	public struct TriggerEvent<T>
	{
		private ITriggerHandler<T> head;

		private ITriggerHandler<T> iteratingHead;

		private bool preserveRemoveSelf;

		private ITriggerHandler<T> iteratingNode;

		private void LogError(Exception ex)
		{
			Debug.LogException(ex);
		}

		public void SetResult(T value)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnNext(value);
				}
				catch (Exception ex)
				{
					LogError(ex);
					Remove(triggerHandler);
				}
				if (preserveRemoveSelf)
				{
					preserveRemoveSelf = false;
					iteratingNode = null;
					ITriggerHandler<T> next = triggerHandler.Next;
					Remove(triggerHandler);
					triggerHandler = next;
				}
				else
				{
					triggerHandler = triggerHandler.Next;
				}
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetCanceled(CancellationToken cancellationToken)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnCanceled(cancellationToken);
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				preserveRemoveSelf = false;
				iteratingNode = null;
				ITriggerHandler<T> next = triggerHandler.Next;
				Remove(triggerHandler);
				triggerHandler = next;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetCompleted()
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnCompleted();
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				preserveRemoveSelf = false;
				iteratingNode = null;
				ITriggerHandler<T> next = triggerHandler.Next;
				Remove(triggerHandler);
				triggerHandler = next;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void SetError(Exception exception)
		{
			if (iteratingNode != null)
			{
				throw new InvalidOperationException("Can not trigger itself in iterating.");
			}
			ITriggerHandler<T> triggerHandler = head;
			while (triggerHandler != null)
			{
				iteratingNode = triggerHandler;
				try
				{
					triggerHandler.OnError(exception);
				}
				catch (Exception ex)
				{
					LogError(ex);
				}
				preserveRemoveSelf = false;
				iteratingNode = null;
				ITriggerHandler<T> next = triggerHandler.Next;
				Remove(triggerHandler);
				triggerHandler = next;
			}
			iteratingNode = null;
			if (iteratingHead != null)
			{
				Add(iteratingHead);
				iteratingHead = null;
			}
		}

		public void Add(ITriggerHandler<T> handler)
		{
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			if (head == null)
			{
				head = handler;
			}
			else if (iteratingNode != null)
			{
				if (iteratingHead == null)
				{
					iteratingHead = handler;
					return;
				}
				ITriggerHandler<T> prev = iteratingHead.Prev;
				if (prev == null)
				{
					iteratingHead.Prev = handler;
					iteratingHead.Next = handler;
					handler.Prev = iteratingHead;
				}
				else
				{
					iteratingHead.Prev = handler;
					prev.Next = handler;
					handler.Prev = prev;
				}
			}
			else
			{
				ITriggerHandler<T> prev2 = head.Prev;
				if (prev2 == null)
				{
					head.Prev = handler;
					head.Next = handler;
					handler.Prev = head;
				}
				else
				{
					head.Prev = handler;
					prev2.Next = handler;
					handler.Prev = prev2;
				}
			}
		}

		public void Remove(ITriggerHandler<T> handler)
		{
			if (handler == null)
			{
				throw new ArgumentNullException("handler");
			}
			if (iteratingNode != null && iteratingNode == handler)
			{
				preserveRemoveSelf = true;
				return;
			}
			ITriggerHandler<T> prev = handler.Prev;
			ITriggerHandler<T> next = handler.Next;
			if (next != null)
			{
				next.Prev = prev;
			}
			if (handler == head)
			{
				head = next;
			}
			else if (handler == iteratingHead)
			{
				iteratingHead = next;
			}
			else if (prev != null)
			{
				prev.Next = next;
			}
			if (head != null && head.Prev == handler)
			{
				if (prev != head)
				{
					head.Prev = prev;
				}
				else
				{
					head.Prev = null;
				}
			}
			if (iteratingHead != null && iteratingHead.Prev == handler)
			{
				if (prev != iteratingHead.Prev)
				{
					iteratingHead.Prev = prev;
				}
				else
				{
					iteratingHead.Prev = null;
				}
			}
			handler.Prev = null;
			handler.Next = null;
		}
	}
	public static class UniTaskCancellationExtensions
	{
		public static CancellationToken GetCancellationTokenOnDestroy(this GameObject gameObject)
		{
			return gameObject.GetAsyncDestroyTrigger().CancellationToken;
		}

		public static CancellationToken GetCancellationTokenOnDestroy(this Component component)
		{
			return component.GetAsyncDestroyTrigger().CancellationToken;
		}
	}
	[StructLayout(LayoutKind.Auto)]
	[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
	public readonly struct UniTask
	{
		private sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
		{
			private static TaskPool<YieldPromise> pool;

			private YieldPromise nextNode;

			private CancellationToken cancellationToken;

			private UniTaskCompletionSourceCore<object> core;

			public ref YieldPromise NextNode => ref nextNode;

			static YieldPromise()
			{
				TaskPool.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size);
			}

			private YieldPromise()
			{
			}

			public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new YieldPromise();
				}
				result.cancellationToken = cancellationToken;
				TaskTracker.TrackActiveTask(result, 3);
				PlayerLoopHelper.AddAction(timing, result);
				token = result.core.Version;
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public bool MoveNext()
			{
				if (cancellationToken.IsCancellationRequested)
				{
					core.TrySetCanceled(cancellationToken);
					return false;
				}
				core.TrySetResult(null);
				return false;
			}

			private bool TryReturn()
			{
				TaskTracker.RemoveTracking(this);
				core.Reset();
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}
		}

		private sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
		{
			private static TaskPool<NextFramePromise> pool;

			private NextFramePromise nextNode;

			private int frameCount;

			private CancellationToken cancellationToken;

			private UniTaskCompletionSourceCore<AsyncUnit> core;

			public ref NextFramePromise NextNode => ref nextNode;

			static NextFramePromise()
			{
				TaskPool.RegisterSizeGetter(typeof(NextFramePromise), () => pool.Size);
			}

			private NextFramePromise()
			{
			}

			public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
			{
				if (cancellationToken.IsCancellationRequested)
				{
					return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
				}
				if (!pool.TryPop(out var result))
				{
					result = new NextFramePromise();
				}
				result.frameCount = (PlayerLoopHelper.IsMainThread ? Time.frameCount : (-1));
				result.cancellationToken = cancellationToken;
				TaskTracker.TrackActiveTask(result, 3);
				PlayerLoopHelper.AddAction(timing, result);
				token = result.core.Version;
				return result;
			}

			public void GetResult(short token)
			{
				try
				{
					core.GetResult(token);
				}
				finally
				{
					TryReturn();
				}
			}

			public UniTaskStatus GetStatus(short token)
			{
				return core.GetStatus(token);
			}

			public UniTaskStatus UnsafeGetStatus()
			{
				return core.UnsafeGetStatus();
			}

			public void OnCompleted(Action<object> continuation, object state, short token)
			{
				core.OnCompleted(continuation, state, token);
			}

			public bool MoveNext()
			{
				if (cancellationToken.IsCancellationRequested)
				{
					core.TrySetCanceled(cancellationToken);
					return false;
				}
				if (frameCount == Time.frameCount)
				{
					return true;
				}
				core.TrySetResult(AsyncUnit.Default);
				return false;
			}

			private bool TryReturn()
			{
				TaskTracker.RemoveTracking(this);
				core.Reset();
				cancellationToken = default(CancellationToken);
				return pool.TryPush(this);
			}
		}

		private sealed class WaitForEndOfFramePromise : IUniTaskSource, ITaskPoolNode<WaitForEndOfFramePromise>, IEnumerator
		{
			private static TaskPool<WaitForEndOfFramePromise> pool;

			private WaitForEndOfFramePromise nextNode;

			private CancellationToken cancellationToken;

			private UniTaskCompletionSourceCore<object> core;

			private static readonly WaitForEndOfFrame waitForEndOfFrameYieldInstruction;

			private bool isFirst = true;

			public ref WaitForEndOfFramePromise NextNode => ref nextNode;

			object IEnumerator.Current => waitForEndOfFrameYieldInstruction;

			st

plugins/OCDheim.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using OCDheim.Utilities;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("OCDheim")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OCDheim")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.2.0")]
[module: UnverifiableCode]
namespace OCDheim
{
	public class GroundLevelSpinner
	{
		public static readonly GroundLevelSpinner RaiseGroundSpinner = new GroundLevelSpinner(1f, 0f, 1f);

		public static readonly GroundLevelSpinner LowerGroundSpinner = new GroundLevelSpinner(-0.5f, -1f, 0f);

		public float value { get; private set; }

		private float maxValue { get; }

		private float minValue { get; }

		private GroundLevelSpinner(float value, float minValue, float maxValue)
		{
			this.value = value;
			this.minValue = minValue;
			this.maxValue = maxValue;
		}

		public void Refresh()
		{
			float num = KeyBinder.ScrollΔ();
			if (num > 0f)
			{
				Up(num);
			}
			if (num < 0f)
			{
				Down(num);
			}
		}

		private void Up(float scrollΔ)
		{
			if (value + scrollΔ > maxValue)
			{
				value = maxValue;
			}
			else
			{
				value = Mathf.Round((value + scrollΔ) * 100f) / 100f;
			}
		}

		private void Down(float scrollΔ)
		{
			if (value + scrollΔ < minValue)
			{
				value = minValue;
			}
			else
			{
				value = Mathf.Round((value + scrollΔ) * 100f) / 100f;
			}
		}
	}
	[HarmonyPatch]
	public static class BlockCameraZoom
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZInput))]
		[HarmonyPatch("GetMouseScrollWheel")]
		public static bool Prefix(ref float __result)
		{
			if (PlayerHelpers.player.HasRaiseGroundTerraformToolEquipped())
			{
				__result = 0f;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public class KeyBinder : MonoBehaviour
	{
		private static readonly ButtonConfig SnapModeKey = new ButtonConfig
		{
			Name = "SnapModeKey",
			Key = (KeyCode)304
		};

		private static readonly ButtonConfig SnapModeJoy = new ButtonConfig
		{
			Name = "SnapModeJoy",
			GamepadButton = (GamepadButton)10
		};

		private static readonly ButtonConfig GridModeKey = new ButtonConfig
		{
			Name = "GridModeKey",
			Key = (KeyCode)308
		};

		private static readonly ButtonConfig GridModeJoy = new ButtonConfig
		{
			Name = "GridModeJoy",
			GamepadButton = (GamepadButton)16
		};

		private static readonly ButtonConfig PrecisionModeKey = new ButtonConfig
		{
			Name = "PrecisionModeKey",
			Key = (KeyCode)122
		};

		private static readonly ButtonConfig PrecisionModeJoy = new ButtonConfig
		{
			Name = "PrecisionModeJoy",
			GamepadButton = (GamepadButton)7
		};

		private const string MouseScrollWheel = "Mouse ScrollWheel";

		private const string JoyScrollUnlock = "JoyLTrigger";

		private const string JoyScrollDown = "JoyDPadDown";

		private const string JoyScrollUp = "JoyDPadUp";

		private const float ScrollPrecision = 0.01f;

		private static bool _gridModeEnabled;

		private static bool _gridModeFreshlyEnabled;

		private static bool _gridModeFreshlyDisabled;

		private static bool snapModeDisabled => ZInput.GetButton(SnapModeKey.Name) || ZInput.GetButton(SnapModeJoy.Name);

		public static bool snapModeEnabled => !snapModeDisabled;

		public static bool gridModeEnabled
		{
			get
			{
				return _gridModeEnabled;
			}
			private set
			{
				_gridModeEnabled = value;
				_gridModeFreshlyEnabled = value;
				_gridModeFreshlyDisabled = !value;
			}
		}

		public static bool gridModeDisabled => !gridModeEnabled;

		public static bool gridModFreshlyEnabled
		{
			get
			{
				bool gridModeFreshlyEnabled = _gridModeFreshlyEnabled;
				_gridModeFreshlyEnabled = false;
				return gridModeFreshlyEnabled;
			}
		}

		public static bool gridModFreshlyDisabled
		{
			get
			{
				bool gridModeFreshlyDisabled = _gridModeFreshlyDisabled;
				_gridModeFreshlyDisabled = false;
				return gridModeFreshlyDisabled;
			}
		}

		public static PrecisionMode precisionMode { get; private set; } = PrecisionMode.ORDINARY;


		private void Awake()
		{
			InputManager.Instance.AddButton("dymek.dev.OCDheim", SnapModeJoy);
			InputManager.Instance.AddButton("dymek.dev.OCDheim", SnapModeKey);
			InputManager.Instance.AddButton("dymek.dev.OCDheim", GridModeKey);
			InputManager.Instance.AddButton("dymek.dev.OCDheim", GridModeJoy);
			InputManager.Instance.AddButton("dymek.dev.OCDheim", PrecisionModeKey);
			InputManager.Instance.AddButton("dymek.dev.OCDheim", PrecisionModeJoy);
		}

		private void Update()
		{
			bool flag = ((ZInput.GetButtonDown(GridModeKey.Name) || (snapModeEnabled && ZInput.GetButtonDown(GridModeJoy.Name))) && (gridModeEnabled || PlayerHelpers.player.HasConstructionToolEquipped())) || (gridModeEnabled && !PlayerHelpers.player.HasConstructionToolEquipped());
			bool flag2 = ((ZInput.GetButtonDown(PrecisionModeKey.Name) || (snapModeEnabled && ZInput.GetButtonDown(PrecisionModeJoy.Name))) && (precisionMode == PrecisionMode.SUPERIOR || PlayerHelpers.player.HasBuildPieceEquipped())) || (precisionMode == PrecisionMode.SUPERIOR && !PlayerHelpers.player.HasBuildPieceEquipped());
			if (flag)
			{
				gridModeEnabled = !gridModeEnabled;
				Logger.Info(() => "[" + (gridModeEnabled ? "ENABLED" : "DISABLED") + "] GRID MODE");
			}
			if (flag2)
			{
				precisionMode = ((precisionMode != PrecisionMode.ORDINARY) ? PrecisionMode.ORDINARY : PrecisionMode.SUPERIOR);
				Logger.Info(() => "[" + ((precisionMode == PrecisionMode.SUPERIOR) ? "ENABLED" : "DISABLED") + "] PRECISION MODE");
			}
		}

		public static float ScrollΔ()
		{
			float axis = Input.GetAxis("Mouse ScrollWheel");
			if (axis != 0f)
			{
				return (axis > 0f) ? 0.01f : (-0.01f);
			}
			if (ZInput.GetButton("JoyLTrigger") && ZInput.GetButtonDown("JoyDPadDown"))
			{
				return -0.01f;
			}
			if (ZInput.GetButton("JoyLTrigger") && ZInput.GetButtonDown("JoyDPadUp"))
			{
				return 0.01f;
			}
			return axis;
		}
	}
	[HarmonyPatch]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("dymek.dev.OCDheim", "OCDheim", "0.2.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class OCDheim : BaseUnityPlugin
	{
		public const string GUID = "dymek.dev.OCDheim";

		private const string Name = "OCDheim";

		private const string Version = "0.2.0";

		public static AssetBundle resourceBundle { get; } = LoadResourceBundle();


		private Texture2D brick1x1 { get; } = LoadTextureFromDisk("brick_1x1.png");


		private Texture2D brick2x1 { get; } = LoadTextureFromDisk("brick_2x1.png");


		private Texture2D brick1x2 { get; } = LoadTextureFromDisk("brick_1x2.png");


		private Texture2D brick4x2 { get; } = LoadTextureFromDisk("brick_4x2.png");


		private Harmony harmony { get; } = new Harmony("dymek.dev.OCDheim");


		private static AssetBundle LoadResourceBundle()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			RuntimePlatform platform = Application.platform;
			RuntimePlatform val = platform;
			if ((int)val <= 2)
			{
				if ((int)val <= 1)
				{
					return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_osx"));
				}
				if ((int)val == 2)
				{
					goto IL_002d;
				}
			}
			else
			{
				if ((int)val == 7)
				{
					goto IL_002d;
				}
				if ((int)val == 13 || (int)val == 16)
				{
					return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_linux"));
				}
			}
			throw new PlatformNotSupportedException();
			IL_002d:
			return AssetUtils.LoadAssetBundleFromResources(Path.Combine("bundle_windows"));
		}

		public static Texture2D LoadTextureFromDisk(string fileName)
		{
			string path = Path.GetDirectoryName(typeof(OCDheim).Assembly.Location) ?? throw new InvalidOperationException();
			string text = Path.Combine(path, fileName);
			return AssetUtils.LoadTexture(text, true);
		}

		private void Awake()
		{
			harmony.PatchAll();
			((Component)this).gameObject.AddComponent<KeyBinder>();
			PrefabManager.OnVanillaPrefabsAvailable += AddOCDheimToolPieces;
			PrefabManager.OnVanillaPrefabsAvailable += AddOCDheimBuildPieces;
			PrefabManager.OnVanillaPrefabsAvailable += ModVanillaValheimTools;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player))]
		[HarmonyPatch("OnSpawned")]
		private static void OnPlayerAvailable()
		{
			Refresher.Of(PrecisionDrill.groundLevels);
			Refresher.Of(PrecisionDrill.floorLevels);
		}

		private void AddOCDheimToolPieces()
		{
			AddToolPiece<RemoveModificationsOverlayVisualizer>("Remove Terrain Modifications", "mud_road_v2", "Hoe", OverlayVisualizer.remove);
		}

		private void AddToolPiece<TOverlayVisualizer>(string pieceName, string basePieceName, string pieceTable, Texture2D iconTexture, bool level = false, bool raise = false, bool smooth = false, bool paint = false) where TOverlayVisualizer : OverlayVisualizer
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			CustomPiece piece = PieceManager.Instance.GetPiece(pieceName);
			if (piece == null)
			{
				Sprite icon = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), Vector2.zero);
				CustomPiece val = new CustomPiece(pieceName, basePieceName, new PieceConfig
				{
					Name = pieceName,
					Icon = icon,
					PieceTable = pieceTable
				});
				Settings settings = val.PiecePrefab.GetComponent<TerrainOp>().m_settings;
				settings.m_level = level;
				settings.m_raise = raise;
				settings.m_smooth = smooth;
				settings.m_paintCleared = paint;
				val.PiecePrefab.AddComponent<TOverlayVisualizer>();
				PieceManager.Instance.AddPiece(val);
			}
		}

		private void AddOCDheimBuildPieces()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			AddBrickBuildPiece("1x1", new Vector3(0.5f, 1f, 0.5f), 3, brick1x1);
			AddBrickBuildPiece("2x1", new Vector3(1f, 1f, 0.5f), 4, brick2x1);
			AddBrickBuildPiece("4x2", new Vector3(2f, 2f, 0.5f), 6, brick4x2);
			AddBrickBuildPiece("1x2", new Vector3(0.5f, 2f, 0.5f), 5, brick1x2);
			PrefabManager.OnVanillaPrefabsAvailable -= AddOCDheimBuildPieces;
		}

		private void AddBrickBuildPiece(string brickSuffix, Vector3 brickScale, int brickPrice, Texture2D iconTexture)
		{
			//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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			string text = "Smooth stone " + brickSuffix;
			CustomPiece piece = PieceManager.Instance.GetPiece(text);
			if (piece == null)
			{
				GameObject val = PrefabManager.Instance.CreateClonedPrefab("stone_floor_" + brickSuffix, "stone_floor_2x2");
				Sprite icon = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), Vector2.zero);
				val.transform.localScale = brickScale;
				PieceConfig val2 = new PieceConfig();
				val2.Name = text;
				val2.PieceTable = "Hammer";
				val2.Category = "HeavyBuild";
				val2.Icon = icon;
				val2.AddRequirement(new RequirementConfig("Stone", brickPrice, 0, true));
				PieceManager.Instance.AddPiece(new CustomPiece(val, false, val2));
			}
		}

		private void ModVanillaValheimTools()
		{
			PrefabManager.Instance.GetPrefab("mud_road_v2").AddComponent<LevelGroundOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("raise_v2").AddComponent<RaiseGroundOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("path_v2").AddComponent<PaveRoadOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("paved_road_v2").AddComponent<PaveRoadOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("cultivate_v2").AddComponent<CultivateOverlayVisualizer>();
			PrefabManager.Instance.GetPrefab("replant_v2").AddComponent<SeedGrassOverlayVisualizer>();
		}
	}
	[HarmonyPatch]
	public static class PileUpper
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(WearNTear))]
		[HarmonyPatch("Start")]
		private static void MakePilesAsDurableAsWood(WearNTear __instance)
		{
			if (((Object)__instance).name.Contains("pile") || ((Object)__instance).name.Contains("stack"))
			{
				__instance.m_supports = true;
			}
		}
	}
	[HarmonyPatch]
	public static class RemoveExpensiveUnnecessaryCalls
	{
		private static bool ShouldSuppressVanillaValheim()
		{
			return (KeyBinder.gridModeEnabled && PrecisePieceSnapper.GridModeRequirementsSatisfied()) || (KeyBinder.snapModeEnabled && PrecisePieceSnapper.SnapModeRequirementsSatisfied());
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Player))]
		[HarmonyPatch("UpdatePlacementGhost")]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			bool foundCodeToRemove = false;
			bool foundCodeToReplace = false;
			foreach (CodeInstruction instruction in instructions)
			{
				foundCodeToRemove = (foundCodeToRemove ? foundCodeToRemove : (instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == "AltPlace"));
				if (foundCodeToRemove && !foundCodeToReplace)
				{
					foundCodeToReplace = (foundCodeToReplace ? foundCodeToReplace : (instruction.opcode == OpCodes.Call));
					if (!foundCodeToReplace)
					{
						instruction.opcode = OpCodes.Nop;
						instruction.operand = null;
						yield return instruction;
						continue;
					}
					instruction.opcode = OpCodes.Call;
					instruction.operand = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => ShouldSuppressVanillaValheim()));
					yield return instruction;
				}
				else
				{
					yield return instruction;
				}
			}
		}
	}
	[HarmonyPatch]
	public static class PrecisePieceSnapper
	{
		private const float NeighbourhoodSize = 2.5f;

		private static readonly int PiecesOnly = LayerMask.GetMask(new string[1] { "piece" });

		private static readonly int LayerMask = PlayerHelpers.player.m_placeRayMask - LayerMask.GetMask(new string[1] { "piece_nonsolid" });

		private static readonly Collider[] NeighbourColliders = (Collider[])(object)new Collider[255];

		private static readonly List<Piece> NeighbourPieces = new List<Piece>();

		public static bool GridModeRequirementsSatisfied()
		{
			return PlayerHelpers.player.HasBuildPieceEquipped() || PlayerHelpers.player.HasOverlayVisible();
		}

		public static bool SnapModeRequirementsSatisfied()
		{
			return (Object)(object)PieceHelpers.buildPiece != (Object)null && (PieceHelpers.buildPiece.Type() != 0 || KeyBinder.precisionMode == PrecisionMode.SUPERIOR);
		}

		private static bool ShouldUsePlayerPositionAsGroundLevelReference()
		{
			return PlayerHelpers.player.HasLevelGroundTerraformToolEquipped() && KeyBinder.snapModeEnabled;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player))]
		[HarmonyPatch("UpdatePlacementGhost")]
		private static void SnapBuildPiece()
		{
			if (KeyBinder.gridModeEnabled && GridModeRequirementsSatisfied())
			{
				SnapToWorldGrid(PieceHelpers.buildPiece);
			}
			else if (KeyBinder.snapModeEnabled && SnapModeRequirementsSatisfied())
			{
				SnapToNeighbourPiece(PieceHelpers.buildPiece);
			}
		}

		private static void SnapToWorldGrid(Piece buildPiece)
		{
			//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_000d: 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_003f: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 playerPoV = DeterminePlayerPoV();
			int precisionMode = (int)KeyBinder.precisionMode;
			var (num, num2) = SnapToWorldGrid(playerPoV, precisionMode);
			if (ShouldUsePlayerPositionAsGroundLevelReference())
			{
				((Component)buildPiece).transform.position = new Vector3(num, PlayerHelpers.playerPos.y, num2);
			}
			else
			{
				Vector2 drillCoords = default(Vector2);
				((Vector2)(ref drillCoords))..ctor(num, num2);
				Vector3 neighbourPieceExit = ((PlayerHelpers.player.HasOverlayVisible() || buildPiece.IsGroundBound()) ? PrecisionDrill.DrillDownTillGround(drillCoords) : PrecisionDrill.DrillDownTillFloor(drillCoords, ((Component)buildPiece).transform.position.y));
				SnapExternallyHelper(buildPiece, neighbourPieceExit, Vector3.up);
			}
			if (PlayerHelpers.player.HasOverlayVisible())
			{
				FixVanillaValheimBugWithSpinningTerrainModificationVFX();
			}
		}

		private static (float xOnGrid, float zOnGrid) SnapToWorldGrid(Vector3 playerPoV, int precision)
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_002b: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			float item;
			float item2;
			if (PlayerHelpers.player.HasColorBrushEquipped())
			{
				float num = Mathf.Floor(playerPoV.x / 64f) * 64f;
				float num2 = Mathf.Floor(playerPoV.z / 64f) * 64f;
				float num3 = num - 32f;
				float num4 = num2 - 32f;
				float num5 = playerPoV.x - num3;
				float num6 = playerPoV.z - num4;
				item = num3 + Mathf.Floor(num5 / (64f / 65f)) * (64f / 65f) + 32f / 65f;
				item2 = num4 + Mathf.Floor(num6 / (64f / 65f)) * (64f / 65f) + 32f / 65f;
			}
			else
			{
				item = Mathf.Round(playerPoV.x * (float)precision) / (float)precision;
				item2 = Mathf.Round(playerPoV.z * (float)precision) / (float)precision;
			}
			return (item, item2);
		}

		private static void SnapToNeighbourPiece(Piece buildPiece)
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			Vector3 playerPoV = DeterminePlayerPoV();
			List<Piece> neighbourPieces = FindNeighbourPieces(playerPoV);
			switch (buildPiece.Type())
			{
			case PieceType.CONSTRUCTION:
				SnapInternally(buildPiece, neighbourPieces);
				break;
			case PieceType.FURNITURE:
			case PieceType.TABLE:
				SnapExternally(buildPiece, neighbourPieces, playerPoV);
				break;
			}
		}

		private static void SnapInternally(Piece buildPiece, List<Piece> neighbourPieces)
		{
			//IL_003b: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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)
			SnapTree.TraversalResult? traversalResult = ((KeyBinder.precisionMode == PrecisionMode.ORDINARY) ? SnapTree.FindNearestOrdinaryPrecisionSnapNodeCombinationOf(buildPiece, neighbourPieces) : SnapTree.FindNearestSuperiorPrecisionSnapNodeCombinationOf(buildPiece, neighbourPieces));
			if (traversalResult.HasValue)
			{
				SnapTree.TraversalResult valueOrDefault = traversalResult.GetValueOrDefault();
				if (true)
				{
					Transform transform = ((Component)buildPiece).transform;
					transform.position += (Vector3)valueOrDefault.neighbourSnapNode - valueOrDefault.buildPieceSnapNode;
				}
			}
		}

		private static void SnapExternally(Piece buildPiece, List<Piece> neighbourPieces, Vector3 playerPoV)
		{
			//IL_0012: 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_0048: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0066: 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)
			SnapTree.TraversalResult? traversalResult = ((KeyBinder.precisionMode == PrecisionMode.ORDINARY) ? SnapTree.FindNearestOrdinaryPrecisionSnapNodeTo(playerPoV, neighbourPieces) : SnapTree.FindNearestSuperiorPrecisionSnapNodeTo(playerPoV, neighbourPieces));
			if (!traversalResult.HasValue)
			{
				return;
			}
			SnapTree.TraversalResult valueOrDefault = traversalResult.GetValueOrDefault();
			if (true)
			{
				var (val, perpendicularToPlayerPoV) = DetermineNeighbourPieceExit(valueOrDefault.neighbourSnapNode, valueOrDefault.neighbourPiece);
				if (!buildPiece.IsGroundBound())
				{
					SnapExternallyHelper(buildPiece, val, perpendicularToPlayerPoV);
				}
				else
				{
					((Component)buildPiece).transform.position = val;
				}
			}
		}

		private static void SnapExternallyHelper(Piece buildPiece, Vector3 neighbourPieceExit, Vector3 perpendicularToPlayerPoV)
		{
			//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_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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			((Component)buildPiece).transform.position = neighbourPieceExit + perpendicularToPlayerPoV * 10f;
			Vector3 buildPieceExit = DeterminePieceExit(buildPiece, neighbourPieceExit);
			SnapPiecesByExits(buildPiece, buildPieceExit, neighbourPieceExit, perpendicularToPlayerPoV);
		}

		private static (Vector3, Vector3) DetermineNeighbourPieceExit(SnapNode neighbourSnapNode, Piece neighbourPiece)
		{
			//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_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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 snapNode = PokeToMiddle(neighbourSnapNode, neighbourPiece);
			Vector3 val = DeterminePerpendicularToPlayerPoVOn(snapNode);
			Vector3 observer = (Vector3)neighbourSnapNode + val;
			Vector3 item = DeterminePieceExit(neighbourPiece, observer);
			return (item, val);
		}

		private static Vector3 DeterminePlayerPoV()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_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_003f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 forward = ((Component)GameCamera.instance).transform.forward;
			RaycastHit val = default(RaycastHit);
			Physics.Raycast(position, forward, ref val, 250f, LayerMask);
			return ((RaycastHit)(ref val)).point;
		}

		private static Vector3 DeterminePerpendicularToPlayerPoVOn(Vector3 snapNode)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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)
			Vector3 position = ((Component)GameCamera.instance).transform.position;
			Vector3 val = snapNode - position;
			RaycastHit val2 = default(RaycastHit);
			Physics.Raycast(position, val, ref val2, 250f, LayerMask);
			return ((RaycastHit)(ref val2)).normal;
		}

		private static List<Piece> FindNeighbourPieces(Vector3 playerPoV)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			NeighbourPieces.Clear();
			int num = Physics.OverlapSphereNonAlloc(playerPoV, 2.5f, NeighbourColliders, PiecesOnly);
			for (int i = 0; i < num; i++)
			{
				Collider val = NeighbourColliders[i];
				Transform root = ((Component)val).transform.root;
				Piece val2 = ((root != null) ? ((Component)root).GetComponentInChildren<Piece>() : null);
				if ((Object)(object)val2 != (Object)null && val2.Type().IsSnappable())
				{
					NeighbourPieces.Add(val2);
				}
			}
			return NeighbourPieces;
		}

		private static Vector3 DeterminePieceExit(Piece piece, Vector3 observer)
		{
			//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_00a1: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_008a: 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)
			float num = float.PositiveInfinity;
			Vector3 result = ((Component)piece).transform.position;
			Collider[] componentsInChildren = ((Component)piece).GetComponentsInChildren<Collider>();
			Collider[] array = componentsInChildren;
			foreach (Collider val in array)
			{
				if (!val.enabled || val.isTrigger)
				{
					continue;
				}
				MeshCollider val2 = (MeshCollider)(object)((val is MeshCollider) ? val : null);
				if ((Object)(object)val2 == (Object)null || val2.convex)
				{
					Vector3 val3 = val.ClosestPoint(observer);
					float num2 = Vector3.Distance(observer, val3);
					if (num2 < num)
					{
						result = val3;
						num = num2;
					}
				}
			}
			return result;
		}

		private static Vector3 PokeToMiddle(Vector3 snapNode, Piece piece)
		{
			//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_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_0015: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)piece).transform.position - snapNode;
			Vector3 val2 = ((Vector3)(ref val)).normalized * 0.05f;
			return snapNode + val2;
		}

		private static void SnapPiecesByExits(Piece buildPiece, Vector3 buildPieceExit, Vector3 neighbourPieceEntry, Vector3 perpendicularToNeighbourPiece)
		{
			//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_0003: 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_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = neighbourPieceEntry - buildPieceExit;
			Vector3 val2 = Vector3.Project(val, perpendicularToNeighbourPiece);
			Transform transform = ((Component)buildPiece).transform;
			transform.position += val2;
		}

		private static void FixVanillaValheimBugWithSpinningTerrainModificationVFX()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			((Component)PieceHelpers.buildPiece).transform.rotation = Quaternion.Euler(0f, 0f, 0f);
		}
	}
	[HarmonyPatch]
	public static class PreciseTerrainModifier
	{
		private const int AoESize = 1;

		public const int HTilesPerChunk = 64;

		private const int PTilesPerChunk = 65;

		public const float HalfPTilesPerChunk = 32f;

		public const float PTileSize = 64f / 65f;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("InternalDoOperation")]
		private static bool Prefix(Vector3 pos, Settings modifier, Heightmap ___m_hmap, ref float[] ___m_levelDelta, ref float[] ___m_smoothDelta, ref Color[] ___m_paintMask, ref bool[] ___m_modifiedHeight, ref bool[] ___m_modifiedPaint)
		{
			//IL_002a: 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)
			if (!modifier.m_level && !modifier.m_raise && !modifier.m_smooth && !modifier.m_paintCleared)
			{
				RemoveTerrainModifications(pos, ___m_hmap, ref ___m_levelDelta, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				RecolorTerrain(pos, (PaintType)3, ___m_hmap, ref ___m_paintMask, ref ___m_modifiedPaint);
			}
			return true;
		}

		public static void SmoothenTerrain(Vector3 worldPos, Heightmap hMap, TerrainComp compiler, ref float[] smoothΔ, ref bool[] modifiedHeight)
		{
			//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_0035: 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)
			Logger.Debug(() => "[INIT] Smooth Terrain Modification");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			float referenceH = worldPos.y - ((Component)compiler).transform.position.y;
			Logger.Debug(() => $"worldPos: {worldPos}, xPos: {xPos}, yPos: {yPos}, referenceH: {referenceH}");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int num = y * 65 + x;
					float tileH = hMap.GetHeight(x, y);
					float Δh = referenceH - tileH;
					float oldΔh = smoothΔ[num];
					float newΔh = oldΔh + Δh;
					float roundedNewΔh = RoundToTwoDecimals(tileH, oldΔh, newΔh);
					float limΔh = Mathf.Clamp(roundedNewΔh, -1f, 1f);
					smoothΔ[num] = limΔh;
					modifiedHeight[num] = true;
					Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, Δh: {Δh}, oldΔh: {oldΔh}, newΔh: {newΔh}, roundedNewΔh: {roundedNewΔh}, limΔh: {limΔh}");
				}
			}
			Logger.Debug(() => "[SUCCESS] Smooth Terrain Modification");
		}

		public static void RaiseTerrain(Vector3 worldPos, Heightmap hMap, TerrainComp compiler, float power, ref float[] levelΔ, ref float[] smoothΔ, ref bool[] modifiedHeight)
		{
			//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_003c: 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)
			Logger.Debug(() => "[INIT] Raise Terrain Modification");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			float referenceH = worldPos.y - ((Component)compiler).transform.position.y + power;
			Logger.Debug(() => $"worldPos: {worldPos}, xPos: {xPos}, yPos: {yPos}, power: {power}, referenceH: {referenceH}");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int num = y * 65 + x;
					float tileH = hMap.GetHeight(x, y);
					float Δh = referenceH - tileH;
					if (Δh >= 0f)
					{
						float oldLevelΔ = levelΔ[num];
						float oldSmoothΔ = smoothΔ[num];
						float newLevelΔ = oldLevelΔ + oldSmoothΔ + Δh;
						float newSmoothΔ = 0f;
						float roundedNewLevelΔ = RoundToTwoDecimals(tileH, oldLevelΔ + oldSmoothΔ, newLevelΔ + newSmoothΔ);
						float limitedNewLevelΔ = Mathf.Clamp(roundedNewLevelΔ, -16f, 16f);
						levelΔ[num] = limitedNewLevelΔ;
						smoothΔ[num] = newSmoothΔ;
						modifiedHeight[num] = true;
						Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, Δh: {Δh}, oldLevelΔ: {oldLevelΔ}, oldSmoothΔ: {oldSmoothΔ}, newLevelΔ: {newLevelΔ}, newSmoothΔ: {newSmoothΔ}, roundedNewLevelΔ: {roundedNewLevelΔ}, limitedNewLevelΔ: {limitedNewLevelΔ}");
					}
					else
					{
						Logger.Debug(() => "Declined to process tile: Δh < 0!");
						Logger.Debug(() => $"tilePos: ({x}, {y}), tileH: {tileH}, Δh: {Δh}");
					}
				}
			}
			Logger.Debug(() => "[SUCCESS] Raise Terrain Modification");
		}

		public static void RecolorTerrain(Vector3 worldPos, PaintType paintType, Heightmap hMap, ref Color[] paintMask, ref bool[] modifiedPaint)
		{
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0052: 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)
			Logger.Info(() => "[INIT] Color Terrain Modification 3x3");
			Color tileColor = ResolveColor(paintType);
			PositionRelativeTo(((Component)hMap).transform.position, worldPos, out var xPos, out var yPos);
			Logger.Info(() => $"worldPos: {worldPos}, chunkPos: {((Component)hMap).transform.position}, relPos: ({xPos}, {yPos})");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int i = minVal; i <= maxVal; i++)
			{
				for (int j = minVal2; j <= maxVal2; j++)
				{
					ApplyColor(i, j, tileColor, ref paintMask, ref modifiedPaint);
				}
			}
			Logger.Info(() => "[SUCCESS] Color Terrain Modification 3x3");
		}

		private static void RemoveTerrainModifications(Vector3 worldPos, Heightmap hMap, ref float[] levelΔ, ref float[] smoothΔ, ref bool[] modifiedHeight)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			Logger.Debug(() => "[INIT] Remove Terrain Modifications");
			int xPos = default(int);
			int yPos = default(int);
			hMap.WorldToVertex(worldPos, ref xPos, ref yPos);
			Logger.Debug(() => $"worldPos: {worldPos}, vertexPos: ({xPos}, {yPos})");
			FindExtremums(xPos, out var minVal, out var maxVal);
			FindExtremums(yPos, out var minVal2, out var maxVal2);
			for (int x = minVal; x <= maxVal; x++)
			{
				for (int y = minVal2; y <= maxVal2; y++)
				{
					int tileIndex = y * 65 + x;
					levelΔ[tileIndex] = 0f;
					smoothΔ[tileIndex] = 0f;
					modifiedHeight[tileIndex] = false;
					Logger.Debug(() => $"tilePos: ({x}, {y}), tileIndex: {tileIndex}");
				}
			}
			Logger.Debug(() => "[SUCCESS] Remove Terrain Modifications");
		}

		private static void FindExtremums(int val, out int minVal, out int maxVal)
		{
			minVal = Mathf.Max(0, val - 1);
			maxVal = Mathf.Min(val + 1, 64);
		}

		private static float RoundToTwoDecimals(float oldH, float oldΔh, float newΔh)
		{
			float newH = oldH - oldΔh + newΔh;
			float roundedNewH = Mathf.Round(newH * 100f) / 100f;
			float roundedNewΔh = roundedNewH - oldH + oldΔh;
			Logger.Debug(() => $"oldH: {oldH}, oldΔH: {oldΔh}, newΔH: {newΔh}, newH: {newH}, roundedNewH: {roundedNewH}, roundedNewΔh: {roundedNewΔh}");
			return roundedNewΔh;
		}

		private static void PositionRelativeTo(Vector3 chunkMid, Vector3 worldPos, out int x, out int y)
		{
			//IL_0001: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0025: 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)
			Vector3 val = chunkMid - new Vector3(32f, 0f, 32f);
			Vector3 val2 = worldPos - val;
			x = Mathf.FloorToInt(val2.x / (64f / 65f));
			y = Mathf.FloorToInt(val2.z / (64f / 65f));
		}

		private static Color ResolveColor(PaintType paintType)
		{
			//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_0003: 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_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			return (Color)((int)paintType switch
			{
				0 => Color.red, 
				2 => Color.blue, 
				1 => Color.green, 
				_ => Color.black, 
			});
		}

		private static void ApplyColor(int x, int y, Color tileColor, ref Color[] paintMask, ref bool[] modifiedPaint)
		{
			//IL_0015: 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_003b: 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_004f: 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)
			int tileIndex = y * 65 + x;
			paintMask[tileIndex] = tileColor;
			modifiedPaint[tileIndex] = tileColor != Color.black;
			Logger.Info(() => $"tilePos: ({x}, {y}), tileIndex: {tileIndex}, tileColor: {tileColor}");
		}
	}
	[HarmonyPatch]
	public static class PreciseSmoothTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("SmoothTerrain")]
		private static bool Prefix(Vector3 worldPos, float radius, bool square, float power, TerrainComp __instance, Heightmap ___m_hmap, ref float[] ___m_smoothDelta, ref bool[] ___m_modifiedHeight)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (ClientSideGridModeOverride.IsGridModeEnabled(radius))
			{
				PreciseTerrainModifier.SmoothenTerrain(worldPos, ___m_hmap, __instance, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class PreciseRaiseTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("RaiseTerrain")]
		private static bool Prefix(Vector3 worldPos, float radius, float delta, bool square, float power, TerrainComp __instance, Heightmap ___m_hmap, ref float[] ___m_levelDelta, ref float[] ___m_smoothDelta, ref bool[] ___m_modifiedHeight)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (ClientSideGridModeOverride.IsGridModeEnabled(radius))
			{
				PreciseTerrainModifier.RaiseTerrain(worldPos, ___m_hmap, __instance, delta, ref ___m_levelDelta, ref ___m_smoothDelta, ref ___m_modifiedHeight);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class PreciseColorTerrainModification
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("PaintCleared")]
		private static bool Prefix(Vector3 worldPos, float radius, PaintType paintType, bool heightCheck, bool apply, Heightmap ___m_hmap, ref Color[] ___m_paintMask, ref bool[] ___m_modifiedPaint)
		{
			//IL_000c: 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)
			if (ClientSideGridModeOverride.IsGridModeEnabled(radius))
			{
				PreciseTerrainModifier.RecolorTerrain(worldPos, paintType, ___m_hmap, ref ___m_paintMask, ref ___m_modifiedPaint);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class ClientSideGridModeOverride
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(TerrainComp))]
		[HarmonyPatch("ApplyOperation")]
		private static bool Prefix(TerrainOp modifier)
		{
			if (KeyBinder.gridModeEnabled)
			{
				if (modifier.m_settings.m_smooth)
				{
					modifier.m_settings.m_smoothRadius = float.NegativeInfinity;
				}
				if (modifier.m_settings.m_raise && modifier.m_settings.m_raiseDelta >= 0f)
				{
					modifier.m_settings.m_raiseRadius = float.NegativeInfinity;
					modifier.m_settings.m_raiseDelta = GroundLevelSpinner.RaiseGroundSpinner.value;
				}
				if (modifier.m_settings.m_raise && modifier.m_settings.m_raiseDelta < 0f)
				{
					modifier.m_settings.m_raiseDelta = GroundLevelSpinner.LowerGroundSpinner.value;
				}
				if (modifier.m_settings.m_paintCleared)
				{
					modifier.m_settings.m_paintRadius = float.NegativeInfinity;
				}
			}
			return true;
		}

		public static bool IsGridModeEnabled(float radius)
		{
			return float.IsNegativeInfinity(radius);
		}
	}
	public static class PrecisionDrill
	{
		public const float DropFromExosphere = 250f;

		private const int MaxDrillsInMemory = 4096;

		private const float DrillSize = 0.01f;

		private static readonly int GroundLayerMask = LayerMask.GetMask(new string[1] { "terrain" });

		private static readonly int FloorLayerMask = LayerMask.GetMask(new string[3] { "terrain", "piece", "static_solid" });

		private static Func<Vector2, Vector2> roundDrillCoords => (Vector2 drillCoords) => new Vector2(Mathf.Round(drillCoords.x * 10f) / 10f, Mathf.Round(drillCoords.y * 10f) / 10f);

		public static IRefreshableMemoryRepo<Vector2, Vector3> groundLevels => new MemoryRepo<Vector2, Vector3>(DrillDownToGround, 4096).EvictionPolicy(TimeSpan.FromMilliseconds(125.0));

		public static IRefreshableMemoryRepo<Vector2, List<float>> floorLevels => new MemoryRepo<Vector2, List<float>>((Vector2 drillCoords) => DrillDownFloors(drillCoords), roundDrillCoords, 4096).EvictionPolicy(TimeSpan.FromMilliseconds(500.0));

		public static Vector3 DrillDownTillGround(Vector2 drillCoords)
		{
			//IL_0005: 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)
			return groundLevels.LookUp(drillCoords);
		}

		private static Vector3 DrillDownToGround(Vector2 drillCoords)
		{
			//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_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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = WhereToDrillFrom(drillCoords);
			RaycastHit val2 = default(RaycastHit);
			if (Physics.Raycast(val, Vector3.down, ref val2, 250f, GroundLayerMask))
			{
				return ((RaycastHit)(ref val2)).point;
			}
			return FallBack(drillCoords);
		}

		private static Vector3 WhereToDrillFrom(Vector2 drillCoords)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(drillCoords.x, 250f, drillCoords.y);
		}

		private static Vector3 FallBack(Vector2 drillCoords)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			Logger.Warn(() => $"[FAILED] Precision Drill for: {drillCoords}");
			return new Vector3(drillCoords.x, ((Component)PlayerHelpers.player).transform.position.y, drillCoords.y);
		}

		public static Vector3 DrillDownTillFloor(Vector2 drillCoords, float referenceLevel)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			List<float> list = floorLevels.LookUp(drillCoords);
			float num = list[0];
			float num2 = Math.Abs(referenceLevel - num);
			foreach (float item in list)
			{
				float num3 = Math.Abs(referenceLevel - item);
				if (num3 < num2)
				{
					num2 = num3;
					num = item;
				}
			}
			return new Vector3(drillCoords.x, num, drillCoords.y);
		}

		private static List<float> DrillDownFloors(Vector2 drillCoords, float drillTill = 250f)
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			Vector3 val = WhereToDrillFrom(drillCoords);
			List<float> list = new List<float>();
			float roofLevel = val.y;
			RaycastHit val2 = default(RaycastHit);
			while (Physics.SphereCast(val, 0.01f, Vector3.down, ref val2, drillTill, FloorLayerMask))
			{
				float y = ((RaycastHit)(ref val2)).point.y;
				if (!ShouldSkipDueToInsufficientSize(((RaycastHit)(ref val2)).collider) && !ShouldSkipDueToInsufficientRoom(y, roofLevel))
				{
					list.Add(y);
				}
				val.y -= ((RaycastHit)(ref val2)).distance + 0.0001f;
				drillTill -= ((RaycastHit)(ref val2)).distance + 0.0001f;
				roofLevel = y;
			}
			return list;
		}

		private static bool ShouldSkipDueToInsufficientSize(Collider collider)
		{
			//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_002b: 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_004b: 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)
			Piece componentInChildren = ((Component)((Component)collider).transform.root).GetComponentInChildren<Piece>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return false;
			}
			Bounds bounds = collider.bounds;
			return ((Bounds)(ref bounds)).max.x - ((Bounds)(ref bounds)).min.x < 0.5f || ((Bounds)(ref bounds)).max.z - ((Bounds)(ref bounds)).min.z < 0.5f;
		}

		private static bool ShouldSkipDueToInsufficientRoom(float floorLevel, float roofLevel)
		{
			return roofLevel - floorLevel < 0.5f;
		}
	}
	public enum PrecisionMode
	{
		ORDINARY = 1,
		SUPERIOR
	}
	public readonly struct Box : ISide
	{
		private const double Epsilon = 1E-08;

		private char name { get; }

		private Vector3 minMinSnapNode { get; }

		private Vector3 minMaxSnapNode { get; }

		private Vector3 maxMinSnapNode { get; }

		private Vector3 maxMaxSnapNode { get; }

		private SnapNode.Type primarySnapNodeType { get; }

		public Box(char name, Vector3 minMinSnapNode, Vector3 minMaxSnapNode, Vector3 maxMinSnapNode, Vector3 maxMaxSnapNode)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0017: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			this.minMinSnapNode = minMinSnapNode;
			this.minMaxSnapNode = minMaxSnapNode;
			this.maxMinSnapNode = maxMinSnapNode;
			this.maxMaxSnapNode = maxMaxSnapNode;
			primarySnapNodeType = SnapNode.Type.PRIMARY;
		}

		public Box(Piece piece, Vector2 shift, char name = 'A')
		{
			//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_0010: 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_001c: 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_002f: 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_003e: 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_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_005c: 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_006c: 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_0077: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00c1: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			this.name = name;
			Vector3 val = piece.TopMiddle();
			minMinSnapNode = val + ((Component)piece).transform.rotation * new Vector3(0f - shift.x, 0f, 0f - shift.y);
			minMaxSnapNode = val + ((Component)piece).transform.rotation * new Vector3(0f - shift.x, 0f, shift.y);
			maxMinSnapNode = val + ((Component)piece).transform.rotation * new Vector3(shift.x, 0f, 0f - shift.y);
			maxMaxSnapNode = val + ((Component)piece).transform.rotation * new Vector3(shift.x, 0f, shift.y);
			primarySnapNodeType = SnapNode.Type.IMPOSED;
		}

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0026: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_009d: 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_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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			Vector3 dimensionΔ = minMaxSnapNode - minMinSnapNode;
			Vector3 dimensionΔ2 = maxMinSnapNode - minMinSnapNode;
			(Vector3, int) tuple = RecursiveSplit(dimensionΔ);
			Vector3 item = tuple.Item1;
			int item2 = tuple.Item2;
			(Vector3, int) tuple2 = RecursiveSplit(dimensionΔ2);
			Vector3 item3 = tuple2.Item1;
			int item4 = tuple2.Item2;
			double num = Math.Pow(2.0, item2) + 1.0;
			double num2 = Math.Pow(2.0, item4) + 1.0;
			for (int i = 0; (double)i < num; i++)
			{
				for (int j = 0; (double)j < num2; j++)
				{
					Vector3 position = minMinSnapNode + item * (float)i + item3 * (float)j;
					if ((i == 0 || Math.Abs((double)i - (num - 1.0)) < 1E-08) && (j == 0 || Math.Abs((double)j - (num2 - 1.0)) < 1E-08))
					{
						snapNodes.Add(new SnapNode(position, primarySnapNodeType, SnapNode.Precision.ORDINARY));
					}
					else if ((float)i % 2f == 0f && (float)j % 2f == 0f)
					{
						snapNodes.Add(new SnapNode(position, SnapNode.Type.DERIVED, SnapNode.Precision.ORDINARY));
					}
					else
					{
						snapNodes.Add(new SnapNode(position, SnapNode.Type.DERIVED, SnapNode.Precision.SUPERIOR));
					}
				}
			}
		}

		private (Vector3, int) RecursiveSplit(Vector3 dimensionΔ, int splitLevel = 0)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref dimensionΔ)).magnitude > 0.75f)
			{
				return RecursiveSplit(dimensionΔ * 0.5f, ++splitLevel);
			}
			return (dimensionΔ, splitLevel);
		}

		public override string ToString()
		{
			//IL_001c: 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_0038: 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)
			return $"Box {name}: ({minMinSnapNode}, {minMaxSnapNode}, {maxMinSnapNode}, {maxMaxSnapNode})";
		}
	}
	public readonly struct Circle : ISide
	{
		private const int CircleDivisions = 8;

		private char name { get; }

		private Vector3 midSnapNode { get; }

		private Vector2 radial { get; }

		public Circle(Piece piece, Vector2 radial, char name = 'A')
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			this.name = name;
			this.radial = radial;
			midSnapNode = piece.TopMiddle();
		}

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//IL_0018: 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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 8; i++)
			{
				Vector3 val = Quaternion.Euler(new Vector3(0f, 45f * (float)i, 0f)) * Vector2.op_Implicit(radial);
				Vector3 val2 = midSnapNode + val;
				snapNodes.Add(new SnapNode(midSnapNode, SnapNode.Type.IMPOSED, SnapNode.Precision.ORDINARY));
				snapNodes.Add(new SnapNode(val2, SnapNode.Type.IMPOSED, SnapNode.Precision.ORDINARY));
				SnapNode.RecursiveSplit(midSnapNode, val2, snapNodes);
			}
		}

		public override string ToString()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			return $"Circle {name}: {midSnapNode} + {radial} * quaternion rotation";
		}
	}
	public interface ISide
	{
		void FillUp(HashSet<SnapNode> snapNodes);
	}
	public readonly struct Line : ISide
	{
		private char name { get; }

		private Vector3 minSnapNode { get; }

		private Vector3 maxSnapNode { get; }

		public void FillUp(HashSet<SnapNode> snapNodes)
		{
			//IL_0001: 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)
			SnapNode.RecursiveSplit(minSnapNode, maxSnapNode, snapNodes);
		}

		public Line(char name, Vector3 minSnapNode, Vector3 maxSnapNode)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			this.name = name;
			this.minSnapNode = minSnapNode;
			this.maxSnapNode = maxSnapNode;
		}

		public override string ToString()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			return $"Line {name}: ({minSnapNode}, {maxSnapNode})";
		}
	}
	public readonly struct SnapNode : IEquatable<SnapNode>
	{
		public enum Type
		{
			PRIMARY,
			IMPOSED,
			DERIVED
		}

		public enum Precision
		{
			ORDINARY,
			SUPERIOR
		}

		public const float OrdinaryPrecisionSplitThreshold = 1.5f;

		public const float SuperiorPrecisionMultiplier = 2f;

		public Precision precision { get; }

		private Vector3 position { get; }

		private Type type { get; }

		private static bool ShouldSplitInOrdinaryPrecisionMode(Vector3 prevSnapNode, Vector3 nextSnapNode)
		{
			//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)
			return Vector3.Distance(prevSnapNode, nextSnapNode) > 1.5f;
		}

		private static bool ShouldSplitInSuperiorPrecisionMode(Vector3 prevSnapNode, Vector3 nextSnapNode)
		{
			//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)
			return Vector3.Distance(prevSnapNode, nextSnapNode) > 0.75f;
		}

		public SnapNode(Vector3 position, Type type, Precision precision)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			this.position = position;
			this.type = type;
			this.precision = precision;
		}

		public static void RecursiveSplit(Vector3 snapNodeA, Vector3 snapNodeB, HashSet<SnapNode> snapNodes)
		{
			//IL_0002: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			snapNodes.Add(new SnapNode(snapNodeA, Type.PRIMARY, Precision.ORDINARY));
			snapNodes.Add(new SnapNode(snapNodeB, Type.PRIMARY, Precision.ORDINARY));
			RecursiveSplitInOrdinaryPrecisionMode(snapNodeA, snapNodeB, snapNodes);
		}

		private static void RecursiveSplitInOrdinaryPrecisionMode(Vector3 snapNodeA, Vector3 snapNodeB, HashSet<SnapNode> snapNodes, int splitLevel = 0)
		{
			//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_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldSplitInOrdinaryPrecisionMode(snapNodeA, snapNodeB))
			{
				Vector3 midSnapNode = (snapNodeA + snapNodeB) * 0.5f;
				snapNodes.Add(new SnapNode(midSnapNode, Type.DERIVED, Precision.ORDINARY));
				Logger.Debug(delegate
				{
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_0049: Unknown result type (might be due to invalid IL or missing references)
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					object[] array = new object[4];
					int num = splitLevel;
					splitLevel = num + 1;
					array[0] = num;
					array[1] = snapNodeA;
					array[2] = snapNodeB;
					array[3] = midSnapNode;
					return string.Format("[SPLIT LEVEL {0}] Ordinary Precision Child of: {1} & {2}, is: {3}", array);
				});
				RecursiveSplitInOrdinaryPrecisionMode(snapNodeA, midSnapNode, snapNodes, splitLevel);
				RecursiveSplitInOrdinaryPrecisionMode(midSnapNode, snapNodeB, snapNodes, splitLevel);
			}
			else
			{
				RecursiveSplitInSuperiorPrecisionMode(snapNodeA, snapNodeB, snapNodes, splitLevel);
			}
		}

		private static void RecursiveSplitInSuperiorPrecisionMode(Vector3 snapNodeA, Vector3 snapNodeB, HashSet<SnapNode> snapNodes, int splitLevel)
		{
			//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_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldSplitInSuperiorPrecisionMode(snapNodeA, snapNodeB))
			{
				Vector3 midSnapNode = (snapNodeA + snapNodeB) * 0.5f;
				snapNodes.Add(new SnapNode(midSnapNode, Type.DERIVED, Precision.SUPERIOR));
				Logger.Debug(delegate
				{
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					//IL_0049: Unknown result type (might be due to invalid IL or missing references)
					//IL_0057: Unknown result type (might be due to invalid IL or missing references)
					object[] array = new object[4];
					int num = splitLevel;
					splitLevel = num + 1;
					array[0] = num;
					array[1] = snapNodeA;
					array[2] = snapNodeB;
					array[3] = midSnapNode;
					return string.Format("[SPLIT LEVEL {0}] Superior Precision Child of: {1} & {2}, is: {3}", array);
				});
				RecursiveSplitInSuperiorPrecisionMode(snapNodeA, midSnapNode, snapNodes, splitLevel);
				RecursiveSplitInSuperiorPrecisionMode(midSnapNode, snapNodeB, snapNodes, splitLevel);
			}
		}

		public static implicit operator Vector3(SnapNode snapNode)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return snapNode.position;
		}

		public override string ToString()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			return $"{type} Snap Node of {precision} precision: {position}";
		}

		public override bool Equals(object other)
		{
			return other is SnapNode snapNode && snapNode.Equals(this);
		}

		public bool Equals(SnapNode snapNode)
		{
			//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)
			return snapNode.position == position;
		}

		public override int GetHashCode()
		{
			//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)
			Vector3 val = position;
			return ((object)(Vector3)(ref val)).GetHashCode();
		}
	}
	public readonly struct SnapTree
	{
		public struct TraversalResult
		{
			public Vector3 buildPieceSnapNode { get; }

			public SnapNode neighbourSnapNode { get; }

			public Piece neighbourPiece { get; }

			public TraversalResult(Vector3 buildPieceSnapNode, SnapNode neighbourSnapNode, Piece neighbourPiece)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				this.buildPieceSnapNode = buildPieceSnapNode;
				this.neighbourSnapNode = neighbourSnapNode;
				this.neighbourPiece = neighbourPiece;
			}
		}

		private const int ZeroSidesAllowed = 0;

		private const int OneSideAllowed = 1;

		private const int SidesOfCube = 6;

		private const int SidesOfOctagon = 10;

		private const float SnapThreshold = 1f;

		private static readonly List<Box> Boxes = new List<Box>(6);

		private static readonly List<Line> Lines = new List<Line>(10);

		private static readonly List<ISide> Sides = new List<ISide>(1);

		private static readonly List<Vector3> HorribleOptimization = new List<Vector3>(1);

		private static readonly HashSet<SnapNode> ZeroSnapNodes = new HashSet<SnapNode>(0);

		private static readonly IMemoryRepo<Piece, SnapTree> SnapTrees = new MemoryRepo<Piece, SnapTree>((Piece piece) => new SnapTree(piece), 1024);

		private static readonly Func<SnapNode.Precision, bool> OrdinaryPrecisionOnly = (SnapNode.Precision precision) => precision == SnapNode.Precision.ORDINARY;

		private static readonly Func<SnapNode.Precision, bool> OrdinaryAndSuperiorPrecision = (SnapNode.Precision precision) => precision == SnapNode.Precision.ORDINARY || precision == SnapNode.Precision.SUPERIOR;

		private HashSet<SnapNode> snapNodes { get; }

		private static bool FormValidTwoDimensionalBoxSide(Vector3 snapNodeA, Vector3 snapNodeB, Vector3 snapNodeC, Vector3 snapNodeD)
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			return snapNodeA != snapNodeB && snapNodeA != snapNodeC && snapNodeB + snapNodeC - snapNodeA == snapNodeD;
		}

		private static Func<Vector3, Vector3, Vector3, Vector3, bool> FormValidThreeDimensionalBoxSide(Piece piece)
		{
			//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)
			Vector3 pieceMid = ((Component)piece).transform.position;
			return delegate(Vector3 snapNodeA, Vector3 snapNodeB, Vector3 snapNodeC, Vector3 snapNodeD)
			{
				//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_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_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: 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_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = (snapNodeA + snapNodeD) * 0.5f;
				return FormValidTwoDimensionalBoxSide(snapNodeA, snapNodeB, snapNodeC, snapNodeD) && pieceMid != val;
			};
		}

		private static bool LiesOnVerticalMiddle(Vector3 snapNode, Piece piece)
		{
			//IL_0000: 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)
			return Mathf.Approximately(snapNode.x, ((Component)piece).transform.position.y);
		}

		private static bool LiesOnHorizontalMiddle(Vector3 snapNode, Piece piece)
		{
			//IL_0000: 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_001d: 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)
			return Mathf.Approximately(snapNode.x, ((Component)piece).transform.position.x) && Mathf.Approximately(snapNode.z, ((Component)piece).transform.position.z);
		}

		private static bool LiesOnSameVerticalSide(Vector3 snapNodeA, Vector3 snapNodeB)
		{
			//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_0013: 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_0026: 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)
			return Mathf.Approximately(snapNodeA.x, snapNodeB.x) && !Mathf.Approximately(snapNodeA.y, snapNodeB.y) && Mathf.Approximately(snapNodeA.z, snapNodeB.z);
		}

		private static bool LiesOnSameHorizontalSide(Vector3 snapNodeA, Vector3 snapNodeB)
		{
			//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)
			return !Mathf.Approximately(snapNodeA.y, snapNodeB.y);
		}

		private SnapTree(Piece piece)
		{
			Logger.Debug(() => $"[INIT] SNAP TREE CONSTRUCTION of piece: '{piece.m_name}' {((Component)piece).transform.position}");
			snapNodes = DeriveSnapNodesFrom(piece);
			SnapTree tree = this;
			Logger.Debug(() => "SNAP NODES: " + string.Join(", ", tree.snapNodes));
			Logger.Debug(() => $"[SUCCESS] SNAP TREE CONSTRUCTION of piece: '{piece.m_name}' {((Component)piece).transform.position}");
		}

		public static TraversalResult? FindNearestOrdinaryPrecisionSnapNodeTo(Vector3 referencePosition, List<Piece> pieces)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return FindNearestSnapNodeTo(referencePosition, pieces, OrdinaryPrecisionOnly);
		}

		public static TraversalResult? FindNearestSuperiorPrecisionSnapNodeTo(Vector3 referencePosition, List<Piece> pieces)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return FindNearestSnapNodeTo(referencePosition, pieces, OrdinaryAndSuperiorPrecision);
		}

		public static TraversalResult? FindNearestOrdinaryPrecisionSnapNodeCombinationOf(Piece buildPiece, List<Piece> neighbourPieces)
		{
			return FindNearestSnapNodeTo(buildPiece.PrimarySnapNodes(), neighbourPieces, OrdinaryPrecisionOnly);
		}

		public static TraversalResult? FindNearestSuperiorPrecisionSnapNodeCombinationOf(Piece buildPiece, List<Piece> neighbourPieces)
		{
			return FindNearestSnapNodeTo(buildPiece.PrimarySnapNodes(), neighbourPieces, OrdinaryAndSuperiorPrecision);
		}

		private static HashSet<SnapNode> DeriveSnapNodesFrom(Piece piece)
		{
			switch (piece.Type())
			{
			case PieceType.CONSTRUCTION:
				switch (piece.Shape())
				{
				case PieceShape.LINE:
					return DeriveSnapNodesFrom(piece, DeriveLineFrom);
				case PieceShape.BOX:
					return DeriveSnapNodesFrom(piece, DeriveBoxFrom);
				case PieceShape.CUBE:
					return DeriveSnapNodesFrom(piece, DeriveSidesFromCube);
				case PieceShape.CYLINDER:
					return DeriveSnapNodesFrom(piece, DeriveSidesFromCylinder);
				case PieceShape.UNDEFINED:
					return DeriveSnapNodesFrom(piece, DeriveSidesFromUndefined);
				}
				break;
			case PieceType.FURNITURE:
				return ZeroSnapNodes;
			case PieceType.TABLE:
				return DeriveSnapNodesFrom(piece, ImposeTopSideOn);
			}
			throw new InvalidOperationException("This is supposedly mathematically impossible :D");
		}

		private static HashSet<SnapNode> DeriveSnapNodesFrom<T>(Piece piece, Func<Piece, List<T>> deriveSidesFrom) where T : ISide
		{
			List<T> sides = deriveSidesFrom(piece);
			Logger.Debug(() => "SIDES: " + string.Join(", ", sides));
			HashSet<SnapNode> result = new HashSet<SnapNode>(255);
			foreach (T item in sides)
			{
				item.FillUp(result);
			}
			return result;
		}

		private static List<Line> DeriveLineFrom(Piece piece)
		{
			List<Line> sides = DeriveSidesFromUndefined(piece);
			if (sides.Count != 1)
			{
				Logger.Warn(() => $"EXPECTED SIDES on Piece '{piece.m_name}' {((Component)piece).transform.position}: {1}, ACTUAL SIDES: {sides.Count}");
			}
			return sides;
		}

		private static List<Box> DeriveBoxFrom(Piece piece)
		{
			return FindSidesOfBoxOrCube(piece, FormValidTwoDimensionalBoxSide, 1);
		}

		private static List<Box> DeriveSidesFromCube(Piece piece)
		{
			return FindSidesOfBoxOrCube(piece, FormValidThreeDimensionalBoxSide(piece), 6);
		}

		private static List<Box> FindSidesOfBoxOrCube(Piece piece, Func<Vector3, Vector3, Vector3, Vector3, bool> isValidSide, int numberOfSides)
		{
			//IL_005a: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_00a0: 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)
			Boxes.Clear();
			char c = 'A';
			List<Vector3> list = piece.PrimarySnapNodes();
			for (int i = 0; i < list.Count; i++)
			{
				for (int j = i + 1; j < list.Count; j++)
				{
					for (int k = j + 1; k < list.Count; k++)
					{
						for (int l = k + 1; l < list.Count; l++)
						{
							if (isValidSide(list[i], list[j], list[k], list[l]))
							{
								Boxes.Add(new Box(c++, list[i], list[j], list[k], list[l]));
							}
						}
					}
				}
			}
			if (Boxes.Count != numberOfSides)
			{
				Logger.Warn(() => $"EXPECTED SIDES on Piece '{piece.m_name}' {((Component)piece).transform.position}: {numberOfSides}, ACTUAL SIDES: {Boxes.Count}");
			}
			return Boxes;
		}

		private static List<Line> DeriveSidesFromCylinder(Piece piece)
		{
			//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)
			//IL_0036: 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_006c: 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_0088: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00cb: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			Lines.Clear();
			char c = 'A';
			for (int i = 0; i < piece.PrimarySnapNodes().Count; i++)
			{
				Vector3 val = piece.PrimarySnapNodes()[i];
				if (LiesOnHorizontalMiddle(val, piece))
				{
					continue;
				}
				for (int j = i + 1; j < piece.PrimarySnapNodes().Count; j++)
				{
					Vector3 val2 = piece.PrimarySnapNodes()[j];
					if (!LiesOnHorizontalMiddle(val2, piece))
					{
						Vector3 snapNode = (val + val2) * 0.5f;
						if (LiesOnSameVerticalSide(val, val2) && !LiesOnHorizontalMiddle(snapNode, piece))
						{
							Lines.Add(new Line(c++, val, val2));
						}
						else if (LiesOnSameHorizontalSide(val, val2) && LiesOnHorizontalMiddle(snapNode, piece))
						{
							Lines.Add(new Line(c++, val, val2));
						}
					}
				}
			}
			if (Lines.Count != 10)
			{
				Logger.Warn(() => $"EXPECTED SIDES on Piece '{piece.m_name}' {((Component)piece).transform.position}: {10}, ACTUAL SIDES: {Lines.Count}");
			}
			return Lines;
		}

		private static List<Line> DeriveSidesFromUndefined(Piece piece)
		{
			//IL_002d: 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)
			Lines.Clear();
			char c = 'A';
			for (int i = 0; i < piece.PrimarySnapNodes().Count; i++)
			{
				for (int j = i + 1; j < piece.PrimarySnapNodes().Count; j++)
				{
					Lines.Add(new Line(c++, piece.PrimarySnapNodes()[i], piece.PrimarySnapNodes()[j]));
				}
			}
			return Lines;
		}

		private static List<ISide> ImposeTopSideOn(Piece piece)
		{
			Sides.Clear();
			ISide item = piece.TopSide();
			Sides.Add(item);
			return Sides;
		}

		private static TraversalResult? FindNearestSnapNodeTo(Vector3 referencePosition, List<Piece> pieces, Func<SnapNode.Precision, bool> isDesired)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			HorribleOptimization.Clear();
			HorribleOptimization.Add(referencePosition);
			return FindNearestSnapNodeTo(HorribleOptimization, pieces, isDesired);
		}

		private static TraversalResult? FindNearestSnapNodeTo(List<Vector3> buildPieceSnapNodes, List<Piece> neighborPieces, Func<SnapNode.Precision, bool> isDesired)
		{
			//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_0066: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			float num = float.PositiveInfinity;
			TraversalResult? result = null;
			foreach (Vector3 buildPieceSnapNode in buildPieceSnapNodes)
			{
				foreach (Piece neighborPiece in neighborPieces)
				{
					foreach (SnapNode snapNode in SnapTrees.LookUp(neighborPiece).snapNodes)
					{
						float num2 = Vector3.Distance(buildPieceSnapNode, (Vector3)snapNode);
						if (isDesired(snapNode.precision) && num > num2 && num2 < 1f)
						{
							num = num2;
							result = new TraversalResult(buildPieceSnapNode, snapNode, neighborPiece);
						}
					}
				}
			}
			return result;
		}
	}
	public static class Logger
	{
		private static LogLevel logLevel => (LogLevel)32;

		public static void Debug(Func<string> func)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)logLevel >= 32)
			{
				Logger.LogDebug((object)func());
			}
		}

		public static void Info(Func<string> func)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			if ((int)logLevel >= 16)
			{
				Logger.LogInfo((object)func());
			}
		}

		public static void Warn(Func<string> func)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)logLevel >= 4)
			{
				Logger.LogWarning((object)func());
			}
		}
	}
	public interface IMemoryRepo<K, V>
	{
		V LookUp(K key);
	}
	public interface IRefreshableMemoryRepo<K, V> : IMemoryRepo<K, V>, IRefresherable
	{
	}
	public class MemoryRepo<K, TK, V> : IMemoryRepo<K, V>
	{
		private class TimeBombMemoryRepo : IRefreshableMemoryRepo<K, V>, IMemoryRepo<K, V>, IRefresherable
		{
			private MemoryRepo<K, TK, V> innerMemoryRepo { get; }

			private TimeSpan explosionTime { get; }

			private Queue<Timed> timeBomb { get; }

			public TimeBombMemoryRepo(MemoryRepo<K, TK, V> innerMemoryRepo, TimeSpan explosionTime)
			{
				timeBomb = new Queue<Timed>();
				this.explosionTime = explosionTime;
				this.innerMemoryRepo = innerMemoryRepo;
			}

			public V LookUp(K key)
			{
				TK key2 = innerMemoryRepo.transformer(key);
				if (!innerMemoryRepo.kvs.ContainsKey(key2))
				{
					timeBomb.Enqueue(new Timed(key2, Time.time + (float)explosionTime.TotalSeconds));
				}
				return innerMemoryRepo.LookUp(key);
			}

			public void Refresh()
			{
				while (timeBomb.Count > 0 && timeBomb.Peek().explosionTime < Time.time)
				{
					Timed boom = timeBomb.Dequeue();
					innerMemoryRepo.kvs.Remove(boom.key);
					Logger.Debug(() => $"[MEMORY REPO EVICTION] on key: {boom.key}");
				}
			}
		}

		private struct Timed
		{
			public float explosionTime { get; }

			public TK key { get; }

			public Timed(TK key, float explosionTime)
			{
				this.key = key;
				this.explosionTime = explosionTime;
			}
		}

		protected Func<K, V> producer { get; }

		private Dictionary<TK, V> kvs { get; }

		private Func<K, TK> transformer { get; }

		public MemoryRepo(Func<K, V> producer, Func<K, TK> transformer, int capacity)
		{
			this.producer = producer;
			this.transformer = transformer;
			kvs = new Dictionary<TK, V>(capacity);
		}

		public V LookUp(K key)
		{
			TK val = transformer(key);
			bool miss = !kvs.ContainsKey(val);
			Logger.Debug(() => string.Format("[MEMORY REPO {0}] on key: {1}", miss ? "MISS" : "HIT", key));
			if (miss)
			{
				kvs[val] = ProduceVal(key, val);
			}
			return kvs[val];
		}

		public IRefreshableMemoryRepo<K, V> EvictionPolicy(TimeSpan explosionTime)
		{
			return new TimeBombMemoryRepo(this, explosionTime);
		}

		protected virtual V ProduceVal(K key, TK _)
		{
			return producer(key);
		}
	}
	public class MemoryRepo<K, V> : MemoryRepo<K, K, V>
	{
		public MemoryRepo(Func<K, V> producer, Func<K, K> transformer, int capacity)
			: base(producer, transformer, capacity)
		{
		}

		public MemoryRepo(Func<K, V> producer, int capacity)
			: this(producer, (Func<K, K>)((K key) => key), capacity)
		{
		}

		protected override V ProduceVal(K _, K transformedKey)
		{
			return base.producer(transformedKey);
		}
	}
	public static class PieceHelpers
	{
		private static readonly IMemoryRepo<Piece, Bounds> PieceSizes = new MemoryRepo<Piece, string, Bounds>(BoundsOf, (Piece piece) => piece.m_name, 255);

		private static readonly IMemoryRepo<Piece, PieceType> PieceTypes = new MemoryRepo<Piece, string, PieceType>(TypeOf, (Piece piece) => piece.m_name, 255);

		private static readonly IMemoryRepo<Piece, PieceShape> PieceShapes = new MemoryRepo<Piece, string, PieceShape>(ShapeOf, (Piece piece) => piece.m_name, 255);

		private static readonly Dictionary<string, Func<Piece, ISide>> Tables = new Dictionary<string, Func<Piece, ISide>>
		{
			["$piece_table_oak"] = (Piece piece) => new Box(piece, new Vector2(3f, 0.8f)),
			["$piece_blackmarble_table"] = (Piece piece) => new Box(piece, new Vector2(1.15f, 0.5f)),
			["$piece_table"] = (Piece piece) => new Box(piece, new Vector2(1.1f, 0.475f)),
			["$piece_table_round"] = (Piece piece) => new Circle(piece, new Vector2(1.15f, 0f))
		};

		private static readonly List<Transform> PrimarySPs = new List<Transform>();

		private static readonly List<Vector3> PrimarySNs = new List<Vector3>();

		public static Piece buildPiece
		{
			get
			{
				GameObject placementGhost = PlayerHelpers.player.m_placementGhost;
				return (placementGhost != null) ? placementGhost.GetComponent<Piece>() : null;
			}
		}

		public static Bounds Bounds(this Piece piece)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return PieceSizes.LookUp(piece);
		}

		public static PieceType Type(this Piece piece)
		{
			return PieceTypes.LookUp(piece);
		}

		public static PieceShape Shape(this Piece piece)
		{
			return PieceShapes.LookUp(piece);
		}

		public static ISide TopSide(this Piece piece)
		{
			return Tables[piece.m_name](piece);
		}

		public static bool IsGroundBound(this Piece piece)
		{
			return piece.m_groundPiece || piece.m_clipGround || piece.m_clipEverything;
		}

		public static List<Vector3> PrimarySnapNodes(this Piece piece)
		{
			piece.FlushPrimarySnapNodes();
			piece.PopulatePrimarySnapNodes();
			return PrimarySNs;
		}

		private static void FlushPrimarySnapNodes(this Piece _)
		{
			PrimarySPs.Clear();
			PrimarySNs.Clear();
			Logger.Debug(() => "[FLUSHED] Primary Snap Nodes of previous piece");
		}

		private static void PopulatePrimarySnapNodes(this Piece piece)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			piece.GetSnapPoints(PrimarySPs);
			foreach (Transform primarySP in PrimarySPs)
			{
				PrimarySNs.Add(((Component)primarySP).transf