Decompiled source of MapDestruction v1.8.1

Mods/MapDestruction.dll

Decompiled 2 days ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Audio;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSystem;
using MapDestruction;
using MapDestruction.Assets;
using MapDestruction.Core;
using MapDestruction.Destruction;
using MapDestruction.Detection;
using MapDestruction.Effects;
using MapDestruction.Meshing;
using MapDestruction.Util;
using MapDestruction.Voxel;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "MapDestruction", "1.8.1", "MapDestruction", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })]
[assembly: InternalsVisibleTo("Tests")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace MapDestruction
{
	public class Mod : MelonMod
	{
		public override void OnInitializeMelon()
		{
			Settings.Init();
			GpuGuard.CheckPreviousCrash();
			UnityApi.Init();
			BundleMeshSetup.Start();
			Hooking.OnLevelLoaded += delegate
			{
				DestructionManager.OnLevelLoaded();
				MenuSetup.TryBuild();
			};
			Hooking.OnLevelUnloaded += DestructionManager.OnLevelUnloaded;
			Hooking.OnPostFireGun += ImpactRouter.OnGunFired;
			MenuSetup.TryBuild();
			((MelonBase)this).LoggerInstance.Msg($"MapDestruction 로드 완료 (품질 {Settings.Tier}, 복셀 {Settings.VoxelSize * 100f:0}cm)");
		}

		public override void OnUpdate()
		{
			Log.Pump();
			DestructionManager.Tick();
			MenuSetup.Tick();
			Prof.Frame(Time.unscaledDeltaTime, Time.realtimeSinceStartup, DebrisSystem.ActiveCount, Chips.Count);
		}
	}
}
namespace MapDestruction.Voxel
{
	public static class DamageModel
	{
		public struct Result
		{
			public float RemovedVolume;

			public bool AnyErosion;

			public bool AnyDisp;

			public float MaxPotential;

			public HashSet<Int3> ChangedChunks;

			public HashSet<Int3> NeighborChunks;

			public bool Changed
			{
				get
				{
					if (!AnyErosion)
					{
						return AnyDisp;
					}
					return true;
				}
			}
		}

		private enum Mode
		{
			Apply,
			Recompute,
			Potential
		}

		private const float DeepCarry = 0.95f;

		private static float KindScale(ImpactKind k)
		{
			return k switch
			{
				ImpactKind.Explosion => 1.6f, 
				ImpactKind.Bullet => 0.45f, 
				_ => 1f, 
			};
		}

		public static float Units(in ImpactEvent e, MaterialProfile p)
		{
			return e.Energy * Settings.DamageMultiplier.Value / MathF.Max(p.Toughness, 1f);
		}

		public static float CraterRadius(in ImpactEvent e, MaterialProfile p)
		{
			float x = MathF.Max(Units(in e, p), 0f);
			return MathF.Min(e.ContactRadius + p.CraterScale * KindScale(e.Kind) * MathF.Cbrt(x), 1.5f);
		}

		public static float InfluenceRadius(in ImpactEvent e, MaterialProfile p)
		{
			return CraterRadius(in e, p) * ((p.Ductility > 0.01f) ? 1.6f : MathF.Max(1.35f, p.Cone * 1.08f));
		}

		private static float MaxErosionFor(VoxelChunk ch, MaterialProfile p)
		{
			float num = p.MaxErosion;
			if (!Settings.AllowHoles.Value)
			{
				num = MathF.Min(num, 0.06f);
			}
			if (ch.Capability == 1)
			{
				num = MathF.Min(num, 0.02f);
			}
			if (ch.Capability <= 0)
			{
				num = 0f;
			}
			return num;
		}

		private static float MaxDentFor(VoxelChunk ch, MaterialProfile p)
		{
			float num = p.MaxDent;
			if (ch.Capability == 1)
			{
				num = MathF.Min(num, 0.02f);
			}
			if (ch.Capability <= 0)
			{
				num = 0f;
			}
			return num;
		}

		public static Result Apply(in ImpactEvent e, MaterialProfile hitProf, List<Int3> chunkKeys, HashSet<Int3> flipped)
		{
			return Run(in e, hitProf, chunkKeys, flipped, Mode.Apply);
		}

		public static Result Recompute(in ImpactEvent e, MaterialProfile hitProf, List<Int3> chunkKeys, HashSet<Int3> flipped)
		{
			return Run(in e, hitProf, chunkKeys, flipped, Mode.Recompute);
		}

		public static float PotentialErosion(in ImpactEvent e, MaterialProfile hitProf, List<Int3> chunkKeys)
		{
			return Run(in e, hitProf, chunkKeys, null, Mode.Potential).MaxPotential;
		}

		private static Result Run(in ImpactEvent e, MaterialProfile hitProf, List<Int3> chunkKeys, HashSet<Int3> flipped, Mode mode)
		{
			Result result = default(Result);
			float cell = VoxelWorld.Cell;
			float num = MathF.Max(CraterRadius(in e, hitProf), cell * 0.75f);
			float num2 = num * 1.6f;
			float num3 = InfluenceRadius(in e, hitProf);
			V3 point = e.Point;
			V3 v = (-e.Normal * 0.6f + e.Direction * 0.4f).Normalized;
			if (v.SqrMag < 0.5f)
			{
				v = -e.Normal;
			}
			float num4 = 1f / (cell * 2.5f);
			V3 b = -e.Normal;
			float num5 = ((mode == Mode.Potential) ? 0f : MathF.Max(0f, 0f - VoxelWorld.SampleSdf0(point, 0f)));
			float num6 = num5 * MathUtil.Clamp01((num5 - cell * 0.5f) / cell) * 0.95f;
			foreach (Int3 chunkKey in chunkKeys)
			{
				VoxelChunk voxelChunk = VoxelWorld.Get(chunkKey);
				if (voxelChunk == null || !voxelChunk.Voxelized)
				{
					continue;
				}
				bool flag = false;
				int num7 = 16;
				int num8 = 16;
				int num9 = 16;
				int num10 = 0;
				int num11 = 0;
				int num12 = 0;
				int num13 = Math.Max(0, (int)MathF.Floor((point.x - num3 - voxelChunk.Origin.x) / cell));
				int num14 = Math.Max(0, (int)MathF.Floor((point.y - num3 - voxelChunk.Origin.y) / cell));
				int num15 = Math.Max(0, (int)MathF.Floor((point.z - num3 - voxelChunk.Origin.z) / cell));
				int num16 = Math.Min(16, (int)MathF.Ceiling((point.x + num3 - voxelChunk.Origin.x) / cell));
				int num17 = Math.Min(16, (int)MathF.Ceiling((point.y + num3 - voxelChunk.Origin.y) / cell));
				int num18 = Math.Min(16, (int)MathF.Ceiling((point.z + num3 - voxelChunk.Origin.z) / cell));
				for (int i = num15; i <= num18; i++)
				{
					for (int j = num14; j <= num17; j++)
					{
						for (int k = num13; k <= num16; k++)
						{
							V3 v2 = voxelChunk.PointPos(k, j, i);
							float mag = (v2 - point).Mag;
							if (mag >= num3)
							{
								continue;
							}
							int num19 = VoxelChunk.Idx(k, j, i);
							MaterialProfile materialProfile = MaterialPalette.ProfileOf(voxelChunk.Mat[num19]) ?? hitProf;
							float num20 = Units(in e, materialProfile);
							float num21 = mag;
							if (materialProfile.Cone > 1.001f)
							{
								float num22 = V3.Dot(v2 - point, b);
								num21 = MathF.Sqrt(MathF.Max(0f, mag * mag - num22 * num22) / (materialProfile.Cone * materialProfile.Cone) + num22 * num22);
							}
							float v3 = 0.5f;
							float edge = 1f;
							bool flag2 = Fracture.Chunky(materialProfile) && num21 < num * 1.25f;
							if (flag2)
							{
								v3 = Fracture.Cell(Fracture.Warp(v2, materialProfile, e.Grain), Fracture.SeedOf(materialProfile), out edge);
								num21 *= Fracture.DistanceScale(v3, materialProfile);
							}
							float num23 = MathUtil.Falloff(num21 / num);
							if (num23 > 0f && materialProfile.ErosionScale > 0f)
							{
								if (mode == Mode.Apply)
								{
									voxelChunk.Damage[num19] += num20 * num23;
								}
								float num24 = MathUtil.Fbm(v2 * num4, 1337);
								float num25 = (flag2 ? Fracture.MultFrom(v3, edge, materialProfile, num24) : (0.6f + 0.8f * num24));
								float num26 = MathF.Max(0f, voxelChunk.Damage[num19] - materialProfile.Threshold) * materialProfile.ErosionScale * num25;
								if (num6 > 0f && num26 > 0f)
								{
									num26 += num6 * MathUtil.Clamp01((1f - num21 / num) * 2.5f);
								}
								if (mode == Mode.Potential)
								{
									if (MathF.Abs(voxelChunk.Sdf0[num19]) < cell * 0.6f)
									{
										result.MaxPotential = MathF.Max(result.MaxPotential, MathF.Min(num26, materialProfile.MaxErosion));
									}
									continue;
								}
								num26 = MathF.Min(num26, MaxErosionFor(voxelChunk, materialProfile));
								float num27 = voxelChunk.Erosion[num19];
								if (num26 > num27 + 0.0001f)
								{
									float num28 = voxelChunk.Sdf0[num19];
									if (num28 >= (0f - cell) * 0.5f && num28 < cell * 0.5f)
									{
										result.RemovedVolume += (num26 - num27) * cell * cell;
									}
									bool num29 = num28 + num27 < 0f;
									bool flag3 = num28 + num26 < 0f;
									if (num29 && !flag3 && num28 < (0f - cell) * 0.5f)
									{
										result.RemovedVolume += cell * cell * cell;
									}
									voxelChunk.Erosion[num19] = num26;
									voxelChunk.HasErosion = true;
									result.AnyErosion = true;
									flag = true;
									VoxelWorld.MarkDamaged(v2);
									if (k < num7)
									{
										num7 = k;
									}
									if (k > num10)
									{
										num10 = k;
									}
									if (j < num8)
									{
										num8 = j;
									}
									if (j > num11)
									{
										num11 = j;
									}
									if (i < num9)
									{
										num9 = i;
									}
									if (i > num12)
									{
										num12 = i;
									}
									if (num29 && !flag3)
									{
										flipped?.Add(new Int3(chunkKey.X * 16 + k, chunkKey.Y * 16 + j, chunkKey.Z * 16 + i));
									}
								}
							}
							if (mode != Mode.Apply || !(materialProfile.Ductility > 0.001f))
							{
								continue;
							}
							float num30 = MathUtil.Falloff(mag / num2);
							float num31 = MaxDentFor(voxelChunk, materialProfile);
							if (!(num30 > 0f) || !(num31 > 0f))
							{
								continue;
							}
							V3 v4 = voxelChunk.Disp[num19] + v * (materialProfile.Ductility * materialProfile.DentScale * num20 * num30);
							float mag2 = v4.Mag;
							if (mag2 > num31)
							{
								v4 *= num31 / mag2;
							}
							if ((v4 - voxelChunk.Disp[num19]).SqrMag > 1E-06f)
							{
								flag = true;
								VoxelWorld.MarkDamaged(v2);
								if (k < num7)
								{
									num7 = k;
								}
								if (k > num10)
								{
									num10 = k;
								}
								if (j < num8)
								{
									num8 = j;
								}
								if (j > num11)
								{
									num11 = j;
								}
								if (i < num9)
								{
									num9 = i;
								}
								if (i > num12)
								{
									num12 = i;
								}
							}
							voxelChunk.Disp[num19] = v4;
							voxelChunk.HasDisp = true;
							result.AnyDisp = true;
						}
					}
				}
				if (!flag)
				{
					continue;
				}
				ref HashSet<Int3> changedChunks = ref result.ChangedChunks;
				(changedChunks ?? (changedChunks = new HashSet<Int3>())).Add(chunkKey);
				int num32 = ((num7 <= 2) ? (-1) : 0);
				int num33 = ((num10 >= 14) ? 1 : 0);
				int num34 = ((num8 <= 2) ? (-1) : 0);
				int num35 = ((num11 >= 14) ? 1 : 0);
				int num36 = ((num9 <= 2) ? (-1) : 0);
				int num37 = ((num12 >= 14) ? 1 : 0);
				for (int l = num36; l <= num37; l++)
				{
					for (int m = num34; m <= num35; m++)
					{
						for (int n = num32; n <= num33; n++)
						{
							if (n != 0 || m != 0 || l != 0)
							{
								Int3 @int = new Int3(chunkKey.X + n, chunkKey.Y + m, chunkKey.Z + l);
								if (VoxelWorld.Get(@int) != null)
								{
									changedChunks = ref result.NeighborChunks;
									(changedChunks ?? (changedChunks = new HashSet<Int3>())).Add(@int);
								}
							}
						}
					}
				}
			}
			return result;
		}
	}
	public sealed class MaterialProfile
	{
		public int Id;

		public string Name;

		public float Toughness;

		public float CraterScale;

		public float ErosionScale;

		public float Threshold;

		public float MaxErosion;

		public float Ductility;

		public float DentScale;

		public float MaxDent;

		public float Density;

		public float DebrisSize;

		public float BrokenTint;

		public bool Splinters;

		public float ChunkSize;

		public float Chunkiness;

		public float Cone = 1f;

		public float Rough;

		public V3 Stretch = new V3(1f, 1f, 1f);

		public float GrainStretch = 1f;

		public MaterialProfile Fracture(float chunk, float chunkiness, float cone, float rough)
		{
			ChunkSize = chunk;
			Chunkiness = chunkiness;
			Cone = cone;
			Rough = rough;
			return this;
		}
	}
	public static class MaterialProfiles
	{
		private static int _id;

		public static readonly MaterialProfile Concrete;

		public static readonly MaterialProfile Brick;

		public static readonly MaterialProfile Rock;

		public static readonly MaterialProfile Plaster;

		public static readonly MaterialProfile Wood;

		public static readonly MaterialProfile Metal;

		public static readonly MaterialProfile Glass;

		public static readonly MaterialProfile Dirt;

		public static readonly MaterialProfile Default;

		private static readonly (string[] keys, MaterialProfile prof)[] Table;

		private static MaterialProfile P(string name, float tough, float crater, float ero, float thr, float maxEro, float duct, float dent, float maxDent, float dens, float dsize, float tint, bool splinter = false)
		{
			return new MaterialProfile
			{
				Id = ++_id,
				Name = name,
				Toughness = tough,
				CraterScale = crater,
				ErosionScale = ero,
				Threshold = thr,
				MaxErosion = maxEro,
				Ductility = duct,
				DentScale = dent,
				MaxDent = maxDent,
				Density = dens,
				DebrisSize = dsize,
				BrokenTint = tint,
				Splinters = splinter
			};
		}

		static MaterialProfiles()
		{
			Concrete = P("Concrete", 140f, 0.13f, 0.075f, 0.06f, 3f, 0f, 0f, 0f, 2400f, 1f, 0.72f).Fracture(0.14f, 0.8f, 1.25f, 0.03f);
			Brick = P("Brick", 120f, 0.13f, 0.08f, 0.05f, 3f, 0f, 0f, 0f, 1900f, 1.1f, 0.7f).Fracture(0.13f, 0.85f, 1.2f, 0.025f);
			Rock = P("Rock", 200f, 0.12f, 0.07f, 0.08f, 3f, 0f, 0f, 0f, 2600f, 1.2f, 0.75f).Fracture(0.22f, 0.85f, 1.15f, 0.045f);
			Plaster = P("Plaster", 50f, 0.16f, 0.11f, 0.02f, 3f, 0f, 0f, 0f, 900f, 0.7f, 0.85f).Fracture(0.08f, 0.65f, 1.4f, 0.012f);
			Wood = P("Wood", 110f, 0.11f, 0.07f, 0.06f, 3f, 0.15f, 0.03f, 0.05f, 600f, 0.9f, 0.8f, splinter: true).Fracture(0.09f, 0.75f, 1f, 0.02f);
			Metal = P("Metal", 300f, 0.11f, 0.05f, 1.6f, 2f, 1f, 0.06f, 0.3f, 7800f, 0.6f, 0.6f);
			Glass = P("Glass", 30f, 0.2f, 0f, 0f, 0f, 0f, 0f, 0f, 2500f, 0.6f, 1f);
			Dirt = P("Dirt", 60f, 0.15f, 0.1f, 0.02f, 3f, 0f, 0f, 0f, 1600f, 0.9f, 0.6f).Fracture(0.18f, 0.35f, 1.1f, 0.02f);
			Default = P("Default", 140f, 0.13f, 0.075f, 0.06f, 3f, 0f, 0f, 0f, 2200f, 1f, 0.72f).Fracture(0.14f, 0.75f, 1.2f, 0.028f);
			Table = new(string[], MaterialProfile)[8]
			{
				(new string[3] { "glass", "window", "mirror" }, Glass),
				(new string[13]
				{
					"metal", "steel", "iron", "alumin", "chrome", "pipe", "rail", "sheet", "tin", "copper",
					"brass", "grate", "vent"
				}, Metal),
				(new string[7] { "wood", "plank", "timber", "plywood", "crate", "log", "bark" }, Wood),
				(new string[7] { "plaster", "drywall", "gypsum", "stucco", "ceiling", "foam", "cardboard" }, Plaster),
				(new string[1] { "brick" }, Brick),
				(new string[8] { "dirt", "soil", "mud", "sand", "grass", "ground", "gravel", "terrain" }, Dirt),
				(new string[7] { "rock", "stone", "cliff", "boulder", "granite", "marble", "cave" }, Rock),
				(new string[8] { "concrete", "cement", "asphalt", "tile", "floor", "wall", "pillar", "road" }, Concrete)
			};
			Brick.Stretch = new V3(0.55f, 1.6f, 0.55f);
			Wood.GrainStretch = 0.25f;
		}

		public static MaterialProfile TryClassify(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			string text2 = text.ToLowerInvariant();
			(string[], MaterialProfile)[] table = Table;
			for (int i = 0; i < table.Length; i++)
			{
				(string[], MaterialProfile) tuple = table[i];
				string[] item = tuple.Item1;
				MaterialProfile item2 = tuple.Item2;
				string[] array = item;
				foreach (string value in array)
				{
					if (text2.Contains(value))
					{
						return item2;
					}
				}
			}
			return null;
		}
	}
	public sealed class PaletteEntry
	{
		public byte Index;

		public MaterialProfile Profile;

		public Material RenderMaterial;

		public GameObject ImpactSource;

		public PhysicMaterial PhysicMat;

		public int Layer;

		private Material _broken;

		public Material Broken
		{
			get
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Expected O, but got Unknown
				if ((Object)(object)_broken == (Object)null && (Object)(object)RenderMaterial != (Object)null)
				{
					_broken = new Material(RenderMaterial);
					((Object)_broken).name = ((Object)RenderMaterial).name + "_MDBroken";
					TintColor(_broken, "_BaseColor", Profile.BrokenTint);
					TintColor(_broken, "_Color", Profile.BrokenTint);
				}
				return _broken;
			}
		}

		private static void TintColor(Material m, string prop, float k)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (m.HasProperty(prop))
				{
					Color color = m.GetColor(prop);
					color.r *= k;
					color.g *= k;
					color.b *= k;
					m.SetColor(prop, color);
				}
			}
			catch
			{
			}
		}

		public void DestroyRuntime()
		{
			if ((Object)(object)_broken != (Object)null)
			{
				Object.Destroy((Object)(object)_broken);
			}
			_broken = null;
		}
	}
	public static class MaterialPalette
	{
		private static readonly List<PaletteEntry> _entries = new List<PaletteEntry> { null };

		private static readonly Dictionary<int, byte> _byCollider = new Dictionary<int, byte>();

		private static readonly Dictionary<long, byte> _byKey = new Dictionary<long, byte>();

		public static PaletteEntry Get(byte i)
		{
			if (i <= 0 || i >= _entries.Count)
			{
				return null;
			}
			return _entries[i];
		}

		public static MaterialProfile ProfileOf(byte i)
		{
			return Get(i)?.Profile;
		}

		public static byte ForCollider(Collider c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return 0;
			}
			int instanceID = ((Object)c).GetInstanceID();
			if (_byCollider.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			if (StaticIndex.TryGetPiecePalette(instanceID, out var palette))
			{
				_byCollider[instanceID] = palette;
				return palette;
			}
			Material val = FindRenderMaterial(c);
			MaterialProfile materialProfile = MaterialProfiles.TryClassify(SlzBridge.SurfaceName(((Component)c).gameObject));
			if (materialProfile == null)
			{
				string text = "";
				try
				{
					if ((Object)(object)c.sharedMaterial != (Object)null)
					{
						text = text + ((Object)c.sharedMaterial).name + " ";
					}
				}
				catch
				{
				}
				if ((Object)(object)val != (Object)null)
				{
					text = text + ((Object)val).name + " ";
				}
				text += ((Object)((Component)c).gameObject).name;
				materialProfile = MaterialProfiles.TryClassify(text) ?? MaterialProfiles.Default;
			}
			byte orAdd = GetOrAdd(materialProfile, val);
			_byCollider[instanceID] = orAdd;
			PaletteEntry paletteEntry = _entries[orAdd];
			if ((Object)(object)paletteEntry.ImpactSource == (Object)null)
			{
				paletteEntry.ImpactSource = ((Component)c).gameObject;
				paletteEntry.Layer = ((Component)c).gameObject.layer;
				try
				{
					paletteEntry.PhysicMat = c.sharedMaterial;
				}
				catch
				{
				}
			}
			Log.Debug($"Palette: '{((Object)((Component)c).gameObject).name}' → {materialProfile.Name} / {(((Object)(object)val != (Object)null) ? ((Object)val).name : "(invisible)")}");
			return orAdd;
		}

		public static byte ForRendererMaterial(Material m, MaterialProfile fallback)
		{
			return GetOrAdd(MaterialProfiles.TryClassify(((Object)(object)m != (Object)null) ? ((Object)m).name : null) ?? fallback ?? MaterialProfiles.Default, m);
		}

		private static byte GetOrAdd(MaterialProfile prof, Material renderMat)
		{
			long key = ((long)prof.Id << 32) | (uint)(((Object)(object)renderMat != (Object)null) ? ((Object)renderMat).GetInstanceID() : 0);
			if (_byKey.TryGetValue(key, out var value))
			{
				return value;
			}
			if (_entries.Count >= 255)
			{
				return 1;
			}
			value = (byte)_entries.Count;
			_entries.Add(new PaletteEntry
			{
				Index = value,
				Profile = prof,
				RenderMaterial = renderMat
			});
			_byKey[key] = value;
			return value;
		}

		private static Material FindRenderMaterial(Collider c)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MeshRenderer component = ((Component)c).GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).sharedMaterial != (Object)null)
				{
					return ((Renderer)component).sharedMaterial;
				}
				component = ((Component)c).GetComponentInParent<MeshRenderer>();
				if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).sharedMaterial != (Object)null)
				{
					return ((Renderer)component).sharedMaterial;
				}
			}
			catch
			{
			}
			StaticIndex.RendererEntry rendererEntry = StaticIndex.FindRendererOverlapping(Box3.FromBounds(c.bounds));
			if (!((Object)(object)rendererEntry?.Renderer != (Object)null))
			{
				return null;
			}
			return ((Renderer)rendererEntry.Renderer).sharedMaterial;
		}

		public static void Clear()
		{
			foreach (PaletteEntry entry in _entries)
			{
				entry?.DestroyRuntime();
			}
			_entries.Clear();
			_entries.Add(null);
			_byCollider.Clear();
			_byKey.Clear();
		}
	}
	public sealed class VoxelizeJob
	{
		private struct Ev
		{
			public float T;

			public bool Enter;

			public byte Mat;
		}

		private struct Interval
		{
			public float A;

			public float B;

			public byte Mat;
		}

		private const int P = 17;

		private const int N = 16;

		private const float Margin = 4f;

		private const float Eps = 0.002f;

		private const int MaxHitsPerPass = 24;

		public readonly VoxelChunk Chunk;

		private readonly float[] _dist = new float[14739];

		private readonly sbyte[] _state = new sbyte[14739];

		private readonly byte[] _mat = new byte[14739];

		private int _axis;

		private int _line;

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

		private static readonly List<Ev> _events = new List<Ev>(64);

		private static readonly List<Interval> _intervals = new List<Interval>(32);

		private static readonly Comparison<Ev> _cmp = delegate(Ev p, Ev q)
		{
			int num = p.T.CompareTo(q.T);
			if (num != 0)
			{
				return num;
			}
			return (p.Enter != q.Enter) ? ((!p.Enter) ? 1 : (-1)) : 0;
		};

		public bool Done { get; private set; }

		public VoxelizeJob(VoxelChunk ch)
		{
			Chunk = ch;
		}

		public bool Step(Stopwatch sw, double budgetMs)
		{
			while (_axis < 3)
			{
				ProcessLine(_axis, _line % 17, _line / 17);
				_line++;
				if (_line >= 289)
				{
					_line = 0;
					_axis++;
				}
				if (sw.Elapsed.TotalMilliseconds > budgetMs)
				{
					break;
				}
			}
			if (_axis >= 3 && !Done)
			{
				Finish();
				Done = true;
			}
			return Done;
		}

		private void ProcessLine(int a, int u, int v)
		{
			int num = (a + 1) % 3;
			int num2 = (a + 2) % 3;
			float cell = Chunk.Cell;
			float num3 = 16f * cell + 8f;
			V3 origin = Chunk.Origin;
			origin[num] += (float)u * cell;
			origin[num2] += (float)v * cell;
			origin[a] -= 4f;
			V3 v2 = V3.Axis(a);
			_events.Clear();
			CastPass(origin, v2, num3, forward: true);
			CastPass(origin + v2 * num3, -v2, num3, forward: false);
			_events.Sort(_cmp);
			BuildIntervals(num3);
			int[] coord = _coord;
			coord[num] = u;
			coord[num2] = v;
			for (int i = 0; i <= 16; i++)
			{
				coord[a] = i;
				int num4 = VoxelChunk.Idx(coord[0], coord[1], coord[2]);
				int num5 = a * 4913 + num4;
				if (_intervals.Count == 0)
				{
					_state[num5] = -1;
					continue;
				}
				float num6 = 4f + (float)i * cell;
				bool flag = false;
				float num7 = float.MaxValue;
				byte b = 0;
				for (int j = 0; j < _intervals.Count; j++)
				{
					Interval interval = _intervals[j];
					if (num6 >= interval.A && num6 <= interval.B)
					{
						flag = true;
					}
					float x = MathF.Abs(num6 - interval.A);
					float y = MathF.Abs(num6 - interval.B);
					float num8 = MathF.Min(x, y);
					if (num8 < num7 || (num6 >= interval.A && num6 <= interval.B && num8 <= num7))
					{
						num7 = num8;
						b = interval.Mat;
					}
				}
				_state[num5] = (flag ? ((sbyte)1) : ((sbyte)0));
				_dist[num5] = MathF.Min(num7, cell * 2f);
				_mat[num5] = b;
			}
		}

		private static void CastPass(V3 start, V3 dir, float L, bool forward)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Vector3 u = dir.U;
			float num = 0f;
			int mapLayerMask = StaticIndex.MapLayerMask;
			RaycastHit val = default(RaycastHit);
			for (int i = 0; i < 24; i++)
			{
				if (!(num < L))
				{
					break;
				}
				if (!Physics.Raycast((start + dir * num).U, u, ref val, L - num, mapLayerMask, (QueryTriggerInteraction)1))
				{
					break;
				}
				float num2 = num + ((RaycastHit)(ref val)).distance;
				Collider collider = ((RaycastHit)(ref val)).collider;
				if ((Object)(object)collider != (Object)null && StaticIndex.IsMapCollider(collider))
				{
					_events.Add(new Ev
					{
						T = (forward ? num2 : (L - num2)),
						Enter = forward,
						Mat = MaterialPalette.ForCollider(collider)
					});
				}
				num = num2 + 0.002f;
			}
		}

		private static void BuildIntervals(float L)
		{
			_intervals.Clear();
			float num = MathF.Max(0.05f, Settings.AssumedThickness.Value);
			int num2 = 0;
			float num3 = 0f;
			float num4 = 0f;
			byte mat = 0;
			foreach (Ev @event in _events)
			{
				if (@event.Enter)
				{
					if (num2 == 0)
					{
						num3 = @event.T;
						mat = @event.Mat;
					}
					num2++;
				}
				else if (num2 == 0)
				{
					float num5 = MathF.Max(num4, @event.T - num);
					if (@event.T - num5 > 0.0001f)
					{
						_intervals.Add(new Interval
						{
							A = num5,
							B = @event.T,
							Mat = @event.Mat
						});
					}
				}
				else
				{
					num2--;
					if (num2 == 0)
					{
						_intervals.Add(new Interval
						{
							A = num3,
							B = @event.T,
							Mat = mat
						});
					}
				}
				num4 = @event.T;
			}
			if (num2 > 0)
			{
				float b = MathF.Min(L, MathF.Max(num3 + num, num4));
				_intervals.Add(new Interval
				{
					A = num3,
					B = b,
					Mat = mat
				});
			}
		}

		private void Finish()
		{
			float num = Chunk.Cell * 2f;
			for (int i = 0; i < 4913; i++)
			{
				int num2 = 0;
				int num3 = 0;
				float num4 = float.MaxValue;
				float num5 = float.MaxValue;
				byte b = 0;
				byte b2 = 0;
				for (int j = 0; j < 3; j++)
				{
					int num6 = j * 4913 + i;
					sbyte b3 = _state[num6];
					if (b3 < 0)
					{
						continue;
					}
					if (b3 == 1)
					{
						num2++;
						if (_dist[num6] < num4)
						{
							num4 = _dist[num6];
							b = _mat[num6];
						}
					}
					else
					{
						num3++;
						if (_dist[num6] < num5)
						{
							num5 = _dist[num6];
							b2 = _mat[num6];
						}
					}
				}
				if (num2 == 0 && num3 == 0)
				{
					Chunk.Sdf0[i] = num;
					Chunk.Mat[i] = 0;
				}
				else
				{
					bool flag = num2 > num3 || (num2 == num3 && num4 <= num5);
					Chunk.Sdf0[i] = (flag ? (0f - MathF.Min(num4, num)) : MathF.Min(num5, num));
					Chunk.Mat[i] = (flag ? b : ((b2 != 0) ? b2 : b));
				}
			}
			Chunk.Voxelized = true;
		}
	}
	public sealed class VoxelChunk
	{
		public const int N = 16;

		public const int P = 17;

		public const int PointCount = 4913;

		public readonly Int3 Key;

		public readonly V3 Origin;

		public readonly float Cell;

		public readonly float[] Sdf0 = new float[4913];

		public readonly byte[] Mat = new byte[4913];

		public readonly float[] Damage = new float[4913];

		public readonly float[] Erosion = new float[4913];

		public readonly V3[] Disp = new V3[4913];

		public bool Voxelized;

		public bool HasErosion;

		public bool HasDisp;

		public int Capability = 2;

		public Box3 Bounds => new Box3(Origin, Origin + new V3(16f * Cell, 16f * Cell, 16f * Cell));

		public VoxelChunk(Int3 key, float cell)
		{
			Key = key;
			Cell = cell;
			Origin = new V3((float)(key.X * 16) * cell, (float)(key.Y * 16) * cell, (float)(key.Z * 16) * cell);
		}

		public static int Idx(int x, int y, int z)
		{
			return x + 17 * (y + 17 * z);
		}

		public V3 PointPos(int x, int y, int z)
		{
			return new V3(Origin.x + (float)x * Cell, Origin.y + (float)y * Cell, Origin.z + (float)z * Cell);
		}
	}
	public static class VoxelWorld
	{
		private static readonly Dictionary<Int3, VoxelChunk> _chunks = new Dictionary<Int3, VoxelChunk>();

		private static float _cell;

		public const float CoarseSize = 0.4f;

		private static readonly HashSet<Int3> _damaged = new HashSet<Int3>();

		public static int DamagedCoarseCount => _damaged.Count;

		public static float Cell => _cell;

		public static float ChunkWorld => _cell * 16f;

		public static int Count => _chunks.Count;

		public static IEnumerable<VoxelChunk> All => _chunks.Values;

		public static void MarkDamaged(V3 p)
		{
			_damaged.Add(Int3.Floor(p / 0.4f));
		}

		public static void DamageBoxesNear(Box3 region, float margin, List<Box3> outBoxes)
		{
			outBoxes.Clear();
			if (_damaged.Count == 0 || region.IsEmpty)
			{
				return;
			}
			Box3 box = region.Expanded(margin + 0.4f);
			Int3 @int = Int3.Floor(box.Min / 0.4f);
			Int3 int2 = Int3.Floor(box.Max / 0.4f);
			if ((long)(int2.X - @int.X + 1) * (long)(int2.Y - @int.Y + 1) * (int2.Z - @int.Z + 1) > _damaged.Count)
			{
				foreach (Int3 item in _damaged)
				{
					if (item.X >= @int.X && item.X <= int2.X && item.Y >= @int.Y && item.Y <= int2.Y && item.Z >= @int.Z && item.Z <= int2.Z)
					{
						outBoxes.Add(CoarseBox(item, margin));
					}
				}
				return;
			}
			for (int i = @int.Z; i <= int2.Z; i++)
			{
				for (int j = @int.Y; j <= int2.Y; j++)
				{
					for (int k = @int.X; k <= int2.X; k++)
					{
						Int3 int3 = new Int3(k, j, i);
						if (_damaged.Contains(int3))
						{
							outBoxes.Add(CoarseBox(int3, margin));
						}
					}
				}
			}
		}

		private static Box3 CoarseBox(Int3 k, float margin)
		{
			return new Box3(new V3(k.X, k.Y, k.Z) * 0.4f, new V3(k.X + 1, k.Y + 1, k.Z + 1) * 0.4f).Expanded(margin);
		}

		public static void Reset(float cell)
		{
			_chunks.Clear();
			_damaged.Clear();
			_cell = cell;
		}

		public static Int3 ChunkKeyOf(V3 p)
		{
			return Int3.Floor(p / ChunkWorld);
		}

		public static VoxelChunk Get(Int3 key)
		{
			if (!_chunks.TryGetValue(key, out var value))
			{
				return null;
			}
			return value;
		}

		public static VoxelChunk GetOrCreate(Int3 key)
		{
			if (!_chunks.TryGetValue(key, out var value))
			{
				value = new VoxelChunk(key, _cell);
				_chunks[key] = value;
			}
			return value;
		}

		public static void ChunksInSphere(V3 c, float r, List<Int3> outKeys)
		{
			outKeys.Clear();
			Int3 @int = ChunkKeyOf(c - new V3(r, r, r));
			Int3 int2 = ChunkKeyOf(c + new V3(r, r, r));
			float chunkWorld = ChunkWorld;
			for (int i = @int.Z; i <= int2.Z; i++)
			{
				for (int j = @int.Y; j <= int2.Y; j++)
				{
					for (int k = @int.X; k <= int2.X; k++)
					{
						if (new Box3(new V3((float)k * chunkWorld, (float)j * chunkWorld, (float)i * chunkWorld), new V3((float)(k + 1) * chunkWorld, (float)(j + 1) * chunkWorld, (float)(i + 1) * chunkWorld)).IntersectsSphere(c, r))
						{
							outKeys.Add(new Int3(k, j, i));
						}
					}
				}
			}
		}

		private static bool Locate(V3 p, out VoxelChunk ch, out int x, out int y, out int z, out float fx, out float fy, out float fz)
		{
			float num = p.x / _cell;
			float num2 = p.y / _cell;
			float num3 = p.z / _cell;
			int num4 = (int)MathF.Floor(num);
			int num5 = (int)MathF.Floor(num2);
			int num6 = (int)MathF.Floor(num3);
			fx = num - (float)num4;
			fy = num2 - (float)num5;
			fz = num3 - (float)num6;
			Int3 key = new Int3(Int3.FloorDiv(num4, 16), Int3.FloorDiv(num5, 16), Int3.FloorDiv(num6, 16));
			x = num4 - key.X * 16;
			y = num5 - key.Y * 16;
			z = num6 - key.Z * 16;
			_chunks.TryGetValue(key, out ch);
			if (ch != null)
			{
				return ch.Voxelized;
			}
			return false;
		}

		private static float Tri(float[] a, int x, int y, int z, float fx, float fy, float fz)
		{
			int num = VoxelChunk.Idx(x, y, z);
			float num2 = a[num] + (a[num + 1] - a[num]) * fx;
			float num3 = a[num + 17] + (a[num + 17 + 1] - a[num + 17]) * fx;
			float num4 = a[num + 289] + (a[num + 289 + 1] - a[num + 289]) * fx;
			float num5 = a[num + 289 + 17] + (a[num + 289 + 17 + 1] - a[num + 289 + 17]) * fx;
			float num6 = num2 + (num3 - num2) * fy;
			float num7 = num4 + (num5 - num4) * fy;
			return num6 + (num7 - num6) * fz;
		}

		public static float SampleSdf0(V3 p, float fallback)
		{
			if (!Locate(p, out var ch, out var x, out var y, out var z, out var fx, out var fy, out var fz))
			{
				return fallback;
			}
			return Tri(ch.Sdf0, x, y, z, fx, fy, fz);
		}

		public static float SampleErosion(V3 p)
		{
			if (!Locate(p, out var ch, out var x, out var y, out var z, out var fx, out var fy, out var fz))
			{
				return 0f;
			}
			if (!ch.HasErosion)
			{
				return 0f;
			}
			return Tri(ch.Erosion, x, y, z, fx, fy, fz);
		}

		public static V3 SampleDisp(V3 p)
		{
			if (!Locate(p, out var ch, out var x, out var y, out var z, out var fx, out var fy, out var fz))
			{
				return V3.Zero;
			}
			if (!ch.HasDisp)
			{
				return V3.Zero;
			}
			V3[] disp = ch.Disp;
			int num = VoxelChunk.Idx(x, y, z);
			V3 a = V3.Lerp(disp[num], disp[num + 1], fx);
			V3 b = V3.Lerp(disp[num + 17], disp[num + 17 + 1], fx);
			V3 a2 = V3.Lerp(disp[num + 289], disp[num + 289 + 1], fx);
			return V3.Lerp(b: V3.Lerp(a2, V3.Lerp(disp[num + 289 + 17], disp[num + 289 + 17 + 1], fx), fy), a: V3.Lerp(a, b, fy), t: fz);
		}

		public static bool TryGetPoint(int gx, int gy, int gz, out VoxelChunk ch, out int idx)
		{
			Int3 key = new Int3(Int3.FloorDiv(gx, 16), Int3.FloorDiv(gy, 16), Int3.FloorDiv(gz, 16));
			idx = 0;
			if (!_chunks.TryGetValue(key, out ch) || !ch.Voxelized)
			{
				return false;
			}
			idx = VoxelChunk.Idx(gx - key.X * 16, gy - key.Y * 16, gz - key.Z * 16);
			return true;
		}

		public static void ForEachCopy(int gx, int gy, int gz, Action<VoxelChunk, int> act)
		{
			int num = Int3.FloorDiv(gx, 16);
			int num2 = Int3.FloorDiv(gy, 16);
			int num3 = Int3.FloorDiv(gz, 16);
			int num4 = gx - num * 16;
			int num5 = gy - num2 * 16;
			int num6 = gz - num3 * 16;
			for (int i = 0; i <= ((num6 == 0) ? 1 : 0); i++)
			{
				for (int j = 0; j <= ((num5 == 0) ? 1 : 0); j++)
				{
					for (int k = 0; k <= ((num4 == 0) ? 1 : 0); k++)
					{
						Int3 key = new Int3(num - k, num2 - j, num3 - i);
						if (_chunks.TryGetValue(key, out var value) && value.Voxelized)
						{
							act(value, VoxelChunk.Idx(num4 + k * 16, num5 + j * 16, num6 + i * 16));
						}
					}
				}
			}
		}

		public static float FieldAt(VoxelChunk ch, int idx, V3 pointPos)
		{
			float num = ch.Sdf0[idx];
			if (ch.HasDisp)
			{
				V3 v = ch.Disp[idx];
				if (v.SqrMag > 1E-08f)
				{
					num = SampleSdf0(pointPos - v, num);
				}
			}
			return num + (ch.HasErosion ? ch.Erosion[idx] : 0f);
		}

		public static float FieldAtGlobal(int gx, int gy, int gz, out float erosion, out byte mat)
		{
			erosion = 0f;
			mat = 0;
			if (!TryGetPoint(gx, gy, gz, out var ch, out var idx))
			{
				return _cell * 2f;
			}
			erosion = (ch.HasErosion ? ch.Erosion[idx] : 0f);
			mat = ch.Mat[idx];
			return FieldAt(ch, idx, new V3((float)gx * _cell, (float)gy * _cell, (float)gz * _cell));
		}

		public static void Clear()
		{
			_chunks.Clear();
			_damaged.Clear();
		}

		public static void RemoveInBox(Box3 b, List<Int3> removed)
		{
			removed.Clear();
			foreach (KeyValuePair<Int3, VoxelChunk> chunk in _chunks)
			{
				if (chunk.Value.Bounds.Intersects(b))
				{
					removed.Add(chunk.Key);
				}
			}
			foreach (Int3 item in removed)
			{
				_chunks.Remove(item);
			}
		}
	}
}
namespace MapDestruction.Util
{
	public static class BackgroundJobs
	{
		public sealed class Job
		{
			internal Func<object> Work;

