Decompiled source of SteadyFrame v1.3.1

SteadyFrame.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SteadyFrame;
using SteadyFrame.Core;
using SteadyFrame.Housekeeping;
using SteadyFrame.SceneStreaming;
using SteadyFrame.Terrain;
using SteadyFrame.Transitions;
using SteadyFrame.Transitions.ObjectLoading;
using SteadyFrame.Vegetation;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using ValheimMods.Shared;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("SteadyFrameDiagnostics")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("SteadyFrame")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyInformationalVersion("1.3.1+24ce96994953df6fa3721ebd878bf87486a95c96")]
[assembly: AssemblyProduct("SteadyFrame")]
[assembly: AssemblyTitle("SteadyFrame")]
[assembly: AssemblyVersion("1.3.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimMods.Shared
{
	internal static class GpuGrass
	{
		private sealed class AuditPatch
		{
			public string Name;

			public Vector3 Position;

			public int Id;

			public int Slot;

			public int Capacity;

			public int Count;

			public int Kind;

			public Vector4 Sphere;

			public Vector4[] Rows;
		}

		private sealed class Audit
		{
			public int IdTop;

			public int Kinds;

			public int Capacity;

			public int VisibleCapacity;

			public int Pending = 7;

			public int Failed;

			public long Regrowths;

			public long Frame;

			public readonly List<AuditPatch> Patches = new List<AuditPatch>();

			public readonly HashSet<int> FreeIds = new HashSet<int>();

			public long[] Totals;

			public uint[] Bases;

			public string[] KindNames;

			public PatchGpu[] Table;

			public Vector4[] ObjectToWorld;

			public Vector4[] WorldToObject;

			public uint[] Draw;

			public uint[] Visible;

			public uint[] Args;
		}

		private sealed class ByReference<T> : IEqualityComparer<T> where T : class
		{
			internal static readonly ByReference<T> Instance = new ByReference<T>();

			public bool Equals(T x, T y)
			{
				return x == y;
			}

			public int GetHashCode(T obj)
			{
				return RuntimeHelpers.GetHashCode(obj);
			}
		}

		private sealed class Patch
		{
			public bool Grass;

			public Kind Kind;

			public int Id = -1;

			public int Member = -1;

			public int Slot = -1;

			public int Capacity;

			public int Uploaded;

			public bool Dirty = true;

			public bool StateDirty = true;

			public Vector3 Center;

			public float Radius;
		}

		private sealed class Kind
		{
			public Mesh Mesh;

			public Material Original;

			public Material Copy;

			public ShadowCastingMode Shadows;

			public int Layer;

			public int Index;

			public MaterialPropertyBlock Block;

			public long Total;

			public int Base;

			public readonly List<Patch> Members = new List<Patch>();

			public bool BoundsDirty = true;

			public Bounds Bounds;

			public KindKey Key;

			public string Name;

			public float Extent;

			public bool Gone;

			public bool Retired;
		}

		private struct PatchGpu
		{
			public Vector4 Sphere;

			public Vector4 Position;

			public float LodMax;

			public uint Flags;

			public uint Count;

			public uint Slot;

			public uint Kind;

			public uint Pad0;

			public uint Pad1;

			public uint Pad2;
		}

		private readonly struct KindKey : IEquatable<KindKey>
		{
			private readonly Mesh _mesh;

			private readonly Material _material;

			private readonly int _shadows;

			private readonly int _layer;

			public KindKey(Mesh mesh, Material material, ShadowCastingMode shadows, int layer)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Expected I4, but got Unknown
				_mesh = mesh;
				_material = material;
				_shadows = (int)shadows;
				_layer = layer;
			}

			public bool Equals(KindKey o)
			{
				if (_mesh == o._mesh && _material == o._material && _shadows == o._shadows)
				{
					return _layer == o._layer;
				}
				return false;
			}

			public override bool Equals(object o)
			{
				if (o is KindKey o2)
				{
					return Equals(o2);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((RuntimeHelpers.GetHashCode(_mesh) * 397) ^ RuntimeHelpers.GetHashCode(_material)) * 31 + _shadows * 7 + _layer;
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "CustomUpdate")]
		private static class Patch_CustomUpdate
		{
			private static bool Prefix(InstanceRenderer __instance)
			{
				return Before(__instance);
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0123: Expected O, but got Unknown
				MethodInfo methodInfo = AccessTools.Method(typeof(Graphics), "DrawMeshInstanced", new Type[9]
				{
					typeof(Mesh),
					typeof(int),
					typeof(Material),
					typeof(Matrix4x4[]),
					typeof(int),
					typeof(MaterialPropertyBlock),
					typeof(ShadowCastingMode),
					typeof(bool),
					typeof(int)
				}, (Type[])null);
				List<CodeInstruction> list = new List<CodeInstruction>(instructions);
				int num = 0;
				foreach (CodeInstruction item in list)
				{
					if (CodeInstructionExtensions.Calls(item, methodInfo))
					{
						num++;
					}
				}
				if (num != 2)
				{
					throw new InvalidOperationException($"InstanceRenderer.CustomUpdate has {num} DrawMeshInstanced calls (expected 2)");
				}
				List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 2);
				foreach (CodeInstruction item2 in list)
				{
					if (CodeInstructionExtensions.Calls(item2, methodInfo))
					{
						CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						CodeInstructionExtensions.MoveLabelsTo(item2, val);
						list2.Add(val);
						item2.opcode = OpCodes.Call;
						item2.operand = AccessTools.Method(typeof(GpuGrass), "Draw", (Type[])null, (Type[])null);
					}
					list2.Add(item2);
				}
				return list2;
			}
		}

		[HarmonyPatch(typeof(MonoUpdatersExtra), "CustomUpdate")]
		private static class Patch_Pass
		{
			private static void Prefix(List<IMonoUpdater> source)
			{
				if (source == InstanceRenderer.Instances)
				{
					BeginPass();
				}
			}

			private static void Postfix(List<IMonoUpdater> source, float deltaTime)
			{
				if (source == InstanceRenderer.Instances)
				{
					EndPass(deltaTime);
				}
			}

			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo addRange = AccessTools.Method(typeof(List<IMonoUpdater>), "AddRange", (Type[])null, (Type[])null);
				List<CodeInstruction> list = new List<CodeInstruction>(instructions);
				List<CodeInstruction> list2 = list.FindAll((CodeInstruction ins) => CodeInstructionExtensions.Calls(ins, addRange));
				if (list2.Count != 1)
				{
					_log.LogWarning((object)$"MonoUpdatersExtra.CustomUpdate has {list2.Count} AddRange calls (expected 1): every renderer keeps its turn");
					return list;
				}
				list2[0].opcode = OpCodes.Call;
				list2[0].operand = AccessTools.Method(typeof(GpuGrass), "AddToPass", (Type[])null, (Type[])null);
				return list;
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "OnEnable")]
		private static class Patch_OnEnable
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Born(__instance);
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "OnDisable")]
		private static class Patch_OnDisable
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Forget(__instance);
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "Clear")]
		private static class Patch_Clear
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Touch(__instance);
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "SetInstance")]
		private static class Patch_SetInstance
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Touch(__instance);
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "SetInstances")]
		private static class Patch_SetInstances
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Touch(__instance);
			}
		}

		[HarmonyPatch(typeof(InstanceRenderer), "SetInstancesBillboard")]
		private static class Patch_SetBillboard
		{
			private static void Postfix(InstanceRenderer __instance)
			{
				Touch(__instance);
			}
		}

		private sealed class TerrainCopy
		{
			public int Width;

			public int MaskWidth;

			public float Scale;

			public float Half;

			public Vector3 Position;

			public float[] Heights;

			public float[] Ocean;

			public Color32[] Mask;

			public Biome[] Corners;
		}

		private sealed class BuildKind
		{
			public Kind Kind;

			public int Index;

			public int Amount;

			public Vector3 Scale;

			public float Extent;

			public float LodMin;

			public float LodMax;

			public uint Flags;

			public Biome Biome;

			public bool InForest;

			public bool OnCleared;

			public bool OnUncleared;

			public bool SnapToWater;

			public bool TerrainTilt;

			public float ForestMin;

			public float ForestMax;

			public float FractalScale;

			public float FractalOffset;

			public float FractalMin;

			public float FractalMax;

			public float MinAlt;

			public float MaxAlt;

			public float MinNormal;

			public float MaxNormal;

			public float MinOcean;

			public float MaxOcean;

			public float MinVegetation;

			public float MaxVegetation;

			public float RandomOffset;

			public float ScaleMin;

			public float ScaleMax;
		}

		private sealed class BuildJob
		{
			public object Owner;

			public Vector2Int Cell;

			public float Size;

			public float Water;

			public BuildKind[] Kinds;

			public readonly TerrainCopy[] Maps = new TerrainCopy[4];

			public readonly List<Patch> Replaces = new List<Patch>();

			public Vector4[] Rows;

			public int[] First;

			public int[] Count;

			public Vector3[] Min;

			public Vector3[] Max;

			public Exception Error;
		}

		private sealed class BuiltPatch
		{
			public Vector2Int Cell;

			public BuildJob Job;

			public readonly List<Patch> Drawn = new List<Patch>();

			public BuildKind[] Kinds;

			public int[] First;

			public int[] Count;

			public Vector4[] Rows;

			public float Size;
		}

		private struct BuildRandom
		{
			private uint _x;

			private uint _y;

			private uint _z;

			private uint _w;

			public BuildRandom(int seed)
			{
				_x = (uint)seed;
				_y = _x * 1812433253 + 1;
				_z = _y * 1812433253 + 1;
				_w = _z * 1812433253 + 1;
			}

			private uint Next()
			{
				uint num = _x ^ (_x << 11);
				_x = _y;
				_y = _z;
				_z = _w;
				return _w = _w ^ (_w >> 19) ^ num ^ (num >> 8);
			}

			public float Range(float min, float max)
			{
				float num = (float)(Next() & 0x7FFFFF) * 1.192093E-07f;
				return min * num + (1f - num) * max;
			}

			public int Range(int min, int max)
			{
				if (max > min)
				{
					return min + (int)(Next() % (uint)(max - min));
				}
				return min;
			}
		}

		[HarmonyPatch(typeof(ClutterSystem), "GenerateVegPatch")]
		private static class Patch_Build
		{
			private static void Prefix(ClutterSystem __instance)
			{
				if (_buildOn && __instance == _buildFor && !__instance.m_menuHack)
				{
					RefreshKinds(__instance);
					BuildKind[] buildKinds = _buildKinds;
					foreach (BuildKind buildKind in buildKinds)
					{
						__instance.m_clutter[buildKind.Index].m_enabled = false;
					}
					_holding = true;
				}
			}

			private static void Postfix(ClutterSystem __instance, object __result, Vector2Int patchID, float size)
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				if (_holding && __result != null)
				{
					BuildJob buildJob = new BuildJob
					{
						Owner = __result,
						Cell = patchID,
						Size = size,
						Water = __instance.m_waterLevel,
						Kinds = _buildKinds
					};
					BuiltPatch value = new BuiltPatch
					{
						Cell = patchID,
						Job = buildJob
					};
					Built[__result] = value;
					BuiltCells[patchID] = value;
					Waiting.Enqueue(buildJob);
				}
			}

			private static void Finalizer(ClutterSystem __instance)
			{
				if (_holding)
				{
					_holding = false;
					BuildKind[] buildKinds = _buildKinds;
					foreach (BuildKind buildKind in buildKinds)
					{
						__instance.m_clutter[buildKind.Index].m_enabled = true;
					}
				}
			}
		}

		[HarmonyPatch(typeof(ClutterSystem), "FreePatch")]
		private static class Patch_FreePatch
		{
			private static void Prefix(object patch)
			{
				Freed(patch);
			}
		}

		[HarmonyPatch(typeof(Heightmap), "Regenerate")]
		private static class Patch_Regenerate
		{
			private static void Postfix(Heightmap __instance)
			{
				Forget(__instance);
			}
		}

		[HarmonyPatch(typeof(Heightmap), "PaintCleared")]
		private static class Patch_PaintCleared
		{
			private static void Postfix(Heightmap __instance)
			{
				Forget(__instance);
			}
		}

		[HarmonyPatch(typeof(Heightmap), "OnDisable")]
		private static class Patch_HeightmapOff
		{
			private static void Postfix(Heightmap __instance)
			{
				Forget(__instance);
			}
		}

		private const float AuditEvery = 20f;

		private const int AuditLogged = 8;

		private static float _nextAudit = 40f;

		private static Audit _audit;

		private const int Version = 5;

		private const string Slot = "ValheimMods.Shared.GpuGrass";

		private const string HarmonyId = "ValheimMods.Shared.GpuGrass";

		private const string SteadyFrameGuid = "ru.ivest.steadyframe";

		private const int RunsAt = 5;

		private static ManualLogSource _log;

		private static Func<bool?>[] _opinions;

		private static bool _wanted;

		private static readonly FieldRef<InstanceRenderer, int> InstanceCount = AccessTools.FieldRefAccess<InstanceRenderer, int>("m_instanceCount");

		private static readonly FieldRef<InstanceRenderer, Matrix4x4[]> Matrices = AccessTools.FieldRefAccess<InstanceRenderer, Matrix4x4[]>("m_instances");

		private static readonly FieldRef<InstanceRenderer, float> LodCount = AccessTools.FieldRefAccess<InstanceRenderer, float>("m_lodCount");

		private static readonly FieldRef<InstanceRenderer, bool> FirstFrame = AccessTools.FieldRefAccess<InstanceRenderer, bool>("m_firstFrame");

		private static readonly Dictionary<InstanceRenderer, Patch> Patches = new Dictionary<InstanceRenderer, Patch>(4096, ByReference<InstanceRenderer>.Instance);

		private static readonly Dictionary<KindKey, Kind> Kinds = new Dictionary<KindKey, Kind>();

		private static readonly List<Kind> KindList = new List<Kind>();

		private static readonly Stack<int> FreeKinds = new Stack<int>();

		private static readonly Dictionary<Material, bool> GrassMaterials = new Dictionary<Material, bool>(ByReference<Material>.Instance);

		private const int MinClass = 4;

		private const int Classes = 7;

		private const int StartSlots = 524288;

		private static readonly Stack<int>[] Free = new Stack<int>[7];

		private static int _top;

		private static int _capacity;

		private static GraphicsBuffer _objectToWorld;

		private static GraphicsBuffer _worldToObject;

		private static GraphicsBuffer _visible;

		private static GraphicsBuffer _invertRecords;

		private static int _visibleCapacity;

		private static int _invertRecordCapacity;

		private const int MaxPatches = 16384;

		private const int MaxKinds = 256;

		private static GraphicsBuffer _patches;

		private static GraphicsBuffer _state;

		private static GraphicsBuffer _draw;

		private static GraphicsBuffer _args;

		private static GraphicsBuffer _kindBase;

		private static readonly Stack<int> FreeIds = new Stack<int>();

		private static int _idTop;

		private static readonly PatchGpu[] OnePatch = new PatchGpu[1];

		private static readonly Vector2[] OneState = (Vector2[])(object)new Vector2[1];

		private static readonly uint[] ArgsData = new uint[1280];

		private static readonly uint[] KindBases = new uint[256];

		private static bool _kindsDirty = true;

		private static bool _activeLast;

		private static bool _lean;

		private const int SliceOf = 64;

		private static readonly HashSet<IMonoUpdater> LeftToGame = new HashSet<IMonoUpdater>(ByReference<IMonoUpdater>.Instance);

		private static readonly List<IMonoUpdater> PassList = new List<IMonoUpdater>(4096);

		private static readonly HashSet<IMonoUpdater> InPass = new HashSet<IMonoUpdater>(ByReference<IMonoUpdater>.Instance);

		private static readonly List<InstanceRenderer> Changed = new List<InstanceRenderer>(4096);

		private static int _sliceAt;

		private static readonly Vector4[] Planes = (Vector4[])(object)new Vector4[6];

		private static int _cull;

		private static int _expand;

		private static int _invert;

		private static int _copy;

		private static readonly Vector4[] Rows = (Vector4[])(object)new Vector4[3072];

		private static int _inverts;

		private static uint[] _invertData = new uint[4096];

		private static bool _ready;

		private static bool _tried;

		private static int _layer = -1;

		private static readonly int GrassFirst = Shader.PropertyToID("_GrassFirst");

		private static long _uploads;

		private static long _uploadedInstances;

		private static long _frames;

		private static long _regrowths;

		private static long _overflow;

		private static uint _lastDrawn;

		private static bool _readbackPending;

		private static float _nextReport;

		internal static bool BuildPaused = false;

		private const float BuildBudgetMs = 0.25f;

		private const float BuildBacklogBudgetMs = 2f;

		private const int BuildBacklog = 64;

		private const int MostPerKind = 1023;

		private static readonly Dictionary<object, BuiltPatch> Built = new Dictionary<object, BuiltPatch>(4096, ByReference<object>.Instance);

		private static readonly Dictionary<Vector2Int, BuiltPatch> BuiltCells = new Dictionary<Vector2Int, BuiltPatch>(4096);

		private static readonly Dictionary<Vector2s, TerrainCopy> Copies = new Dictionary<Vector2s, TerrainCopy>();

		private static readonly Queue<BuildJob> Waiting = new Queue<BuildJob>();

		private static readonly Queue<BuildJob> ToBuild = new Queue<BuildJob>();

		private static readonly Queue<BuildJob> Finished = new Queue<BuildJob>();

		private static readonly List<BuildKind> KindsNow = new List<BuildKind>();

		private static BuildKind[] _buildKinds;

		private static int _buildKindsFrame = -1;

		private static bool _buildOn;

		private static bool _buildLast;

		private static bool _holding;

		private static bool _buildBroken;

		private static bool _foreign;

		private static ClutterSystem _buildFor;

		private static ClutterSystem _foreignChecked;

		private static Thread _worker;

		private static readonly FieldRef<Heightmap, List<float>> HmHeights = AccessTools.FieldRefAccess<Heightmap, List<float>>("m_heights");

		private static readonly FieldRef<Heightmap, Texture2D> HmMask = AccessTools.FieldRefAccess<Heightmap, Texture2D>("m_paintMask");

		private static readonly FieldRef<Heightmap, float[]> HmOcean = AccessTools.FieldRefAccess<Heightmap, float[]>("m_oceanDepth");

		private static readonly FieldRef<Heightmap, BiomeSector[]> HmCorners = AccessTools.FieldRefAccess<Heightmap, BiomeSector[]>("m_cornerBiomes");

		private static readonly FieldRef<ClutterSystem, Quality> Quality = AccessTools.FieldRefAccess<ClutterSystem, Quality>("m_quality");

		private static Vector4[] _buildRows = (Vector4[])(object)new Vector4[12288];

		private static readonly float[] Weights = new float[10];

		private static List<object[]> Offers => SharedElection.Offers("ValheimMods.Shared.GpuGrass");

		internal static bool AnyActive
		{
			get
			{
				if (AppDomain.CurrentDomain.GetData("ValheimMods.Shared.GpuGrass.active") is Func<bool> func)
				{
					return func();
				}
				return false;
			}
		}

		private static bool Wanted => _wanted;

		private static bool Active
		{
			get
			{
				if (_ready)
				{
					return Wanted;
				}
				return false;
			}
		}

		private static bool GameLogicToo => GrassCheck.GameLogicToo;

		private static void AuditIfDue()
		{
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			if (!SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.On || _audit != null || (Time.time < _nextAudit && !GrassSnapshot.TakeAudit()))
			{
				return;
			}
			_nextAudit = Time.time + 20f;
			Audit a = new Audit
			{
				IdTop = _idTop,
				Kinds = KindList.Count,
				Capacity = _capacity,
				VisibleCapacity = _visibleCapacity,
				Regrowths = _regrowths,
				Frame = Time.frameCount,
				Totals = new long[KindList.Count],
				Bases = new uint[KindList.Count],
				KindNames = new string[KindList.Count]
			};
			for (int i = 0; i < KindList.Count; i++)
			{
				a.Totals[i] = KindList[i].Total;
				a.Bases[i] = KindBases[i];
				a.KindNames[i] = (((Object)(object)KindList[i].Mesh != (Object)null) ? ((Object)KindList[i].Mesh).name : "?");
			}
			foreach (int freeId in FreeIds)
			{
				a.FreeIds.Add(freeId);
			}
			foreach (KeyValuePair<InstanceRenderer, Patch> patch in Patches)
			{
				Patch value = patch.Value;
				if (!value.Grass)
				{
					continue;
				}
				InstanceRenderer key = patch.Key;
				AuditPatch auditPatch = new AuditPatch
				{
					Name = (((Object)(object)key != (Object)null) ? ((Object)key).name : "(destroyed)"),
					Position = (((Object)(object)key != (Object)null) ? ((Component)key).transform.position : Vector3.zero),
					Id = value.Id,
					Slot = value.Slot,
					Capacity = value.Capacity,
					Count = value.Uploaded,
					Kind = value.Kind.Index,
					Sphere = new Vector4(value.Center.x, value.Center.y, value.Center.z, value.Radius)
				};
				if ((Object)(object)key != (Object)null && !value.Dirty && InstanceCount.Invoke(key) == value.Uploaded)
				{
					Matrix4x4[] array = Matrices.Invoke(key);
					auditPatch.Rows = (Vector4[])(object)new Vector4[value.Uploaded * 3];
					for (int j = 0; j < value.Uploaded; j++)
					{
						Matrix4x4 val = array[j];
						auditPatch.Rows[j * 3] = new Vector4(val.m00, val.m01, val.m02, val.m03);
						auditPatch.Rows[j * 3 + 1] = new Vector4(val.m10, val.m11, val.m12, val.m13);
						auditPatch.Rows[j * 3 + 2] = new Vector4(val.m20, val.m21, val.m22, val.m23);
					}
				}
				a.Patches.Add(auditPatch);
			}
			foreach (BuiltPatch value2 in Built.Values)
			{
				foreach (Patch item in value2.Drawn)
				{
					AddBuilt(a, item);
				}
				if (value2.Job == null)
				{
					continue;
				}
				foreach (Patch replace in value2.Job.Replaces)
				{
					AddBuilt(a, replace);
				}
			}
			_audit = a;
			Read(_patches, a, delegate(PatchGpu[] d)
			{
				a.Table = d;
			});
			Read<Vector4>(_objectToWorld, a, (Action<Vector4[]>)delegate(Vector4[] d)
			{
				a.ObjectToWorld = d;
			});
			Read<Vector4>(_worldToObject, a, (Action<Vector4[]>)delegate(Vector4[] d)
			{
				a.WorldToObject = d;
			});
			Read(_draw, a, delegate(uint[] d)
			{
				a.Draw = d;
			});
			Read(_visible, a, delegate(uint[] d)
			{
				a.Visible = d;
			});
			Read(_args, a, delegate(uint[] d)
			{
				a.Args = d;
			});
			Read<uint>(_kindBase, a, delegate
			{
			});
		}

		private static void AddBuilt(Audit a, Patch p)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			a.Patches.Add(new AuditPatch
			{
				Name = "(built off the main thread)",
				Position = p.Center,
				Id = p.Id,
				Slot = p.Slot,
				Capacity = p.Capacity,
				Count = p.Uploaded,
				Kind = p.Kind.Index,
				Sphere = new Vector4(p.Center.x, p.Center.y, p.Center.z, p.Radius)
			});
		}

		private static void Read<T>(GraphicsBuffer buffer, Audit a, Action<T[]> store) where T : struct
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (buffer == null)
			{
				Arrived(a, failed: true);
				return;
			}
			AsyncGPUReadback.Request(buffer, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest req)
			{
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				if (!((AsyncGPUReadbackRequest)(ref req)).hasError)
				{
					store(((AsyncGPUReadbackRequest)(ref req)).GetData<T>(0).ToArray());
				}
				Arrived(a, ((AsyncGPUReadbackRequest)(ref req)).hasError);
			});
		}

		private static void Arrived(Audit a, bool failed)
		{
			if (failed)
			{
				a.Failed++;
			}
			if (--a.Pending > 0)
			{
				return;
			}
			if (_audit == a)
			{
				_audit = null;
			}
			if (a.Failed > 0)
			{
				SteadyFramePlugin.Log.LogInfo((object)$"[grass] GPU buffers check at frame {a.Frame}: {a.Failed} reads failed, skipped");
				return;
			}
			try
			{
				Check(a);
			}
			catch (Exception arg)
			{
				SteadyFramePlugin.Log.LogError((object)$"[grass] GPU buffers check failed: {arg}");
			}
		}

		private static void Check(Audit a)
		{
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0449: Unknown result type (might be due to invalid IL or missing references)
			//IL_0450: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_050d: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, (int count, StringBuilder text)> problems = new Dictionary<string, (int, StringBuilder)>();
			Dictionary<int, AuditPatch> dictionary = new Dictionary<int, AuditPatch>();
			long num = 0L;
			long num2 = 0L;
			Vector3 val5 = default(Vector3);
			foreach (AuditPatch patch in a.Patches)
			{
				dictionary[patch.Id] = patch;
				num += patch.Count;
				PatchGpu patchGpu = a.Table[patch.Id];
				uint num3 = (uint)Math.Max(patch.Slot, 0);
				if ((patchGpu.Flags & 1) == 0 || patchGpu.Count != patch.Count || patchGpu.Slot != num3 || patchGpu.Kind != patch.Kind)
				{
					Problem("table", $"{Describe(patch)}: GPU has flags {patchGpu.Flags} count {patchGpu.Count} slot {patchGpu.Slot} kind {patchGpu.Kind}");
				}
				if (patch.Count > 0 && (patch.Slot < 0 || patch.Count > patch.Capacity || patch.Slot + patch.Capacity > a.Capacity))
				{
					Problem("table", $"{Describe(patch)}: allocation out of bounds (buffer {a.Capacity})");
				}
				if (patch.Count == 0 || patch.Slot < 0)
				{
					continue;
				}
				for (int i = 0; i < patch.Count; i++)
				{
					int num4 = (patch.Slot + i) * 3;
					Vector4 val = a.ObjectToWorld[num4];
					Vector4 val2 = a.ObjectToWorld[num4 + 1];
					Vector4 val3 = a.ObjectToWorld[num4 + 2];
					if (patch.Rows != null)
					{
						num2++;
						if (val != patch.Rows[i * 3] || val2 != patch.Rows[i * 3 + 1] || val3 != patch.Rows[i * 3 + 2])
						{
							Problem("rows", $"{Describe(patch)}, instance {i}: GPU position ({val.w:F2}, {val2.w:F2}, {val3.w:F2}), " + $"game ({patch.Rows[i * 3].w:F2}, {patch.Rows[i * 3 + 1].w:F2}, {patch.Rows[i * 3 + 2].w:F2})");
						}
					}
					Vector4 w = a.WorldToObject[num4];
					Vector4 w2 = a.WorldToObject[num4 + 1];
					Vector4 w3 = a.WorldToObject[num4 + 2];
					InverseError(val, val2, val3, w, w2, w3, out var linear, out var offset);
					Vector3 val4 = new Vector3(val.w, val2.w, val3.w);
					float magnitude = ((Vector3)(ref val4)).magnitude;
					if (!(linear < 0.001f) || !(offset < 1E-05f * (1f + magnitude)))
					{
						Problem("inverse", $"{Describe(patch)}, instance {i}: world-to-object x object-to-world off identity by {linear:G3} (3x3), {offset:G3} m (offset)");
					}
					((Vector3)(ref val5))..ctor(val.w, val2.w, val3.w);
					val4 = new Vector3(val.x, val2.x, val3.x);
					float magnitude2 = ((Vector3)(ref val4)).magnitude;
					val4 = new Vector3(val.y, val2.y, val3.y);
					float magnitude3 = ((Vector3)(ref val4)).magnitude;
					val4 = new Vector3(val.z, val2.z, val3.z);
					float num5 = Mathf.Max(magnitude2, Mathf.Max(magnitude3, ((Vector3)(ref val4)).magnitude));
					val4 = val5 - Vector4.op_Implicit(patch.Sphere);
					if (((Vector3)(ref val4)).magnitude > patch.Sphere.w + 0.01f || !(num5 < 20f) || !(num5 > 0.01f))
					{
						Problem("sanity", $"{Describe(patch)}, instance {i}: at {val5:F2}, scale {num5:G3}, sphere {patch.Sphere:F1}");
					}
				}
			}
			List<AuditPatch> list = new List<AuditPatch>();
			foreach (AuditPatch patch2 in a.Patches)
			{
				if (patch2.Slot >= 0)
				{
					list.Add(patch2);
				}
			}
			list.Sort((AuditPatch x, AuditPatch y) => x.Slot.CompareTo(y.Slot));
			for (int num6 = 1; num6 < list.Count; num6++)
			{
				if (list[num6 - 1].Slot + list[num6 - 1].Capacity > list[num6].Slot)
				{
					Problem("slots", Describe(list[num6 - 1]) + " overlaps " + Describe(list[num6]));
				}
			}
			for (int num7 = 0; num7 < a.IdTop; num7++)
			{
				if (!dictionary.ContainsKey(num7) && (a.Table[num7].Flags & 1) != 0)
				{
					Problem("table", $"id {num7} (free {a.FreeIds.Contains(num7)}) has no live patch but is active: count {a.Table[num7].Count} slot {a.Table[num7].Slot} kind {a.Table[num7].Kind}");
				}
			}
			long[] array = new long[a.Kinds];
			long num8 = 0L;
			for (int num9 = 0; num9 < a.IdTop; num9++)
			{
				uint num10 = a.Draw[num9 * 4];
				uint num11 = a.Draw[num9 * 4 + 1];
				uint num12 = a.Draw[num9 * 4 + 2];
				if (num11 == 0)
				{
					continue;
				}
				PatchGpu patchGpu2 = a.Table[num9];
				AuditPatch value;
				string text = (dictionary.TryGetValue(num9, out value) ? Describe(value) : $"id {num9} (no live patch)");
				if (patchGpu2.Kind >= a.Kinds)
				{
					Problem("draws", $"{text}: kind {patchGpu2.Kind} of {a.Kinds}");
					continue;
				}
				array[patchGpu2.Kind] += num11;
				if (num10 != patchGpu2.Slot || num11 > patchGpu2.Count)
				{
					Problem("draws", $"{text}: record slot {num10} count {num11}, table slot {patchGpu2.Slot} count {patchGpu2.Count}");
				}
				long num13 = a.Bases[patchGpu2.Kind];
				long num14 = num13 + a.Totals[patchGpu2.Kind];
				if (num12 < num13 || num12 + num11 > num14 || num12 + num11 > a.Visible.Length)
				{
					Problem("draws", $"{text}: places {num12}..{num12 + num11} outside its kind's {num13}..{num14} (visible list {a.Visible.Length})");
					continue;
				}
				for (uint num15 = 0u; num15 < num11; num15++)
				{
					num8++;
					if (a.Visible[num12 + num15] != num10 + num15)
					{
						Problem("visible", $"{text}: visible[{num12 + num15}] = {a.Visible[num12 + num15]}, expected {num10 + num15}");
						break;
					}
				}
			}
			for (int num16 = 0; num16 < a.Kinds; num16++)
			{
				uint num17 = a.Args[num16 * 5 + 1];
				if (num17 != array[num16] || num17 > a.Totals[num16])
				{
					Problem("args", $"kind {num16} ({a.KindNames[num16]}): draws {num17} instances, records sum {array[num16]}, total {a.Totals[num16]}");
				}
			}
			string text2 = $"frame {a.Frame}: {a.Patches.Count} patches, {num} instances ({num2} rows compared), " + $"{a.Kinds} kinds, slots {a.Capacity} (grown {a.Regrowths}), {num8} visible entries";
			if (problems.Count == 0)
			{
				SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.Agreed();
				SteadyFramePlugin.Log.LogInfo((object)("[grass] GPU buffers check " + text2 + ": consistent"));
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(text2);
			foreach (KeyValuePair<string, (int, StringBuilder)> item in problems)
			{
				stringBuilder.Append($"\n  {item.Key}: {item.Value.Item1}").Append(item.Value.Item2);
			}
			SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.Diverged(stringBuilder.ToString());
			string Describe(AuditPatch p)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				return $"patch id {p.Id} '{p.Name}' at {p.Position:F1}, kind {p.Kind} ({a.KindNames[p.Kind]}), slot {p.Slot} cap {p.Capacity}, count {p.Count}";
			}
			void Problem(string kind, string detail)
			{
				if (!problems.TryGetValue(kind, out (int, StringBuilder) value2))
				{
					value2 = (0, new StringBuilder());
				}
				if (value2.Item1 < 8)
				{
					value2.Item2.Append("\n    ").Append(detail);
				}
				problems[kind] = (value2.Item1 + 1, value2.Item2);
			}
		}

		private static void InverseError(Vector4 r0, Vector4 r1, Vector4 r2, Vector4 w0, Vector4 w1, Vector4 w2, out float linear, out float offset)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 val = default(Matrix4x4);
			Matrix4x4 val2 = default(Matrix4x4);
			((Matrix4x4)(ref val)).SetRow(0, r0);
			((Matrix4x4)(ref val)).SetRow(1, r1);
			((Matrix4x4)(ref val)).SetRow(2, r2);
			((Matrix4x4)(ref val)).SetRow(3, new Vector4(0f, 0f, 0f, 1f));
			((Matrix4x4)(ref val2)).SetRow(0, w0);
			((Matrix4x4)(ref val2)).SetRow(1, w1);
			((Matrix4x4)(ref val2)).SetRow(2, w2);
			((Matrix4x4)(ref val2)).SetRow(3, new Vector4(0f, 0f, 0f, 1f));
			Matrix4x4 val3 = val2 * val;
			linear = (offset = 0f);
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					linear = Mathf.Max(linear, Mathf.Abs(((Matrix4x4)(ref val3))[i, j] - ((i == j) ? 1f : 0f)));
				}
				offset = Mathf.Max(offset, Mathf.Abs(((Matrix4x4)(ref val3))[i, 3]));
			}
		}

		internal static void Offer(string guid, Func<bool?> wanted, Func<bool> runs = null)
		{
			Offers.Add(new object[6]
			{
				5,
				guid,
				new Action(Install),
				wanted,
				true,
				runs ?? ((Func<bool>)(() => true))
			});
		}

		internal static void Elect()
		{
			List<object[]> offers = Offers;
			if (offers.Count != 0 && AppDomain.CurrentDomain.GetData("ValheimMods.Shared.GpuGrass.elected") == null)
			{
				if (Chainloader.PluginInfos.ContainsKey("ru.ivest.steadyframe") && !offers.Exists((object[] o) => (string)o[1] == "ru.ivest.steadyframe"))
				{
					AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.elected", "none");
					Logger.CreateLogSource("GPU grass").LogInfo((object)"An older SteadyFrame draws the grass on the GPU itself; left to it.");
				}
				else
				{
					SharedElection.Elect("ValheimMods.Shared.GpuGrass", 5, WithChecks);
				}
			}
		}

		private static bool WithChecks(object[] offer, object[] best)
		{
			if ((bool)offer[4])
			{
				return !(bool)best[4];
			}
			return false;
		}

		private static void Install()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			if (SharedElection.HandedOn("ValheimMods.Shared.GpuGrass", typeof(GpuGrass), 5, WithChecks))
			{
				return;
			}
			_log = Logger.CreateLogSource("GPU grass");
			_opinions = Offers.ConvertAll((object[] o) => (Func<bool?>)o[3]).ToArray();
			Harmony val = new Harmony("ValheimMods.Shared.GpuGrass");
			try
			{
				Type[] array = new Type[13]
				{
					typeof(Patch_CustomUpdate),
					typeof(Patch_Pass),
					typeof(Patch_OnEnable),
					typeof(Patch_OnDisable),
					typeof(Patch_Clear),
					typeof(Patch_SetInstance),
					typeof(Patch_SetInstances),
					typeof(Patch_SetBillboard),
					typeof(Patch_Build),
					typeof(Patch_FreePatch),
					typeof(Patch_Regenerate),
					typeof(Patch_PaintCleared),
					typeof(Patch_HeightmapOff)
				};
				foreach (Type type in array)
				{
					val.CreateClassProcessor(type).Patch();
				}
			}
			catch (Exception ex)
			{
				val.UnpatchSelf();
				_log.LogWarning((object)("The grass is left to the game: " + ex.Message));
				return;
			}
			AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.active", (Func<bool>)(() => Active));
			AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.around", new Func<Vector3, float, object[]>(BuiltAround));
			_log.LogInfo((object)$"The grass can be drawn on the GPU (version {5}; this copy: {typeof(GpuGrass).Assembly.GetName().Name}).");
		}

		private static bool Opinion()
		{
			bool flag = false;
			Func<bool?>[] opinions = _opinions;
			foreach (Func<bool?> func in opinions)
			{
				bool? flag2 = null;
				try
				{
					flag2 = func();
				}
				catch
				{
				}
				if (flag2 == false)
				{
					return false;
				}
				flag |= flag2 == true;
			}
			return flag;
		}

		internal static Material CopyOf(InstanceRenderer r)
		{
			if (!Patches.TryGetValue(r, out var value) || !value.Grass)
			{
				return null;
			}
			return value.Kind.Copy;
		}

		private static bool Init()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			string text = GrassBundle.Load();
			if (text != null)
			{
				GrassBundle.Unload();
				_log.LogWarning((object)("[grass] GPU drawing unavailable (" + text + "); grass drawn the game's way."));
				return false;
			}
			for (int i = 0; i < 7; i++)
			{
				Free[i] = new Stack<int>();
			}
			ComputeShader kernels = GrassBundle.Kernels;
			_cull = kernels.FindKernel("Cull");
			_expand = kernels.FindKernel("Expand");
			_invert = kernels.FindKernel("Invert");
			_copy = kernels.FindKernel("Copy");
			_patches = new GraphicsBuffer((Target)16, 16384, Marshal.SizeOf<PatchGpu>());
			_patches.SetData((Array)new PatchGpu[16384]);
			_state = new GraphicsBuffer((Target)16, 16384, 8);
			_draw = new GraphicsBuffer((Target)16, 16384, 16);
			_args = new GraphicsBuffer((Target)256, 1280, 4);
			_kindBase = new GraphicsBuffer((Target)16, 256, 4);
			_layer = LayerMask.NameToLayer("InstanceRenderer");
			Grow(524288);
			_log.LogInfo((object)$"[grass] GPU drawing ready ({SystemInfo.graphicsDeviceType})");
			return true;
		}

		internal static void ResetState()
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			_ready = false;
			_tried = false;
			GraphicsBuffer[] array = (GraphicsBuffer[])(object)new GraphicsBuffer[9] { _objectToWorld, _worldToObject, _visible, _invertRecords, _patches, _state, _draw, _args, _kindBase };
			foreach (GraphicsBuffer obj in array)
			{
				if (obj != null)
				{
					obj.Release();
				}
			}
			_objectToWorld = (_worldToObject = (_visible = (_invertRecords = (_patches = (_state = (_draw = (_args = (_kindBase = null))))))));
			foreach (Kind kind in KindList)
			{
				if ((Object)(object)kind.Copy != (Object)null)
				{
					Object.Destroy((Object)(object)kind.Copy);
				}
			}
			Patches.Clear();
			Kinds.Clear();
			KindList.Clear();
			FreeKinds.Clear();
			GrassMaterials.Clear();
			FreeIds.Clear();
			_idTop = (_top = (_capacity = (_visibleCapacity = (_invertRecordCapacity = (_inverts = (_sliceAt = 0))))));
			_kindsDirty = true;
			if (Built.Count > 0 && (Object)(object)ClutterSystem.instance != (Object)null)
			{
				ClutterSystem.instance.ResetGrass(Vector3.zero, float.MaxValue);
			}
			_activeLast = (_lean = (_buildLast = (_buildOn = false)));
			LeftToGame.Clear();
			Changed.Clear();
			PassList.Clear();
			InPass.Clear();
			ClearBuilt(onCard: false);
			GrassBundle.Unload();
			GrassCheck.ResetState();
			GrassSnapshot.ResetState();
		}

		private static void Grow(int capacity)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			GraphicsBuffer objectToWorld = _objectToWorld;
			GraphicsBuffer worldToObject = _worldToObject;
			int capacity2 = _capacity;
			_capacity = capacity;
			_objectToWorld = new GraphicsBuffer((Target)16, capacity * 3, 16);
			_worldToObject = new GraphicsBuffer((Target)16, capacity * 3, 16);
			if (objectToWorld != null)
			{
				ComputeShader kernels = GrassBundle.Kernels;
				kernels.SetInt("_CopyCount", capacity2 * 3);
				kernels.SetBuffer(_copy, "_CopySource", objectToWorld);
				kernels.SetBuffer(_copy, "_CopyDest", _objectToWorld);
				kernels.Dispatch(_copy, Math.Min(4096, (capacity2 * 3 + 255) / 256), 1, 1);
				kernels.SetBuffer(_copy, "_CopySource", worldToObject);
				kernels.SetBuffer(_copy, "_CopyDest", _worldToObject);
				kernels.Dispatch(_copy, Math.Min(4096, (capacity2 * 3 + 255) / 256), 1, 1);
				objectToWorld.Release();
				worldToObject.Release();
			}
			Shader.SetGlobalBuffer("_GrassObjectToWorld", _objectToWorld);
			Shader.SetGlobalBuffer("_GrassWorldToObject", _worldToObject);
		}

		private static int ClassOf(int count)
		{
			int i;
			for (i = 0; 1 << i + 4 < count; i++)
			{
			}
			return i;
		}

		private static void Allocate(Patch p, int count)
		{
			int num = ClassOf(count);
			int num2 = 1 << num + 4;
			if (Free[num].Count > 0)
			{
				p.Slot = Free[num].Pop();
				p.Capacity = num2;
				return;
			}
			if (_top + num2 > _capacity)
			{
				_regrowths++;
				Grow(_capacity * 2);
			}
			p.Slot = _top;
			p.Capacity = num2;
			_top += num2;
		}

		private static void Deallocate(Patch p)
		{
			if (p.Slot >= 0)
			{
				Free[ClassOf(p.Capacity)].Push(p.Slot);
			}
			p.Slot = -1;
			p.Capacity = 0;
		}

		private static bool IsGrass(Material m)
		{
			if (!GrassMaterials.TryGetValue(m, out var value))
			{
				value = (Object)(object)m.shader != (Object)null && ((Object)m.shader).name == "Custom/Grass";
				GrassMaterials[m] = value;
			}
			return value;
		}

		private static bool Before(InstanceRenderer r)
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if (!_ready)
			{
				return true;
			}
			if (!Patches.TryGetValue(r, out var value))
			{
				value = Register(r);
				Patches.Add(r, value);
				if (!value.Grass)
				{
					LeftToGame.Add((IMonoUpdater)(object)r);
				}
			}
			if (!value.Grass)
			{
				return true;
			}
			if (value.Kind.Gone)
			{
				return false;
			}
			int num = InstanceCount.Invoke(r);
			if (value.Dirty || num != value.Uploaded)
			{
				if ((Object)(object)r.m_mesh == (Object)null)
				{
					return false;
				}
				Upload(value, r, num);
			}
			if (!Active)
			{
				return true;
			}
			if (value.StateDirty)
			{
				OneState[0] = new Vector2(LodCount.Invoke(r), FirstFrame.Invoke(r) ? 1f : 0f);
				_state.SetData((Array)OneState, 0, value.Id, 1);
				value.StateDirty = false;
			}
			return GameLogicToo;
		}

		private static Patch Register(InstanceRenderer r)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			Patch patch = new Patch();
			if ((Object)(object)r.m_mesh == (Object)null || (Object)(object)r.m_material == (Object)null || !IsGrass(r.m_material))
			{
				return patch;
			}
			Kind kind = KindFor(r.m_mesh, r.m_material, r.m_shadowCasting);
			if (kind != null)
			{
				Join(patch, kind);
			}
			return patch;
		}

		private static Kind KindFor(Mesh mesh, Material material, ShadowCastingMode shadows)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			KindKey key = new KindKey(mesh, material, shadows, _layer);
			if (Kinds.TryGetValue(key, out var value))
			{
				return value;
			}
			if (FreeKinds.Count == 0 && KindList.Count == 256)
			{
				_overflow++;
				return null;
			}
			Kind obj = new Kind
			{
				Mesh = mesh,
				Original = material,
				Shadows = shadows,
				Layer = _layer,
				Index = ((FreeKinds.Count > 0) ? FreeKinds.Pop() : KindList.Count),
				Key = key,
				Name = ((Object)mesh).name
			};
			Bounds bounds = mesh.bounds;
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			obj.Extent = ((Vector3)(ref extents)).magnitude;
			obj.Copy = new Material(material)
			{
				shader = GrassBundle.Shader,
				name = ((Object)material).name + " (GPU grass)"
			};
			obj.Block = new MaterialPropertyBlock();
			value = obj;
			value.Copy.CopyPropertiesFromMaterial(material);
			Kinds.Add(key, value);
			if (value.Index == KindList.Count)
			{
				KindList.Add(value);
			}
			else
			{
				KindList[value.Index] = value;
			}
			return value;
		}

		private static bool Join(Patch p, Kind k)
		{
			if (FreeIds.Count > 0)
			{
				p.Id = FreeIds.Pop();
			}
			else
			{
				if (_idTop >= 16384)
				{
					_overflow++;
					return false;
				}
				p.Id = _idTop++;
			}
			p.Grass = true;
			p.Kind = k;
			p.Member = k.Members.Count;
			k.Members.Add(p);
			return true;
		}

		private static void Upload(Patch p, InstanceRenderer r, int total)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4[] array = Matrices.Invoke(r);
			Bounds bounds = r.m_mesh.bounds;
			Vector3 val = ((Bounds)(ref bounds)).extents;
			float magnitude = ((Vector3)(ref val)).magnitude;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(9999999f, 9999999f, 9999999f);
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(-9999999f, -9999999f, -9999999f);
			Vector3 val5 = default(Vector3);
			for (int i = 0; i < total; i++)
			{
				Matrix4x4 val4 = array[i];
				((Vector3)(ref val5))..ctor(val4.m03, val4.m13, val4.m23);
				Vector3 lossyScale = ((Matrix4x4)(ref val4)).lossyScale;
				float num = Mathf.Max(Mathf.Max(lossyScale.x, lossyScale.y), lossyScale.z) * magnitude;
				val2 = Vector3.Min(val2, val5 - Vector3.one * num);
				val3 = Vector3.Max(val3, val5 + Vector3.one * num);
				Rows[i * 3] = new Vector4(val4.m00, val4.m01, val4.m02, val4.m03);
				Rows[i * 3 + 1] = new Vector4(val4.m10, val4.m11, val4.m12, val4.m13);
				Rows[i * 3 + 2] = new Vector4(val4.m20, val4.m21, val4.m22, val4.m23);
			}
			Vector3 val6 = (val2 + val3) * 0.5f;
			Vector4[] rows = Rows;
			val = val3 - val6;
			Store(p, rows, 0, total, val6, ((Vector3)(ref val)).magnitude, ((Component)r).transform.position, r.m_lodMinDistance, r.m_lodMaxDistance, FlagsOf(r));
		}

		private static uint FlagsOf(InstanceRenderer r)
		{
			return (uint)(1 | (r.m_frustumCull ? 2 : 0) | (r.m_useLod ? 4 : 0) | (r.m_useXZLodDistance ? 8 : 0));
		}

		private static void Store(Patch p, Vector4[] rows, int firstRow, int total, Vector3 center, float radius, Vector3 at, float lodMin, float lodMax, uint flags)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if (total > 0 && (p.Slot < 0 || total > p.Capacity))
			{
				Deallocate(p);
				Allocate(p, total);
			}
			if (total > 0)
			{
				_objectToWorld.SetData((Array)rows, firstRow, p.Slot * 3, total * 3);
				if (_inverts * 4 + 4 > _invertData.Length)
				{
					Array.Resize(ref _invertData, _invertData.Length * 2);
				}
				_invertData[_inverts * 4] = (uint)p.Slot;
				_invertData[_inverts * 4 + 1] = (uint)total;
				_inverts++;
			}
			p.Center = center;
			p.Radius = radius;
			p.Kind.Total += total - p.Uploaded;
			p.Kind.BoundsDirty = true;
			_kindsDirty = true;
			p.Uploaded = total;
			p.Dirty = false;
			_uploads++;
			_uploadedInstances += total;
			OnePatch[0] = new PatchGpu
			{
				Sphere = new Vector4(p.Center.x, p.Center.y, p.Center.z, p.Radius),
				Position = new Vector4(at.x, at.y, at.z, lodMin),
				LodMax = lodMax,
				Flags = flags,
				Count = (uint)total,
				Slot = (uint)Math.Max(p.Slot, 0),
				Kind = (uint)p.Kind.Index
			};
			_patches.SetData((Array)OnePatch, 0, p.Id, 1);
		}

		private static void Forget(InstanceRenderer r)
		{
			if (_ready && Patches.TryGetValue(r, out var value))
			{
				Patches.Remove(r);
				if (!value.Grass)
				{
					LeftToGame.Remove((IMonoUpdater)(object)r);
				}
				else
				{
					ForgetPatch(value);
				}
			}
		}

		private static void ForgetPatch(Patch p)
		{
			OnePatch[0] = default(PatchGpu);
			_patches.SetData((Array)OnePatch, 0, p.Id, 1);
			FreeIds.Push(p.Id);
			Deallocate(p);
			Kind kind = p.Kind;
			kind.Total -= p.Uploaded;
			Patch patch = kind.Members[kind.Members.Count - 1];
			kind.Members[p.Member] = patch;
			patch.Member = p.Member;
			kind.Members.RemoveAt(kind.Members.Count - 1);
			kind.BoundsDirty = true;
			_kindsDirty = true;
		}

		private static void Touch(InstanceRenderer r)
		{
			if (Patches.TryGetValue(r, out var value) && value.Grass)
			{
				if (!value.Dirty && _activeLast)
				{
					Changed.Add(r);
				}
				value.Dirty = true;
			}
		}

		private static void Born(InstanceRenderer r)
		{
			if (_activeLast)
			{
				Changed.Add(r);
			}
		}

		public static void Draw(Mesh mesh, int submesh, Material material, Matrix4x4[] matrices, int count, MaterialPropertyBlock props, ShadowCastingMode shadows, bool receive, int layer, InstanceRenderer self)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Patch value = null;
			if (!Active || !Patches.TryGetValue(self, out value) || !value.Grass)
			{
				Graphics.DrawMeshInstanced(mesh, submesh, material, matrices, count, props, shadows, receive, layer);
			}
			else if (GrassCheck.Frame)
			{
				GrassCheck.DrawGame(mesh, material, value.Kind.Copy, matrices, count, shadows, receive, layer);
			}
		}

		private static void BeginPass()
		{
			_lean = false;
			_wanted = Opinion();
			if (!Wanted)
			{
				if (_tried)
				{
					ResetState();
				}
				_activeLast = false;
				_buildOn = false;
				return;
			}
			if (!_tried)
			{
				_tried = true;
				_ready = Init();
			}
			bool active = Active;
			if (active && !_activeLast)
			{
				foreach (Patch value in Patches.Values)
				{
					value.StateDirty = true;
				}
			}
			BuildPass(active);
			_lean = active && _activeLast && !GameLogicToo;
			_activeLast = active;
			if (_lean)
			{
				GatherPass();
			}
			else
			{
				Changed.Clear();
			}
			if (active)
			{
				GrassCheck.BeginPass();
			}
		}

		private static void GatherPass()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			PassList.Clear();
			InPass.Clear();
			foreach (IMonoUpdater item in LeftToGame)
			{
				PassList.Add(item);
				InPass.Add(item);
			}
			foreach (InstanceRenderer item2 in Changed)
			{
				if ((Object)(object)item2 != (Object)null && ((Behaviour)item2).isActiveAndEnabled && InPass.Add((IMonoUpdater)(object)item2))
				{
					PassList.Add((IMonoUpdater)(object)item2);
				}
			}
			Changed.Clear();
			List<IMonoUpdater> instances = InstanceRenderer.Instances;
			for (int num = ((instances.Count != 0) ? (instances.Count / 64 + 1) : 0); num > 0; num--)
			{
				if (_sliceAt >= instances.Count)
				{
					_sliceAt = 0;
				}
				InstanceRenderer val = (InstanceRenderer)instances[_sliceAt++];
				if ((!Patches.TryGetValue(val, out var value) || (value.Grass && (value.Dirty || InstanceCount.Invoke(val) != value.Uploaded))) && InPass.Add((IMonoUpdater)(object)val))
				{
					PassList.Add((IMonoUpdater)(object)val);
				}
			}
		}

		public static void AddToPass(List<IMonoUpdater> container, IEnumerable<IMonoUpdater> source)
		{
			IEnumerable<IMonoUpdater> collection;
			if (!_lean || source != InstanceRenderer.Instances)
			{
				collection = source;
			}
			else
			{
				IEnumerable<IMonoUpdater> passList = PassList;
				collection = passList;
			}
			container.AddRange(collection);
		}

		private static void Ensure(ref GraphicsBuffer buffer, ref int capacity, int needed, int stride, string global)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			if (buffer == null || capacity < needed)
			{
				GraphicsBuffer obj = buffer;
				if (obj != null)
				{
					obj.Release();
				}
				capacity = Math.Max(needed, Math.Max(capacity * 2, 1024));
				buffer = new GraphicsBuffer((Target)16, capacity, stride);
				if (global != null)
				{
					Shader.SetGlobalBuffer(global, buffer);
				}
			}
		}

		private static void EndPass(float deltaTime)
		{
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0621: Unknown result type (might be due to invalid IL or missing references)
			//IL_0623: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0504: Unknown result type (might be due to invalid IL or missing references)
			//IL_0509: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0514: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_052a: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0550: Unknown result type (might be due to invalid IL or missing references)
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			//IL_055f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0561: Unknown result type (might be due to invalid IL or missing references)
			//IL_0563: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Unknown result type (might be due to invalid IL or missing references)
			if (!_ready)
			{
				return;
			}
			ComputeShader kernels = GrassBundle.Kernels;
			if (_inverts > 0)
			{
				Ensure(ref _invertRecords, ref _invertRecordCapacity, _inverts, 16, null);
				_invertRecords.SetData((Array)_invertData, 0, 0, _inverts * 4);
				kernels.SetBuffer(_invert, "_Records", _invertRecords);
				kernels.SetBuffer(_invert, "_ObjectToWorld", _objectToWorld);
				kernels.SetBuffer(_invert, "_WorldToObject", _worldToObject);
				kernels.SetInt("_RecordCount", _inverts);
				kernels.Dispatch(_invert, _inverts, 1, 1);
				_inverts = 0;
			}
			if (!Active || _idTop == 0)
			{
				return;
			}
			Camera mainCamera = Utils.GetMainCamera();
			Plane[] mainCameraFrustumPlanes = Utils.GetMainCameraFrustumPlanes();
			if ((Object)(object)mainCamera == (Object)null || mainCameraFrustumPlanes == null)
			{
				return;
			}
			_frames++;
			int count = KindList.Count;
			if (_kindsDirty)
			{
				long num = 0L;
				for (int i = 0; i < count; i++)
				{
					KindList[i].Base = (int)num;
					KindBases[i] = (uint)num;
					num += KindList[i].Total;
				}
				_kindBase.SetData((Array)KindBases, 0, 0, count);
				Ensure(ref _visible, ref _visibleCapacity, (int)Math.Max(num, 1L), 4, "_GrassVisible");
				_kindsDirty = false;
			}
			for (int j = 0; j < count; j++)
			{
				Kind kind = KindList[j];
				if (!kind.Gone && ((Object)(object)kind.Mesh == (Object)null || (Object)(object)kind.Original == (Object)null))
				{
					kind.Gone = true;
					_log.LogInfo((object)("[grass] the mesh or material of grass '" + kind.Name + "' was destroyed (another mod's grass?); " + $"its {kind.Members.Count} patches are no longer drawn"));
				}
				if (kind.Gone)
				{
					if (!kind.Retired && kind.Members.Count == 0)
					{
						Kinds.Remove(kind.Key);
						if ((Object)(object)kind.Copy != (Object)null)
						{
							Object.Destroy((Object)(object)kind.Copy);
						}
						kind.Retired = true;
						FreeKinds.Push(kind.Index);
					}
					Array.Clear(ArgsData, j * 5, 5);
				}
				else
				{
					Mesh mesh = kind.Mesh;
					ArgsData[j * 5] = mesh.GetIndexCount(0);
					ArgsData[j * 5 + 1] = 0u;
					ArgsData[j * 5 + 2] = mesh.GetIndexStart(0);
					ArgsData[j * 5 + 3] = mesh.GetBaseVertex(0);
					ArgsData[j * 5 + 4] = 0u;
				}
			}
			_args.SetData((Array)ArgsData, 0, 0, count * 5);
			for (int k = 0; k < 6; k++)
			{
				Planes[k] = new Vector4(((Plane)(ref mainCameraFrustumPlanes[k])).normal.x, ((Plane)(ref mainCameraFrustumPlanes[k])).normal.y, ((Plane)(ref mainCameraFrustumPlanes[k])).normal.z, ((Plane)(ref mainCameraFrustumPlanes[k])).distance);
			}
			Vector3 position = ((Component)mainCamera).transform.position;
			kernels.SetVectorArray("_Planes", Planes);
			kernels.SetVector("_Camera", new Vector4(position.x, position.y, position.z, deltaTime));
			kernels.SetInt("_PatchCount", _idTop);
			kernels.SetBuffer(_cull, "_Patches", _patches);
			kernels.SetBuffer(_cull, "_State", _state);
			kernels.SetBuffer(_cull, "_Draw", _draw);
			kernels.SetBuffer(_cull, "_Args", _args);
			kernels.SetBuffer(_cull, "_KindBase", _kindBase);
			kernels.Dispatch(_cull, (_idTop + 63) / 64, 1, 1);
			kernels.SetBuffer(_expand, "_Draw", _draw);
			kernels.SetBuffer(_expand, "_Visible", _visible);
			kernels.Dispatch(_expand, _idTop, 1, 1);
			foreach (Kind kind2 in KindList)
			{
				if (kind2.Total == 0L || kind2.Gone)
				{
					continue;
				}
				if (kind2.BoundsDirty)
				{
					Vector3 val = Vector3.one * float.MaxValue;
					Vector3 val2 = Vector3.one * float.MinValue;
					foreach (Patch member in kind2.Members)
					{
						if (member.Uploaded != 0)
						{
							val = Vector3.Min(val, member.Center - Vector3.one * member.Radius);
							val2 = Vector3.Max(val2, member.Center + Vector3.one * member.Radius);
						}
					}
					kind2.Bounds = new Bounds((val + val2) * 0.5f, val2 - val);
					kind2.BoundsDirty = false;
				}
				kind2.Copy.CopyPropertiesFromMaterial(kind2.Original);
				kind2.Block.SetInteger(GrassFirst, kind2.Base);
				RenderParams val3 = new RenderParams(kind2.Copy);
				((RenderParams)(ref val3)).worldBounds = kind2.Bounds;
				((RenderParams)(ref val3)).matProps = kind2.Block;
				((RenderParams)(ref val3)).shadowCastingMode = kind2.Shadows;
				((RenderParams)(ref val3)).receiveShadows = true;
				((RenderParams)(ref val3)).layer = kind2.Layer;
				((RenderParams)(ref val3)).camera = (GrassCheck.Frame ? GrassCheck.Gpu : null);
				((RenderParams)(ref val3)).lightProbeUsage = (LightProbeUsage)1;
				((RenderParams)(ref val3)).reflectionProbeUsage = (ReflectionProbeUsage)1;
				((RenderParams)(ref val3)).motionVectorMode = (MotionVectorGenerationMode)0;
				RenderParams val4 = val3;
				Graphics.RenderMeshIndirect(ref val4, kind2.Mesh, _args, 1, kind2.Index);
			}
			AuditIfDue();
			if (_readbackPending || !(Time.realtimeSinceStartup >= _nextReport))
			{
				return;
			}
			_readbackPending = true;
			AsyncGPUReadback.Request(_args, count * 20, 0, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest req)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				_readbackPending = false;
				if (!((AsyncGPUReadbackRequest)(ref req)).hasError)
				{
					NativeArray<uint> data = ((AsyncGPUReadbackRequest)(ref req)).GetData<uint>(0);
					uint num2 = 0u;
					for (int l = 0; l < data.Length / 5; l++)
					{
						num2 += data[l * 5 + 1];
					}
					_lastDrawn = num2;
				}
			});
		}

		internal static void LateTick()
		{
			if (_ready)
			{
				bool frame = GrassCheck.Frame;
				GrassCheck.LateUpdate();
				GrassSnapshot.LateUpdate(Active, frame);
				if (!(Time.realtimeSinceStartup < _nextReport) && (GameLogicToo || GrassCheck.BuffersCheck))
				{
					_nextReport = Time.realtimeSinceStartup + 600f;
					_log.LogInfo((object)(string.Format("[grass] GPU drawing {0}: patches {1} in {2} kinds, ", Active ? "on" : "off", _idTop - FreeIds.Count, KindList.Count - FreeKinds.Count) + $"slots {_top}/{_capacity} (grown {_regrowths}), uploads {_uploads} ({_uploadedInstances} instances), " + $"{_lastDrawn} instances drawn in the last sampled frame, {_frames} frames, over limits {_overflow}"));
				}
			}
		}

		private static void BuildPass(bool on)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			ClutterSystem instance = ClutterSystem.instance;
			if (instance != _buildFor)
			{
				ClearBuilt(onCard: true);
				_buildFor = instance;
				_buildLast = false;
			}
			bool flag = on && !GameLogicToo && !BuildPaused && !_buildBroken && (Object)(object)instance != (Object)null && !instance.m_menuHack && !ForeignBuild(instance);
			if (flag != _buildLast)
			{
				_buildLast = flag;
				if (!flag && Built.Count > 0 && (Object)(object)instance != (Object)null)
				{
					instance.ResetGrass(Vector3.zero, float.MaxValue);
				}
			}
			_buildOn = flag;
			if (on && (Waiting.Count > 0 || Built.Count > 0))
			{
				PumpBuild();
			}
		}

		private static bool ForeignBuild(ClutterSystem cs)
		{
			if (_foreignChecked == cs)
			{
				return _foreign;
			}
			_foreignChecked = cs;
			HashSet<string> hashSet = new HashSet<string>();
			MethodBase[] array = new MethodBase[3]
			{
				AccessTools.Method(typeof(ClutterSystem), "GenerateVegPatch", (Type[])null, (Type[])null),
				AccessTools.Method(typeof(InstanceRenderer), "AddInstance", new Type[3]
				{
					typeof(Vector3),
					typeof(Quaternion),
					typeof(float)
				}, (Type[])null),
				AccessTools.Method(typeof(InstanceRenderer), "AddInstance", new Type[1] { typeof(Matrix4x4) }, (Type[])null)
			};
			foreach (MethodBase methodBase in array)
			{
				Patches val = ((methodBase == null) ? null : Harmony.GetPatchInfo(methodBase));
				if (val == null)
				{
					continue;
				}
				foreach (string owner in val.Owners)
				{
					if (owner != "ValheimMods.Shared.GpuGrass" && !owner.StartsWith("farlands.stand"))
					{
						hashSet.Add(owner);
					}
				}
			}
			_foreign = hashSet.Count > 0;
			if (_foreign)
			{
				_log.LogWarning((object)("[grass] patches are left to the game's build: " + string.Join(", ", hashSet) + " patch it"));
			}
			return _foreign;
		}

		private static void PumpBuild()
		{
			float num = ((Waiting.Count + ToBuild.Count + Finished.Count > 64) ? 2f : 0.25f);
			long started = Stopwatch.GetTimestamp();
			while (Waiting.Count > 0 && Spent() < (double)num)
			{
				BuildJob buildJob = Waiting.Dequeue();
				if (Current(buildJob))
				{
					Prepare(buildJob);
					if (_worker == null)
					{
						_worker = new Thread(WorkerLoop)
						{
							IsBackground = true,
							Name = "GPU grass build",
							Priority = ThreadPriority.BelowNormal
						};
						_worker.Start();
					}
					lock (ToBuild)
					{
						ToBuild.Enqueue(buildJob);
						Monitor.Pulse(ToBuild);
					}
				}
			}
			do
			{
				BuildJob buildJob2;
				lock (Finished)
				{
					if (Finished.Count == 0)
					{
						break;
					}
					buildJob2 = Finished.Dequeue();
				}
				if (buildJob2.Error != null && !_buildBroken)
				{
					_buildBroken = true;
					_log.LogWarning((object)$"[grass] building a patch failed, patches are the game's again: {buildJob2.Error}");
				}
				if (Current(buildJob2))
				{
					Apply(buildJob2);
				}
			}
			while (Spent() < (double)num);
			double Spent()
			{
				return (double)(Stopwatch.GetTimestamp() - started) * 1000.0 / (double)Stopwatch.Frequency;
			}
		}

		private static bool Current(BuildJob job)
		{
			if (Built.TryGetValue(job.Owner, out var value))
			{
				return value.Job == job;
			}
			return false;
		}

		private static void Apply(BuildJob job)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			BuiltPatch builtPatch = Built[job.Owner];
			builtPatch.Job = null;
			if (job.Error == null)
			{
				for (int i = 0; i < job.Kinds.Length; i++)
				{
					int num = job.Count[i];
					BuildKind buildKind = job.Kinds[i];
					if (num != 0 && !buildKind.Kind.Gone)
					{
						Patch patch = new Patch();
						if (Join(patch, buildKind.Kind))
						{
							Vector3 val = (job.Min[i] + job.Max[i]) * 0.5f;
							Vector3 val2 = job.Max[i] - val;
							float magnitude = ((Vector3)(ref val2)).magnitude;
							Store(patch, job.Rows, job.First[i] * 3, num, val, magnitude, new Vector3((float)((Vector2Int)(ref job.Cell)).x * job.Size, 0f, (float)((Vector2Int)(ref job.Cell)).y * job.Size), buildKind.LodMin, buildKind.LodMax, buildKind.Flags);
							OneState[0] = new Vector2(0f, 1f);
							_state.SetData((Array)OneState, 0, patch.Id, 1);
							patch.StateDirty = false;
							builtPatch.Drawn.Add(patch);
						}
					}
				}
			}
			if (job.Error == null)
			{
				builtPatch.Kinds = job.Kinds;
				builtPatch.First = job.First;
				builtPatch.Count = job.Count;
				builtPatch.Rows = job.Rows;
				builtPatch.Size = job.Size;
			}
			foreach (Patch replace in job.Replaces)
			{
				ForgetPatch(replace);
			}
			job.Rows = null;
		}

		private static object[] BuiltAround(Vector3 point, float radius)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			List<object> list = new List<object>();
			foreach (BuiltPatch value in Built.Values)
			{
				if (value.Rows == null)
				{
					continue;
				}
				float num = radius + value.Size;
				float num2 = (float)((Vector2Int)(ref value.Cell)).x * value.Size - point.x;
				float num3 = (float)((Vector2Int)(ref value.Cell)).y * value.Size - point.z;
				if (num2 * num2 + num3 * num3 > num * num)
				{
					continue;
				}
				for (int i = 0; i < value.Kinds.Length; i++)
				{
					int num4 = value.Count[i];
					Kind kind = value.Kinds[i].Kind;
					if (num4 != 0 && !kind.Gone)
					{
						Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num4];
						int num5 = 0;
						int num6 = value.First[i] * 3;
						while (num5 < num4)
						{
							Vector4 val = value.Rows[num6];
							Vector4 val2 = value.Rows[num6 + 1];
							Vector4 val3 = value.Rows[num6 + 2];
							array[num5] = new Matrix4x4
							{
								m00 = val.x,
								m01 = val.y,
								m02 = val.z,
								m03 = val.w,
								m10 = val2.x,
								m11 = val2.y,
								m12 = val2.z,
								m13 = val2.w,
								m20 = val3.x,
								m21 = val3.y,
								m22 = val3.z,
								m23 = val3.w,
								m33 = 1f
							};
							num5++;
							num6 += 3;
						}
						list.Add(new object[4] { kind.Mesh, kind.Original, kind.Shadows, array });
					}
				}
			}
			return list.ToArray();
		}

		private static void Freed(object owner)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!Built.TryGetValue(owner, out var value))
			{
				return;
			}
			Built.Remove(owner);
			int num;
			if (BuiltCells.TryGetValue(value.Cell, out var value2))
			{
				num = ((value2 != value) ? 1 : 0);
				if (num != 0)
				{
					goto IL_004e;
				}
			}
			else
			{
				num = 0;
			}
			BuiltCells.Remove(value.Cell);
			goto IL_004e;
			IL_004e:
			if (num != 0 && value2.Job != null)
			{
				value2.Job.Replaces.AddRange(value.Drawn);
				if (value.Job != null)
				{
					value2.Job.Replaces.AddRange(value.Job.Replaces);
				}
			}
			else
			{
				foreach (Patch item in value.Drawn)
				{
					ForgetPatch(item);
				}
				if (value.Job != null)
				{
					foreach (Patch replace in value.Job.Replaces)
					{
						ForgetPatch(replace);
					}
				}
			}
			value.Job = null;
		}

		private static void ClearBuilt(bool onCard)
		{
			if (onCard && _ready)
			{
				foreach (BuiltPatch value in Built.Values)
				{
					foreach (Patch item in value.Drawn)
					{
						ForgetPatch(item);
					}
					if (value.Job == null)
					{
						continue;
					}
					foreach (Patch replace in value.Job.Replaces)
					{
						ForgetPatch(replace);
					}
				}
			}
			Built.Clear();
			BuiltCells.Clear();
			Copies.Clear();
			Waiting.Clear();
			lock (ToBuild)
			{
				ToBuild.Clear();
			}
			lock (Finished)
			{
				Finished.Clear();
			}
			_buildKindsFrame = -1;
		}

		private static void RefreshKinds(ClutterSystem cs)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Invalid comparison between Unknown and I4
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Invalid comparison between Unknown and I4
			if (_buildKindsFrame == Time.frameCount)
			{
				return;
			}
			_buildKindsFrame = Time.frameCount;
			KindsNow.Clear();
			Quality val = Quality.Invoke(cs);
			float num = cs.m_distance - cs.m_grassPatchSize / 2f;
			for (int i = 0; i < cs.m_clutter.Count; i++)
			{
				Clutter val2 = cs.m_clutter[i];
				if (!val2.m_enabled || !val2.m_instanced || (Object)(object)val2.m_prefab == (Object)null)
				{
					continue;
				}
				InstanceRenderer component = val2.m_prefab.GetComponent<InstanceRenderer>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_mesh == (Object)null) && !((Object)(object)component.m_material == (Object)null) && IsGrass(component.m_material))
				{
					Kind kind = KindFor(component.m_mesh, component.m_material, component.m_shadowCasting);
					if (kind != null && !kind.Gone)
					{
						KindsNow.Add(new BuildKind
						{
							Kind = kind,
							Index = i,
							Scale = component.m_scale,
							Extent = kind.Extent,
							Biome = val2.m_biome,
							Amount = (int)((float)(((int)val == 1) ? (val2.m_amount / 4) : (((int)val == 2) ? (val2.m_amount / 2) : val2.m_amount)) * cs.m_amountScale),
							LodMin = component.m_lodMinDistance,
							LodMax = Mathf.Min(component.m_lodMaxDistance, num),
							Flags = FlagsOf(component),
							InForest = val2.m_inForest,
							ForestMin = val2.m_forestTresholdMin,
							ForestMax = val2.m_forestTresholdMax,
							FractalScale = val2.m_fractalScale,
							FractalOffset = val2.m_fractalOffset,
							FractalMin = val2.m_fractalTresholdMin,
							FractalMax = val2.m_fractalTresholdMax,
							MinAlt = val2.m_minAlt,
							MaxAlt = val2.m_maxAlt,
							MinNormal = Mathf.Cos(MathF.PI / 180f * val2.m_maxTilt),
							MaxNormal = Mathf.Cos(MathF.PI / 180f * val2.m_minTilt),
							MinOcean = val2.m_minOceanDepth,
							MaxOcean = val2.m_maxOceanDepth,
							MinVegetation = val2.m_minVegetation,
							MaxVegetation = val2.m_maxVegetation,
							OnCleared = val2.m_onCleared,
							OnUncleared = val2.m_onUncleared,
							SnapToWater = val2.m_snapToWater,
							TerrainTilt = val2.m_terrainTilt,
							RandomOffset = val2.m_randomOffset,
							ScaleMin = val2.m_scaleMin,
							ScaleMax = val2.m_scaleMax
						});
					}
				}
			}
			_buildKinds = KindsNow.ToArray();
		}

		private static void Prepare(BuildJob job)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			float num = job.Size / 2f;
			float num2 = (float)((Vector2Int)(ref job.Cell)).x * job.Size;
			float num3 = (float)((Vector2Int)(ref job.Cell)).y * job.Size;
			job.Maps[0] = CopyAt(new Vector3(num2 - num, 0f, num3 - num));
			job.Maps[1] = CopyAt(new Vector3(num2 + num, 0f, num3 - num));
			job.Maps[2] = CopyAt(new Vector3(num2 - num, 0f, num3 + num));
			job.Maps[3] = CopyAt(new Vector3(num2 + num, 0f, num3 + num));
		}

		private static TerrainCopy CopyAt(Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected I4, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected I4, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected I4, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Expected I4, but got Unknown
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			Vector2s zone = ZoneSystem.GetZone(point);
			if (Copies.TryGetValue(zone, out var value))
			{
				return value;
			}
			foreach (Heightmap allHeightmap in Heightmap.GetAllHeightmaps())
			{
				if (!allHeightmap.IsDistantLod && allHeightmap.IsPointInside(point, 0f))
				{
					Texture2D val = HmMask.Invoke(allHeightmap);
					List<float> list = HmHeights.Invoke(allHeightmap);
					if ((Object)(object)val == (Object)null || list.Count == 0)
					{
						return null;
					}
					BiomeSector[] array = HmCorners.Invoke(allHeightmap);
					TerrainCopy terrainCopy = new TerrainCopy();
					terrainCopy.Width = allHeightmap.m_width;
					terrainCopy.Scale = allHeightmap.m_scale;
					terrainCopy.Half = (float)allHeightmap.m_width * allHeightmap.m_scale * 0.5f;
					terrainCopy.Position = ((Component)allHeightmap).transform.position;
					terrainCopy.Heights = list.ToArray();
					terrainCopy.Mask = val.GetPixels32();
					terrainCopy.MaskWidth = ((Texture)val).width;
					terrainCopy.Ocean = (float[])HmOcean.Invoke(allHeightmap).Clone();
					terrainCopy.Corners = (Biome[])(object)new Biome[4]
					{
						(Biome)(int)array[0].Biome,
						(Biome)(int)array[1].Biome,
						(Biome)(int)array[2].Biome,
						(Biome)(int)array[3].Biome
					};
					value = terrainCopy;
					Copies[zone] = value;
					return value;
				}
			}
			return null;
		}

		private static void Forget(Heightmap h)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!h.IsDistantLod && Copies.Count > 0)
			{
				Copies.Remove(ZoneSystem.GetZone(((Component)h).transform.position));
			}
		}

		private static void WorkerLoop()
		{
			while (true)
			{
				BuildJob buildJob;
				lock (ToBuild)
				{
					while (ToBuild.Count == 0)
					{
						Monitor.Wait(ToBuild);
					}
					buildJob = ToBuild.Dequeue();
				}
				try
				{
					Build(buildJob);
				}
				catch (Exception error)
				{
					buildJob.Error = error;
				}
				lock (Finished)
				{
					Finished.Enqueue(buildJob);
				}
			}
		}

		private static TerrainCopy MapAt(BuildJob job, float x, float z)
		{
			TerrainCopy[] maps = job.Maps;
			foreach (TerrainCopy terrainCopy in maps)
			{
				if (terrainCopy != null && x >= terrainCopy.Position.x - terrainCopy.Half && x <= terrainCopy.Position.x + terrainCopy.Half && z >= terrainCopy.Position.z - terrainCopy.Half && z <= terrainCopy.Position.z + terrainCopy.Half)
				{
					return terrainCopy;
				}
			}
			return null;
		}

		private static float CornerPull(float x, float y, float rx, float ry)
		{
			float num = (float)((double)x - (double)rx);
			float num2 = (float)((double)y - (double)ry);
			float num3 = (float)(1.4140000343322754 - (double)(float)Math.Sqrt((float)((double)num * (double)num + (double)num2 * (double)num2)));
			return (float)((double)num3 * (double)num3 * (double)num3);
		}

		private static Biome BiomeOf(TerrainCopy m, float px, float pz)
		{
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			Biome[] corners = m.Corners;
			if ((int)corners[0] == (int)corners[1] && (int)corners[0] == (int)corners[2] && (int)corners[0] == (int)corners[3])
			{
				return corners[0];
			}
			float num = (float)m.Width * m.Scale;
			float x = (px - m.Position.x) / num + 0.5f;
			float y = (pz - m.Position.z) / num + 0.5f;
			Array.Clear(Weights, 0, Weights.Length);
			Weights[BiomeHelpers.ToIndex(corners[0])] += CornerPull(x, y, 0f, 0f);
			Weights[BiomeHelpers.ToIndex(corners[1])] += CornerPull(x, y, 1f, 0f);
			Weights[BiomeHelpers.ToIndex(corners[2])] += CornerPull(x, y, 0f, 1f);
			Weights[BiomeHelpers.ToIndex(corners[3])] += CornerPull(x, y, 1f, 1f);
			int num2 = 0;
			float num3 = -99999f;
			for (int i = 1; i < Weights.Length; i++)
			{
				if (Weights[i] > num3)
				{
					num2 = i;
					num3 = Weights[i];
				}
			}
			return BiomeHelpers.ToBiome((BiomeIndex)(byte)num2);
		}

		private static void GroundOf(TerrainCopy m, float px, float pz, out float y, out Vector3 normal)
		{
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			float num = (px - m.Position.x) / m.Scale + (float)m.Width * 0.5f;
			float num2 = (pz - m.Position.z) / m.Scale + (float)m.Width * 0.5f;
			int num3 = Mathf.Clamp((int)Math.Floor(num), 0, m.Width - 1);
			int num4 = Mathf.Clamp((int)Math.Floor(num2), 0, m.Width - 1);
			float num5 = num - (float)num3;
			float num6 = num2 - (float)num4;
			int num7 = m.Width + 1;
			float num8 = m.Heights[num4 * num7 + num3];
			float num9 = m.Heights[num4 * num7 + num3 + 1];
			float num10 = m.Heights[(num4 + 1) * num7 + num3];
			float num11 = m.Heights[(num4 + 1) * num7 + num3 + 1];
			float num12;
			float num13;
			if (num5 + num6 <= 1f)
			{
				num12 = num9 - num8;
				num13 = num10 - num8;
				y = num8 + num12 * num5 + num13 * num6;
			}
			else
			{
				num12 = num11 - num10;
				num13 = num11 - num9;
				y = num11 + num12 * (num5 - 1f) + num13 * (num6 - 1f);
			}
			y += m.Position.y;
			Vector3 val = new Vector3(0f - num12, m.Scale, 0f - num13);
			normal = ((Vector3)(ref val)).normalized;
		}

		private static Color32 PixelOf(TerrainCopy m, float px, float pz)
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			int num = (m.Width + 1) / 2;
			int num2 = Mathf.Clamp((int)Math.Floor((px - m.Position.x) / m.Scale + 0.5f + (float)num), 0, m.MaskWidth - 1);
			int num3 = Mathf.Clamp((int)Math.Floor((pz - m.Position.z) / m.Scale + 0.5f + (float)num), 0, m.MaskWidth - 1);
			return m.Mask[num3 * m.MaskWidth + num2];
		}

		private static void Build(BuildJob job)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing