Decompiled source of LowSpecGaming v0.3.3

LowSpecGaming.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AK;
using AssetShards;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Hook;
using CellMenu;
using ChainedPuzzles;
using CullingSystem;
using Decals;
using FluffyUnderware.Curvy;
using GTFO.API;
using GameData;
using HarmonyLib;
using IRF;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using LowSpecGaming.Misc;
using LowSpecGaming.Patches;
using LowSpecGaming.Settings;
using LowSpecGaming.Util;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityMeshSimplifier;
using UnityMeshSimplifier.Internal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("LowSpecGaming")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LowSpecGaming")]
[assembly: AssemblyTitle("LowSpecGaming")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NativeIntegerAttribute : Attribute
	{
		public readonly bool[] TransformFlags;

		public NativeIntegerAttribute()
		{
			TransformFlags = new bool[1] { true };
		}

		public NativeIntegerAttribute(bool[] P_0)
		{
			TransformFlags = P_0;
		}
	}
}
namespace UnityMeshSimplifier
{
	public static class MathHelper
	{
		public const float PI = (float)Math.PI;

		public const double PId = Math.PI;

		public const float Deg2Rad = (float)Math.PI / 180f;

		public const double Deg2Radd = Math.PI / 180.0;

		public const float Rad2Deg = 180f / (float)Math.PI;

		public const double Rad2Degd = 180.0 / Math.PI;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Min(double val1, double val2, double val3)
		{
			if (!(val1 < val2))
			{
				if (!(val2 < val3))
				{
					return val3;
				}
				return val2;
			}
			if (!(val1 < val3))
			{
				return val3;
			}
			return val1;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Clamp(double value, double min, double max)
		{
			if (!(value >= min))
			{
				return min;
			}
			if (!(value <= max))
			{
				return max;
			}
			return value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double TriangleArea(ref Vector3d p0, ref Vector3d p1, ref Vector3d p2)
		{
			Vector3d from = p1 - p0;
			Vector3d to = p2 - p0;
			return from.Magnitude * (Math.Sin((float)(Vector3d.Angle(ref from, ref to) * (Math.PI / 180.0))) * to.Magnitude) * 0.5;
		}
	}
	public class MeshSimplifier
	{
		private const int TriangleEdgeCount = 3;

		private const int TriangleVertexCount = 3;

		private const double DoubleEpsilon = 0.001;

		private const double DenomEpilson = 1E-08;

		private static readonly int UVChannelCount = MeshUtils.UVChannelCount;

		private SimplificationOptions simplificationOptions = SimplificationOptions.Default;

		private bool verbose;

		private int subMeshCount;

		private int[] subMeshOffsets;

		private ResizableArray<Triangle> triangles;

		private ResizableArray<Vertex> vertices;

		private ResizableArray<Ref> refs;

		private ResizableArray<Vector3> vertNormals;

		private ResizableArray<Vector4> vertTangents;

		private UVChannels<Vector2> vertUV2D;

		private UVChannels<Vector3> vertUV3D;

		private UVChannels<Vector4> vertUV4D;

		private ResizableArray<Color> vertColors;

		private ResizableArray<BoneWeight> vertBoneWeights;

		private Matrix4x4[] bindposes;

		private readonly double[] errArr = new double[3];

		private readonly int[] attributeIndexArr = new int[3];

		private readonly HashSet<Triangle> triangleHashSet1 = new HashSet<Triangle>();

		private readonly HashSet<Triangle> triangleHashSet2 = new HashSet<Triangle>();

		public Vector3[] Vertices
		{
			get
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				int length = vertices.Length;
				Vector3[] array = (Vector3[])(object)new Vector3[length];
				ResizableArray<Vertex> resizableArray = vertices;
				for (int i = 0; i < length; i++)
				{
					array[i] = (Vector3)resizableArray[i].p;
				}
				return array;
			}
			set
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				vertices.Resize(value.Length);
				ResizableArray<Vertex> resizableArray = vertices;
				for (int i = 0; i < value.Length; i++)
				{
					resizableArray[i] = new Vertex(i, value[i]);
				}
			}
		}

		public Vector3[] Normals
		{
			get
			{
				if (vertNormals == null)
				{
					return null;
				}
				return vertNormals.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertNormals, "normals");
			}
		}