			public volatile bool Done;

			public object Result;

			public string Error;

			public volatile bool Cancelled;
		}

		private static readonly ConcurrentQueue<Job> _q = new ConcurrentQueue<Job>();

		private static readonly AutoResetEvent _wake = new AutoResetEvent(initialState: false);

		private static Thread _thread;

		public static Job Run(Func<object> work)
		{
			Job job = new Job
			{
				Work = work
			};
			if (_thread == null)
			{
				_thread = new Thread(Loop)
				{
					IsBackground = true,
					Name = "MapDestruction 계산",
					Priority = ThreadPriority.BelowNormal
				};
				_thread.Start();
			}
			_q.Enqueue(job);
			_wake.Set();
			return job;
		}

		private static void Loop()
		{
			while (true)
			{
				if (_q.TryDequeue(out var result))
				{
					if (result.Cancelled)
					{
						result.Done = true;
						continue;
					}
					try
					{
						result.Result = result.Work();
					}
					catch (Exception ex)
					{
						result.Error = ex.Message;
					}
					result.Done = true;
				}
				else
				{
					_wake.WaitOne(1000);
				}
			}
		}
	}
	public static class Fracture
	{
		public static float Cell(V3 q, int seed, out float edge)
		{
			int num = (int)MathF.Floor(q.x);
			int num2 = (int)MathF.Floor(q.y);
			int num3 = (int)MathF.Floor(q.z);
			float num4 = float.MaxValue;
			float num5 = float.MaxValue;
			int x = 0;
			int y = 0;
			int z = 0;
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					for (int k = -1; k <= 1; k++)
					{
						int num6 = num + k;
						int num7 = num2 + j;
						int num8 = num3 + i;
						float num9 = (float)num6 + 0.1f + 0.8f * MathUtil.Hash01(num6, num7, num8, seed) - q.x;
						float num10 = (float)num7 + 0.1f + 0.8f * MathUtil.Hash01(num6, num7, num8, seed + 1) - q.y;
						float num11 = (float)num8 + 0.1f + 0.8f * MathUtil.Hash01(num6, num7, num8, seed + 2) - q.z;
						float num12 = num9 * num9 + num10 * num10 + num11 * num11;
						if (num12 < num4)
						{
							num5 = num4;
							num4 = num12;
							x = num6;
							y = num7;
							z = num8;
						}
						else if (num12 < num5)
						{
							num5 = num12;
						}
					}
				}
			}
			edge = (MathF.Sqrt(num5) - MathF.Sqrt(num4)) * 0.5f;
			return MathUtil.Hash01(x, y, z, seed + 3);
		}

		public static V3 Warp(V3 p, MaterialProfile prof, V3 grain)
		{
			V3 stretch = prof.Stretch;
			V3 v = new V3(p.x * stretch.x, p.y * stretch.y, p.z * stretch.z) / prof.ChunkSize;
			if (prof.GrainStretch != 1f && grain.SqrMag > 0.5f)
			{
				v += grain * (V3.Dot(grain, v) * (prof.GrainStretch - 1f));
			}
			return v;
		}

		public static float ErosionMult(V3 p, MaterialProfile prof, V3 grain, float smooth)
		{
			if (!Chunky(prof))
			{
				return 0.6f + 0.8f * smooth;
			}
			float edge;
			return MultFrom(Cell(Warp(p, prof, grain), SeedOf(prof), out edge), edge, prof, smooth);
		}

		public static bool Chunky(MaterialProfile prof)
		{
			if (prof != null && prof.ChunkSize > 0f)
			{
				return prof.Chunkiness > 0f;
			}
			return false;
		}

		public static int SeedOf(MaterialProfile prof)
		{
			return 4242 + prof.Id * 31;
		}

		public static float MultFrom(float v, float edge, MaterialProfile prof, float smooth)
		{
			float num = 0.6f + 0.8f * smooth;
			float num2 = 0.5f + 0.9f * v;
			num2 += 0.25f * MathUtil.Clamp01(1f - edge / 0.12f);
			return num + (num2 - num) * prof.Chunkiness;
		}

		public static float DistanceScale(float v, MaterialProfile prof)
		{
			return 1f - prof.Chunkiness * 0.3f * (v - 0.5f);
		}

		public static float Relief(V3 p, MaterialProfile prof, V3 grain)
		{
			if (prof == null || prof.Rough <= 0f)
			{
				return 0f;
			}
			V3 stretch = prof.Stretch;
			V3 v = new V3(p.x * stretch.x, p.y * stretch.y, p.z * stretch.z);
			float num = 1f - MathF.Abs(MathUtil.ValueNoise(v / 0.3f, 911 + prof.Id) * 2f - 1f);
			float num2 = MathUtil.ValueNoise(v / 0.13f, 937 + prof.Id) - 0.5f;
			return prof.Rough * ((num - 0.55f) * 1.8f + num2 * 0.8f);
		}
	}
	public static class GpuGuard
	{
		public const string Gpu = "gpu";

		public const string MeshInfo = "meshinfo";

		private static string _path;

		private static bool _active;

		public static string PendingNotice;

		private static string PathOf()
		{
			if (_path != null)
			{
				return _path;
			}
			try
			{
				_path = Path.Combine(MelonEnvironment.UserDataDirectory, "MapDestruction_native.lock");
			}
			catch
			{
				_path = "MapDestruction_native.lock";
			}
			return _path;
		}

		public static void CheckPreviousCrash()
		{
			try
			{
				string path = PathOf();
				if (File.Exists(path))
				{
					string text = "";
					try
					{
						text = File.ReadAllText(path).Trim();
					}
					catch
					{
					}
					try
					{
						File.Delete(path);
					}
					catch
					{
					}
					int num = text.IndexOf('|');
					string obj3 = ((num >= 0) ? text.Substring(0, num) : text);
					string text2 = ((num >= 0) ? text.Substring(num + 1) : "");
					string value;
					if (obj3 == "meshinfo")
					{
						Settings.MeshInfoQueries.Value = false;
						value = "잠긴 메시의 삼각형 수 조회";
					}
					else
					{
						Settings.GpuMeshRead.Value = false;
						value = "그래픽 카드 메모리 읽기";
					}
					Settings.Save();
					Log.Warn($"[안전장치] 지난번 실행에서 {value} 도중 게임이 꺼졌습니다{((text2.Length > 0) ? (" (대상: " + text2 + ")") : "")}. 이 기능을 자동으로 껐습니다.");
					PendingNotice = "Safety: a risky feature was turned off after the last crash (see log)";
				}
			}
			catch
			{
			}
		}

		public static void Begin(string feature, string what)
		{
			try
			{
				File.WriteAllText(PathOf(), feature + "|" + (what ?? "?"));
				_active = true;
			}
			catch
			{
			}
		}

		public static void End()
		{
			if (!_active)
			{
				return;
			}
			_active = false;
			try
			{
				File.Delete(PathOf());
			}
			catch
			{
			}
		}
	}
	public struct V3
	{
		public float x;

		public float y;

		public float z;

		public static readonly V3 Zero = new V3(0f, 0f, 0f);

		public static readonly V3 One = new V3(1f, 1f, 1f);

		public float SqrMag => x * x + y * y + z * z;

		public float Mag => MathF.Sqrt(x * x + y * y + z * z);

		public V3 Normalized
		{
			get
			{
				float mag = Mag;
				if (!(mag > 1E-08f))
				{
					return Zero;
				}
				return this / mag;
			}
		}

		public float this[int i]
		{
			get
			{
				return i switch
				{
					1 => y, 
					0 => x, 
					_ => z, 
				};
			}
			set
			{
				switch (i)
				{
				case 0:
					x = value;
					break;
				case 1:
					y = value;
					break;
				default:
					z = value;
					break;
				}
			}
		}

		public Vector3 U => new Vector3
		{
			x = x,
			y = y,
			z = z
		};

		public V3(float x, float y, float z)
		{
			this.x = x;
			this.y = y;
			this.z = z;
		}

		public static V3 operator +(V3 a, V3 b)
		{
			return new V3(a.x + b.x, a.y + b.y, a.z + b.z);
		}

		public static V3 operator -(V3 a, V3 b)
		{
			return new V3(a.x - b.x, a.y - b.y, a.z - b.z);
		}

		public static V3 operator -(V3 a)
		{
			return new V3(0f - a.x, 0f - a.y, 0f - a.z);
		}

		public static V3 operator *(V3 a, float s)
		{
			return new V3(a.x * s, a.y * s, a.z * s);
		}

		public static V3 operator *(float s, V3 a)
		{
			return new V3(a.x * s, a.y * s, a.z * s);
		}

		public static V3 operator /(V3 a, float s)
		{
			float num = 1f / s;
			return new V3(a.x * num, a.y * num, a.z * num);
		}

		public static float Dot(V3 a, V3 b)
		{
			return a.x * b.x + a.y * b.y + a.z * b.z;
		}

		public static V3 Cross(V3 a, V3 b)
		{
			return new V3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
		}

		public static V3 Lerp(V3 a, V3 b, float t)
		{
			return new V3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t);
		}

		public static V3 Min(V3 a, V3 b)
		{
			return new V3(MathF.Min(a.x, b.x), MathF.Min(a.y, b.y), MathF.Min(a.z, b.z));
		}

		public static V3 Max(V3 a, V3 b)
		{
			return new V3(MathF.Max(a.x, b.x), MathF.Max(a.y, b.y), MathF.Max(a.z, b.z));
		}

		public static V3 Axis(int a)
		{
			return a switch
			{
				1 => new V3(0f, 1f, 0f), 
				0 => new V3(1f, 0f, 0f), 
				_ => new V3(0f, 0f, 1f), 
			};
		}

		public static V3 F(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new V3(v.x, v.y, v.z);
		}

		public static V3 RotateFromTo(V3 v, V3 a, V3 b)
		{
			V3 v2 = Cross(a, b);
			float mag = v2.Mag;
			float num = Dot(a, b);
			if (mag < 1E-06f)
			{
				if (num > 0f)
				{
					return v;
				}
				V3 v3 = ((MathF.Abs(a.x) < 0.9f) ? Cross(a, new V3(1f, 0f, 0f)).Normalized : Cross(a, new V3(0f, 1f, 0f)).Normalized);
				return v3 * (2f * Dot(v, v3)) - v;
			}
			V3 v4 = v2 / mag;
			return v * num + Cross(v4, v) * mag + v4 * (Dot(v4, v) * (1f - num));
		}

		public override string ToString()
		{
			return $"({x:0.###}, {y:0.###}, {z:0.###})";
		}
	}
	public struct V2
	{
		public float x;

		public float y;

		public Vector2 U => new Vector2
		{
			x = x,
			y = y
		};

		public V2(float x, float y)
		{
			this.x = x;
			this.y = y;
		}

		public static V2 Lerp(V2 a, V2 b, float t)
		{
			return new V2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
		}

		public static V2 operator +(V2 a, V2 b)
		{
			return new V2(a.x + b.x, a.y + b.y);
		}

		public static V2 operator -(V2 a, V2 b)
		{
			return new V2(a.x - b.x, a.y - b.y);
		}

		public static V2 operator *(V2 a, float s)
		{
			return new V2(a.x * s, a.y * s);
		}

		public static V2 F(Vector2 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return new V2(v.x, v.y);
		}
	}
	public struct V4
	{
		public float x;

		public float y;

		public float z;

		public float w;

		public V3 Xyz => new V3(x, y, z);

		public Vector4 U => new Vector4
		{
			x = x,
			y = y,
			z = z,
			w = w
		};

		public V4(float x, float y, float z, float w)
		{
			this.x = x;
			this.y = y;
			this.z = z;
			this.w = w;
		}

		public static V4 F(Vector4 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new V4(v.x, v.y, v.z, v.w);
		}
	}
	public struct C4
	{
		public float r;

		public float g;

		public float b;

		public float a;

		public static readonly C4 White = new C4(1f, 1f, 1f, 1f);

		public Color U => new Color
		{
			r = r,
			g = g,
			b = b,
			a = a
		};

		public C4(float r, float g, float b, float a)
		{
			this.r = r;
			this.g = g;
			this.b = b;
			this.a = a;
		}

		public static C4 Lerp(C4 p, C4 q, float t)
		{
			return new C4(p.r + (q.r - p.r) * t, p.g + (q.g - p.g) * t, p.b + (q.b - p.b) * t, p.a + (q.a - p.a) * t);
		}

		public static C4 F(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new C4(c.r, c.g, c.b, c.a);
		}
	}
	public struct Box3
	{
		public V3 Min;

		public V3 Max;

		public static Box3 Empty => new Box3(new V3(float.MaxValue, float.MaxValue, float.MaxValue), new V3(float.MinValue, float.MinValue, float.MinValue));

		public bool IsEmpty => Min.x > Max.x;

		public V3 Center => (Min + Max) * 0.5f;

		public V3 Size => Max - Min;

		public Box3(V3 min, V3 max)
		{
			Min = min;
			Max = max;
		}

		public void Encapsulate(V3 p)
		{
			Min = V3.Min(Min, p);
			Max = V3.Max(Max, p);
		}

		public void Encapsulate(Box3 b)
		{
			if (!b.IsEmpty)
			{
				Min = V3.Min(Min, b.Min);
				Max = V3.Max(Max, b.Max);
			}
		}

		public Box3 Expanded(float d)
		{
			return new Box3(Min - new V3(d, d, d), Max + new V3(d, d, d));
		}

		public V3 ClosestPoint(V3 p)
		{
			return V3.Min(V3.Max(p, Min), Max);
		}

		public bool Contains(V3 p)
		{
			if (p.x >= Min.x && p.x <= Max.x && p.y >= Min.y && p.y <= Max.y && p.z >= Min.z)
			{
				return p.z <= Max.z;
			}
			return false;
		}

		public bool Intersects(Box3 o)
		{
			if (Min.x <= o.Max.x && Max.x >= o.Min.x && Min.y <= o.Max.y && Max.y >= o.Min.y && Min.z <= o.Max.z)
			{
				return Max.z >= o.Min.z;
			}
			return false;
		}

		public bool IntersectsSphere(V3 c, float r)
		{
			float num = MathF.Max(MathF.Max(Min.x - c.x, 0f), c.x - Max.x);
			float num2 = MathF.Max(MathF.Max(Min.y - c.y, 0f), c.y - Max.y);
			float num3 = MathF.Max(MathF.Max(Min.z - c.z, 0f), c.z - Max.z);
			return num * num + num2 * num2 + num3 * num3 <= r * r;
		}

		public static Box3 FromBounds(Bounds b)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			V3 v = V3.F(((Bounds)(ref b)).center);
			V3 v2 = V3.F(((Bounds)(ref b)).extents);
			return new Box3(v - v2, v + v2);
		}
	}
	public struct Mat4
	{
		public float m00;

		public float m01;

		public float m02;

		public float m03;

		public float m10;

		public float m11;

		public float m12;

		public float m13;

		public float m20;

		public float m21;

		public float m22;

		public float m23;

		public static Mat4 Identity => new Mat4
		{
			m00 = 1f,
			m11 = 1f,
			m22 = 1f
		};

		public float Det3 => m00 * (m11 * m22 - m12 * m21) - m01 * (m10 * m22 - m12 * m20) + m02 * (m10 * m21 - m11 * m20);

		public static Mat4 F(Matrix4x4 m)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			return new Mat4
			{
				m00 = m.m00,
				m01 = m.m01,
				m02 = m.m02,
				m03 = m.m03,
				m10 = m.m10,
				m11 = m.m11,
				m12 = m.m12,
				m13 = m.m13,
				m20 = m.m20,
				m21 = m.m21,
				m22 = m.m22,
				m23 = m.m23
			};
		}

		public V3 Point(V3 p)
		{
			return new V3(m00 * p.x + m01 * p.y + m02 * p.z + m03, m10 * p.x + m11 * p.y + m12 * p.z + m13, m20 * p.x + m21 * p.y + m22 * p.z + m23);
		}

		public V3 Vector(V3 v)
		{
			return new V3(m00 * v.x + m01 * v.y + m02 * v.z, m10 * v.x + m11 * v.y + m12 * v.z, m20 * v.x + m21 * v.y + m22 * v.z);
		}

		public Mat4 NormalMatrix()
		{
			float det = Det3;
			if (MathF.Abs(det) < 1E-12f)
			{
				return this;
			}
			float num = 1f / det;
			return new Mat4
			{
				m00 = (m11 * m22 - m12 * m21) * num,
				m01 = (0f - (m10 * m22 - m12 * m20)) * num,
				m02 = (m10 * m21 - m11 * m20) * num,
				m10 = (0f - (m01 * m22 - m02 * m21)) * num,
				m11 = (m00 * m22 - m02 * m20) * num,
				m12 = (0f - (m00 * m21 - m01 * m20)) * num,
				m20 = (m01 * m12 - m02 * m11) * num,
				m21 = (0f - (m00 * m12 - m02 * m10)) * num,
				m22 = (m00 * m11 - m01 * m10) * num
			};
		}
	}
	public readonly struct Int3 : IEquatable<Int3>
	{
		public readonly int X;

		public readonly int Y;

		public readonly int Z;

		public Int3(int x, int y, int z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public bool Equals(Int3 o)
		{
			if (X == o.X && Y == o.Y)
			{
				return Z == o.Z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is Int3 o)
			{
				return Equals(o);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (X * 73856093) ^ (Y * 19349663) ^ (Z * 83492791);
		}

		public static bool operator ==(Int3 a, Int3 b)
		{
			return a.Equals(b);
		}

		public static bool operator !=(Int3 a, Int3 b)
		{
			return !a.Equals(b);
		}

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

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

		public static Int3 operator *(Int3 a, int s)
		{
			return new Int3(a.X * s, a.Y * s, a.Z * s);
		}

		public static int FloorDiv(int a, int d)
		{
			if (a < 0)
			{
				return -((-a + d - 1) / d);
			}
			return a / d;
		}

		public static Int3 FloorDiv(Int3 a, int d)
		{
			return new Int3(FloorDiv(a.X, d), FloorDiv(a.Y, d), FloorDiv(a.Z, d));
		}

		public static Int3 Floor(V3 v)
		{
			return new Int3((int)MathF.Floor(v.x), (int)MathF.Floor(v.y), (int)MathF.Floor(v.z));
		}

		public override string ToString()
		{
			return $"({X},{Y},{Z})";
		}
	}
	public static class MathUtil
	{
		public static float Hash01(int x, int y, int z, int seed)
		{
			int num = x * 374761393 + y * 668265263 + z * 1274126177 + seed * 144665;
			int num2 = (num ^ (num >>> 13)) * 1274126177;
			return (float)(uint)((num2 ^ (num2 >>> 16)) & 0xFFFFFF) / 16777215f;
		}

		private static float Smooth(float t)
		{
			return t * t * (3f - 2f * t);
		}

		public static float ValueNoise(V3 p, int seed)
		{
			int num = (int)MathF.Floor(p.x);
			int num2 = (int)MathF.Floor(p.y);
			int num3 = (int)MathF.Floor(p.z);
			float num4 = Smooth(p.x - (float)num);
			float num5 = Smooth(p.y - (float)num2);
			float num6 = Smooth(p.z - (float)num3);
			float num7 = Hash01(num, num2, num3, seed);
			float num8 = Hash01(num + 1, num2, num3, seed);
			float num9 = Hash01(num, num2 + 1, num3, seed);
			float num10 = Hash01(num + 1, num2 + 1, num3, seed);
			float num11 = Hash01(num, num2, num3 + 1, seed);
			float num12 = Hash01(num + 1, num2, num3 + 1, seed);
			float num13 = Hash01(num, num2 + 1, num3 + 1, seed);
			float num14 = Hash01(num + 1, num2 + 1, num3 + 1, seed);
			float num15 = num7 + (num8 - num7) * num4;
			float num16 = num9 + (num10 - num9) * num4;
			float num17 = num11 + (num12 - num11) * num4;
			float num18 = num13 + (num14 - num13) * num4;
			float num19 = num15 + (num16 - num15) * num5;
			float num20 = num17 + (num18 - num17) * num5;
			return num19 + (num20 - num19) * num6;
		}

		public static float Fbm(V3 p, int seed)
		{
			return ValueNoise(p, seed) * 0.65f + ValueNoise(p * 2.13f, seed + 17) * 0.35f;
		}

		public static float Falloff(float x)
		{
			if (x >= 1f)
			{
				return 0f;
			}
			float num = 1f - x * x;
			return num * num;
		}

		public static float Clamp(float v, float a, float b)
		{
			if (!(v < a))
			{
				if (!(v > b))
				{
					return v;
				}
				return b;
			}
			return a;
		}

		public static float Clamp01(float v)
		{
			if (!(v < 0f))
			{
				if (!(v > 1f))
				{
					return v;
				}
				return 1f;
			}
			return 0f;
		}
	}
	public sealed class Rng
	{
		private uint _s;

		public float Value => (float)(NextU() & 0xFFFFFF) / 16777215f;

		public Rng(uint seed)
		{
			_s = ((seed == 0) ? 2654435769u : seed);
		}

		public uint NextU()
		{
			_s ^= _s << 13;
			_s ^= _s >> 17;
			_s ^= _s << 5;
			return _s;
		}

		public float Range(float a, float b)
		{
			return a + (b - a) * Value;
		}

		public int Range(int a, int b)
		{
			return a + (int)(NextU() % (uint)Math.Max(1, b - a));
		}

		public V3 InsideSphere()
		{
			V3 result;
			do
			{
				result = new V3(Range(-1f, 1f), Range(-1f, 1f), Range(-1f, 1f));
			}
			while (!(result.SqrMag <= 1f));
			return result;
		}
	}
	internal static class UnityApi
	{
		public struct SubMeshInfo
		{
			public int IndexStart;

			public int IndexCount;

			public int BaseVertex;

			public int FirstVertex;

			public int VertexCount;

			public int Topology;
		}

		private const BindingFlags Inst = BindingFlags.Instance | BindingFlags.Public;

		private static readonly Dictionary<string, PropertyInfo> _props = new Dictionary<string, PropertyInfo>();

		private static readonly Dictionary<string, MethodInfo> _methods = new Dictionary<string, MethodInfo>();

		private static readonly HashSet<string> _warned = new HashSet<string>();

		public const int AttrPosition = 0;

		public const int AttrNormal = 1;

		public const int AttrTangent = 2;

		public const int AttrColor = 3;

		public const int AttrTexCoord0 = 4;

		public const int AttrTexCoord1 = 5;

		public const int FmtFloat32 = 0;

		public const int FmtFloat16 = 1;

		public const int FmtUNorm8 = 2;

		public const int FmtSNorm8 = 3;

		public const int FmtUNorm16 = 4;

		public const int FmtSNorm16 = 5;

		public static readonly string[] RendererProps = new string[12]
		{
			"shadowCastingMode", "receiveShadows", "lightmapIndex", "lightmapScaleOffset", "realtimeLightmapIndex", "realtimeLightmapScaleOffset", "lightProbeUsage", "reflectionProbeUsage", "renderingLayerMask", "probeAnchor",
			"allowOcclusionWhenDynamic", "staticShadowCaster"
		};

		public static bool GpuReadAvailable { get; private set; }

		public static string LastError { get; private set; }

		public static bool CanUse32BitIndices => FindProp(typeof(Mesh), "indexFormat")?.CanWrite ?? false;

		public static int FormatSize(int fmt)
		{
			switch (fmt)
			{
			default:
				return 1;
			case 1:
			case 4:
			case 5:
				return 2;
			case 0:
				return 4;
			}
		}

		public static void Init()
		{
			bool flag = FindMethod(typeof(Mesh), "GetVertexBufferImpl", 1) != null || FindMethod(typeof(Mesh), "GetVertexBuffer", 1) != null;
			bool flag2 = FindMethod(typeof(Mesh), "GetIndexBufferImpl", 0) != null || FindMethod(typeof(Mesh), "GetIndexBuffer", 0) != null;
			bool flag3 = FindMethod(typeof(Mesh), "GetSubMesh", 1) != null;
			bool flag4 = FindMethod(typeof(Mesh), "GetVertexAttributeOffset", 1) != null;
			GpuReadAvailable = flag && flag2 && flag3 && flag4;
			Log.Msg($"[API] GPU 메시 읽기: {(GpuReadAvailable ? "가능" : "불가")} (VB:{flag} IB:{flag2} SubMesh:{flag3} Attr:{flag4})");
			Log.Msg($"[API] subMeshStartIndex: {FindProp(typeof(MeshRenderer), "subMeshStartIndex") != null}, isPartOfStaticBatch: {FindProp(typeof(Renderer), "isPartOfStaticBatch") != null}");
		}

		private static PropertyInfo FindProp(Type t, string name)
		{
			string key = t.FullName + "." + name;
			if (_props.TryGetValue(key, out var value))
			{
				return value;
			}
			try
			{
				value = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
			}
			catch
			{
				value = null;
			}
			_props[key] = value;
			return value;
		}

		private static MethodInfo FindMethod(Type t, string name, int paramCount, Func<ParameterInfo[], bool> extra = null, string tag = "")
		{
			string key = t.FullName + "." + name + "/" + paramCount + tag;
			if (_methods.TryGetValue(key, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != name) && !methodInfo.IsGenericMethodDefinition)
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						if (parameters.Length == paramCount && (extra == null || extra(parameters)))
						{
							value = methodInfo;
							break;
						}
					}
				}
			}
			catch
			{
			}
			_methods[key] = value;
			return value;
		}

		private static void WarnOnce(string what, Exception e = null)
		{
			if (_warned.Add(what))
			{
				Log.Warn("[API] " + what + " 사용 불가" + ((e != null) ? (": " + (e.InnerException ?? e).Message) : ""));
			}
		}

		private static object Get(object o, string prop)
		{
			PropertyInfo propertyInfo = FindProp(o.GetType(), prop);
			if (propertyInfo == null)
			{
				return null;
			}
			try
			{
				return propertyInfo.GetValue(o);
			}
			catch (Exception e)
			{
				WarnOnce(prop, e);
				return null;
			}
		}

		private static bool Set(object o, string prop, object value)
		{
			PropertyInfo propertyInfo = FindProp(o.GetType(), prop);
			if (propertyInfo == null || !propertyInfo.CanWrite)
			{
				WarnOnce(o.GetType().Name + "." + prop);
				return false;
			}
			try
			{
				propertyInfo.SetValue(o, value);
				return true;
			}
			catch (Exception e)
			{
				WarnOnce(prop, e);
				return false;
			}
		}

		private static object EnumValue(Type enumType, int v)
		{
			return Enum.ToObject(enumType, v);
		}

		private static int ReadIntMember(object o, string name)
		{
			Type type = o.GetType();
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public);
			if (property != null)
			{
				return Convert.ToInt32(property.GetValue(o));
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.Name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return Convert.ToInt32(fieldInfo.GetValue(o));
				}
			}
			throw new MissingMemberException(type.Name, name);
		}

		public static void CopyProperties(object src, object dst, string[] names)
		{
			foreach (string text in names)
			{
				PropertyInfo propertyInfo = FindProp(src.GetType(), text);
				PropertyInfo propertyInfo2 = FindProp(dst.GetType(), text);
				if (!(propertyInfo == null) && !(propertyInfo2 == null) && propertyInfo2.CanWrite)
				{
					try
					{
						propertyInfo2.SetValue(dst, propertyInfo.GetValue(src));
					}
					catch (Exception e)
					{
						WarnOnce("복사 " + text, e);
					}
				}
			}
		}

		public static void MakeProbeLit(Renderer r)
		{
			Set(r, "lightmapIndex", -1);
			PropertyInfo propertyInfo = FindProp(((object)r).GetType(), "lightProbeUsage");
			if (propertyInfo != null && propertyInfo.CanWrite)
			{
				try
				{
					propertyInfo.SetValue(r, EnumValue(propertyInfo.PropertyType, 1));
				}
				catch
				{
				}
			}
		}

		public static bool IsStaticBatched(Renderer r)
		{
			object obj = Get(r, "isPartOfStaticBatch");
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		public static int SubMeshStartIndex(MeshRenderer r)
		{
			object obj = Get(r, "subMeshStartIndex");
			if (obj == null)
			{
				return -1;
			}
			return Convert.ToInt32(obj);
		}

		public static void ForceLod(LODGroup g, int level)
		{
			MethodInfo methodInfo = FindMethod(typeof(LODGroup), "ForceLOD", 1);
			if (methodInfo == null)
			{
				WarnOnce("LODGroup.ForceLOD");
				return;
			}
			try
			{
				methodInfo.Invoke(g, new object[1] { level });
			}
			catch (Exception e)
			{
				WarnOnce("ForceLOD", e);
			}
		}

		public static void SetTangents(Mesh m, Vector4[] v)
		{
			Set(m, "tangents", new Il2CppStructArray<Vector4>(v));
		}

		public static void SetUv2(Mesh m, Vector2[] v)
		{
			Set(m, "uv2", new Il2CppStructArray<Vector2>(v));
		}

		public static void SetColors(Mesh m, Color[] v)
		{
			Set(m, "colors", new Il2CppStructArray<Color>(v));
		}

		public static bool SetIndexFormat32(Mesh m)
		{
			PropertyInfo propertyInfo = FindProp(typeof(Mesh), "indexFormat");
			if (propertyInfo == null || !propertyInfo.CanWrite)
			{
				WarnOnce("Mesh.indexFormat");
				return false;
			}
			try
			{
				propertyInfo.SetValue(m, EnumValue(propertyInfo.PropertyType, 1));
				return true;
			}
			catch (Exception e)
			{
				WarnOnce("indexFormat", e);
				return false;
			}
		}

		public static void SetSubmeshTriangles(Mesh m, int[] tris, int sub)
		{
			Il2CppStructArray<int> val = new Il2CppStructArray<int>(tris);
			MethodInfo methodInfo = null;
			for (int i = 2; i <= 4; i++)
			{
				if (!(methodInfo == null))
				{
					break;
				}
				methodInfo = FindMethod(typeof(Mesh), "SetTriangles", i, (ParameterInfo[] ps) => ps[0].ParameterType.Name.StartsWith("Il2CppStructArray") && ps[1].ParameterType == typeof(int), "arr");
			}
			if (methodInfo != null)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				object[] array = new object[parameters.Length];
				array[0] = val;
				array[1] = sub;
				for (int num = 2; num < parameters.Length; num++)
				{
					array[num] = ((parameters[num].ParameterType == typeof(bool)) ? ((object)true) : ((object)0));
				}
				try
				{
					methodInfo.Invoke(m, array);
					return;
				}
				catch (Exception e)
				{
					WarnOnce("SetTriangles", e);
				}
			}
			if (sub == 0)
			{
				m.triangles = val;
			}
		}

		public static int IsReadable(Mesh m)
		{
			if (!(Get(m, "isReadable") is bool flag))
			{
				return -1;
			}
			return flag ? 1 : 0;
		}

		public static Vector4[] GetTangents(Mesh m)
		{
			if (!(Get(m, "tangents") is Il2CppStructArray<Vector4> val))
			{
				return null;
			}
			return Il2CppArrayBase<Vector4>.op_Implicit((Il2CppArrayBase<Vector4>)(object)val);
		}

		public static Vector2[] GetUv2(Mesh m)
		{
			if (!(Get(m, "uv2") is Il2CppStructArray<Vector2> val))
			{
				return null;
			}
			return Il2CppArrayBase<Vector2>.op_Implicit((Il2CppArrayBase<Vector2>)(object)val);
		}

		public static Color[] GetColors(Mesh m)
		{
			if (!(Get(m, "colors") is Il2CppStructArray<Color> val))
			{
				return null;
			}
			return Il2CppArrayBase<Color>.op_Implicit((Il2CppArrayBase<Color>)(object)val);
		}

		public static int[] GetTriangles(Mesh m, int sub)
		{
			MethodInfo methodInfo = FindMethod(typeof(Mesh), "GetTriangles", 1, (ParameterInfo[] ps) => ps[0].ParameterType == typeof(int), "int");
			if (methodInfo != null)
			{
				try
				{
					if (methodInfo.Invoke(m, new object[1] { sub }) is Il2CppStructArray<int> val)
					{
						return Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)val);
					}
				}
				catch (Exception e)
				{
					WarnOnce("GetTriangles", e);
				}
			}
			if (sub == 0)
			{
				return Il2CppArrayBase<int>.op_Implicit((Il2CppArrayBase<int>)(object)m.triangles);
			}
			return null;
		}

		public static bool TryGetSubMesh(Mesh m, int i, out SubMeshInfo info)
		{
			info = default(SubMeshInfo);
			MethodInfo methodInfo = FindMethod(typeof(Mesh), "GetSubMesh", 1);
			if (methodInfo == null)
			{
				return false;
			}
			try
			{
				object o = methodInfo.Invoke(m, new object[1] { i });
				info.IndexStart = ReadIntMember(o, "indexStart");
				info.IndexCount = ReadIntMember(o, "indexCount");
				info.BaseVertex = ReadIntMember(o, "baseVertex");
				info.FirstVertex = ReadIntMember(o, "firstVertex");
				info.VertexCount = ReadIntMember(o, "vertexCount");
				info.Topology = ReadIntMember(o, "topology");
				return true;
			}
			catch (Exception e)
			{
				WarnOnce("GetSubMesh", e);
				return false;
			}
		}

		public static long GetIndexCount(Mesh m, int sub)
		{
			MethodInfo methodInfo = FindMethod(typeof(Mesh), "GetIndexCount", 1, (ParameterInfo[] ps) => ps[0].ParameterType == typeof(int), "int");
			if (methodInfo == null)
			{
				return -1L;
			}
			try
			{
				return Convert.ToInt64(methodInfo.Invoke(m, new object[1] { sub }));
			}
			catch (Exception e)
			{
				WarnOnce("GetIndexCount", e);
				return -1L;
			}
		}

		private static object CallAttr(Mesh m, string name, int attr)
		{
			MethodInfo methodInfo = FindMethod(typeof(Mesh), name, 1);
			if (methodInfo == null)
			{
				return null;
			}
			try
			{
				return methodInfo.Invoke(m, new object[1] { EnumValue(methodInfo.GetParameters()[0].ParameterType, attr) });
			}
			catch (Exception e)
			{
				WarnOnce(name, e);
				return null;
			}
		}

		public static bool TryGetAttribute(Mesh m, int attr, out int stream, out int offset, out int format, out int dim)
		{
			stream = (offset = (format = (dim = 0)));
			object obj = CallAttr(m, "HasVertexAttribute", attr);
			if (!(obj is bool) || !(bool)obj)
			{
				return false;
			}
			object obj2 = CallAttr(m, "GetVertexAttributeStream", attr);
			object obj3 = CallAttr(m, "GetVertexAttributeOffset", attr);
			object obj4 = CallAttr(m, "GetVertexAttributeFormat", attr);
			object obj5 = CallAttr(m, "GetVertexAttributeDimension", attr);
			if (obj2 == null || obj3 == null || obj4 == null || obj5 == null)
			{
				return false;
			}
			stream = Convert.ToInt32(obj2);
			offset = Convert.ToInt32(obj3);
			format = Convert.ToInt32(obj4);
			dim = Convert.ToInt32(obj5);
			return offset >= 0;
		}

		public static int GetVertexBufferStride(Mesh m, int stream)
		{
			MethodInfo methodInfo = FindMethod(typeof(Mesh), "GetVertexBufferStride", 1);
			if (methodInfo == null)
			{
				return 0;
			}
			try
			{
				return Convert.ToInt32(methodInfo.Invoke(m, new object[1] { stream }));
			}
			catch
			{
				return 0;
			}
		}

		public static bool IndexIs32Bit(Mesh m)
		{
			object obj = Get(m, "indexFormat");
			if (obj != null)
			{
				return Convert.ToInt32(obj) == 1;
			}
			return false;
		}

		private static byte[] ReadBuffer(object gb, int byteOffset, int byteCount)
		{
			if (gb == null)
			{
				LastError = "버퍼를 받지 못함(null)";
				return null;
			}
			if (byteCount <= 0)
			{
				LastError = "읽을 크기 0";
				return null;
			}
			LastError = null;
			try
			{
				MethodInfo methodInfo = FindMethod(gb.GetType(), "InternalGetData", 5, (ParameterInfo[] ps) => ps[0].ParameterType.Name == "Array" && ps[4].ParameterType == typeof(int), "arr5");
				Il2CppStructArray<byte> val = new Il2CppStructArray<byte>((long)byteCount);
				if (methodInfo != null)
				{
					object obj = Activator.CreateInstance(methodInfo.GetParameters()[0].ParameterType, ((Il2CppObjectBase)val).Pointer);
					methodInfo.Invoke(gb, new object[5] { obj, 0, byteOffset, byteCount, 1 });
				}
				else
				{
					MethodInfo methodInfo2 = FindMethod(gb.GetType(), "GetData", 4, (ParameterInfo[] ps) => ps[0].ParameterType.Name == "Array" && ps[1].ParameterType == typeof(int), "arr");
					if (methodInfo2 == null)
					{
						WarnOnce("GraphicsBuffer 읽기 함수 없음");
						return null;
					}
					object obj2 = Activator.CreateInstance(methodInfo2.GetParameters()[0].ParameterType, ((Il2CppObjectBase)val).Pointer);
					methodInfo2.Invoke(gb, new object[4] { obj2, 0, byteOffset, byteCount });
				}
				return Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)val);
			}
			catch (Exception ex)
			{
				LastError = (ex.InnerException ?? ex).Message;
				WarnOnce("GPU 버퍼 읽기", ex);
				return null;
			}
			finally
			{
				try
				{
					FindMethod(gb.GetType(), "Dispose", 0)?.Invoke(gb, null);
				}
				catch
				{
				}
			}
		}

		private static object GetBuffer(Mesh m, string implName, string wrapperName, object[] args)
		{
			int paramCount = ((args != null) ? args.Length : 0);
			MethodInfo methodInfo = FindMethod(typeof(Mesh), implName, paramCount) ?? FindMethod(typeof(Mesh), wrapperName, paramCount);
			if (methodInfo == null)
			{
				LastError = wrapperName + " 없음";
				WarnOnce(wrapperName);
				return null;
			}
			try
			{
				return methodInfo.Invoke(m, args);
			}
			catch (Exception ex)
			{
				LastError = methodInfo.Name + ": " + (ex.InnerException ?? ex).Message;
				WarnOnce(methodInfo.Name, ex);
				return null;
			}
		}

		public static byte[] ReadVertexBytes(Mesh m, int stream, int byteOffset, int byteCount)
		{
			return ReadBuffer(GetBuffer(m, "GetVertexBufferImpl", "GetVertexBuffer", new object[1] { stream }), byteOffset, byteCount);
		}

		public static int[] ReadIndices(Mesh m, int indexStart, int count)
		{
			if (count <= 0)
			{
				return null;
			}
			bool flag = IndexIs32Bit(m);
			int num = (flag ? 4 : 2);
			byte[] array = ReadBuffer(GetBuffer(m, "GetIndexBufferImpl", "GetIndexBuffer", null), indexStart * num, count * num);
			if (array == null)
			{
				return null;
			}
			int[] array2 = new int[count];
			for (int i = 0; i < count; i++)
			{
				array2[i] = (flag ? BitConverter.ToInt32(array, i * 4) : BitConverter.ToUInt16(array, i * 2));
			}
			return array2;
		}
	}
}
namespace MapDestruction.Meshing
{
	public sealed class ChunkedMesh
	{
		public sealed class Group
		{
			public Int3 Key;

			public List<int>[] Sub;

			public Box3 Box = Box3.Empty;

			public int TriangleCount
			{
				get
				{
					int num = 0;
					List<int>[] sub = Sub;
					foreach (List<int> list in sub)
					{
						num += list.Count / 3;
					}
					return num;
				}
			}
		}

		public readonly MeshData Src;

		private readonly int _subs;

		private readonly float _chunk;

		private readonly int _gc;

		private readonly float _group;

		private readonly Dictionary<Int3, Group> _groups = new Dictionary<Int3, Group>();

		private readonly HashSet<Int3> _detached = new HashSet<Int3>();

		private readonly Dictionary<(long, int, float), int> _splitCache = new Dictionary<(long, int, float), int>();

		private readonly List<int> _below = new List<int>(16);

		private readonly List<int> _above = new List<int>(16);

		public IEnumerable<Group> Groups => _groups.Values;

		public int GroupCount => _groups.Count;

		public bool Overflow { get; private set; }

		public ChunkedMesh(MeshData src, float chunkSize, int groupChunks, int maxTriangles)
		{
			Src = src;
			_subs = src.Sub.Length;
			_chunk = chunkSize;
			_gc = groupChunks;
			_group = chunkSize * (float)groupChunks;
			int num = 0;
			for (int i = 0; i < _subs; i++)
			{
				List<int> list = src.Sub[i];
				for (int j = 0; j + 2 < list.Count; j += 3)
				{
					List<int> poly = new List<int>(3)
					{
						list[j],
						list[j + 1],
						list[j + 2]
					};
					num += SplitToGroups(i, poly, 0);
					if (num > maxTriangles)
					{
						Overflow = true;
						return;
					}
				}
			}
		}