		public Vector4[] Tangents
		{
			get
			{
				if (vertTangents == null)
				{
					return null;
				}
				return vertTangents.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertTangents, "tangents");
			}
		}

		public Vector2[] UV1
		{
			get
			{
				return GetUVs2D(0);
			}
			set
			{
				SetUVs(0, value);
			}
		}

		public Vector2[] UV2
		{
			get
			{
				return GetUVs2D(1);
			}
			set
			{
				SetUVs(1, value);
			}
		}

		public Vector2[] UV3
		{
			get
			{
				return GetUVs2D(2);
			}
			set
			{
				SetUVs(2, value);
			}
		}

		public Vector2[] UV4
		{
			get
			{
				return GetUVs2D(3);
			}
			set
			{
				SetUVs(3, value);
			}
		}

		public Color[] Colors
		{
			get
			{
				if (vertColors == null)
				{
					return null;
				}
				return vertColors.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertColors, "colors");
			}
		}

		public MeshSimplifier()
		{
			triangles = new ResizableArray<Triangle>(0);
			vertices = new ResizableArray<Vertex>(0);
			refs = new ResizableArray<Ref>(0);
		}

		public MeshSimplifier(Mesh mesh)
			: this()
		{
			if ((Object)(object)mesh != (Object)null)
			{
				Initialize(mesh);
			}
		}

		public int[][] GetAllSubMeshTriangles()
		{
			int[][] array = new int[subMeshCount][];
			for (int i = 0; i < subMeshCount; i++)
			{
				array[i] = GetSubMeshTriangles(i);
			}
			return array;
		}

		public int[] GetSubMeshTriangles(int subMeshIndex)
		{
			if (subMeshIndex < 0)
			{
				throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is negative.");
			}
			if (subMeshOffsets == null)
			{
				CalculateSubMeshOffsets();
			}
			if (subMeshIndex >= subMeshOffsets.Length)
			{
				throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is greater than or equals to the sub mesh count.");
			}
			if (subMeshOffsets.Length != subMeshCount)
			{
				throw new InvalidOperationException("The sub-mesh triangle offsets array is not the same size as the count of sub-meshes. This should not be possible to happen.");
			}
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int num = subMeshOffsets[subMeshIndex];
			if (num >= length)
			{
				return new int[0];
			}
			int num2 = ((subMeshIndex + 1 < subMeshCount) ? subMeshOffsets[subMeshIndex + 1] : length);
			int num3 = num2 - num;
			if (num3 < 0)
			{
				num3 = 0;
			}
			int[] array = new int[num3 * 3];
			for (int i = num; i < num2; i++)
			{
				Triangle triangle = data[i];
				int num4 = (i - num) * 3;
				array[num4] = triangle.v0;
				array[num4 + 1] = triangle.v1;
				array[num4 + 2] = triangle.v2;
			}
			return array;
		}

		private void CalculateSubMeshOffsets()
		{
			int num = -1;
			subMeshOffsets = new int[subMeshCount];
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			for (int i = 0; i < length; i++)
			{
				Triangle triangle = data[i];
				if (triangle.subMeshIndex > num)
				{
					for (int j = num + 1; j < triangle.subMeshIndex; j++)
					{
						subMeshOffsets[j] = i;
					}
					subMeshOffsets[triangle.subMeshIndex] = i;
					num = triangle.subMeshIndex;
				}
			}
			for (int k = num + 1; k < subMeshCount; k++)
			{
				subMeshOffsets[k] = length;
			}
		}

		public void Initialize(Mesh mesh)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			Vertices = Il2CppArrayBase<Vector3>.op_Implicit((Il2CppArrayBase<Vector3>)(object)mesh.vertices);
			Normals = Il2CppArrayBase<Vector3>.op_Implicit((Il2CppArrayBase<Vector3>)(object)mesh.normals);
			Tangents = Il2CppArrayBase<Vector4>.op_Implicit((Il2CppArrayBase<Vector4>)(object)mesh.tangents);
			Colors = Il2CppArrayBase<Color>.op_Implicit((Il2CppArrayBase<Color>)(object)mesh.colors);
			Il2CppStructArray<Vector2> uv2 = (mesh.uv = mesh.uv);
			mesh.uv2 = uv2;
			ClearSubMeshes();
			int num = mesh.subMeshCount;
			int[][] array = new int[num][];
			for (int i = 0; i < num; i++)
			{
				array[i] = Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)mesh.GetTriangles(i));
			}
			AddSubMeshTriangles(array);
		}

		private void InitializeVertexAttribute<T>(T[] attributeValues, ref ResizableArray<T> attributeArray, string attributeName)
		{
			if (attributeValues != null && attributeValues.Length == vertices.Length)
			{
				if (attributeArray == null)
				{
					attributeArray = new ResizableArray<T>(attributeValues.Length, attributeValues.Length);
				}
				else
				{
					attributeArray.Resize(attributeValues.Length);
				}
				T[] data = attributeArray.Data;
				Array.Copy(attributeValues, 0, data, 0, attributeValues.Length);
				return;
			}
			if (attributeValues != null && attributeValues.Length != 0)
			{
				Debug.LogErrorFormat("Failed to set vertex attribute '{0}' with {1} length of array, when {2} was needed.", (Object[])(object)new Object[3]
				{
					Object.op_Implicit(attributeName),
					Object.op_Implicit(attributeValues.Length),
					Object.op_Implicit(vertices.Length)
				});
			}
			attributeArray = null;
		}

		public void GetUVs(int channel, List<Vector2> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV2D != null && vertUV2D[channel] != null)
			{
				Vector2[] data = vertUV2D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void GetUVs(int channel, List<Vector3> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV3D != null && vertUV3D[channel] != null)
			{
				Vector3[] data = vertUV3D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void GetUVs(int channel, List<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV4D != null && vertUV4D[channel] != null)
			{
				Vector4[] data = vertUV4D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void SetUVs(int channel, IList<Vector2> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV2D == null)
				{
					vertUV2D = new UVChannels<Vector2>();
				}
				int count = uvs.Count;
				ResizableArray<Vector2> resizableArray = vertUV2D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector2>(count, count);
					vertUV2D[channel] = resizableArray;
				}
				Vector2[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector3> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV3D == null)
				{
					vertUV3D = new UVChannels<Vector3>();
				}
				int count = uvs.Count;
				ResizableArray<Vector3> resizableArray = vertUV3D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector3>(count, count);
					vertUV3D[channel] = resizableArray;
				}
				Vector3[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV4D == null)
				{
					vertUV4D = new UVChannels<Vector4>();
				}
				int count = uvs.Count;
				ResizableArray<Vector4> resizableArray = vertUV4D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector4>(count, count);
					vertUV4D[channel] = resizableArray;
				}
				Vector4[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector4> uvs, int uvComponentCount)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvComponentCount < 0 || uvComponentCount > 4)
			{
				throw new ArgumentOutOfRangeException("uvComponentCount");
			}
			if (uvs != null && uvs.Count > 0 && uvComponentCount > 0)
			{
				if (uvComponentCount <= 2)
				{
					Vector2[] uvs2 = MeshUtils.ConvertUVsTo2D(uvs);
					SetUVs(channel, uvs2);
				}
				else if (uvComponentCount == 3)
				{
					Vector3[] uvs3 = MeshUtils.ConvertUVsTo3D(uvs);
					SetUVs(channel, uvs3);
				}
				else
				{
					SetUVs(channel, uvs);
				}
				return;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVsAuto(int channel, IList<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			int usedUVComponents = MeshUtils.GetUsedUVComponents(uvs);
			SetUVs(channel, uvs, usedUVComponents);
		}

		public Vector2[] GetUVs2D(int channel)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (vertUV2D != null && vertUV2D[channel] != null)
			{
				return vertUV2D[channel].Data;
			}
			return null;
		}

		public void ClearSubMeshes()
		{
			subMeshCount = 0;
			subMeshOffsets = null;
			triangles.Resize(0);
		}

		public void AddSubMeshTriangles(int[] triangles)
		{
			if (triangles == null)
			{
				throw new ArgumentNullException("triangles");
			}
			if (triangles.Length % 3 != 0)
			{
				throw new ArgumentException("The index array length must be a multiple of 3 in order to represent triangles.", "triangles");
			}
			int subMeshIndex = subMeshCount++;
			int length = this.triangles.Length;
			int num = triangles.Length / 3;
			this.triangles.Resize(this.triangles.Length + num);
			Triangle[] data = this.triangles.Data;
			for (int i = 0; i < num; i++)
			{
				int num2 = i * 3;
				int v = triangles[num2];
				int v2 = triangles[num2 + 1];
				int v3 = triangles[num2 + 2];
				int num3 = length + i;
				data[num3] = new Triangle(num3, v, v2, v3, subMeshIndex);
			}
		}

		public void AddSubMeshTriangles(int[][] triangles)
		{
			if (triangles == null)
			{
				throw new ArgumentNullException("triangles");
			}
			int num = 0;
			for (int i = 0; i < triangles.Length; i++)
			{
				if (triangles[i] == null)
				{
					throw new ArgumentException($"The index array at index {i} is null.");
				}
				if (triangles[i].Length % 3 != 0)
				{
					throw new ArgumentException($"The index array length at index {i} must be a multiple of 3 in order to represent triangles.", "triangles");
				}
				num += triangles[i].Length / 3;
			}
			int num2 = this.triangles.Length;
			this.triangles.Resize(this.triangles.Length + num);
			Triangle[] data = this.triangles.Data;
			for (int j = 0; j < triangles.Length; j++)
			{
				int subMeshIndex = subMeshCount++;
				int[] array = triangles[j];
				int num3 = array.Length / 3;
				for (int k = 0; k < num3; k++)
				{
					int num4 = k * 3;
					int v = array[num4];
					int v2 = array[num4 + 1];
					int v3 = array[num4 + 2];
					int num5 = num2 + k;
					data[num5] = new Triangle(num5, v, v2, v3, subMeshIndex);
				}
				num2 += num3;
			}
		}

		public void SimplifyMesh(float quality)
		{
			quality = Mathf.Clamp01(quality);
			int deletedTris = 0;
			ResizableArray<bool> deleted = new ResizableArray<bool>(20);
			ResizableArray<bool> deleted2 = new ResizableArray<bool>(20);
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int num = length;
			_ = vertices.Data;
			int num2 = Mathf.RoundToInt((float)length * quality);
			for (int i = 0; i < simplificationOptions.MaxIterationCount; i++)
			{
				if (num - deletedTris <= num2)
				{
					break;
				}
				if (i % 5 == 0)
				{
					UpdateMesh(i);
					data = triangles.Data;
					length = triangles.Length;
					_ = vertices.Data;
				}
				for (int j = 0; j < length; j++)
				{
					data[j].dirty = false;
				}
				double num3 = 1E-09 * Math.Pow(i + 3, simplificationOptions.Agressiveness);
				if (verbose)
				{
					Debug.LogFormat("iteration {0} - triangles {1} threshold {2}", (Object[])(object)new Object[3]
					{
						Object.op_Implicit(i),
						Object.op_Implicit(num - deletedTris),
						Object.op_Implicit(num3)
					});
				}
				RemoveVertexPass(num, num2, num3, deleted, deleted2, ref deletedTris);
			}
			CompactMesh();
			if (verbose)
			{
				Debug.LogFormat("Finished simplification with triangle count {0}", (Object[])(object)new Object[1] { Object.op_Implicit(triangles.Length) });
			}
		}

		public MeshSimplifier SimplifyMeshLossless()
		{
			int deletedTris = 0;
			ResizableArray<bool> deleted = new ResizableArray<bool>(0);
			ResizableArray<bool> deleted2 = new ResizableArray<bool>(0);
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int startTrisCount = length;
			_ = vertices.Data;
			for (int i = 0; i < 9999; i++)
			{
				UpdateMesh(i);
				data = triangles.Data;
				length = triangles.Length;
				_ = vertices.Data;
				for (int num = length - 1; num > 0; num--)
				{
					data[num].dirty = false;
				}
				double threshold = 0.001;
				if (verbose)
				{
					Debug.LogFormat("Lossless iteration {0} - triangles {1}", (Object[])(object)new Object[2]
					{
						Object.op_Implicit(i),
						Object.op_Implicit(length)
					});
				}
				RemoveVertexPass(startTrisCount, 0, threshold, deleted, deleted2, ref deletedTris);
				if (deletedTris <= 0)
				{
					break;
				}
				deletedTris = 0;
			}
			CompactMesh();
			if (verbose)
			{
				Debug.LogFormat("Finished simplification with triangle count {0}", (Object[])(object)new Object[1] { Object.op_Implicit(triangles.Length) });
			}
			return this;
		}

		private void UpdateMesh(int iteration)
		{
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			int num = triangles.Length;
			int length = vertices.Length;
			if (iteration > 0)
			{
				int num2 = 0;
				for (int i = 0; i < num; i++)
				{
					if (!data[i].deleted)
					{
						if (num2 != i)
						{
							data[num2] = data[i];
							data[num2].index = num2;
						}
						num2++;
					}
				}
				triangles.Resize(num2);
				data = triangles.Data;
				num = num2;
			}
			UpdateReferences();
			if (iteration != 0)
			{
				return;
			}
			Ref[] data3 = refs.Data;
			List<int> list = new List<int>(8);
			List<int> list2 = new List<int>(8);
			int num3 = 0;
			for (int j = 0; j < length; j++)
			{
				data2[j].borderEdge = false;
				data2[j].uvSeamEdge = false;
				data2[j].uvFoldoverEdge = false;
			}
			int num4 = 0;
			double num5 = double.MaxValue;
			double num6 = double.MinValue;
			double num7 = simplificationOptions.VertexLinkDistance * simplificationOptions.VertexLinkDistance;
			for (int k = 0; k < length; k++)
			{
				int tstart = data2[k].tstart;
				int tcount = data2[k].tcount;
				list.Clear();
				list2.Clear();
				num3 = 0;
				for (int l = 0; l < tcount; l++)
				{
					int tid = data3[tstart + l].tid;
					for (int m = 0; m < 3; m++)
					{
						int n = 0;
						int num8;
						for (num8 = data[tid][m]; n < num3 && list2[n] != num8; n++)
						{
						}
						if (n == num3)
						{
							list.Add(1);
							list2.Add(num8);
							num3++;
						}
						else
						{
							int index = n;
							int value = list[index] + 1;
							list[index] = value;
						}
					}
				}
				for (int num9 = 0; num9 < num3; num9++)
				{
					if (list[num9] != 1)
					{
						continue;
					}
					int num8 = list2[num9];
					data2[num8].borderEdge = true;
					num4++;
					if (simplificationOptions.EnableSmartLink)
					{
						if (data2[num8].p.x < num5)
						{
							num5 = data2[num8].p.x;
						}
						if (data2[num8].p.x > num6)
						{
							num6 = data2[num8].p.x;
						}
					}
				}
			}
			if (simplificationOptions.EnableSmartLink)
			{
				BorderVertex[] array = new BorderVertex[num4];
				int num10 = 0;
				double num11 = num6 - num5;
				for (int num12 = 0; num12 < length; num12++)
				{
					if (data2[num12].borderEdge)
					{
						int hash = (int)(((data2[num12].p.x - num5) / num11 * 2.0 - 1.0) * 2147483647.0);
						array[num10] = new BorderVertex(num12, hash);
						num10++;
					}
				}
				Array.Sort(array, 0, num10, BorderVertexComparer.instance);
				int num13 = Math.Max((int)(Math.Sqrt(num7) / num11 * 2147483647.0), 1);
				for (int num14 = 0; num14 < num10; num14++)
				{
					int index2 = array[num14].index;
					if (index2 == -1)
					{
						continue;
					}
					Vector3d p = data2[index2].p;
					for (int num15 = num14 + 1; num15 < num10; num15++)
					{
						int index3 = array[num15].index;
						if (index3 == -1)
						{
							continue;
						}
						if (array[num15].hash - array[num14].hash > num13)
						{
							break;
						}
						Vector3d p2 = data2[index3].p;
						double num16 = (p.x - p2.x) * (p.x - p2.x);
						double num17 = (p.y - p2.y) * (p.y - p2.y);
						double num18 = (p.z - p2.z) * (p.z - p2.z);
						if (num16 + num17 + num18 <= num7)
						{
							array[num15].index = -1;
							data2[index2].borderEdge = false;
							data2[index3].borderEdge = false;
							if (AreUVsTheSame(0, index2, index3))
							{
								data2[index2].uvFoldoverEdge = true;
								data2[index3].uvFoldoverEdge = true;
							}
							else
							{
								data2[index2].uvSeamEdge = true;
								data2[index3].uvSeamEdge = true;
							}
							int tcount2 = data2[index3].tcount;
							int tstart2 = data2[index3].tstart;
							for (int num19 = 0; num19 < tcount2; num19++)
							{
								Ref @ref = data3[tstart2 + num19];
								data[@ref.tid][@ref.tvertex] = index2;
							}
						}
					}
				}
				UpdateReferences();
			}
			for (int num20 = 0; num20 < length; num20++)
			{
				data2[num20].q = default(SymmetricMatrix);
			}
			for (int num21 = 0; num21 < num; num21++)
			{
				int v = data[num21].v0;
				int v2 = data[num21].v1;
				int v3 = data[num21].v2;
				Vector3d rhs = data2[v].p;
				Vector3d p3 = data2[v2].p;
				Vector3d p4 = data2[v3].p;
				Vector3d lhs = p3 - rhs;
				Vector3d rhs2 = p4 - rhs;
				Vector3d.Cross(ref lhs, ref rhs2, out var result);
				result.Normalize();
				data[num21].n = result;
				SymmetricMatrix symmetricMatrix = new SymmetricMatrix(result.x, result.y, result.z, 0.0 - Vector3d.Dot(ref result, ref rhs));
				data2[v].q += symmetricMatrix;
				data2[v2].q += symmetricMatrix;
				data2[v3].q += symmetricMatrix;
			}
			for (int num22 = 0; num22 < num; num22++)
			{
				Triangle triangle = data[num22];
				data[num22].err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result2);
				data[num22].err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result2);
				data[num22].err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result2);
				data[num22].err3 = MathHelper.Min(data[num22].err0, data[num22].err1, data[num22].err2);
			}
		}

		private void UpdateReferences()
		{
			int length = triangles.Length;
			int length2 = vertices.Length;
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			for (int i = 0; i < length2; i++)
			{
				data2[i].tstart = 0;
				data2[i].tcount = 0;
			}
			for (int j = 0; j < length; j++)
			{
				data2[data[j].v0].tcount++;
				data2[data[j].v1].tcount++;
				data2[data[j].v2].tcount++;
			}
			int num = 0;
			for (int k = 0; k < length2; k++)
			{
				data2[k].tstart = num;
				num += data2[k].tcount;
				data2[k].tcount = 0;
			}
			refs.Resize(num);
			Ref[] data3 = refs.Data;
			for (int l = 0; l < length; l++)
			{
				int v = data[l].v0;
				int v2 = data[l].v1;
				int v3 = data[l].v2;
				int tstart = data2[v].tstart;
				int num2 = data2[v].tcount++;
				int tstart2 = data2[v2].tstart;
				int num3 = data2[v2].tcount++;
				int tstart3 = data2[v3].tstart;
				int num4 = data2[v3].tcount++;
				data3[tstart + num2].Set(l, 0);
				data3[tstart2 + num3].Set(l, 1);
				data3[tstart3 + num4].Set(l, 2);
			}
		}

		private void RemoveVertexPass(int startTrisCount, int targetTrisCount, double threshold, ResizableArray<bool> deleted0, ResizableArray<bool> deleted1, ref int deletedTris)
		{
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			Vertex[] data2 = vertices.Data;
			for (int i = 0; i < length; i++)
			{
				if (data[i].dirty || data[i].deleted || data[i].err3 > threshold)
				{
					continue;
				}
				data[i].GetErrors(errArr);
				data[i].GetAttributeIndices(attributeIndexArr);
				for (int j = 0; j < 3; j++)
				{
					if (errArr[j] > threshold)
					{
						continue;
					}
					int num = (j + 1) % 3;
					int num2 = data[i][j];
					int num3 = data[i][num];
					if (data2[num2].borderEdge != data2[num3].borderEdge || data2[num2].uvSeamEdge != data2[num3].uvSeamEdge || data2[num2].uvFoldoverEdge != data2[num3].uvFoldoverEdge || (simplificationOptions.PreserveBorderEdges && data2[num2].borderEdge) || (simplificationOptions.PreserveUVSeamEdges && data2[num2].uvSeamEdge) || (simplificationOptions.PreserveUVFoldoverEdges && data2[num2].uvFoldoverEdge))
					{
						continue;
					}
					CalculateError(ref data2[num2], ref data2[num3], out var result);
					deleted0.Resize(data2[num2].tcount);
					deleted1.Resize(data2[num3].tcount);
					if (Flipped(ref result, num2, num3, ref data2[num2], deleted0.Data) || Flipped(ref result, num3, num2, ref data2[num3], deleted1.Data))
					{
						continue;
					}
					int num4 = (j + 2) % 3;
					int num5 = data[i][num4];
					CalculateBarycentricCoords(ref result, ref data2[num2].p, ref data2[num3].p, ref data2[num5].p, out var result2);
					data2[num2].p = result;
					data2[num2].q += data2[num3].q;
					int num6 = attributeIndexArr[j];
					int i2 = attributeIndexArr[num];
					int i3 = attributeIndexArr[num4];
					InterpolateVertexAttributes(num6, num6, i2, i3, ref result2);
					if (data2[num2].uvSeamEdge)
					{
						num6 = -1;
					}
					int length2 = refs.Length;
					UpdateTriangles(num2, num6, ref data2[num2], deleted0, ref deletedTris);
					UpdateTriangles(num2, num6, ref data2[num3], deleted1, ref deletedTris);
					int num7 = refs.Length - length2;
					if (num7 <= data2[num2].tcount)
					{
						if (num7 > 0)
						{
							Ref[] data3 = refs.Data;
							Array.Copy(data3, length2, data3, data2[num2].tstart, num7);
						}
					}
					else
					{
						data2[num2].tstart = length2;
					}
					data2[num2].tcount = num7;
					break;
				}
				if (startTrisCount - deletedTris <= targetTrisCount)
				{
					break;
				}
			}
		}

		private void UpdateTriangles(int i0, int ia0, ref Vertex v, ResizableArray<bool> deleted, ref int deletedTriangles)
		{
			int tcount = v.tcount;
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			for (int j = 0; j < tcount; j++)
			{
				Ref item = refs[v.tstart + j];
				int tid = item.tid;
				Triangle triangle = data[tid];
				if (triangle.deleted)
				{
					continue;
				}
				if (deleted[j])
				{
					data[tid].deleted = true;
					deletedTriangles++;
					continue;
				}
				triangle[item.tvertex] = i0;
				if (ia0 != -1)
				{
					triangle.SetAttributeIndex(item.tvertex, ia0);
				}
				triangle.dirty = true;
				triangle.err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result);
				triangle.err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result);
				triangle.err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result);
				triangle.err3 = MathHelper.Min(triangle.err0, triangle.err1, triangle.err2);
				data[tid] = triangle;
				refs.Add(item);
			}
		}

		private void CompactMesh()
		{
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Vertex[] data = vertices.Data;
			int length = vertices.Length;
			for (int i = 0; i < length; i++)
			{
				data[i].tcount = 0;
			}
			Vector3[] array = ((vertNormals != null) ? vertNormals.Data : null);
			Vector4[] array2 = ((vertTangents != null) ? vertTangents.Data : null);
			Vector2[][] array3 = ((vertUV2D != null) ? vertUV2D.Data : null);
			Vector3[][] array4 = ((vertUV3D != null) ? vertUV3D.Data : null);
			Vector4[][] array5 = ((vertUV4D != null) ? vertUV4D.Data : null);
			Color[] array6 = ((vertColors != null) ? vertColors.Data : null);
			int num2 = -1;
			subMeshOffsets = new int[subMeshCount];
			Triangle[] data2 = triangles.Data;
			int length2 = triangles.Length;
			for (int j = 0; j < length2; j++)
			{
				Triangle triangle = data2[j];
				if (triangle.deleted)
				{
					continue;
				}
				if (triangle.va0 != triangle.v0)
				{
					int va = triangle.va0;
					int v = triangle.v0;
					data[va].p = data[v].p;
					if (vertBoneWeights != null)
					{
						vertBoneWeights[va] = vertBoneWeights[v];
					}
					triangle.v0 = triangle.va0;
				}
				if (triangle.va1 != triangle.v1)
				{
					int va2 = triangle.va1;
					int v2 = triangle.v1;
					data[va2].p = data[v2].p;
					if (vertBoneWeights != null)
					{
						vertBoneWeights[va2] = vertBoneWeights[v2];
					}
					triangle.v1 = triangle.va1;
				}
				if (triangle.va2 != triangle.v2)
				{
					int va3 = triangle.va2;
					int v3 = triangle.v2;
					data[va3].p = data[v3].p;
					if (vertBoneWeights != null)
					{
						vertBoneWeights[va3] = vertBoneWeights[v3];
					}
					triangle.v2 = triangle.va2;
				}
				int num3 = num++;
				data2[num3] = triangle;
				data2[num3].index = num3;
				data[triangle.v0].tcount = 1;
				data[triangle.v1].tcount = 1;
				data[triangle.v2].tcount = 1;
				if (triangle.subMeshIndex > num2)
				{
					for (int k = num2 + 1; k < triangle.subMeshIndex; k++)
					{
						subMeshOffsets[k] = num3;
					}
					subMeshOffsets[triangle.subMeshIndex] = num3;
					num2 = triangle.subMeshIndex;
				}
			}
			length2 = num;
			for (int l = num2 + 1; l < subMeshCount; l++)
			{
				subMeshOffsets[l] = length2;
			}
			triangles.Resize(length2);
			data2 = triangles.Data;
			num = 0;
			for (int m = 0; m < length; m++)
			{
				Vertex vertex = data[m];
				if (vertex.tcount <= 0)
				{
					continue;
				}
				data[m].tstart = num;
				if (num != m)
				{
					data[num].index = num;
					data[num].p = vertex.p;
					if (array != null)
					{
						array[num] = array[m];
					}
					if (array2 != null)
					{
						array2[num] = array2[m];
					}
					if (array3 != null)
					{
						for (int n = 0; n < UVChannelCount; n++)
						{
							Vector2[] array7 = array3[n];
							if (array7 != null)
							{
								array7[num] = array7[m];
							}
						}
					}
					if (array4 != null)
					{
						for (int num4 = 0; num4 < UVChannelCount; num4++)
						{
							Vector3[] array8 = array4[num4];
							if (array8 != null)
							{
								array8[num] = array8[m];
							}
						}
					}
					if (array5 != null)
					{
						for (int num5 = 0; num5 < UVChannelCount; num5++)
						{
							Vector4[] array9 = array5[num5];
							if (array9 != null)
							{
								array9[num] = array9[m];
							}
						}
					}
					if (array6 != null)
					{
						array6[num] = array6[m];
					}
				}
				num++;
			}
			for (int num6 = 0; num6 < length2; num6++)
			{
				Triangle triangle2 = data2[num6];
				triangle2.v0 = data[triangle2.v0].tstart;
				triangle2.v1 = data[triangle2.v1].tstart;
				triangle2.v2 = data[triangle2.v2].tstart;
				data2[num6] = triangle2;
			}
			length = num;
			vertices.Resize(length);
			if (array != null)
			{
				vertNormals.Resize(length, trimExess: true);
			}
			if (array2 != null)
			{
				vertTangents.Resize(length, trimExess: true);
			}
			if (array3 != null)
			{
				vertUV2D.Resize(length, trimExess: true);
			}
			if (array4 != null)
			{
				vertUV3D.Resize(length, trimExess: true);
			}
			if (array5 != null)
			{
				vertUV4D.Resize(length, trimExess: true);
			}
			if (array6 != null)
			{
				vertColors.Resize(length, trimExess: true);
			}
		}

		private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d result)
		{
			SymmetricMatrix q = vert0.q + vert1.q;
			bool flag = vert0.borderEdge && vert1.borderEdge;
			double num = 0.0;
			double num2 = q.Determinant1();
			if (num2 != 0.0 && !flag)
			{
				result = new Vector3d(-1.0 / num2 * q.Determinant2(), 1.0 / num2 * q.Determinant3(), -1.0 / num2 * q.Determinant4());
				double num3 = 0.0;
				if (simplificationOptions.PreserveSurfaceCurvature)
				{
					num3 = CurvatureError(ref vert0, ref vert1);
				}
				num = VertexError(ref q, result.x, result.y, result.z) + num3;
			}
			else
			{
				Vector3d p = vert0.p;
				Vector3d p2 = vert1.p;
				Vector3d vector3d = (p + p2) * 0.5;
				double num4 = VertexError(ref q, p.x, p.y, p.z);
				double num5 = VertexError(ref q, p2.x, p2.y, p2.z);
				double num6 = VertexError(ref q, vector3d.x, vector3d.y, vector3d.z);
				if (num4 < num5)
				{
					if (num4 < num6)
					{
						num = num4;
						result = p;
					}
					else
					{
						num = num6;
						result = vector3d;
					}
				}
				else if (num5 < num6)
				{
					num = num5;
					result = p2;
				}
				else
				{
					num = num6;
					result = vector3d;
				}
			}
			return num;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private double CurvatureError(ref Vertex vert0, ref Vertex vert1)
		{
			double magnitude = (vert0.p - vert1.p).Magnitude;
			HashSet<Triangle> hashSet = triangleHashSet1;
			hashSet.Clear();
			GetTrianglesContainingVertex(ref vert0, hashSet);
			GetTrianglesContainingVertex(ref vert1, hashSet);
			HashSet<Triangle> hashSet2 = triangleHashSet2;
			hashSet2.Clear();
			GetTrianglesContainingBothVertices(ref vert0, ref vert1, hashSet2);
			double num = 0.0;
			foreach (Triangle item in hashSet)
			{
				double num2 = 0.0;
				Vector3d lhs = item.n;
				foreach (Triangle item2 in hashSet2)
				{
					Vector3d rhs = item2.n;
					double num3 = Vector3d.Dot(ref lhs, ref rhs);
					if (num3 > num2)
					{
						num2 = num3;
					}
				}
				if (num2 > num)
				{
					num = num2;
				}
			}
			return magnitude * num;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void GetTrianglesContainingVertex(ref Vertex vert, HashSet<Triangle> tris)
		{
			int tcount = vert.tcount;
			int tstart = vert.tstart;
			for (int i = tstart; i < tstart + tcount; i++)
			{
				tris.Add(triangles[refs[i].tid]);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void GetTrianglesContainingBothVertices(ref Vertex vert0, ref Vertex vert1, HashSet<Triangle> tris)
		{
			int tcount = vert0.tcount;
			int tstart = vert0.tstart;
			for (int i = tstart; i < tstart + tcount; i++)
			{
				int tid = refs[i].tid;
				Triangle item = triangles[tid];
				if (vertices[item.v0].index == vert1.index || vertices[item.v1].index == vert1.index || vertices[item.v2].index == vert1.index)
				{
					tris.Add(item);
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static double VertexError(ref SymmetricMatrix q, double x, double y, double z)
		{
			return q.m0 * x * x + 2.0 * q.m1 * x * y + 2.0 * q.m2 * x * z + 2.0 * q.m3 * x + q.m4 * y * y + 2.0 * q.m5 * y * z + 2.0 * q.m6 * y + q.m7 * z * z + 2.0 * q.m8 * z + q.m9;
		}

		private void InterpolateVertexAttributes(int dst, int i0, int i1, int i2, ref Vector3 barycentricCoord)
		{
			//IL_0016: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			if (vertNormals != null)
			{
				vertNormals[dst] = Vector3.Normalize(vertNormals[i0] * barycentricCoord.x + vertNormals[i1] * barycentricCoord.y + vertNormals[i2] * barycentricCoord.z);
			}
			if (vertTangents != null)
			{
				vertTangents[dst] = NormalizeTangent(vertTangents[i0] * barycentricCoord.x + vertTangents[i1] * barycentricCoord.y + vertTangents[i2] * barycentricCoord.z);
			}
			if (vertUV2D != null)
			{
				for (int j = 0; j < UVChannelCount; j++)
				{
					ResizableArray<Vector2> resizableArray = vertUV2D[j];
					if (resizableArray != null)
					{
						resizableArray[dst] = resizableArray[i0] * barycentricCoord.x + resizableArray[i1] * barycentricCoord.y + resizableArray[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertUV3D != null)
			{
				for (int k = 0; k < UVChannelCount; k++)
				{
					ResizableArray<Vector3> resizableArray2 = vertUV3D[k];
					if (resizableArray2 != null)
					{
						resizableArray2[dst] = resizableArray2[i0] * barycentricCoord.x + resizableArray2[i1] * barycentricCoord.y + resizableArray2[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertUV4D != null)
			{
				for (int l = 0; l < UVChannelCount; l++)
				{
					ResizableArray<Vector4> resizableArray3 = vertUV4D[l];
					if (resizableArray3 != null)
					{
						resizableArray3[dst] = resizableArray3[i0] * barycentricCoord.x + resizableArray3[i1] * barycentricCoord.y + resizableArray3[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertColors != null)
			{
				vertColors[dst] = vertColors[i0] * barycentricCoord.x + vertColors[i1] * barycentricCoord.y + vertColors[i2] * barycentricCoord.z;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static Vector4 NormalizeTangent(Vector4 tangent)
		{
			//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_000e: 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_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)
			//IL_0032: 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 = default(Vector3);
			((Vector3)(ref val))..ctor(tangent.x, tangent.y, tangent.z);
			((Vector3)(ref val)).Normalize();
			return new Vector4(val.x, val.y, val.z, tangent.w);
		}

		private bool Flipped(ref Vector3d p, int i0, int i1, ref Vertex v0, bool[] deleted)
		{
			int tcount = v0.tcount;
			Ref[] data = refs.Data;
			Triangle[] data2 = triangles.Data;
			Vertex[] data3 = vertices.Data;
			for (int j = 0; j < tcount; j++)
			{
				Ref @ref = data[v0.tstart + j];
				if (data2[@ref.tid].deleted)
				{
					continue;
				}
				int tvertex = @ref.tvertex;
				int num = data2[@ref.tid][(tvertex + 1) % 3];
				int num2 = data2[@ref.tid][(tvertex + 2) % 3];
				if (num == i1 || num2 == i1)
				{
					deleted[j] = true;
					continue;
				}
				Vector3d lhs = data3[num].p - p;
				lhs.Normalize();
				Vector3d rhs = data3[num2].p - p;
				rhs.Normalize();
				if (Math.Abs(Vector3d.Dot(ref lhs, ref rhs)) > 0.999)
				{
					return true;
				}
				Vector3d.Cross(ref lhs, ref rhs, out var result);
				result.Normalize();
				deleted[j] = false;
				if (Vector3d.Dot(ref result, ref data2[@ref.tid].n) < 0.2)
				{
					return true;
				}
			}
			return false;
		}

		private static void CalculateBarycentricCoords(ref Vector3d point, ref Vector3d a, ref Vector3d b, ref Vector3d c, out Vector3 result)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Vector3d lhs = b - a;
			Vector3d rhs = c - a;
			Vector3d lhs2 = point - a;
			double num = Vector3d.Dot(ref lhs, ref lhs);
			double num2 = Vector3d.Dot(ref lhs, ref rhs);
			double num3 = Vector3d.Dot(ref rhs, ref rhs);
			double num4 = Vector3d.Dot(ref lhs2, ref lhs);
			double num5 = Vector3d.Dot(ref lhs2, ref rhs);
			double num6 = num * num3 - num2 * num2;
			if (Math.Abs(num6) < 1E-08)
			{
				num6 = 1E-08;
			}
			double num7 = (num3 * num4 - num2 * num5) / num6;
			double num8 = (num * num5 - num2 * num4) / num6;
			double num9 = 1.0 - num7 - num8;
			result = new Vector3((float)num9, (float)num7, (float)num8);
		}

		private bool AreUVsTheSame(int channel, int indexA, int indexB)
		{
			//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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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)
			//IL_005a: 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_0081: 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_0090: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			if (vertUV2D != null)
			{
				ResizableArray<Vector2> resizableArray = vertUV2D[channel];
				if (resizableArray != null)
				{
					Vector2 val = resizableArray[indexA];
					Vector2 val2 = resizableArray[indexB];
					return val == val2;
				}
			}
			if (vertUV3D != null)
			{
				ResizableArray<Vector3> resizableArray2 = vertUV3D[channel];
				if (resizableArray2 != null)
				{
					Vector3 val3 = resizableArray2[indexA];
					Vector3 val4 = resizableArray2[indexB];
					return val3 == val4;
				}
			}
			if (vertUV4D != null)
			{
				ResizableArray<Vector4> resizableArray3 = vertUV4D[channel];
				if (resizableArray3 != null)
				{
					Vector4 val5 = resizableArray3[indexA];
					Vector4 val6 = resizableArray3[indexB];
					return val5 == val6;
				}
			}
			return false;
		}

		public Mesh ToMesh()
		{
			Vector3[] array = Vertices;
			Vector3[] normals = Normals;
			Vector4[] tangents = Tangents;
			Color[] colors = Colors;
			int[][] allSubMeshTriangles = GetAllSubMeshTriangles();
			List<Vector2>[] array2 = null;
			List<Vector3>[] array3 = null;
			List<Vector4>[] array4 = null;
			if (vertUV2D != null)
			{
				array2 = new List<Vector2>[UVChannelCount];
				for (int i = 0; i < UVChannelCount; i++)
				{
					if (vertUV2D[i] != null)
					{
						List<Vector2> list = new List<Vector2>(array.Length);
						GetUVs(i, list);
						array2[i] = list;
					}
				}
			}
			if (vertUV3D != null)
			{
				array3 = new List<Vector3>[UVChannelCount];
				for (int j = 0; j < UVChannelCount; j++)
				{
					if (vertUV3D[j] != null)
					{
						List<Vector3> list2 = new List<Vector3>(array.Length);
						GetUVs(j, list2);
						array3[j] = list2;
					}
				}
			}
			if (vertUV4D != null)
			{
				array4 = new List<Vector4>[UVChannelCount];
				for (int k = 0; k < UVChannelCount; k++)
				{
					if (vertUV4D[k] != null)
					{
						List<Vector4> list3 = new List<Vector4>(array.Length);
						GetUVs(k, list3);
						array4[k] = list3;
					}
				}
			}
			return MeshUtils.CreateMesh(array, allSubMeshTriangles, normals, tangents, colors, array2, array3, array4);
		}
	}
	public static class MeshUtils
	{
		public static readonly int UVChannelCount = 4;

		public static Mesh CreateMesh(Vector3[] vertices, int[][] indices, Vector3[] normals, Vector4[] tangents, Color[] colors, List<Vector2>[] uvs)
		{
			return CreateMesh(vertices, indices, normals, tangents, colors, uvs, null, null);
		}

		public static Mesh CreateMesh(Vector3[] vertices, int[][] indices, Vector3[] normals, Vector4[] tangents, Color[] colors, List<Vector4>[] uvs)
		{
			return CreateMesh(vertices, indices, normals, tangents, colors, null, null, uvs);
		}

		public static Mesh CreateMesh(Vector3[] vertices, int[][] indices, Vector3[] normals, Vector4[] tangents, Color[] colors, List<Vector2>[] uvs2D, List<Vector3>[] uvs3D, List<Vector4>[] uvs4D)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			//IL_0030: 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)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (vertices == null)
			{
				throw new ArgumentNullException("vertices");
			}
			if (indices == null)
			{
				throw new ArgumentNullException("indices");
			}
			Mesh val = new Mesh();
			int num = indices.Length;
			IndexFormat indexFormat;
			Vector2Int[] subMeshIndexMinMax = GetSubMeshIndexMinMax(indices, out indexFormat);
			val.indexFormat = indexFormat;
			val.subMeshCount = num;
			val.vertices = Il2CppStructArray<Vector3>.op_Implicit(vertices);
			if (normals != null && normals.Length != 0)
			{
				val.normals = Il2CppStructArray<Vector3>.op_Implicit(normals);
			}
			if (tangents != null && tangents.Length != 0)
			{
				val.tangents = Il2CppStructArray<Vector4>.op_Implicit(tangents);
			}
			if (colors != null && colors.Length != 0)
			{
				val.colors = Il2CppStructArray<Color>.op_Implicit(colors);
			}
			if (uvs2D != null)
			{
				for (int i = 0; i < uvs2D.Length; i++)
				{
					if (uvs2D[i] != null && uvs2D[i].Count > 0)
					{
						val.SetUVs(i, Il2CppStructArray<Vector2>.op_Implicit(uvs2D[i].ToArray()));
					}
				}
			}
			if (uvs3D != null)
			{
				for (int j = 0; j < uvs3D.Length; j++)
				{
					if (uvs3D[j] != null && uvs3D[j].Count > 0)
					{
						val.SetUVs(j, Il2CppStructArray<Vector3>.op_Implicit(uvs3D[j].ToArray()));
					}
				}
			}
			if (uvs4D != null)
			{
				for (int k = 0; k < uvs4D.Length; k++)
				{
					if (uvs4D[k] != null && uvs4D[k].Count > 0)
					{
						val.SetUVs(k, Il2CppStructArray<Vector4>.op_Implicit(uvs4D[k].ToArray()));
					}
				}
			}
			for (int l = 0; l < num; l++)
			{
				int[] array = indices[l];
				Vector2Int val2 = subMeshIndexMinMax[l];
				if ((int)indexFormat == 0 && ((Vector2Int)(ref val2)).y > 65535)
				{
					int x = ((Vector2Int)(ref val2)).x;
					for (int m = 0; m < array.Length; m++)
					{
						array[m] -= x;
					}
					val.SetTriangles(Il2CppStructArray<int>.op_Implicit(array), l, false, x);
				}
				else
				{
					val.SetTriangles(Il2CppStructArray<int>.op_Implicit(array), l, false, 0);
				}
			}
			val.RecalculateBounds();
			return val;
		}

		public static IList<Vector4>[] GetMeshUVs(Mesh mesh)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			IList<Vector4>[] array = new IList<Vector4>[UVChannelCount];
			for (int i = 0; i < UVChannelCount; i++)
			{
				array[i] = GetMeshUVs(mesh, i);
			}
			return array;
		}

		public static IList<Vector2> GetMeshUVs2D(Mesh mesh, int channel)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			new List<Vector2>(mesh.vertexCount);
			return (IList<Vector2>)mesh.uv;
		}

		public static IList<Vector3> GetMeshUVs3D(Mesh mesh, int channel)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			List<Vector3> val = new List<Vector3>(mesh.vertexCount);
			mesh.GetUVs(channel, val);
			return (IList<Vector3>)val.ToArray();
		}

		public static IList<Vector4> GetMeshUVs(Mesh mesh, int channel)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			List<Vector4> val = new List<Vector4>(mesh.vertexCount);
			mesh.GetUVs(channel, val);
			return (IList<Vector4>)val.ToArray();
		}

		public static int GetUsedUVComponents(IList<Vector4> uvs)
		{
			//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_0023: 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_0049: 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)
			if (uvs == null || uvs.Count == 0)
			{
				return 0;
			}
			int num = 0;
			foreach (Vector4 uv in uvs)
			{
				if (num < 1 && uv.x != 0f)
				{
					num = 1;
				}
				if (num < 2 && uv.y != 0f)
				{
					num = 2;
				}
				if (num < 3 && uv.z != 0f)
				{
					num = 3;
				}
				if (num < 4 && uv.w != 0f)
				{
					num = 4;
					break;
				}
			}
			return num;
		}

		public static Vector2[] ConvertUVsTo2D(IList<Vector4> uvs)
		{
			//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_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (uvs == null)
			{
				return null;
			}
			Vector2[] array = (Vector2[])(object)new Vector2[uvs.Count];
			for (int i = 0; i < array.Length; i++)
			{
				Vector4 val = uvs[i];
				array[i] = new Vector2(val.x, val.y);
			}
			return array;
		}

		public static Vector3[] ConvertUVsTo3D(IList<Vector4> uvs)
		{
			//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_001f: 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_002b: 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)
			if (uvs == null)
			{
				return null;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[uvs.Count];
			for (int i = 0; i < array.Length; i++)
			{
				Vector4 val = uvs[i];
				array[i] = new Vector3(val.x, val.y, val.z);
			}
			return array;
		}

		public static Vector2Int[] GetSubMeshIndexMinMax(int[][] indices, out IndexFormat indexFormat)
		{
			//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)
			if (indices == null)
			{
				throw new ArgumentNullException("indices");
			}
			Vector2Int[] array = (Vector2Int[])(object)new Vector2Int[indices.Length];
			indexFormat = (IndexFormat)0;
			for (int i = 0; i < indices.Length; i++)
			{
				GetIndexMinMax(indices[i], out var minIndex, out var maxIndex);
				array[i] = new Vector2Int(minIndex, maxIndex);
				if (maxIndex - minIndex > 65535)
				{
					indexFormat = (IndexFormat)1;
				}
			}
			return array;
		}

		private static void GetIndexMinMax(int[] indices, out int minIndex, out int maxIndex)
		{
			if (indices == null || indices.Length == 0)
			{
				minIndex = (maxIndex = 0);
				return;
			}
			minIndex = int.MaxValue;
			maxIndex = int.MinValue;
			for (int i = 0; i < indices.Length; i++)
			{
				if (indices[i] < minIndex)
				{
					minIndex = indices[i];
				}
				if (indices[i] > maxIndex)
				{
					maxIndex = indices[i];
				}
			}
		}
	}
	internal class ResizableArray<T>
	{
		private T[] items;

		private int length;

		private static T[] emptyArr = new T[0];

		public int Length
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return length;
			}
		}

		public T[] Data
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return items;
			}
		}

		public T this[int index]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return items[index];
			}
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			set
			{
				items[index] = value;
			}
		}

		public ResizableArray(int capacity)
			: this(capacity, 0)
		{
		}

		public ResizableArray(int capacity, int length)
		{
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			if (length < 0 || length > capacity)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (capacity > 0)
			{
				items = new T[capacity];
			}
			else
			{
				items = emptyArr;
			}
			this.length = length;
		}

		public ResizableArray(T[] initialArray)
		{
			if (initialArray == null)
			{
				throw new ArgumentNullException("initialArray");
			}
			if (initialArray.Length != 0)
			{
				items = new T[initialArray.Length];
				length = initialArray.Length;
				Array.Copy(initialArray, 0, items, 0, initialArray.Length);
			}
			else
			{
				items = emptyArr;
				length = 0;
			}
		}

		private void IncreaseCapacity(int capacity)
		{
			T[] destinationArray = new T[capacity];
			Array.Copy(items, 0, destinationArray, 0, Math.Min(length, capacity));
			items = destinationArray;
		}

		public void Clear()
		{
			Array.Clear(items, 0, length);
			length = 0;
		}

		public void Resize(int length, bool trimExess = false, bool clearMemory = false)
		{
			if (length < 0)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (length > items.Length)
			{
				IncreaseCapacity(length);
			}
			else if (length < this.length && clearMemory)
			{
				Array.Clear(items, length, this.length - length);
			}
			this.length = length;
			if (trimExess)
			{
				TrimExcess();
			}
		}

		public void TrimExcess()
		{
			if (items.Length != length)
			{
				T[] destinationArray = new T[length];
				Array.Copy(items, 0, destinationArray, 0, length);
				items = destinationArray;
			}
		}

		public void Add(T item)
		{
			if (length >= items.Length)
			{
				IncreaseCapacity(items.Length << 1);
			}
			items[length++] = item;
		}

		public T[] ToArray()
		{
			T[] array = new T[length];
			Array.Copy(items, 0, array, 0, length);
			return array;
		}
	}
	public struct SimplificationOptions
	{
		public static readonly SimplificationOptions Default = new SimplificationOptions
		{
			PreserveBorderEdges = false,
			PreserveUVSeamEdges = false,
			PreserveUVFoldoverEdges = false,
			PreserveSurfaceCurvature = false,
			EnableSmartLink = true,
			VertexLinkDistance = double.Epsilon,
			MaxIterationCount = 100,
			Agressiveness = 7.0,
			ManualUVComponentCount = false,
			UVComponentCount = 2
		};

		public bool PreserveBorderEdges;

		public bool PreserveUVSeamEdges;

		public bool PreserveUVFoldoverEdges;

		public bool PreserveSurfaceCurvature;

		public bool EnableSmartLink;

		public double VertexLinkDistance;

		public int MaxIterationCount;

		public double Agressiveness;

		public bool ManualUVComponentCount;

		public int UVComponentCount;
	}
	public struct SymmetricMatrix
	{
		public double m0;

		public double m1;

		public double m2;

		public double m3;

		public double m4;

		public double m5;

		public double m6;

		public double m7;

		public double m8;

		public double m9;

		public double this[int index]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return index switch
				{
					0 => m0, 
					1 => m1, 
					2 => m2, 
					3 => m3, 
					4 => m4, 
					5 => m5, 
					6 => m6, 
					7 => m7, 
					8 => m8, 
					9 => m9, 
					_ => throw new ArgumentOutOfRangeException("index"), 
				};
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public SymmetricMatrix(double c)
		{
			m0 = c;
			m1 = c;
			m2 = c;
			m3 = c;
			m4 = c;
			m5 = c;
			m6 = c;
			m7 = c;
			m8 = c;
			m9 = c;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public SymmetricMatrix(double m0, double m1, double m2, double m3, double m4, double m5, double m6, double m7, double m8, double m9)
		{
			this.m0 = m0;
			this.m1 = m1;
			this.m2 = m2;
			this.m3 = m3;
			this.m4 = m4;
			this.m5 = m5;
			this.m6 = m6;
			this.m7 = m7;
			this.m8 = m8;
			this.m9 = m9;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public SymmetricMatrix(double a, double b, double c, double d)
		{
			m0 = a * a;
			m1 = a * b;
			m2 = a * c;
			m3 = a * d;
			m4 = b * b;
			m5 = b * c;
			m6 = b * d;
			m7 = c * c;
			m8 = c * d;
			m9 = d * d;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static SymmetricMatrix operator +(SymmetricMatrix a, SymmetricMatrix b)
		{
			return new SymmetricMatrix(a.m0 + b.m0, a.m1 + b.m1, a.m2 + b.m2, a.m3 + b.m3, a.m4 + b.m4, a.m5 + b.m5, a.m6 + b.m6, a.m7 + b.m7, a.m8 + b.m8, a.m9 + b.m9);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal double Determinant1()
		{
			return m0 * m4 * m7 + m2 * m1 * m5 + m1 * m5 * m2 - m2 * m4 * m2 - m0 * m5 * m5 - m1 * m1 * m7;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal double Determinant2()
		{
			return m1 * m5 * m8 + m3 * m4 * m7 + m2 * m6 * m5 - m3 * m5 * m5 - m1 * m6 * m7 - m2 * m4 * m8;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal double Determinant3()
		{
			return m0 * m5 * m8 + m3 * m1 * m7 + m2 * m6 * m2 - m3 * m5 * m2 - m0 * m6 * m7 - m2 * m1 * m8;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal double Determinant4()
		{
			return m0 * m4 * m8 + m3 * m1 * m5 + m1 * m6 * m2 - m3 * m4 * m2 - m0 * m6 * m5 - m1 * m1 * m8;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public double Determinant(int a11, int a12, int a13, int a21, int a22, int a23, int a31, int a32, int a33)
		{
			return this[a11] * this[a22] * this[a33] + this[a13] * this[a21] * this[a32] + this[a12] * this[a23] * this[a31] - this[a13] * this[a22] * this[a31] - this[a11] * this[a23] * this[a32] - this[a12] * this[a21] * this[a33];
		}
	}
	public struct Vector3d : IEquatable<Vector3d>
	{
		public static readonly Vector3d zero = new Vector3d(0.0, 0.0, 0.0);

		public const double Epsilon = double.Epsilon;

		public double x;

		public double y;

		public double z;

		public double Magnitude
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return Math.Sqrt(x * x + y * y + z * z);
			}
		}

		public double MagnitudeSqr
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return x * x + y * y + z * z;
			}
		}

		public Vector3d Normalized
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				Normalize(ref this, out var result);
				return result;
			}
		}

		public double this[int index]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return index switch
				{
					0 => x, 
					1 => y, 
					2 => z, 
					_ => throw new ArgumentOutOfRangeException("index", "Invalid Vector3d index!"), 
				};
			}
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			set
			{
				switch (index)
				{
				case 0:
					x = value;
					break;
				case 1:
					y = value;
					break;
				case 2:
					z = value;
					break;
				default:
					throw new ArgumentOutOfRangeException("index", "Invalid Vector3d index!");
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vector3d(double value)
		{
			x = value;
			y = value;
			z = value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vector3d(double x, double y, double z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vector3d(Vector3 vector)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			x = vector.x;
			y = vector.y;
			z = vector.z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator +(Vector3d a, Vector3d b)
		{
			return new Vector3d(a.x + b.x, a.y + b.y, a.z + b.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator -(Vector3d a, Vector3d b)
		{
			return new Vector3d(a.x - b.x, a.y - b.y, a.z - b.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator *(Vector3d a, double d)
		{
			return new Vector3d(a.x * d, a.y * d, a.z * d);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator *(double d, Vector3d a)
		{
			return new Vector3d(a.x * d, a.y * d, a.z * d);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator /(Vector3d a, double d)
		{
			return new Vector3d(a.x / d, a.y / d, a.z / d);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vector3d operator -(Vector3d a)
		{
			return new Vector3d(0.0 - a.x, 0.0 - a.y, 0.0 - a.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator ==(Vector3d lhs, Vector3d rhs)
		{
			return (lhs - rhs).MagnitudeSqr < double.Epsilon;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator !=(Vector3d lhs, Vector3d rhs)
		{
			return (lhs - rhs).MagnitudeSqr >= double.Epsilon;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Vector3d(Vector3 v)
		{
			//IL_0000: 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)
			return new Vector3d(v.x, v.y, v.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static explicit operator Vector3(Vector3d v)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3((float)v.x, (float)v.y, (float)v.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Set(double x, double y, double z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Scale(ref Vector3d scale)
		{
			x *= scale.x;
			y *= scale.y;
			z *= scale.z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Normalize()
		{
			double magnitude = Magnitude;
			if (magnitude > double.Epsilon)
			{
				x /= magnitude;
				y /= magnitude;
				z /= magnitude;
			}
			else
			{
				x = (y = (z = 0.0));
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Clamp(double min, double max)
		{
			if (x < min)
			{
				x = min;
			}
			else if (x > max)
			{
				x = max;
			}
			if (y < min)
			{
				y = min;
			}
			else if (y > max)
			{
				y = max;
			}
			if (z < min)
			{
				z = min;
			}
			else if (z > max)
			{
				z = max;
			}
		}

		public override int GetHashCode()
		{
			return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2);
		}

		public override bool Equals(object obj)
		{
			if (!(obj is Vector3d vector3d))
			{
				return false;
			}
			if (x == vector3d.x && y == vector3d.y)
			{
				return z == vector3d.z;
			}
			return false;
		}

		public bool Equals(Vector3d other)
		{
			if (x == other.x && y == other.y)
			{
				return z == other.z;
			}
			return false;
		}

		public override string ToString()
		{
			return $"({x:F1}, {y:F1}, {z:F1})";
		}

		public string ToString(string format)
		{
			return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})";
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Dot(ref Vector3d lhs, ref Vector3d rhs)
		{
			return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Cross(ref Vector3d lhs, ref Vector3d rhs, out Vector3d result)
		{
			result = new Vector3d(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Angle(ref Vector3d from, ref Vector3d to)
		{
			Vector3d lhs = from.Normalized;
			Vector3d rhs = to.Normalized;
			return Math.Acos(MathHelper.Clamp(Dot(ref lhs, ref rhs), -1.0, 1.0)) * (180.0 / Math.PI);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Lerp(ref Vector3d a, ref Vector3d b, double t, out Vector3d result)
		{
			result = new Vector3d(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Scale(ref Vector3d a, ref Vector3d b, out Vector3d result)
		{
			result = new Vector3d(a.x * b.x, a.y * b.y, a.z * b.z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Normalize(ref Vector3d value, out Vector3d result)
		{
			double magnitude = value.Magnitude;
			if (magnitude > double.Epsilon)
			{
				result = new Vector3d(value.x / magnitude, value.y / magnitude, value.z / magnitude);
			}
			else
			{
				result = zero;
			}
		}
	}
}
namespace UnityMeshSimplifier.Internal
{
	internal struct BorderVertex
	{
		public int index;

		public int hash;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public BorderVertex(int index, int hash)
		{
			this.index = index;
			this.hash = hash;
		}
	}
	internal class BorderVertexComparer : IComparer<BorderVertex>
	{
		public static readonly BorderVertexComparer instance = new BorderVertexComparer();

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public int Compare(BorderVertex x, BorderVertex y)
		{
			return x.hash.CompareTo(y.hash);
		}
	}
	internal struct Ref
	{
		public int tid;

		public int tvertex;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Set(int tid, int tvertex)
		{
			this.tid = tid;
			this.tvertex = tvertex;
		}
	}
	internal struct Triangle : IEquatable<Triangle>
	{
		public int index;

		public int v0;

		public int v1;

		public int v2;

		public int subMeshIndex;

		public int va0;

		public int va1;

		public int va2;

		public double err0;

		public double err1;

		public double err2;

		public double err3;

		public bool deleted;

		public bool dirty;

		public Vector3d n;

		public int this[int index]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return index switch
				{
					1 => v1, 
					0 => v0, 
					_ => v2, 
				};
			}
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			set
			{
				switch (index)
				{
				case 0:
					v0 = value;
					break;
				case 1:
					v1 = value;
					break;
				case 2:
					v2 = value;
					break;
				default:
					throw new ArgumentOutOfRangeException("index");
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Triangle(int index, int v0, int v1, int v2, int subMeshIndex)
		{
			this.index = index;
			this.v0 = v0;
			this.v1 = v1;
			this.v2 = v2;
			this.subMeshIndex = subMeshIndex;
			va0 = v0;
			va1 = v1;
			va2 = v2;
			err0 = (err1 = (err2 = (err3 = 0.0)));
			deleted = (dirty = false);
			n = default(Vector3d);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void GetAttributeIndices(int[] attributeIndices)
		{
			attributeIndices[0] = va0;
			attributeIndices[1] = va1;
			attributeIndices[2] = va2;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void SetAttributeIndex(int index, int value)
		{
			switch (index)
			{
			case 0:
				va0 = value;
				break;
			case 1:
				va1 = value;
				break;
			case 2:
				va2 = value;
				break;
			default:
				throw new ArgumentOutOfRangeException("index");
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void GetErrors(double[] err)
		{
			err[0] = err0;
			err[1] = err1;
			err[2] = err2;
		}

		public override int GetHashCode()
		{
			return index;
		}

		public override bool Equals(object obj)
		{
			if (obj is Triangle triangle)
			{
				return index == triangle.index;
			}
			return false;
		}

		public bool Equals(Triangle other)
		{
			return index == other.index;
		}
	}
	internal class UVChannels<TVec>
	{
		private static readonly int UVChannelCount = MeshUtils.UVChannelCount;

		private ResizableArray<TVec>[] channels;

		private TVec[][] channelsData;

		public TVec[][] Data
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				for (int i = 0; i < UVChannelCount; i++)
				{
					if (channels[i] != null)
					{
						channelsData[i] = channels[i].Data;
					}
					else
					{
						channelsData[i] = null;
					}
				}
				return channelsData;
			}
		}

		public ResizableArray<TVec> this[int index]
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return channels[index];
			}
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			set
			{
				channels[index] = value;
			}
		}

		public UVChannels()
		{
			channels = new ResizableArray<TVec>[UVChannelCount];
			channelsData = new TVec[UVChannelCount][];
		}

		public void Resize(int capacity, bool trimExess = false)
		{
			for (int i = 0; i < UVChannelCount; i++)
			{
				if (channels[i] != null)
				{
					channels[i].Resize(capacity, trimExess);
				}
			}
		}
	}
	internal struct Vertex : IEquatable<Vertex>
	{
		public int index;

		public Vector3d p;

		public int tstart;

		public int tcount;

		public SymmetricMatrix q;

		public bool borderEdge;

		public bool uvSeamEdge;

		public bool uvFoldoverEdge;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vertex(int index, Vector3d p)
		{
			this.index = index;
			this.p = p;
			tstart = 0;
			tcount = 0;
			q = default(SymmetricMatrix);
			borderEdge = true;
			uvSeamEdge = false;
			uvFoldoverEdge = false;
		}

		public override int GetHashCode()
		{
			return index;
		}

		public override bool Equals(object obj)
		{
			if (obj is Vertex vertex)
			{
				return index == vertex.index;
			}
			return false;
		}

		public bool Equals(Vertex other)
		{
			return index == other.index;
		}
	}
}
namespace LowSpecGaming
{
	[BepInPlugin("Mushroom.LowSpecGaming", "LowSpecGaming", "0.3.3")]
	public class EntryPoint : BasePlugin
	{
		public static ConfigEntry<DynamicResolution> dynamicResolution;

		public static ConfigEntry<IRFDrawing> irfDrawing;

		public static ConfigEntry<GameEnvironment> gameEnvironment;

		public static ConfigEntry<BioScanBlink> BioScanUpdate;

		public static ConfigEntry<HateSpitter> hateSpitter;

		public static ConfigEntry<EnemyBehaviourCulling> enemyBehaviourCulling;

		public static ConfigEntry<string> currentFolderPath;

		public static ConfigEntry<bool> dumpTexture;

		public static ConfigEntry<TextureSize> textureSize;

		public static ConfigEntry<OneFlashLight> oneFlashLight;

		public static ConfigEntry<MeshSimply> meshSimply;

		public static ConfigEntry<ShaderReplace> shaderReplace;

		public static ConfigEntry<Experimental> redundantComponents;

		public static ConfigFile configFile;

		public static EntryPoint e;

		public override void Load()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			e = this;
			Harmony val = new Harmony("Mushroom.LowSpecGaming");
			((BasePlugin)this).Log.LogInfo((object)"Mushroom Low Spec Gaming is IN~!!");
			GetTheSettings();
			ClassInjector.RegisterTypeInIl2Cpp<LowSpecGaming>();
			ClassInjector.RegisterTypeInIl2Cpp<LowSpecCamera>();
			SightPatch.sightPaths = new Dictionary<string, string[]>();
			SightPatch.GetSightFolders();
			LogIt(Paths.BepInExRootPath);
			val.PatchAll();
			LevelAPI.OnBuildDone += C_CullingClusterPatch.GetAllClusters;
			LevelAPI.OnLevelCleanup += C_CullingClusterPatch.CleanAllClusters;
		}

		public static void GetTheSettings()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "mushroom.lowspecgaming.cfg"), true);
			dynamicResolution = configFile.Bind<DynamicResolution>("Setup", "dynamicResolution", DynamicResolution.Stable, "Scales down your resolution whenever you move your camera, will improve this in the future");
			irfDrawing = configFile.Bind<IRFDrawing>("Setup", "irfDrawing", IRFDrawing.Draw, "whether or not to draw IRF like trees, I hope this doesn't break the Kraken");
			gameEnvironment = configFile.Bind<GameEnvironment>("Setup", "gameEnvironment", GameEnvironment.Full, "Reduce fog distance, shadow distance, no more dust particles (requires restart to take effect)");
			BioScanUpdate = configFile.Bind<BioScanBlink>("Setup", "BioScanUpdate", BioScanBlink.DontBlink, "Whether or not Bio Scans would blink, courtesy to McCad, this is his online code");
			hateSpitter = configFile.Bind<HateSpitter>("Setup", "hateSpitter", HateSpitter.HATE, "If you hate spitters, make them low quality");
			enemyBehaviourCulling = configFile.Bind<EnemyBehaviourCulling>("Setup", "enemyBehaviourCulling", EnemyBehaviourCulling.Full, "Reduce Enemy Update in order to save performance, will improve this feature in the future for better performance");
			textureSize = configFile.Bind<TextureSize>("Setup", "textureSize", TextureSize.Full, "Texture size, for the potata army");
			oneFlashLight = configFile.Bind<OneFlashLight>("Setup", "oneFlashLight", OneFlashLight.All, "All for vanilla, use One to load only 1 and also the best flashlight for all guns (DMR)");
			meshSimply = configFile.Bind<MeshSimply>("Setup", "meshSimply", MeshSimply.NoSimply, "VERY EXPERIMENTAL, turn on to reduce vertices for about 20%, improves GPU performance");
			shaderReplace = configFile.Bind<ShaderReplace>("Setup", "shaderReplace", ShaderReplace.Vanilla, "VERY EXPERIMENTAL, use very basic shader");
			redundantComponents = configFile.Bind<Experimental>("Setup", "redundantComponents", Experimental.TurnOn, "VERY EXPERIMENTAL, turn off some redundant compenents in game || You might gain 5fps");
			currentFolderPath = configFile.Bind<string>("Setup", "currentFolderPath", "", "Manual Path to the current folder that has the plugin if it fails to load normally, This will be removed soon");
			dumpTexture = configFile.Bind<bool>("Setup", "dumpTexture", false, "Dump and extract sight textures in order to load hi res textures even at low res texture settings");
		}

		public static void LogIt(object data)
		{
			((BasePlugin)e).Log.LogInfo(data);
		}

		public override bool Unload()
		{
			return ((BasePlugin)this).Unload();
		}

		public static void DecompressFolder(string compressedFilePath, string decompressedFolderPath)
		{
			ZipFile.ExtractToDirectory(compressedFilePath, decompressedFolderPath);
			LogIt("Folder decompressed successfully.");
		}
	}
	public enum BioScanBlink
	{
		Blink,
		DontBlink
	}
	public enum GameEnvironment
	{
		Full,
		Reduced
	}
	public enum IRFDrawing
	{
		Draw,
		HalfDraw,
		DontDraw
	}
	public enum DynamicResolution
	{
		Stable,
		Dynamic
	}
	public enum HateSpitter
	{
		HATE,
		LOVE
	}
	public enum EnemyBehaviourCulling
	{
		Full,
		Reduced
	}
	public enum MeshSimply
	{
		Simply,
		NoSimply
	}
	public enum ShaderReplace
	{
		Replace,
		Vanilla
	}
	public enum Experimental
	{
		TurnOn,
		TurnOff
	}
	public enum TextureSize
	{
		Full,
		Half,
		Quater,
		Eigth,
		Low,
		PentaLow,
		VeryLow,
		SuperLow,
		UltraLow,
		POTATA,
		YouLiveLikeThis
	}
	public enum OneFlashLight
	{
		All,
		One
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "Mushroom.LowSpecGaming";

		public const string PLUGIN_NAME = "LowSpecGaming";

		public const string PLUGIN_VERSION = "0.3.3";

		public const string AUTHOR = "time1pm";

		public const string BRANCH = "beta";

		public const string INTERNAL_VERSION = "000799";
	}
	internal class LowSpecGaming : MonoBehaviour
	{
		public static List<Texture2D> lightTextures;

		public static Texture2D text;

		public void Start()
		{
			EntryPoint.GetTheSettings();
			lightTextures = new List<Texture2D>();
			LevelAPI.OnEnterLevel += HateTheGameFeel;
			LevelAPI.OnEnterLevel += ClusterRenderingOff;
			EntryPoint.LogIt("Applying settings in 12s");
			((MonoBehaviour)this).Invoke("ApplySettings", 12f);
			((MonoBehaviour)this).Invoke("GetFlashLights", 10f);
		}

		public void GetFlashLights()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			if (!EntryPoint.dumpTexture.Value)
			{
				return;
			}
			foreach (FlashlightSettingsDataBlock allBlock in GameDataBlockBase<FlashlightSettingsDataBlock>.GetAllBlocks())
			{
				lightTextures.Add(((Il2CppObjectBase)AssetShardManager.GetLoadedAsset(allBlock.cookie, false)).Cast<Texture2D>());
			}
			foreach (Texture2D lightTexture in lightTextures)
			{
				try
				{
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)lightTexture).width, ((Texture)lightTexture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					RenderTexture active = RenderTexture.active;
					Graphics.Blit((Texture)(object)lightTexture, temporary);
					RenderTexture.active = active;
					Texture2D val = new Texture2D(((Texture)lightTexture).width, ((Texture)lightTexture).height);
					_ = RenderTexture.active;
					RenderTexture.active = temporary;
					val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0);
					val.Apply();
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)ImageConversion.EncodeToPNG(val));
					string text = Paths.BepInExRootPath + "\\LowSpec\\";
					if (!Directory.Exists(text))
					{
						Directory.CreateDirectory(text);
					}
					if (!Directory.Exists(text + "FlashLights\\"))
					{
						Directory.CreateDirectory(text + "FlashLights\\");
					}
					File.WriteAllBytes(text + "FlashLights\\" + ((Object)lightTexture).name + ".png", bytes);
				}
				catch
				{
					EntryPoint.LogIt("Skipping Texture");
				}
			}
		}

		public void ApplySettings()
		{
			int value = 10;
			EntryPoint.LogIt("Apply Settings");
			StartUpSettings.PotatoTexture(ref value);
		}

		private static void HateTheGameFeel()
		{
			if (EntryPoint.gameEnvironment.Value != 0)
			{
				((Behaviour)((Component)PreLitVolume.Current).gameObject.GetComponent<AmbientParticles>()).enabled = false;
				PreLitVolume.Current.m_fogDistance = 45f;
				PreLitVolume.Current.FogPostBlur = 1;
				PreLitVolume.Current.FogShadowSamples = 0;
				PreLitVolume.Current.IndirectBlurSamples = 0;
				PreLitVolume.Current.IndirectDownsampling = 0;
				QualitySettings.shadowDistance = 15f;
				QualitySettings.softParticles = false;
			}
		}

		public static void ClusterRenderingOff()
		{
			((Behaviour)ClusteredRendering.Current).enabled = false;
		}
	}
}
namespace LowSpecGaming.Util
{
	public static class C_Combine
	{
		public static bool simplify;

		public static List<Renderer> CombineMeshes(Renderer[] renderersToCombine)
		{
			return CombineMeshes(renderersToCombine.ToList());
		}

		[MethodImpl(MethodImplOptions.AggressiveOptimization)]
		public static List<Renderer> CombineMeshes(List<Renderer> renderersToCombine)
		{
			//IL_00a0: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			if (renderersToCombine.Count < 2)
			{
				return renderersToCombine;
			}
			Material val;
			try
			{
				val = renderersToCombine[0].sharedMaterial;
				foreach (Renderer item2 in renderersToCombine)
				{
					if ((Object)(object)item2.sharedMaterial != (Object)(object)val)
					{
						return renderersToCombine;
					}
				}
			}
			catch
			{
				val = renderersToCombine[0].material;
			}
			List<CombineInstance> list = new List<CombineInstance>();
			foreach (Renderer item3 in renderersToCombine)
			{
				MeshFilter component = ((Component)item3).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null)
				{
					return renderersToCombine;
				}
				CombineInstance val2 = default(CombineInstance);
				((CombineInstance)(ref val2)).mesh = component.sharedMesh;
				((CombineInstance)(ref val2)).transform = ((Component)item3).transform.localToWorldMatrix;
				CombineInstance item = val2;
				list.Add(item);
				item3.enabled = false;
				item3.forceRenderingOff = true;
				Object.Destroy((Object)(object)component);
			}
			GameObject val3 = new GameObject(((Object)((Component)renderersToCombine[0]).gameObject).name + "_Combined");
			val3.isStatic = true;
			C_CullingClusterPatch.CombinedGameObjects.Add(val3);
			MeshFilter val4 = val3.AddComponent<MeshFilter>();
			MeshRenderer val5 = val3.AddComponent<MeshRenderer>();
			Mesh val6 = new Mesh();
			val6.CombineMeshes(Il2CppStructArray<CombineInstance>.op_Implicit(list.ToArray()), true, true);
			if (simplify)
			{
				MeshSimplifier meshSimplifier = new MeshSimplifier(val6);
				meshSimplifier.SimplifyMesh(0.8f);
				val4.mesh = meshSimplifier.ToMesh();
			}
			else
			{
				val4.mesh = val6;
			}
			((Renderer)val5).sharedMaterial = val;
			((Renderer)val5).enabled = false;
			((Renderer)val5).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val5).receiveShadows = false;
			((Renderer)val5).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)val5).reflectionProbeUsage = (ReflectionProbeUsage)0;
			return new List<Renderer> { (Renderer)(object)val5 };
		}

		public static List<Renderer> CombineShadowMeshes(List<Renderer> renderersToCombine)
		{
			//IL_0073: 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_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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			if (renderersToCombine.Count < 2)
			{
				return renderersToCombine;
			}
			Material sharedMaterial;
			try
			{
				sharedMaterial = renderersToCombine[0].sharedMaterial;
			}
			catch
			{
				sharedMaterial = renderersToCombine[0].material;
			}
			string name = ((Object)((Component)renderersToCombine[0]).gameObject).name;
			List<CombineInstance> list = new List<CombineInstance>();
			foreach (Renderer item2 in renderersToCombine)
			{
				MeshFilter component = ((Component)item2).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null)
				{
					return renderersToCombine;
				}
				CombineInstance val = default(CombineInstance);
				((CombineInstance)(ref val)).mesh = component.sharedMesh;
				((CombineInstance)(ref val)).transform = ((Component)item2).transform.localToWorldMatrix;
				CombineInstance item = val;
				list.Add(item);
				item2.enabled = false;
				item2.forceRenderingOff = true;
				Object.Destroy((Object)(object)component);
			}
			GameObject val2 = new GameObject(name + "_Combined");
			val2.isStatic = true;
			C_CullingClusterPatch.CombinedGameObjects.Add(val2);
			MeshFilter obj2 = val2.AddComponent<MeshFilter>();
			MeshRenderer val3 = val2.AddComponent<MeshRenderer>();
			Mesh val4 = new Mesh();
			val4.CombineMeshes(Il2CppStructArray<CombineInstance>.op_Implicit(list.ToArray()), true, true);
			obj2.mesh = val4;
			((Renderer)val3).sharedMaterial = sharedMaterial;
			((Renderer)val3).enabled = false;
			((Renderer)val3).forceRenderingOff = true;
			((Renderer)val3).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)val3).receiveShadows = false;
			((Renderer)val3).lightProbeUsage = (LightProbeUsage)0;
			((Renderer)val3).reflectionProbeUsage = (ReflectionProbeUsage)0;
			return new List<Renderer> { (Renderer)(object)val3 };
		}
	}
}
namespace LowSpecGaming.Settings
{
	[HarmonyPatch]
	internal class GlobalSettingsPatch
	{
		private static GameObject newButton;

		private static GameObject newMenu;

		private static CM_ScrollWindow[] menu_list;

		private static CM_Item[] button_list;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CM_PageSettings), "Setup")]
		public static void UpdateSettings(CM_PageSettings __instance)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			GameObject gameObject = ((Component)GameObject.Find("GUI").transform.GetChild(0).GetChild(3).GetChild(10)
				.GetChild(3)
				.GetChild(20)).gameObject;
			button_list = Il2CppArrayBase<CM_Item>.op_Implicit(((Component)GameObject.Find("GUI").transform.GetChild(0).GetChild(3).GetChild(10)
				.GetChild(3)).GetComponentsInChildren<CM_Item>());
			GameObject gameObject2 = ((Component)GameObject.Find("GUI").transform.GetChild(0).GetChild(3).GetChild(10)
				.GetChild(3)
				.GetChild(21)).gameObject;
			newButton = Object.Instantiate<GameObject>(gameObject, gameObject.transform.parent);
			newMenu = Object.Instantiate<GameObject>(gameObject2, gameObject2.transform.parent);
			newButton.transform.position = gameObject.transform.position - new Vector3(0f, 160f, 0f);
			newButton.transform.localScale = gameObject.transform.localScale;
			newMenu.transform.position = gameObject2.transform.position;
			newMenu.transform.localScale = gameObject2.transform.localScale;
			newMenu.SetActive(false);
			((TMP_Text)newButton.GetComponent<TextMeshPro>()).SetText("LowSpecGaming", true);
			newButton.GetComponent<CM_Item>().SetOnBtnPressCallback(Action<int>.op_Implicit((Action<int>)SetMenuActive));
			CM_Item[] array = button_list;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].OnBtnPressCallback += Action<int>.op_Implicit((Action<int>)SetMenuInactive);
			}
		}

		public static void SetMenuActive(int a)
		{
			menu_list = Il2CppArrayBase<CM_ScrollWindow>.op_Implicit(((Component)GameObject.Find("GUI").transform.GetChild(0).GetChild(3).GetChild(10)
				.GetChild(3)).GetComponentsInChildren<CM_ScrollWindow>());
			CM_ScrollWindow[] array = menu_list;
			for (int i = 0; i < array.Length; i++)
			{
				((Component)array[i]).gameObject.SetActive(false);
			}
			newMenu.SetActive(true);
		}

		public static void SetMenuInactive(int a)
		{
			newMenu.SetActive(false);
		}
	}
	[HarmonyPatch]
	internal class StartUpSettings
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartMainGame), "Start")]
		public static void MakeItWork(StartMainGame __instance)
		{
			((Component)__instance).gameObject.AddComponent<LowSpecGaming>();
			QualitySettings.masterTextureLimit = 0;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(CellSettingsApply), "ApplyTextureSize")]
		public static bool PotatoTexture(ref int value)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			EntryPoint.GetTheSettings();
			LowSpecCamera.dynamic = EntryPoint.dynamicResolution.Value == DynamicResolution.Dynamic;
			LowSpecCamera.markerLayer = ((Component)GameObject.Find("GUI").transform.GetChild(0).GetChild(0)).GetComponent<UI_Canvas>();
			LowSpecCamera.canvasScale = CellSettingsManager.SettingsData.Video.Resolution.Value.y / 1080f;
			SpitterPatch.hate = EntryPoint.hateSpitter.Value == HateSpitter.HATE;
			BioScanPatch.update = EntryPoint.BioScanUpdate.Value == BioScanBlink.Blink;
			IRFPatch.draw = EntryPoint.irfDrawing.Value == IRFDrawing.Draw;
			ClusterRestruct.shader = EntryPoint.shaderReplace.Value == ShaderReplace.Replace;
			C_Combine.simplify = EntryPoint.meshSimply.Value == MeshSimply.Simply;
			if (EntryPoint.dumpTexture.Value)
			{
				QualitySettings.masterTextureLimit = 0;
			}
			else
			{
				value = (int)EntryPoint.textureSize.Value;
				if (QualitySettings.masterTextureLimit != value)
				{
					QualitySettings.masterTextureLimit = value;
				}
			}
			return false;
		}
	}
}
namespace LowSpecGaming.Patches
{
	public static class ClusterRestruct
	{
		public static bool shader;

		public static Shader diffuse = Shader.Find("Diffuse");

		public static Renderer[] Restruct(Renderer[] initialRenderers)
		{
			if (initialRenderers.Length < 2)
			{
				C_CullingClusterPatch.initial_renderer += initialRenderers.Length;
				C_CullingClusterPatch.after_renderer += initialRenderers.Length;
				for (int i = 0; i < initialRenderers.Length; i++)
				{
					Material material = initialRenderers[i].material;
					if ((Object)(object)material == (Object)null)
					{
						break;
					}
					if (shader && ((Object)material.shader).name == "GTFO/CMS_WorldProp")
					{
						material.shader = diffuse;
						material.enableInstancing = true;
					}
				}
				return initialRenderers;
			}
			return Restruct(initialRenderers.ToList());
		}

		public static Renderer[] Restruct(List<Renderer> initialRenderers)
		{
			int count = initialRenderers.Count;
			Dictionary<string, List<Renderer>> dictionary = new Dictionary<string, List<Renderer>>();
			for (int i = 0; i < initialRenderers.Count; i++)
			{
				MeshFilter component = ((Component)initialRenderers[i]).GetComponent<MeshFilter>();
				if (!((Object)(object)component == (Object)null))
				{
					string key = component.mesh.vertexCount.ToString();
					if (!dictionary.TryGetValue(key, out var _))
					{
						dictionary[key] = new List<Renderer>();
					}
					dictionary[key].Add(initialRenderers[i]);
				}
			}
			List<Renderer> list = new List<Renderer>();
			List<string> list2 = new List<string>();
			foreach (string key2 in dictionary.Keys)
			{
				list2.Add(key2);
			}
			foreach (string item in list2)
			{
				if (item != null)
				{
					int length = item.Length;
					if (length != 3)
					{
						if (length == 4)
						{
							switch (item[1])
							{
							case '2':
								break;
							case '0':
								goto IL_01f2;
							case '4':
								goto IL_0202;
							case '3':
								goto IL_0212;
							case '1':
								goto IL_0222;
							default:
								goto IL_0235;
							}
							if (item == "1200")
							{
								goto IL_0230;
							}
						}
					}
					else
					{
						switch (item[2])
						{
						case '0':
							break;
						case '8':
							goto IL_017a;
						case '4':
							goto IL_01b2;
						case '5':
							goto IL_01c2;
						case '3':
							goto IL_01d2;
						default:
							goto IL_0235;
						}
						if (item == "340")
						{
							goto IL_0230;
						}
					}
				}
				goto IL_0235;
				IL_01c2:
				if (item == "105")
				{
					goto IL_0230;
				}
				goto IL_0235;
				IL_01b2:
				if (item == "764")
				{
					goto IL_0230;
				}
				goto IL_0235;
				IL_017a:
				switch (item)
				{
				case "408":
				ca