		private static long EdgeKey(int a, int b)
		{
			if (a >= b)
			{
				return ((long)b << 32) | (uint)a;
			}
			return ((long)a << 32) | (uint)b;
		}

		private int SplitVertex(int a, int b, int axis, float v)
		{
			(long, int, float) key = (EdgeKey(a, b), axis, v);
			if (_splitCache.TryGetValue(key, out var value))
			{
				return value;
			}
			int num = Math.Min(a, b);
			int num2 = Math.Max(a, b);
			float num3 = Src.Pos[num][axis];
			float num4 = Src.Pos[num2][axis];
			float t = MathUtil.Clamp01((v - num3) / (num4 - num3));
			value = Src.LerpVertex(Src, num, num2, t);
			_splitCache[key] = value;
			return value;
		}

		private void SplitPoly(List<int> poly, int axis, float v, List<int> below, List<int> above)
		{
			below.Clear();
			above.Clear();
			int count = poly.Count;
			for (int i = 0; i < count; i++)
			{
				int num = poly[i];
				int num2 = poly[(i + 1) % count];
				float num3 = Src.Pos[num][axis] - v;
				float num4 = Src.Pos[num2][axis] - v;
				if (num3 <= 0f)
				{
					below.Add(num);
				}
				if (num3 >= 0f)
				{
					above.Add(num);
				}
				if ((num3 < 0f && num4 > 0f) || (num3 > 0f && num4 < 0f))
				{
					int item = SplitVertex(num, num2, axis, v);
					below.Add(item);
					above.Add(item);
				}
			}
		}

		private Box3 PolyBox(List<int> poly)
		{
			Box3 empty = Box3.Empty;
			foreach (int item in poly)
			{
				empty.Encapsulate(Src.Pos[item]);
			}
			return empty;
		}

		private static void CellRange(float min, float max, float size, out int a, out int b)
		{
			float num = size * 0.0001f;
			a = (int)MathF.Floor((min + num) / size);
			b = (int)MathF.Floor((max - num) / size);
			if (b < a)
			{
				b = a;
			}
		}

		private static int Fan(List<int> poly, List<int> dst)
		{
			if (poly.Count < 3)
			{
				return 0;
			}
			for (int i = 1; i + 1 < poly.Count; i++)
			{
				dst.Add(poly[0]);
				dst.Add(poly[i]);
				dst.Add(poly[i + 1]);
			}
			return poly.Count - 2;
		}

		private int SplitToGroups(int sub, List<int> poly, int depth)
		{
			if (poly.Count < 3)
			{
				return 0;
			}
			Box3 b = PolyBox(poly);
			for (int i = 0; i < 3; i++)
			{
				if (depth >= 64)
				{
					break;
				}
				CellRange(b.Min[i], b.Max[i], _group, out var a, out var b2);
				if (b2 > a)
				{
					float v = (float)(a + (b2 - a + 1) / 2) * _group;
					SplitPoly(poly, i, v, _below, _above);
					List<int> poly2 = new List<int>(_below);
					List<int> poly3 = new List<int>(_above);
					return SplitToGroups(sub, poly2, depth + 1) + SplitToGroups(sub, poly3, depth + 1);
				}
			}
			CellRange(b.Min.x, b.Max.x, _group, out var a2, out var b3);
			CellRange(b.Min.y, b.Max.y, _group, out var a3, out b3);
			CellRange(b.Min.z, b.Max.z, _group, out var a4, out b3);
			Int3 key = new Int3(a2, a3, a4);
			if (!_groups.TryGetValue(key, out var value))
			{
				value = new Group
				{
					Key = key,
					Sub = new List<int>[_subs]
				};
				for (int j = 0; j < _subs; j++)
				{
					value.Sub[j] = new List<int>();
				}
				_groups[key] = value;
			}
			value.Box.Encapsulate(b);
			return Fan(poly, value.Sub[sub]);
		}

		private Box3 ChunkBox(Int3 k)
		{
			return new Box3(new V3(k.X, k.Y, k.Z) * _chunk, new V3(k.X + 1, k.Y + 1, k.Z + 1) * _chunk);
		}

		public bool IsDetached(Int3 chunkKey)
		{
			return _detached.Contains(chunkKey);
		}

		public bool Covers(Int3 chunkKey)
		{
			if (_detached.Contains(chunkKey))
			{
				return true;
			}
			if (!_groups.TryGetValue(Int3.FloorDiv(chunkKey, _gc), out var value))
			{
				return false;
			}
			if (!value.Box.IsEmpty)
			{
				return value.Box.Expanded(_chunk * 0.01f).Intersects(ChunkBox(chunkKey));
			}
			return false;
		}

		public void CollectChunks(V3 c, float r, List<Int3> outKeys)
		{
			Int3 @int = Int3.Floor((c - new V3(r, r, r)) / _chunk);
			Int3 int2 = Int3.Floor((c + new V3(r, r, r)) / _chunk);
			for (int i = @int.Z; i <= int2.Z; i++)
			{
				for (int j = @int.Y; j <= int2.Y; j++)
				{
					for (int k = @int.X; k <= int2.X; k++)
					{
						Int3 int3 = new Int3(k, j, i);
						if (ChunkBox(int3).IntersectsSphere(c, r) && Covers(int3))
						{
							outKeys.Add(int3);
						}
					}
				}
			}
		}

		public MeshData Detach(Int3 chunkKey, out Group changed)
		{
			changed = null;
			if (!_groups.TryGetValue(Int3.FloorDiv(chunkKey, _gc), out var value))
			{
				_detached.Add(chunkKey);
				return null;
			}
			if (!_detached.Add(chunkKey))
			{
				return null;
			}
			Box3 o = ChunkBox(chunkKey);
			List<int>[] array = new List<int>[_subs];
			int num = 0;
			List<int> list = new List<int>(16);
			List<int> list2 = new List<int>(16);
			List<int> list3 = new List<int>(16);
			for (int i = 0; i < _subs; i++)
			{
				array[i] = new List<int>();
				List<int> list4 = value.Sub[i];
				List<int> list5 = new List<int>(list4.Count);
				for (int j = 0; j + 2 < list4.Count; j += 3)
				{
					int num2 = list4[j];
					int num3 = list4[j + 1];
					int num4 = list4[j + 2];
					if (!new Box3(V3.Min(V3.Min(Src.Pos[num2], Src.Pos[num3]), Src.Pos[num4]), V3.Max(V3.Max(Src.Pos[num2], Src.Pos[num3]), Src.Pos[num4])).Intersects(o))
					{
						list5.Add(num2);
						list5.Add(num3);
						list5.Add(num4);
						continue;
					}
					list.Clear();
					list.Add(num2);
					list.Add(num3);
					list.Add(num4);
					bool flag = false;
					for (int k = 0; k < 3; k++)
					{
						if (list.Count < 3)
						{
							break;
						}
						if (flag)
						{
							break;
						}
						int num5 = PlaneSide(list, k, o.Min[k]);
						if (num5 < 0)
						{
							flag = true;
							break;
						}
						if (num5 == 2)
						{
							SplitPoly(list, k, o.Min[k], _below, _above);
							list2.Clear();
							list2.AddRange(_below);
							list3.Clear();
							list3.AddRange(_above);
							if (Area2(list2) > 1E-12f)
							{
								Fan(list2, list5);
							}
							list.Clear();
							list.AddRange(list3);
							if (list.Count < 3)
							{
								break;
							}
						}
						num5 = PlaneSide(list, k, o.Max[k]);
						if (num5 >= 0 && num5 != 2)
						{
							flag = true;
							break;
						}
						if (num5 == 2)
						{
							SplitPoly(list, k, o.Max[k], _below, _above);
							list2.Clear();
							list2.AddRange(_above);
							list3.Clear();
							list3.AddRange(_below);
							if (Area2(list2) > 1E-12f)
							{
								Fan(list2, list5);
							}
							list.Clear();
							list.AddRange(list3);
						}
					}
					if (flag)
					{
						if (Area2(list) > 1E-12f)
						{
							Fan(list, list5);
						}
					}
					else if (list.Count >= 3 && Area2(list) > 1E-12f)
					{
						num += Fan(list, array[i]);
					}
				}
				value.Sub[i] = list5;
			}
			value.Box = Box3.Empty;
			List<int>[] sub = value.Sub;
			for (int l = 0; l < sub.Length; l++)
			{
				foreach (int item in sub[l])
				{
					value.Box.Encapsulate(Src.Pos[item]);
				}
			}
			changed = value;
			if (num <= 0)
			{
				return null;
			}
			return Src.Extract(array);
		}

		public MeshData SplitOff(Func<V3, V3, bool> pred, Box3 region, List<Group> changed)
		{
			List<int>[] array = new List<int>[_subs];
			for (int i = 0; i < _subs; i++)
			{
				array[i] = new List<int>();
			}
			bool flag = false;
			foreach (Group value in _groups.Values)
			{
				if (value.Box.IsEmpty || !value.Box.Intersects(region))
				{
					continue;
				}
				bool flag2 = false;
				for (int j = 0; j < _subs; j++)
				{
					List<int> list = value.Sub[j];
					List<int> list2 = new List<int>(list.Count);
					for (int k = 0; k + 2 < list.Count; k += 3)
					{
						int num = list[k];
						int num2 = list[k + 1];
						int num3 = list[k + 2];
						V3 v = Src.Pos[num];
						V3 v2 = Src.Pos[num2];
						V3 v3 = Src.Pos[num3];
						if (pred((v + v2 + v3) / 3f, V3.Cross(v2 - v, v3 - v).Normalized))
						{
							array[j].Add(num);
							array[j].Add(num2);
							array[j].Add(num3);
							flag = true;
							flag2 = true;
						}
						else
						{
							list2.Add(num);
							list2.Add(num2);
							list2.Add(num3);
						}
					}
					value.Sub[j] = list2;
				}
				if (!flag2)
				{
					continue;
				}
				value.Box = Box3.Empty;
				List<int>[] sub = value.Sub;
				for (int l = 0; l < sub.Length; l++)
				{
					foreach (int item in sub[l])
					{
						value.Box.Encapsulate(Src.Pos[item]);
					}
				}
				changed.Add(value);
			}
			if (!flag)
			{
				return null;
			}
			return Src.Extract(array);
		}

		private int PlaneSide(List<int> poly, int axis, float v)
		{
			float num = _chunk * 1E-05f;
			bool flag = false;
			bool flag2 = false;
			foreach (int item in poly)
			{
				float num2 = Src.Pos[item][axis] - v;
				if (num2 < 0f - num)
				{
					flag = true;
				}
				else if (num2 > num)
				{
					flag2 = true;
				}
			}
			if (flag && flag2)
			{
				return 2;
			}
			if (flag)
			{
				return -1;
			}
			return flag2 ? 1 : 0;
		}

		private float Area2(List<int> poly)
		{
			if (poly.Count < 3)
			{
				return 0f;
			}
			V3 zero = V3.Zero;
			V3 v = Src.Pos[poly[0]];
			for (int i = 1; i + 1 < poly.Count; i++)
			{
				zero += V3.Cross(Src.Pos[poly[i]] - v, Src.Pos[poly[i + 1]] - v);
			}
			return zero.SqrMag;
		}
	}
	public static class CraterMesher
	{
		public sealed class Result
		{
			public MeshData Render;

			public readonly List<byte> SubPalette = new List<byte>();

			public readonly List<V3> ColPos = new List<V3>();

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

			public bool IsEmpty
			{
				get
				{
					if (Render == null || Render.TriangleCount == 0)
					{
						return ColIdx.Count == 0;
					}
					return false;
				}
			}
		}

		private const int N = 16;

		private const int G = 18;

		private const int CG = 17;

		private const float MinErosion = 0.004f;

		private const float BiasMax = 0.015f;

		private static readonly float[] _f = new float[5832];

		private static readonly float[] _e = new float[5832];

		private static readonly float[] _ed = new float[5832];

		private static readonly byte[] _m = new byte[5832];

		private static readonly int[] _cellVert = new int[4913];

		private static readonly int[] _cellColVert = new int[4913];

		private static readonly List<bool> _border = new List<bool>();

		private const float CreaseCos = 0.707f;

		private const float ReliefStart = 0.03f;

		private const float ReliefFull = 0.08f;

		private static readonly float[] _cf = new float[8];

		private static int PI(int x, int y, int z)
		{
			return x + 1 + 18 * (y + 1 + 18 * (z + 1));
		}

		private static int CI(int x, int y, int z)
		{
			return x + 1 + 17 * (y + 1 + 17 * (z + 1));
		}

		public static Result Build(VoxelChunk ch, float rimEps, float uvScale, bool wantCollision)
		{
			if (!ch.Voxelized || !ch.HasErosion)
			{
				return null;
			}
			float cell = ch.Cell;
			int num = ch.Key.X * 16;
			int num2 = ch.Key.Y * 16;
			int num3 = ch.Key.Z * 16;
			bool flag = false;
			for (int i = -1; i <= 16; i++)
			{
				for (int j = -1; j <= 16; j++)
				{
					for (int k = -1; k <= 16; k++)
					{
						int num4 = PI(k, j, i);
						float num5 = VoxelWorld.FieldAtGlobal(num + k, num2 + j, num3 + i, out _e[num4], out _m[num4]);
						_f[num4] = num5 + 0.015f;
						if (_e[num4] > 0.004f)
						{
							flag = true;
						}
					}
				}
			}
			if (!flag)
			{
				return null;
			}
			for (int l = -1; l <= 16; l++)
			{
				for (int m = -1; m <= 16; m++)
				{
					for (int n = -1; n <= 16; n++)
					{
						float num6 = 0f;
						for (int num7 = -1; num7 <= 1; num7++)
						{
							for (int num8 = -1; num8 <= 1; num8++)
							{
								for (int num9 = -1; num9 <= 1; num9++)
								{
									int num10 = n + num9;
									int num11 = m + num8;
									int num12 = l + num7;
									if (num10 >= -1 && num11 >= -1 && num12 >= -1 && num10 <= 16 && num11 <= 16 && num12 <= 16)
									{
										float num13 = _e[PI(num10, num11, num12)];
										if (num13 > num6)
										{
											num6 = num13;
										}
									}
								}
							}
						}
						_ed[PI(n, m, l)] = num6;
					}
				}
			}
			for (int num14 = 0; num14 < _cellVert.Length; num14++)
			{
				_cellVert[num14] = -1;
				_cellColVert[num14] = -1;
			}
			_border.Clear();
			Result result = new Result();
			MeshData meshData = new MeshData(0, nrm: true, tan: true, uv0: true, uv1: false, col: false);
			meshData.Sub = new List<int>[0];
			List<List<int>> list = new List<List<int>>();
			Dictionary<byte, int> dictionary = new Dictionary<byte, int>();
			float num15 = 0.004f;
			for (int num16 = 0; num16 < 3; num16++)
			{
				int num17 = (num16 + 1) % 3;
				int num18 = (num16 + 2) % 3;
				for (int num19 = 0; num19 < 16; num19++)
				{
					for (int num20 = 0; num20 < 16; num20++)
					{
						for (int num21 = 0; num21 < 16; num21++)
						{
							int x = num21 + ((num16 == 0) ? 1 : 0);
							int y = num20 + ((num16 == 1) ? 1 : 0);
							int z = num19 + ((num16 == 2) ? 1 : 0);
							int num22 = PI(num21, num20, num19);
							int num23 = PI(x, y, z);
							float num24 = _f[num22];
							float num25 = _f[num23];
							bool flag2 = num24 < 0f;
							bool flag3 = num25 < 0f;
							if (flag2 == flag3 || MathF.Max(_ed[num22], _ed[num23]) <= num15)
							{
								continue;
							}
							int[] array = new int[3] { num21, num20, num19 };
							int[] array2 = new int[3]
							{
								array[0],
								array[1],
								array[2]
							};
							array2[num17]--;
							array2[num18]--;
							int[] array3 = new int[3]
							{
								array[0],
								array[1],
								array[2]
							};
							array3[num18]--;
							int[] cmin = new int[3]
							{
								array[0],
								array[1],
								array[2]
							};
							int[] array4 = new int[3]
							{
								array[0],
								array[1],
								array[2]
							};
							array4[num17]--;
							byte b = (flag2 ? _m[num22] : _m[num23]);
							PaletteEntry paletteEntry = MaterialPalette.Get(b);
							if (paletteEntry != null && (Object)(object)paletteEntry.RenderMaterial != (Object)null)
							{
								MaterialProfile prof = MaterialPalette.ProfileOf(b);
								int num26 = CellVertex(meshData, ch, array2, cell, uvScale, prof);
								int num27 = CellVertex(meshData, ch, array3, cell, uvScale, prof);
								int num28 = CellVertex(meshData, ch, cmin, cell, uvScale, prof);
								int num29 = CellVertex(meshData, ch, array4, cell, uvScale, prof);
								if (num26 >= 0 && num27 >= 0 && num28 >= 0 && num29 >= 0)
								{
									if (!dictionary.TryGetValue(b, out var value))
									{
										value = list.Count;
										list.Add(new List<int>());
										dictionary[b] = value;
										result.SubPalette.Add(b);
									}
									AddQuadShort(meshData, list[value], num26, num27, num28, num29, flag2);
								}
							}
							if (wantCollision)
							{
								int num30 = CellColVertex(result, ch, array2, cell);
								int num31 = CellColVertex(result, ch, array3, cell);
								int num32 = CellColVertex(result, ch, cmin, cell);
								int num33 = CellColVertex(result, ch, array4, cell);
								if (num30 >= 0 && num31 >= 0 && num32 >= 0 && num33 >= 0)
								{
									AddQuad(result.ColIdx, num30, num31, num32, num33, flag2);
								}
							}
						}
					}
				}
			}
			meshData.Sub = list.ToArray();
			Facet(meshData);
			ProjectUVs(meshData, uvScale);
			result.Render = meshData;
			return result;
		}

		private static void Facet(MeshData md)
		{
			int count = md.Pos.Count;
			if (count == 0)
			{
				return;
			}
			int num = 0;
			List<int>[] sub = md.Sub;
			foreach (List<int> list in sub)
			{
				num += list.Count / 3;
			}
			if (num == 0)
			{
				return;
			}
			V3[] array = new V3[num];
			int[] array2 = new int[count + 1];
			int num2 = 0;
			sub = md.Sub;
			foreach (List<int> list2 in sub)
			{
				int num3 = 0;
				while (num3 + 2 < list2.Count)
				{
					V3 v = md.Pos[list2[num3]];
					V3 v2 = md.Pos[list2[num3 + 1]];
					V3 v3 = md.Pos[list2[num3 + 2]];
					array[num2] = V3.Cross(v2 - v, v3 - v);
					array2[list2[num3]]++;
					array2[list2[num3 + 1]]++;
					array2[list2[num3 + 2]]++;
					num3 += 3;
					num2++;
				}
			}
			int[] array3 = new int[count + 1];
			for (int j = 0; j < count; j++)
			{
				array3[j + 1] = array3[j] + array2[j];
			}
			int[] array4 = new int[count];
			int[] array5 = new int[array3[count]];
			for (int k = 0; k < md.Sub.Length; k++)
			{
				List<int> list3 = md.Sub[k];
				for (int l = 0; l < list3.Count; l++)
				{
					int num4 = list3[l];
					array5[array3[num4] + array4[num4]++] = (k << 24) | l;
				}
			}
			int[] array6 = new int[md.Sub.Length];
			for (int m = 1; m < md.Sub.Length; m++)
			{
				array6[m] = array6[m - 1] + md.Sub[m - 1].Count / 3;
			}
			List<(V3, int)> list4 = new List<(V3, int)>(4);
			for (int n = 0; n < count; n++)
			{
				if (n < _border.Count && _border[n])
				{
					continue;
				}
				list4.Clear();
				for (int num5 = array3[n]; num5 < array3[n + 1]; num5++)
				{
					int num6 = array5[num5] >> 24;
					int num7 = array5[num5] & 0xFFFFFF;
					V3 v4 = array[array6[num6] + num7 / 3];
					float mag = v4.Mag;
					if (mag < 1E-12f)
					{
						continue;
					}
					V3 b = v4 / mag;
					int num8 = -1;
					for (int num9 = 0; num9 < list4.Count; num9++)
					{
						if (V3.Dot(list4[num9].Item1.Normalized, b) >= 0.707f)
						{
							num8 = num9;
							break;
						}
					}
					if (num8 < 0)
					{
						int item = n;
						if (list4.Count > 0)
						{
							md.Pos.Add(md.Pos[n]);
							md.Nrm.Add(md.Nrm[n]);
							md.Tan.Add(md.Tan[n]);
							md.Uv0.Add(md.Uv0[n]);
							item = md.Pos.Count - 1;
						}
						list4.Add((v4, item));
						num8 = list4.Count - 1;
					}
					else
					{
						list4[num8] = (list4[num8].Item1 + v4, list4[num8].Item2);
					}
					md.Sub[num6][num7] = list4[num8].Item2;
				}
				foreach (var item4 in list4)
				{
					V3 item2 = item4.Item1;
					int item3 = item4.Item2;
					V3 normalized = item2.Normalized;
					if (!(normalized.SqrMag < 0.5f))
					{
						md.Nrm[item3] = normalized;
						V4 v5 = md.Tan[item3];
						V3 v6 = new V3(v5.x, v5.y, v5.z);
						v6 = (v6 - normalized * V3.Dot(normalized, v6)).Normalized;
						if (v6.SqrMag < 0.5f)
						{
							v6 = V3.Cross(normalized, (MathF.Abs(normalized.y) < 0.9f) ? new V3(0f, 1f, 0f) : new V3(1f, 0f, 0f)).Normalized;
						}
						md.Tan[item3] = new V4(v6.x, v6.y, v6.z, v5.w);
					}
				}
			}
		}

		private static void AddQuad(List<int> l, int v00, int v10, int v11, int v01, bool in0)
		{
			if (in0)
			{
				l.Add(v00);
				l.Add(v10);
				l.Add(v11);
				l.Add(v00);
				l.Add(v11);
				l.Add(v01);
			}
			else
			{
				l.Add(v00);
				l.Add(v11);
				l.Add(v10);
				l.Add(v00);
				l.Add(v01);
				l.Add(v11);
			}
		}

		private static void AddQuadShort(MeshData md, List<int> l, int v00, int v10, int v11, int v01, bool in0)
		{
			float sqrMag = (md.Pos[v00] - md.Pos[v11]).SqrMag;
			float sqrMag2 = (md.Pos[v10] - md.Pos[v01]).SqrMag;
			if (sqrMag <= sqrMag2)
			{
				AddQuad(l, v00, v10, v11, v01, in0);
			}
			else if (in0)
			{
				l.Add(v10);
				l.Add(v11);
				l.Add(v01);
				l.Add(v10);
				l.Add(v01);
				l.Add(v00);
			}
			else
			{
				l.Add(v10);
				l.Add(v01);
				l.Add(v11);
				l.Add(v10);
				l.Add(v00);
				l.Add(v01);
			}
		}

		private static void ProjectUVs(MeshData md, float uvScale)
		{
			int count = md.Pos.Count;
			if (count == 0)
			{
				return;
			}
			sbyte[] array = new sbyte[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = -1;
			}
			Dictionary<long, int> dictionary = new Dictionary<long, int>();
			List<int>[] sub = md.Sub;
			foreach (List<int> list in sub)
			{
				for (int k = 0; k + 2 < list.Count; k += 3)
				{
					V3 v = md.Pos[list[k]];
					V3 v2 = md.Pos[list[k + 1]];
					V3 v3 = V3.Cross(b: md.Pos[list[k + 2]] - v, a: v2 - v);
					if (v3.SqrMag < 1E-14f)
					{
						v3 = md.Nrm[list[k]];
					}
					v3 = v3.Normalized;
					int num = BestAxis(v3);
					float num2 = MathF.Abs(v3[num >> 1]);
					int num3 = array[list[k]];
					if (num3 >= 0 && num3 != num && AxisDot(v3, num3) >= num2 * 0.75f)
					{
						num = num3;
					}
					for (int l = 0; l < 3; l++)
					{
						int num4 = list[k + l];
						if (array[num4] < 0)
						{
							array[num4] = (sbyte)num;
							SetUv(md, num4, num, uvScale);
						}
						else if (array[num4] != num)
						{
							long key = (long)num4 * 8L + num;
							if (!dictionary.TryGetValue(key, out var value))
							{
								md.Pos.Add(md.Pos[num4]);
								md.Nrm.Add(md.Nrm[num4]);
								md.Tan.Add(md.Tan[num4]);
								md.Uv0.Add(md.Uv0[num4]);
								value = md.Pos.Count - 1;
								SetUv(md, value, num, uvScale);
								dictionary[key] = value;
							}
							list[k + l] = value;
						}
					}
				}
			}
		}

		private static int BestAxis(V3 n)
		{
			float num = MathF.Abs(n.x);
			float num2 = MathF.Abs(n.y);
			float num3 = MathF.Abs(n.z);
			if (num >= num2 && num >= num3)
			{
				return (!(n.x >= 0f)) ? 1 : 0;
			}
			if (num2 >= num3)
			{
				if (!(n.y >= 0f))
				{
					return 3;
				}
				return 2;
			}
			if (!(n.z >= 0f))
			{
				return 5;
			}
			return 4;
		}

		private static float AxisDot(V3 n, int axis)
		{
			float num = n[axis >> 1];
			if ((axis & 1) != 0)
			{
				return 0f - num;
			}
			return num;
		}

		private static void SetUv(MeshData md, int v, int axis, float uvScale)
		{
			V3 v2;
			V3 v3;
			switch (axis >> 1)
			{
			case 0:
				v2 = new V3(0f, 0f, ((axis & 1) != 0) ? 1 : (-1));
				v3 = new V3(0f, 1f, 0f);
				break;
			case 1:
				v2 = new V3(1f, 0f, 0f);
				v3 = new V3(0f, 0f, ((axis & 1) == 0) ? 1 : (-1));
				break;
			default:
				v2 = new V3(((axis & 1) == 0) ? 1 : (-1), 0f, 0f);
				v3 = new V3(0f, 1f, 0f);
				break;
			}
			V3 a = md.Pos[v];
			V3 v4 = md.Nrm[v];
			md.Uv0[v] = new V2(V3.Dot(a, v2) * uvScale, V3.Dot(a, v3) * uvScale);
			V3 normalized = (v2 - v4 * V3.Dot(v4, v2)).Normalized;
			if (normalized.SqrMag < 0.5f)
			{
				normalized = (v3 - v4 * V3.Dot(v4, v3)).Normalized;
			}
			float w = ((V3.Dot(V3.Cross(v4, normalized), v3) >= 0f) ? 1f : (-1f));
			md.Tan[v] = new V4(normalized.x, normalized.y, normalized.z, w);
		}

		private static void AddVertex(MeshData md, V3 pos, V3 n, float uvScale)
		{
			float num = MathF.Abs(n.x);
			float num2 = MathF.Abs(n.y);
			float num3 = MathF.Abs(n.z);
			V3 v;
			V3 b;
			if (num >= num2 && num >= num3)
			{
				v = new V3(0f, 0f, (!(n.x >= 0f)) ? 1 : (-1));
				b = new V3(0f, 1f, 0f);
			}
			else if (num2 >= num3)
			{
				v = new V3(1f, 0f, 0f);
				b = new V3(0f, 0f, (n.y >= 0f) ? 1 : (-1));
			}
			else
			{
				v = new V3((n.z >= 0f) ? 1 : (-1), 0f, 0f);
				b = new V3(0f, 1f, 0f);
			}
			V2 item = new V2(V3.Dot(pos, v) * uvScale, V3.Dot(pos, b) * uvScale);
			V3 normalized = (v - n * V3.Dot(n, v)).Normalized;
			float w = ((V3.Dot(V3.Cross(n, normalized), b) >= 0f) ? 1f : (-1f));
			md.Pos.Add(pos);
			md.Nrm.Add(n);
			md.Tan.Add(new V4(normalized.x, normalized.y, normalized.z, w));
			md.Uv0.Add(item);
		}

		private static bool CellCorners(int[] cmin, float[] cf)
		{
			for (int i = 0; i < 8; i++)
			{
				cf[i] = _f[PI(cmin[0] + (i & 1), cmin[1] + ((i >> 1) & 1), cmin[2] + ((i >> 2) & 1))];
			}
			return true;
		}

		private static bool CellSurfacePoint(int[] cmin, out V3 local)
		{
			local = V3.Zero;
			if (cmin[0] < -1 || cmin[1] < -1 || cmin[2] < -1 || cmin[0] > 15 || cmin[1] > 15 || cmin[2] > 15)
			{
				return false;
			}
			CellCorners(cmin, _cf);
			int num = 0;
			V3 zero = V3.Zero;
			for (int i = 0; i < 8; i++)
			{
				for (int num2 = 1; num2 <= 4; num2 <<= 1)
				{
					if ((i & num2) == 0)
					{
						int num3 = i | num2;
						float num4 = _cf[i];
						float num5 = _cf[num3];
						if (num4 < 0f != num5 < 0f)
						{
							float t = num4 / (num4 - num5);
							V3 a = new V3(i & 1, (i >> 1) & 1, (i >> 2) & 1);
							V3 b = new V3(num3 & 1, (num3 >> 1) & 1, (num3 >> 2) & 1);
							zero += V3.Lerp(a, b, t);
							num++;
						}
					}
				}
			}
			if (num == 0)
			{
				return false;
			}
			local = zero / num;
			return true;
		}

		private static V3 Gradient(V3 u)
		{
			float x = u.x;
			float y = u.y;
			float z = u.z;
			float[] cf = _cf;
			float x2 = (1f - y) * (1f - z) * (cf[1] - cf[0]) + y * (1f - z) * (cf[3] - cf[2]) + (1f - y) * z * (cf[5] - cf[4]) + y * z * (cf[7] - cf[6]);
			float y2 = (1f - x) * (1f - z) * (cf[2] - cf[0]) + x * (1f - z) * (cf[3] - cf[1]) + (1f - x) * z * (cf[6] - cf[4]) + x * z * (cf[7] - cf[5]);
			float z2 = (1f - x) * (1f - y) * (cf[4] - cf[0]) + x * (1f - y) * (cf[5] - cf[1]) + (1f - x) * y * (cf[6] - cf[2]) + x * y * (cf[7] - cf[3]);
			V3 normalized = new V3(x2, y2, z2).Normalized;
			if (!(normalized.SqrMag > 0.5f))
			{
				return new V3(0f, 1f, 0f);
			}
			return normalized;
		}

		private static int CellVertex(MeshData md, VoxelChunk ch, int[] cmin, float cell, float uvScale, MaterialProfile prof)
		{
			int num = CI(cmin[0], cmin[1], cmin[2]);
			if (num < 0 || num >= _cellVert.Length)
			{
				return -1;
			}
			if (_cellVert[num] >= 0)
			{
				return _cellVert[num];
			}
			if (!CellSurfacePoint(cmin, out var local))
			{
				return -1;
			}
			V3 v = Gradient(local);
			V3 v2 = ch.Origin + new V3((float)cmin[0] + local.x, (float)cmin[1] + local.y, (float)cmin[2] + local.z) * cell;
			if (prof != null && prof.Rough > 0f)
			{
				float num2 = MathUtil.Clamp01((0f - VoxelWorld.SampleSdf0(v2, 0f) - 0.03f) / 0.049999997f);
				if (num2 > 0f)
				{
					v2 += v * (Fracture.Relief(v2, prof, V3.Zero) * num2);
				}
			}
			bool item = cmin[0] <= -1 || cmin[1] <= -1 || cmin[2] <= -1 || cmin[0] >= 15 || cmin[1] >= 15 || cmin[2] >= 15;
			AddVertex(md, v2, v, uvScale);
			_border.Add(item);
			int num3 = md.Pos.Count - 1;
			_cellVert[num] = num3;
			return num3;
		}

		private static int CellColVertex(Result res, VoxelChunk ch, int[] cmin, float cell)
		{
			int num = CI(cmin[0], cmin[1], cmin[2]);
			if (num < 0 || num >= _cellColVert.Length)
			{
				return -1;
			}
			if (_cellColVert[num] >= 0)
			{
				return _cellColVert[num];
			}
			if (!CellSurfacePoint(cmin, out var local))
			{
				return -1;
			}
			res.ColPos.Add(ch.Origin + new V3((float)cmin[0] + local.x, (float)cmin[1] + local.y, (float)cmin[2] + local.z) * cell);
			int num2 = res.ColPos.Count - 1;
			_cellColVert[num] = num2;
			return num2;
		}
	}
	public sealed class MeshData
	{
		public readonly List<V3> Pos = new List<V3>();

		public readonly List<V3> Nrm;

		public readonly List<V4> Tan;

		public readonly List<V2> Uv0;

		public readonly List<V2> Uv1;

		public readonly List<C4> Col;

		public List<int>[] Sub;

		public bool HasNrm => Nrm != null;

		public bool HasTan => Tan != null;

		public bool HasUv0 => Uv0 != null;

		public bool HasUv1 => Uv1 != null;

		public bool HasCol => Col != null;

		public int VertexCount => Pos.Count;

		public int TriangleCount
		{
			get
			{
				int num = 0;
				List<int>[] sub = Sub;
				foreach (Lis