Decompiled source of ValheimOptimized v1.1.1

ValheimOptimized_1.1.1/ValheimOptimized.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SoftReferenceableAssets;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.PostProcessing;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimOptimized")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_postprocessing")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
[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;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public string AssemblyName { get; }

		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
			AssemblyName = assemblyName;
		}
	}
}
namespace ValheimOptimized
{
	internal static class AllocTrim
	{
		private sealed class ModCache
		{
			public SharedData R;

			public SharedData L;

			public SharedData C;

			public SharedData G;

			public SharedData H;

			public SharedData S;

			public SharedData U;

			public SharedData T;
		}

		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyTranspiler]
			[HarmonyPatch(typeof(Player), "Update")]
			private static IEnumerable<CodeInstruction> Update_Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_015a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0161: Expected O, but got Unknown
				List<CodeInstruction> list = instructions.ToList();
				MethodInfo methodInfo = AccessTools.Method(typeof(string), "Format", new Type[2]
				{
					typeof(string),
					typeof(object)
				}, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(AllocTrim), "HotbarName", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(AllocTrim), "HotbarAltName", (Type[])null, (Type[])null);
				int num = 0;
				for (int i = 0; i + 3 < list.Count; i++)
				{
					if (!(list[i].opcode != OpCodes.Ldstr) && list[i].operand is string text && (!(text != "Hotbar{0}") || !(text != "Hotbar{0}Alt")) && !(list[i + 2].opcode != OpCodes.Box) && CodeInstructionExtensions.Calls(list[i + 3], methodInfo))
					{
						list[i].opcode = OpCodes.Nop;
						list[i].operand = null;
						list[i + 2].opcode = OpCodes.Nop;
						list[i + 2].operand = null;
						CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)((text == "Hotbar{0}") ? methodInfo2 : methodInfo3));
						val.labels.AddRange(list[i + 3].labels);
						val.blocks.AddRange(list[i + 3].blocks);
						list[i + 3] = val;
						num++;
					}
				}
				if (num == 0)
				{
					Plugin.Log.LogWarning((object)"AllocTrim: Player.Update hotbar pattern not found (hotbar string cache inactive)");
				}
				return list;
			}

			[HarmonyTranspiler]
			[HarmonyPatch(/*Could not decode attribute arguments.*/)]
			private static IEnumerable<CodeInstruction> InstanceRenderer_Ctor(IEnumerable<CodeInstruction> instructions)
			{
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Expected O, but got Unknown
				List<CodeInstruction> list = instructions.ToList();
				MethodInfo methodInfo = AccessTools.Method(typeof(AllocTrim), "RentMatrices", (Type[])null, (Type[])null);
				int num = 0;
				for (int i = 0; i + 1 < list.Count; i++)
				{
					if (list[i].opcode == OpCodes.Ldc_I4 && list[i].operand is int num2 && num2 == 1024 && list[i + 1].opcode == OpCodes.Newarr && list[i + 1].operand as Type == typeof(Matrix4x4))
					{
						list[i].opcode = OpCodes.Nop;
						list[i].operand = null;
						CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)methodInfo);
						val.labels.AddRange(list[i + 1].labels);
						list[i + 1] = val;
						num++;
					}
				}
				if (num == 0)
				{
					Plugin.Log.LogWarning((object)"AllocTrim: InstanceRenderer allocation pattern not found (grass matrix pool inactive)");
				}
				return list;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ClutterSystem), "FreePatch")]
			private static void FreePatch_Prefix(PatchData patch)
			{
				if (patch == null)
				{
					return;
				}
				List<GameObject> objects = patch.m_objects;
				for (int i = 0; i < objects.Count; i++)
				{
					GameObject val = objects[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					InstanceRenderer component = val.GetComponent<InstanceRenderer>();
					if ((Object)(object)component == (Object)null)
					{
						continue;
					}
					Matrix4x4[] instances = component.m_instances;
					if (instances == null || instances.Length != 1024)
					{
						continue;
					}
					component.m_instanceCount = 0;
					component.m_instances = NoMatrices;
					lock (MatrixPool)
					{
						if (MatrixPool.Count < 256)
						{
							MatrixPool.Push(instances);
							PoolReturned++;
						}
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Utils), "ChebyshevDistance", new Type[]
			{
				typeof(Vector3),
				typeof(Vector3)
			})]
			private static bool Chebyshev_Prefix(Vector3 a, Vector3 b, ref float __result)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				float num = a.x - b.x;
				if (num < 0f)
				{
					num = 0f - num;
				}
				float num2 = a.y - b.y;
				if (num2 < 0f)
				{
					num2 = 0f - num2;
				}
				float num3 = a.z - b.z;
				if (num3 < 0f)
				{
					num3 = 0f - num3;
				}
				float num4 = num;
				if (num2 > num4)
				{
					num4 = num2;
				}
				if (num3 > num4)
				{
					num4 = num3;
				}
				__result = num4;
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Player), "UpdateModifiers")]
			private static bool UpdateModifiers_Prefix(Player __instance)
			{
				ModCache orCreateValue = Cache.GetOrCreateValue(__instance);
				SharedData val = ((Humanoid)__instance).m_rightItem?.m_shared;
				SharedData val2 = ((Humanoid)__instance).m_leftItem?.m_shared;
				SharedData val3 = ((Humanoid)__instance).m_chestItem?.m_shared;
				SharedData val4 = ((Humanoid)__instance).m_legItem?.m_shared;
				SharedData val5 = ((Humanoid)__instance).m_helmetItem?.m_shared;
				SharedData val6 = ((Humanoid)__instance).m_shoulderItem?.m_shared;
				SharedData val7 = ((Humanoid)__instance).m_utilityItem?.m_shared;
				SharedData val8 = ((Humanoid)__instance).m_trinketItem?.m_shared;
				if (orCreateValue.R == val && orCreateValue.L == val2 && orCreateValue.C == val3 && orCreateValue.G == val4 && orCreateValue.H == val5 && orCreateValue.S == val6 && orCreateValue.U == val7 && orCreateValue.T == val8)
				{
					return false;
				}
				orCreateValue.R = val;
				orCreateValue.L = val2;
				orCreateValue.C = val3;
				orCreateValue.G = val4;
				orCreateValue.H = val5;
				orCreateValue.S = val6;
				orCreateValue.U = val7;
				orCreateValue.T = val8;
				return true;
			}
		}

		private static readonly string[] Hotbar;

		private static readonly string[] HotbarAlt;

		private static readonly ConditionalWeakTable<Player, ModCache> Cache;

		private static readonly Stack<Matrix4x4[]> MatrixPool;

		private static readonly Matrix4x4[] NoMatrices;

		internal static int PoolHits;

		internal static int PoolMisses;

		internal static int PoolReturned;

		static AllocTrim()
		{
			Hotbar = new string[9];
			HotbarAlt = new string[9];
			Cache = new ConditionalWeakTable<Player, ModCache>();
			MatrixPool = new Stack<Matrix4x4[]>();
			NoMatrices = (Matrix4x4[])(object)new Matrix4x4[0];
			for (int i = 0; i < 9; i++)
			{
				Hotbar[i] = "Hotbar" + i;
				HotbarAlt[i] = "Hotbar" + i + "Alt";
			}
		}

		public static string HotbarName(int i)
		{
			if ((uint)i >= 9u)
			{
				return "Hotbar" + i;
			}
			return Hotbar[i];
		}

		public static string HotbarAltName(int i)
		{
			if ((uint)i >= 9u)
			{
				return "Hotbar" + i + "Alt";
			}
			return HotbarAlt[i];
		}

		public static Matrix4x4[] RentMatrices()
		{
			lock (MatrixPool)
			{
				if (MatrixPool.Count > 0)
				{
					PoolHits++;
					return MatrixPool.Pop();
				}
			}
			PoolMisses++;
			return (Matrix4x4[])(object)new Matrix4x4[1024];
		}
	}
	internal static class DepthNormalsFix
	{
		private static Camera _cam;

		private static bool _strippedLastFrame;

		private static bool _backedOff;

		private static bool _wasActive;

		private static int _readdCount;

		internal static void Tick()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			GameCamera instance = GameCamera.instance;
			if ((Object)(object)instance == (Object)null)
			{
				_cam = null;
				return;
			}
			Camera camera = instance.m_camera;
			if ((Object)(object)camera == (Object)null)
			{
				return;
			}
			if ((Object)(object)camera != (Object)(object)_cam)
			{
				_cam = camera;
				_strippedLastFrame = false;
				_backedOff = false;
				_readdCount = 0;
			}
			bool flag = (camera.depthTextureMode & 2) > 0;
			if (_backedOff)
			{
				return;
			}
			if (flag && _strippedLastFrame && ++_readdCount >= 3)
			{
				_backedOff = true;
				Plugin.Log.LogWarning((object)"DepthNormals is re-requested by another camera effect; leaving it on.");
			}
			else if (flag)
			{
				if (!IsSafe(instance, out var why))
				{
					_backedOff = true;
					Plugin.Log.LogWarning((object)("DepthNormals kept: " + why));
				}
				else
				{
					camera.depthTextureMode = (DepthTextureMode)((camera.depthTextureMode & -3) | 1);
					_strippedLastFrame = true;
					_wasActive = true;
				}
			}
			else
			{
				_strippedLastFrame = false;
				_wasActive = true;
			}
		}

		private static bool IsSafe(GameCamera gc, out string why)
		{
			//IL_0081: 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_0022: Invalid comparison between Unknown and I4
			why = null;
			AmplifyOcclusionEffect component = ((Component)gc).GetComponent<AmplifyOcclusionEffect>();
			if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled && (int)component.PerPixelNormals == 1)
			{
				why = "Amplify Occlusion uses camera normals";
				return false;
			}
			PostProcessingBehaviour component2 = ((Component)gc).GetComponent<PostProcessingBehaviour>();
			if ((Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled && (Object)(object)component2.profile != (Object)null && component2.profile.ambientOcclusion != null && ((PostProcessingModel)component2.profile.ambientOcclusion).enabled)
			{
				why = "PostProcessing ambient occlusion is enabled";
				return false;
			}
			_ = gc.m_camera.actualRenderingPath;
			_ = 3;
			return true;
		}
	}
	internal static class FrameLoad
	{
		private static float _avg = 1f / 60f;

		internal static bool Busy
		{
			get
			{
				float num = _avg * 1.8f;
				if (num < 0.009f)
				{
					num = 0.009f;
				}
				return Time.unscaledDeltaTime > num;
			}
		}

		internal static void Tick()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			if (unscaledDeltaTime > 0f && unscaledDeltaTime < 0.1f)
			{
				_avg += (unscaledDeltaTime - _avg) * 0.02f;
			}
		}
	}
	internal static class MinimapUpload
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
			{
				typeof(Vector3),
				typeof(float)
			})]
			private static bool Explore_Prefix(Minimap __instance, Vector3 p, float radius)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				Texture2D fogTexture = __instance.m_fogTexture;
				if ((Object)(object)fogTexture == (Object)null)
				{
					return true;
				}
				int textureSize = __instance.m_textureSize;
				int num = (int)Mathf.Ceil(radius / __instance.m_pixelSize);
				int num2 = default(int);
				int num3 = default(int);
				__instance.WorldToPixel(p, ref num2, ref num3);
				int num4 = int.MaxValue;
				int num5 = int.MaxValue;
				int num6 = -1;
				int num7 = -1;
				for (int i = num3 - num; i <= num3 + num; i++)
				{
					if (i < 0 || i >= textureSize)
					{
						continue;
					}
					for (int j = num2 - num; j <= num2 + num; j++)
					{
						if (j < 0 || j >= textureSize)
						{
							continue;
						}
						Vector2 val = new Vector2((float)(j - num2), (float)(i - num3));
						if (!(((Vector2)(ref val)).magnitude > (float)num) && __instance.Explore(j, i))
						{
							if (j < num4)
							{
								num4 = j;
							}
							if (j > num6)
							{
								num6 = j;
							}
							if (i < num5)
							{
								num5 = i;
							}
							if (i > num7)
							{
								num7 = i;
							}
						}
					}
				}
				if (num6 >= 0)
				{
					try
					{
						Upload(fogTexture, num4, num5, num6 - num4 + 1, num7 - num5 + 1);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Minimap partial upload failed, falling back to vanilla: " + ex.Message));
						_supported = 0;
						fogTexture.Apply();
					}
				}
				return false;
			}
		}

		private const int StageSize = 64;

		private static Texture2D _stage;

		private static int _supported = -1;

		private static bool Supported(Texture2D tex)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (_supported < 0)
			{
				_supported = (((SystemInfo.copyTextureSupport & 1) > 0) ? 1 : 0);
			}
			if (_supported == 1)
			{
				return ((Texture)tex).mipmapCount == 1;
			}
			return false;
		}

		private static void Upload(Texture2D tex, int x, int y, int w, int h)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			if (w > 64 || h > 64 || !Supported(tex))
			{
				tex.Apply();
				return;
			}
			if ((Object)(object)_stage == (Object)null || ((Texture)_stage).graphicsFormat != ((Texture)tex).graphicsFormat)
			{
				if ((Object)(object)_stage != (Object)null)
				{
					Object.Destroy((Object)(object)_stage);
				}
				_stage = new Texture2D(64, 64, ((Texture)tex).graphicsFormat, (TextureCreationFlags)0)
				{
					name = "ValheimOptimized_FogStage",
					hideFlags = (HideFlags)61,
					wrapMode = (TextureWrapMode)1,
					filterMode = (FilterMode)0
				};
			}
			Color[] pixels = tex.GetPixels(x, y, w, h);
			_stage.SetPixels(0, 0, w, h, pixels);
			_stage.Apply(false, false);
			Graphics.CopyTexture((Texture)(object)_stage, 0, 0, 0, 0, w, h, (Texture)(object)tex, 0, 0, x, y);
		}
	}
	internal static class ObjectSpawn
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNetScene), "CreateObjects")]
			private static void CreateObjects_Prefix(ZNetScene __instance, List<ZDO> currentNearObjects)
			{
				_t0 = Stopwatch.GetTimestamp();
				float num = ((Plugin.CObjectBudget != null) ? Plugin.CObjectBudget.Value : 1f);
				int count = currentNearObjects.Count;
				if (count > 1500)
				{
					num *= 3f;
				}
				else if (count > 500)
				{
					num *= 2f;
				}
				_budget = (long)((double)num * Tick);
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZoneSystem), "ShouldDelayProxyLocationSpawning")]
			private static void DelayLocation_Post(ref bool __result)
			{
				if (__result)
				{
					return;
				}
				ZNetScene instance = ZNetScene.instance;
				if ((Object)(object)instance == (Object)null || instance.InLoadingScreen())
				{
					return;
				}
				if (Stopwatch.GetTimestamp() < _locNextAllowed)
				{
					__result = true;
					return;
				}
				int frameCount = Time.frameCount;
				if (frameCount == _locBusyFrame)
				{
					__result = true;
				}
				else if (FrameLoad.Busy && _locBusySkips < 6)
				{
					_locBusySkips++;
					_locBusyFrame = frameCount;
					__result = true;
				}
				else
				{
					_locBusySkips = 0;
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZoneSystem), "SpawnProxyLocation")]
			private static void SpawnLoc_Pre()
			{
				_locStart = Stopwatch.GetTimestamp();
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZoneSystem), "SpawnProxyLocation")]
			private static void SpawnLoc_Post()
			{
				long timestamp = Stopwatch.GetTimestamp();
				double num = (double)(timestamp - _locStart) / Tick;
				double num2 = Math.Min(400.0, Math.Max(50.0, num * 2.0));
				_locNextAllowed = timestamp + (long)(num2 * Tick);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNetScene), "CreateObjectsSorted")]
			private static bool CreateObjectsSorted_Prefix(ZNetScene __instance, List<ZDO> currentNearObjects, int maxCreatedPerFrame, ref int created)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: 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)
				if (!Active(__instance))
				{
					return true;
				}
				if (!ZoneSystem.instance.IsActiveAreaLoaded())
				{
					return false;
				}
				List<ZDO> tempCurrentObjects = __instance.m_tempCurrentObjects2;
				tempCurrentObjects.Clear();
				Vector3 referencePosition = ZNet.instance.GetReferencePosition();
				foreach (ZDO currentNearObject in currentNearObjects)
				{
					if (!currentNearObject.Created)
					{
						currentNearObject.m_tempSortValue = Utils.DistanceSqr(referencePosition, currentNearObject.GetPosition());
						tempCurrentObjects.Add(currentNearObject);
					}
				}
				if (tempCurrentObjects.Count == 0)
				{
					return false;
				}
				int num = Mathf.Max(tempCurrentObjects.Count / 100, maxCreatedPerFrame);
				tempCurrentObjects.Sort((Comparison<ZDO>)ZNetScene.ZDOCompare);
				foreach (ZDO item in tempCurrentObjects)
				{
					if (!ZoneSystem.instance.IsZoneReadyForType(item.GetSector(), item.Type))
					{
						continue;
					}
					if ((Object)(object)__instance.CreateObject(item) != (Object)null)
					{
						created++;
						if (created >= num || OverBudget())
						{
							break;
						}
					}
					else if (ZNet.instance.IsServer())
					{
						item.SetOwner(ZDOMan.GetSessionID());
						ZLog.Log((object)("Destroyed invalid prefab ZDO:" + ((object)Unsafe.As<ZDOID, ZDOID>(ref item.m_uid)/*cast due to .constrained prefix*/).ToString()));
						ZDOMan.instance.DestroyZDO(item);
					}
				}
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNetScene), "CreateDistantObjects")]
			private static bool CreateDistantObjects_Prefix(ZNetScene __instance, List<ZDO> objects, int maxCreatedPerFrame, ref int created)
			{
				if (!Active(__instance))
				{
					return true;
				}
				if (created > maxCreatedPerFrame || OverBudget())
				{
					return false;
				}
				foreach (ZDO @object in objects)
				{
					if (@object.Created)
					{
						continue;
					}
					if ((Object)(object)__instance.CreateObject(@object) != (Object)null)
					{
						created++;
						if (created > maxCreatedPerFrame || OverBudget())
						{
							break;
						}
					}
					else if (ZNet.instance.IsServer())
					{
						@object.SetOwner(ZDOMan.GetSessionID());
						ZLog.Log((object)("Destroyed invalid predab ZDO:" + ((object)Unsafe.As<ZDOID, ZDOID>(ref @object.m_uid)/*cast due to .constrained prefix*/).ToString() + "  prefab hash:" + @object.GetPrefab()));
						ZDOMan.instance.DestroyZDO(@object);
					}
				}
				return false;
			}
		}

		private static readonly double Tick = (double)Stopwatch.Frequency / 1000.0;

		private static long _t0;

		private static long _budget;

		private static long _locNextAllowed;

		private static long _locStart;

		private static int _locBusySkips;

		private static int _locBusyFrame = -1;

		private static bool Active(ZNetScene zs)
		{
			if (!zs.InLoadingScreen())
			{
				return (Object)(object)ZNet.instance != (Object)null;
			}
			return false;
		}

		private static bool OverBudget()
		{
			return Stopwatch.GetTimestamp() - _t0 > _budget;
		}
	}
	internal static class ShadowCull
	{
		private static Light _light;

		private static bool _dirty = true;

		private static bool _applied;

		private static float _next;

		internal static void MarkDirty()
		{
			_dirty = true;
		}

		internal static void Tick()
		{
			if (Time.unscaledTime < _next && !_dirty)
			{
				return;
			}
			_next = Time.unscaledTime + 1f;
			EnvMan instance = EnvMan.instance;
			Light val = (((Object)(object)instance != (Object)null) ? instance.m_dirLight : null);
			if ((Object)(object)val == (Object)null)
			{
				_light = null;
				return;
			}
			if ((Object)(object)val != (Object)(object)_light || _dirty || !_applied)
			{
				val.layerShadowCullDistances = Build();
				_light = val;
				_applied = true;
			}
			_dirty = false;
		}

		private static float[] Build()
		{
			float[] array = new float[32];
			Set(array, "piece", Plugin.CShadowPiece.Value);
			Set(array, "piece_nonsolid", Plugin.CShadowSmall.Value);
			Set(array, "Default_small", Plugin.CShadowSmall.Value);
			Set(array, "effect", Plugin.CShadowSmall.Value);
			Set(array, "item", Plugin.CShadowItem.Value);
			Set(array, "weapon", Plugin.CShadowItem.Value);
			Set(array, "character", Plugin.CShadowCharacter.Value);
			Set(array, "character_net", Plugin.CShadowCharacter.Value);
			Set(array, "character_noenv", Plugin.CShadowCharacter.Value);
			Set(array, "character_ghost", Plugin.CShadowCharacter.Value);
			Set(array, "vehicle", Plugin.CShadowVehicle.Value);
			return array;
		}

		private static void Set(float[] d, string layer, float dist)
		{
			int num = LayerMask.NameToLayer(layer);
			if (num >= 0 && num < 32)
			{
				d[num] = Mathf.Max(0f, dist);
			}
		}
	}
	internal static class SkyAlphaThrottle
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(DepthCamera), "RenderDepth")]
			private static bool RenderDepth_Prefix(DepthCamera __instance)
			{
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_012b: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
				Camera mainCamera = Utils.GetMainCamera();
				if ((Object)(object)mainCamera == (Object)null)
				{
					return true;
				}
				if ((Object)(object)__instance.m_camera != (Object)null)
				{
					_mask = __instance.m_camera.cullingMask;
				}
				Vector3 val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Component)Player.m_localPlayer).transform.position : ((Component)mainCamera).transform.position);
				float time = Time.time;
				bool flag = (Object)(object)__instance.m_texture != (Object)null && !__instance.m_texture.IsCreated();
				bool flag2 = !_has || _dirty || flag || time - _lastTime >= Plugin.CSkyMaxInterval.Value;
				if (!flag2)
				{
					float num = val.x - _lastCenter.x;
					float num2 = val.z - _lastCenter.z;
					float value = Plugin.CSkyMove.Value;
					if (num * num + num2 * num2 > value * value || Mathf.Abs(val.y - _lastCenter.y) > Plugin.CSkyVertical.Value)
					{
						flag2 = true;
					}
				}
				if (!flag2)
				{
					return false;
				}
				_has = true;
				_dirty = false;
				_lastCenter = val;
				_lastTime = time;
				return true;
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZNetView), "Awake")]
			private static void ZNetView_Awake(ZNetView __instance)
			{
				MarkIfRelevant(((Component)__instance).gameObject);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNetView), "OnDestroy")]
			private static void ZNetView_OnDestroy(ZNetView __instance)
			{
				MarkIfRelevant(((Component)__instance).gameObject);
			}
		}

		private static bool _has;

		private static Vector3 _lastCenter;

		private static float _lastTime;

		private static bool _dirty = true;

		private static int _mask = 33792;

		private const float DirtyRadius = 60f;

		private static void MarkIfRelevant(GameObject go)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (_has && !_dirty && !((Object)(object)go == (Object)null))
			{
				Vector3 position = go.transform.position;
				float num = position.x - _lastCenter.x;
				float num2 = position.z - _lastCenter.z;
				if (!(num * num + num2 * num2 > 3600f) && ((_mask & (1 << go.layer)) != 0 || !((Object)(object)go.GetComponent<Piece>() == (Object)null)))
				{
					_dirty = true;
				}
			}
		}
	}
	internal static class SyncCoalesce
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyTranspiler]
			[HarmonyPatch(typeof(ZSyncTransform), "SyncPosition")]
			private static IEnumerable<CodeInstruction> SyncPosition_Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo target = AccessTools.Method(typeof(Physics), "SyncTransforms", (Type[])null, (Type[])null);
				MethodInfo repl = AccessTools.Method(typeof(SyncCoalesce), "Sync", (Type[])null, (Type[])null);
				int n = 0;
				foreach (CodeInstruction instruction in instructions)
				{
					if (CodeInstructionExtensions.Calls(instruction, target))
					{
						n++;
						yield return CodeInstructionExtensions.MoveBlocksFrom(CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)repl), instruction), instruction);
					}
					else
					{
						yield return instruction;
					}
				}
				if (n == 0)
				{
					Plugin.Log.LogWarning((object)"SyncCoalesce: no Physics.SyncTransforms call found in ZSyncTransform.SyncPosition (inactive)");
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(MonoUpdatersExtra), "CustomFixedUpdate")]
			private static void Loop_Prefix(List<IMonoUpdater> source)
			{
				if (source == ZSyncTransform.Instances)
				{
					_inLoop = true;
					_dirty = false;
				}
			}

			[HarmonyFinalizer]
			[HarmonyPatch(typeof(MonoUpdatersExtra), "CustomFixedUpdate")]
			private static void Loop_Finalizer()
			{
				if (_inLoop)
				{
					_inLoop = false;
					if (_dirty)
					{
						_dirty = false;
						Physics.SyncTransforms();
					}
				}
			}
		}

		private static bool _inLoop;

		private static bool _dirty;

		public static void Sync()
		{
			if (_inLoop)
			{
				_dirty = true;
			}
			else
			{
				Physics.SyncTransforms();
			}
		}
	}
	internal static class TerrainAsync
	{
		private struct BakeJob : IJob
		{
			public int MeshId;

			public MeshColliderCookingOptions Options;

			public void Execute()
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Physics.BakeMesh(MeshId, false, Options);
			}
		}

		private class Pending
		{
			public Heightmap Hm;

			public Mesh Mesh;

			public JobHandle Handle;

			public int Frame;
		}

		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "RebuildCollisionMesh")]
			private static bool RebuildCollisionMesh_Prefix(Heightmap __instance)
			{
				//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_0093: Expected O, but got Unknown
				//IL_022b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0242: Unknown result type (might be due to invalid IL or missing references)
				//IL_0247: 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_025c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0261: Unknown result type (might be due to invalid IL or missing references)
				//IL_0277: Unknown result type (might be due to invalid IL or missing references)
				//IL_027c: Unknown result type (might be due to invalid IL or missing references)
				//IL_028d: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_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_00e7: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
				CompleteOnly(__instance);
				_deferredThisCall = null;
				bool num = (Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.InLoadingScreen();
				bool flag = (Object)(object)__instance.m_collider != (Object)null && (Object)(object)__instance.m_collider.sharedMesh != (Object)null && (Object)(object)__instance.m_collisionMesh != (Object)null;
				if (!(num && flag) || WorldGenFix.SpawningZones != 0)
				{
					return true;
				}
				if ((Object)(object)__instance.m_collisionMesh == (Object)null)
				{
					__instance.m_collisionMesh = new Mesh
					{
						name = "___Heightmap m_collisionMesh"
					};
				}
				int num2 = __instance.m_width + 1;
				float num3 = -999999f;
				float num4 = 999999f;
				Heightmap.s_tempVertices.Clear();
				for (int i = 0; i < num2; i++)
				{
					for (int j = 0; j < num2; j++)
					{
						Vector3 val = __instance.CalcVertex(j, i);
						Heightmap.s_tempVertices.Add(val);
						if (val.y > num3)
						{
							num3 = val.y;
						}
						if (val.y < num4)
						{
							num4 = val.y;
						}
					}
				}
				__instance.m_collisionMesh.SetVertices(Heightmap.s_tempVertices);
				int num5 = (num2 - 1) * (num2 - 1) * 6;
				if (__instance.m_collisionMesh.GetIndexCount(0) != num5)
				{
					Heightmap.s_tempIndices.Clear();
					for (int k = 0; k < num2 - 1; k++)
					{
						for (int l = 0; l < num2 - 1; l++)
						{
							int item = k * num2 + l;
							int item2 = k * num2 + l + 1;
							int item3 = (k + 1) * num2 + l + 1;
							int item4 = (k + 1) * num2 + l;
							Heightmap.s_tempIndices.Add(item);
							Heightmap.s_tempIndices.Add(item4);
							Heightmap.s_tempIndices.Add(item2);
							Heightmap.s_tempIndices.Add(item2);
							Heightmap.s_tempIndices.Add(item4);
							Heightmap.s_tempIndices.Add(item3);
						}
					}
					__instance.m_collisionMesh.SetIndices(Heightmap.s_tempIndices.ToArray(), (MeshTopology)0, 0);
				}
				_deferredThisCall = __instance;
				float num6 = (float)__instance.m_width * __instance.m_scale * 0.5f;
				((Bounds)(ref __instance.m_bounds)).SetMinMax(((Component)__instance).transform.position + new Vector3(0f - num6, num4, 0f - num6), ((Component)__instance).transform.position + new Vector3(num6, num3, num6));
				__instance.m_boundingSphere.position = ((Bounds)(ref __instance.m_bounds)).center;
				__instance.m_boundingSphere.radius = Vector3.Distance(__instance.m_boundingSphere.position, ((Bounds)(ref __instance.m_bounds)).max);
				return false;
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(Heightmap), "Regenerate")]
			private static void Regenerate_Postfix(Heightmap __instance)
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: 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)
				if (_deferredThisCall == __instance)
				{
					_deferredThisCall = null;
					if (!((Object)(object)__instance.m_collider == (Object)null) && !((Object)(object)__instance.m_collisionMesh == (Object)null))
					{
						JobHandle handle = IJobExtensions.Schedule<BakeJob>(new BakeJob
						{
							MeshId = ((Object)__instance.m_collisionMesh).GetInstanceID(),
							Options = __instance.m_collider.cookingOptions
						}, default(JobHandle));
						JobHandle.ScheduleBatchedJobs();
						_pending.Add(new Pending
						{
							Hm = __instance,
							Mesh = __instance.m_collisionMesh,
							Handle = handle,
							Frame = Time.frameCount
						});
					}
				}
			}

			[HarmonyFinalizer]
			[HarmonyPatch(typeof(Heightmap), "Regenerate")]
			private static void Regenerate_Finalizer(Heightmap __instance, Exception __exception)
			{
				if (__exception != null && _deferredThisCall == __instance)
				{
					_deferredThisCall = null;
					if ((Object)(object)__instance.m_collider != (Object)null && (Object)(object)__instance.m_collisionMesh != (Object)null)
					{
						__instance.m_collider.sharedMesh = __instance.m_collisionMesh;
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "OnDestroy")]
			private static void OnDestroy_Prefix(Heightmap __instance)
			{
				CompleteOnly(__instance);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "Clear")]
			private static void Clear_Prefix(Heightmap __instance)
			{
				CompleteOnly(__instance);
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(Heightmap), "HaveQueuedRebuild", new Type[]
			{
				typeof(Vector3),
				typeof(float)
			})]
			private static void HaveQueuedRebuild_Postfix(Vector3 point, float radius, ref bool __result)
			{
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				if (__result || _pending.Count == 0)
				{
					return;
				}
				for (int i = 0; i < _pending.Count; i++)
				{
					Heightmap hm = _pending[i].Hm;
					if ((Object)(object)hm != (Object)null && hm.IsPointInside(point, radius))
					{
						__result = true;
						break;
					}
				}
			}
		}

		private static readonly List<Pending> _pending = new List<Pending>();

		private static readonly FieldRef<Heightmap, Action> _wntCache = AccessTools.FieldRefAccess<Heightmap, Action>("m_clearConnectedWearNTearCache");

		private static Heightmap _deferredThisCall;

		private static int IndexOf(Heightmap hm)
		{
			for (int i = 0; i < _pending.Count; i++)
			{
				if (_pending[i].Hm == hm)
				{
					return i;
				}
			}
			return -1;
		}

		private static void CompleteOnly(Heightmap hm)
		{
			int num = IndexOf(hm);
			if (num >= 0)
			{
				((JobHandle)(ref _pending[num].Handle)).Complete();
				_pending.RemoveAt(num);
			}
		}

		private static void Finish(int i)
		{
			Pending pending = _pending[i];
			((JobHandle)(ref pending.Handle)).Complete();
			_pending.RemoveAt(i);
			Heightmap hm = pending.Hm;
			if (!((Object)(object)hm == (Object)null) && !((Object)(object)hm.m_collider == (Object)null) && !((Object)(object)hm.m_collisionMesh == (Object)null) && hm.m_collisionMesh == pending.Mesh)
			{
				hm.m_collider.sharedMesh = hm.m_collisionMesh;
				_wntCache.Invoke(hm)?.Invoke();
			}
		}

		internal static void Tick()
		{
			if (_pending.Count == 0)
			{
				return;
			}
			int frameCount = Time.frameCount;
			for (int num = _pending.Count - 1; num >= 0; num--)
			{
				Pending pending = _pending[num];
				if ((Object)(object)pending.Hm == (Object)null)
				{
					((JobHandle)(ref pending.Handle)).Complete();
					_pending.RemoveAt(num);
				}
				else if (((JobHandle)(ref pending.Handle)).IsCompleted || frameCount - pending.Frame >= 2)
				{
					Finish(num);
				}
			}
		}

		internal static void CompleteAll()
		{
			for (int num = _pending.Count - 1; num >= 0; num--)
			{
				Finish(num);
			}
		}
	}
	internal static class TerrainMeshAsync
	{
		private sealed class Buffers
		{
			public float[] Heights;

			public Vector3[] Verts;

			public Color32[] Colors;

			public Vector3[] Normals;

			public Vector4[] Tangents;

			public Buffers(int n)
			{
				Heights = new float[n];
				Verts = (Vector3[])(object)new Vector3[n];
				Colors = (Color32[])(object)new Color32[n];
				Normals = (Vector3[])(object)new Vector3[n];
				Tangents = (Vector4[])(object)new Vector4[n];
			}
		}

		private sealed class Job
		{
			public Heightmap Hm;

			public int Width;

			public float Scale;

			public bool DistantLod;

			public BiomeSector[] Corners;

			public Buffers Buf;

			public Vector3 Origin;

			public WorldGenerator WorldGen;

			public long Seq;

			public Vector2[] Uvs;

			public int[] Indices;

			public Bounds Bounds;
		}

		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "RebuildRenderMesh")]
			private static bool RebuildRenderMesh_Prefix(Heightmap __instance)
			{
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.m_renderMesh == (Object)null && MustBeInstant(__instance))
				{
					return true;
				}
				if (PendingCount() >= 24)
				{
					return true;
				}
				Schedule(__instance, __instance.m_width, __instance.m_scale, __instance.IsDistantLod, __instance.m_cornerBiomes, __instance.m_heights, ((Component)__instance).transform.position, WorldGenerator.instance);
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "OnDestroy")]
			private static void OnDestroy_Prefix(Heightmap __instance)
			{
				lock (_lock)
				{
					_latestSeq.Remove(__instance);
				}
			}
		}

		private const int WorkerCount = 2;

		private const int MaxQueueDepth = 24;

		private static readonly double TickToMs = 1000.0 / (double)Stopwatch.Frequency;

		private const double ApplyBudgetMs = 1.5;

		private static readonly Dictionary<int, Stack<Buffers>> _pool = new Dictionary<int, Stack<Buffers>>();

		private static readonly object _lock = new object();

		private static readonly Queue<Job> _toBuild = new Queue<Job>();

		private static readonly Queue<Job> _ready = new Queue<Job>();

		private static readonly Dictionary<Heightmap, long> _latestSeq = new Dictionary<Heightmap, long>();

		private static long _seq;

		private static Thread[] _workers;

		private static bool _stop;

		private static readonly Dictionary<int, (Vector2[] uvs, int[] indices)> _gridCache = new Dictionary<int, (Vector2[], int[])>();

		private static readonly FieldRef<Heightmap, Action> _wntCache = AccessTools.FieldRefAccess<Heightmap, Action>("m_clearConnectedWearNTearCache");

		private static Buffers Rent(int width)
		{
			lock (_pool)
			{
				if (_pool.TryGetValue(width, out var value) && value.Count > 0)
				{
					return value.Pop();
				}
			}
			int num = width + 1;
			return new Buffers(num * num);
		}

		private static void Return(Job job, int width)
		{
			if (job.Buf == null)
			{
				return;
			}
			lock (_pool)
			{
				if (!_pool.TryGetValue(width, out var value))
				{
					value = (_pool[width] = new Stack<Buffers>());
				}
				if (value.Count < 24)
				{
					value.Push(job.Buf);
				}
			}
			job.Buf = null;
		}

		private static void EnsureStarted()
		{
			if (_workers != null)
			{
				return;
			}
			lock (_lock)
			{
				if (_workers == null)
				{
					_workers = new Thread[2];
					for (int i = 0; i < 2; i++)
					{
						Thread thread = new Thread(WorkerLoop)
						{
							IsBackground = true,
							Name = "ValheimOptimized.MeshBuild" + i
						};
						thread.Start();
						_workers[i] = thread;
					}
				}
			}
		}

		internal static void Shutdown()
		{
			lock (_lock)
			{
				_stop = true;
			}
			if (_workers != null)
			{
				Thread[] workers = _workers;
				foreach (Thread thread in workers)
				{
					try
					{
						thread.Join(500);
					}
					catch
					{
					}
				}
			}
			_workers = null;
		}

		private static (Vector2[] uvs, int[] indices) GridFor(int width)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			lock (_gridCache)
			{
				if (_gridCache.TryGetValue(width, out (Vector2[], int[]) value))
				{
					return value;
				}
				int num = width + 1;
				Vector2[] array = (Vector2[])(object)new Vector2[num * num];
				for (int i = 0; i < num; i++)
				{
					for (int j = 0; j < num; j++)
					{
						array[i * num + j] = new Vector2((float)j / (float)width, (float)i / (float)width);
					}
				}
				int[] array2 = new int[(num - 1) * (num - 1) * 6];
				int num2 = 0;
				for (int k = 0; k < num - 1; k++)
				{
					for (int l = 0; l < num - 1; l++)
					{
						int num3 = k * num + l;
						int num4 = k * num + l + 1;
						int num5 = (k + 1) * num + l + 1;
						int num6 = (k + 1) * num + l;
						array2[num2++] = num3;
						array2[num2++] = num6;
						array2[num2++] = num4;
						array2[num2++] = num4;
						array2[num2++] = num6;
						array2[num2++] = num5;
					}
				}
				value = (array, array2);
				_gridCache[width] = value;
				return value;
			}
		}

		private static int PendingCount()
		{
			lock (_lock)
			{
				return _toBuild.Count;
			}
		}

		private static void Schedule(Heightmap hm, int width, float scale, bool distantLod, BiomeSector[] corners, List<float> heights, Vector3 origin, WorldGenerator worldGen)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			EnsureStarted();
			Job job = new Job
			{
				Hm = hm,
				Width = width,
				Scale = scale,
				DistantLod = distantLod,
				Corners = (BiomeSector[])corners.Clone(),
				Buf = Rent(width),
				Origin = origin,
				WorldGen = worldGen
			};
			heights.CopyTo(job.Buf.Heights);
			lock (_lock)
			{
				job.Seq = ++_seq;
				_latestSeq[hm] = job.Seq;
				_toBuild.Enqueue(job);
			}
		}

		private static void WorkerLoop()
		{
			while (true)
			{
				Job job = null;
				lock (_lock)
				{
					if (_stop)
					{
						break;
					}
					if (_toBuild.Count > 0)
					{
						job = _toBuild.Dequeue();
					}
				}
				if (job == null)
				{
					Thread.Sleep(1);
					continue;
				}
				try
				{
					Build(job);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("TerrainMeshAsync build failed: " + ex.Message));
					continue;
				}
				lock (_lock)
				{
					_ready.Enqueue(job);
				}
			}
		}

		private static void Build(Job job)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: 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_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: 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_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_034d: 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_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: 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_0379: 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_0380: 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_0392: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			int width = job.Width;
			int num = width + 1;
			(Vector2[] uvs, int[] indices) tuple = GridFor(width);
			Vector2[] item = tuple.uvs;
			int[] item2 = tuple.indices;
			float[] heights = job.Buf.Heights;
			float scale = job.Scale;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor((float)width * scale * -0.5f, 0f, (float)width * scale * -0.5f);
			Vector3[] verts = job.Buf.Verts;
			Color32[] colors = job.Buf.Colors;
			float num2 = float.MaxValue;
			float num3 = float.MinValue;
			Color32 biomeColor = Heightmap.GetBiomeColor(job.Corners[0]);
			Color32 biomeColor2 = Heightmap.GetBiomeColor(job.Corners[1]);
			Color32 biomeColor3 = Heightmap.GetBiomeColor(job.Corners[2]);
			Color32 biomeColor4 = Heightmap.GetBiomeColor(job.Corners[3]);
			bool flag = job.Corners[0] == job.Corners[1] && job.Corners[0] == job.Corners[2] && job.Corners[0] == job.Corners[3];
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					int num4 = i * num + j;
					float num5 = heights[num4];
					verts[num4] = new Vector3(val.x + (float)j * scale, num5, val.z + (float)i * scale);
					if (num5 < num2)
					{
						num2 = num5;
					}
					if (num5 > num3)
					{
						num3 = num5;
					}
					if (job.DistantLod)
					{
						float num6 = job.Origin.x + val.x + (float)j * scale;
						float num7 = job.Origin.z + val.z + (float)i * scale;
						colors[num4] = Heightmap.GetBiomeColor(job.WorldGen.GetBiomeSector(num6, num7, false));
					}
					else if (flag)
					{
						colors[num4] = biomeColor;
					}
					else
					{
						float num8 = DUtils.SmoothStep(0f, 1f, (float)j / (float)width);
						float num9 = DUtils.SmoothStep(0f, 1f, (float)i / (float)width);
						Color32 val2 = Color32.Lerp(biomeColor, biomeColor2, num8);
						Color32 val3 = Color32.Lerp(biomeColor3, biomeColor4, num8);
						colors[num4] = Color32.Lerp(val2, val3, num9);
					}
				}
			}
			Vector3[] normals = job.Buf.Normals;
			Vector4[] tangents = job.Buf.Tangents;
			Vector3 val5 = default(Vector3);
			for (int k = 0; k < num; k++)
			{
				int num10 = Math.Max(k - 1, 0);
				int num11 = Math.Min(k + 1, num - 1);
				float num12 = ((num10 == num11) ? 1f : ((float)(num11 - num10) * scale));
				for (int l = 0; l < num; l++)
				{
					int num13 = Math.Max(l - 1, 0);
					int num14 = Math.Min(l + 1, num - 1);
					float num15 = ((num13 == num14) ? 1f : ((float)(num14 - num13) * scale));
					float num16 = heights[k * num + num13];
					float num17 = heights[k * num + num14];
					float num18 = heights[num10 * num + l];
					float num19 = heights[num11 * num + l];
					float num20 = (num17 - num16) / num15;
					float num21 = (num19 - num18) / num12;
					Vector3 val4 = new Vector3(0f - num20, 1f, 0f - num21);
					Vector3 normalized = ((Vector3)(ref val4)).normalized;
					int num22 = k * num + l;
					normals[num22] = normalized;
					((Vector3)(ref val5))..ctor(1f, num20, 0f);
					val5 -= normalized * Vector3.Dot(val5, normalized);
					Vector3 normalized2;
					if (!(((Vector3)(ref val5)).sqrMagnitude > 1E-08f))
					{
						val4 = Vector3.Cross(Vector3.up, normalized);
						normalized2 = ((Vector3)(ref val4)).normalized;
					}
					else
					{
						normalized2 = ((Vector3)(ref val5)).normalized;
					}
					val5 = normalized2;
					tangents[num22] = new Vector4(val5.x, val5.y, val5.z, -1f);
				}
			}
			float num23 = (float)width * scale * 0.5f;
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds)).SetMinMax(new Vector3(0f - num23, num2, 0f - num23), new Vector3(num23, num3, num23));
			job.Uvs = item;
			job.Indices = item2;
			job.Bounds = bounds;
		}

		internal static void Tick()
		{
			if (_workers == null)
			{
				return;
			}
			long num = (long)(1.5 / TickToMs);
			long num2 = 0L;
			while (true)
			{
				Job job;
				lock (_lock)
				{
					if (_ready.Count == 0)
					{
						break;
					}
					job = _ready.Dequeue();
				}
				bool flag;
				lock (_lock)
				{
					flag = !_latestSeq.TryGetValue(job.Hm, out var value) || value != job.Seq;
				}
				if (flag)
				{
					Return(job, job.Width);
					continue;
				}
				long timestamp = Stopwatch.GetTimestamp();
				Apply(job);
				Return(job, job.Width);
				lock (_lock)
				{
					_latestSeq.Remove(job.Hm);
				}
				num2 += Stopwatch.GetTimestamp() - timestamp;
				if (num2 <= num)
				{
					continue;
				}
				break;
			}
		}

		private static void Apply(Job job)
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Heightmap hm = job.Hm;
			if (!((Object)(object)hm == (Object)null) && !((Object)(object)hm.m_meshFilter == (Object)null))
			{
				Mesh val = hm.m_renderMesh;
				if ((Object)(object)val == (Object)null)
				{
					val = (hm.m_renderMesh = new Mesh
					{
						name = "___Heightmap m_renderMesh"
					});
				}
				val.Clear();
				int num = (job.Width + 1) * (job.Width + 1);
				val.SetVertices(job.Buf.Verts, 0, num);
				val.SetColors(job.Buf.Colors, 0, num);
				val.SetUVs(0, job.Uvs);
				val.SetIndices(job.Indices, (MeshTopology)0, 0);
				val.SetNormals(job.Buf.Normals, 0, num);
				val.SetTangents(job.Buf.Tangents, 0, num);
				val.bounds = job.Bounds;
				hm.m_meshFilter.mesh = val;
				_wntCache.Invoke(hm)?.Invoke();
			}
		}

		internal static bool MustBeInstant(Heightmap hm)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNetScene.instance == (Object)null || ZNetScene.instance.InLoadingScreen())
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return true;
			}
			Vector3 val = ((Component)hm).transform.position - ((Component)localPlayer).transform.position;
			val.y = 0f;
			if (!hm.IsDistantLod)
			{
				return ((Vector3)(ref val)).sqrMagnitude < 5184f;
			}
			return false;
		}
	}
	internal static class TerrainStream
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyTranspiler]
			[HarmonyPatch(typeof(HeightmapBuilder), "BuildThread")]
			private static IEnumerable<CodeInstruction> BuildThread_Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo sleep = AccessTools.Method(typeof(Thread), "Sleep", new Type[1] { typeof(int) }, (Type[])null);
				MethodInfo repl = AccessTools.Method(typeof(TerrainStream), "BuilderSleep", (Type[])null, (Type[])null);
				int n = 0;
				foreach (CodeInstruction instruction in instructions)
				{
					if (CodeInstructionExtensions.Calls(instruction, sleep))
					{
						n++;
						yield return CodeInstructionExtensions.MoveBlocksFrom(CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)repl), instruction), instruction);
					}
					else if ((instruction.opcode == OpCodes.Ldc_I4_S || instruction.opcode == OpCodes.Ldc_I4) && Convert.ToInt32(instruction.operand) == 16)
					{
						n++;
						yield return CodeInstructionExtensions.MoveBlocksFrom(CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(TerrainStream), "ReadyCap", (Type[])null, (Type[])null)), instruction), instruction);
					}
					else
					{
						yield return instruction;
					}
				}
				if (n != 2)
				{
					Plugin.Log.LogWarning((object)$"TerrainStream: BuildThread patched {n} site(s), expected 2 (terrain streaming priority may be inactive)");
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(HeightmapBuilder), "RequestTerrainSync")]
			private static void RequestTerrainSync_Prefix(HeightmapBuilder __instance, Vector3 center, int width, float scale, bool distantLod, WorldGenerator worldGen)
			{
				//IL_002b: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Expected O, but got Unknown
				object obj = __instance.m_lock;
				if (obj == null)
				{
					return;
				}
				lock (obj)
				{
					List<HMBuildData> ready = __instance.m_ready;
					for (int i = 0; i < ready.Count; i++)
					{
						if (ready[i].IsEqual(center, width, scale, distantLod, worldGen))
						{
							return;
						}
					}
					List<HMBuildData> toBuild = __instance.m_toBuild;
					int num = -1;
					for (int j = 0; j < toBuild.Count; j++)
					{
						if (toBuild[j].IsEqual(center, width, scale, distantLod, worldGen))
						{
							num = j;
							break;
						}
					}
					if (num > 1)
					{
						HMBuildData item = toBuild[num];
						toBuild.RemoveAt(num);
						toBuild.Insert(1, item);
					}
					else if (num < 0)
					{
						toBuild.Insert(Mathf.Min(1, toBuild.Count), new HMBuildData(center, width, scale, distantLod, worldGen));
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(TerrainLod), "RebuildAllHeightmaps")]
			private static bool RebuildAll_Prefix(TerrainLod __instance)
			{
				//IL_004a: 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_0094: Unknown result type (might be due to invalid IL or missing references)
				if (!_lodDone.TryGetValue(__instance, out var value))
				{
					value = (_lodDone[__instance] = new HashSet<int>());
				}
				List<HeightmapWithOffset> heightmaps = __instance.m_heightmaps;
				for (int i = 0; i < heightmaps.Count; i++)
				{
					if (!value.Contains(i))
					{
						__instance.RebuildHeightmap(heightmaps[i]);
						heightmaps[i].m_state = (HeightmapState)1;
						value.Add(i);
						if (value.Count >= heightmaps.Count)
						{
							break;
						}
						return false;
					}
				}
				for (int j = 0; j < heightmaps.Count; j++)
				{
					heightmaps[j].m_state = (HeightmapState)2;
				}
				__instance.m_heightmapState = (HeightmapState)2;
				value.Clear();
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "LateUpdate")]
			private static bool HmLateUpdate_Prefix(Heightmap __instance)
			{
				if (__instance.m_doLateUpdate != 1)
				{
					return true;
				}
				return AllowDeferred();
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "CustomLateUpdate")]
			private static bool HmCustomLateUpdate_Prefix(Heightmap __instance)
			{
				if (__instance.m_doLateUpdate != 2)
				{
					return true;
				}
				return AllowDeferred();
			}

			[HarmonyPrefix]
			[HarmonyPriority(600)]
			[HarmonyPatch(typeof(Heightmap), "Regenerate")]
			private static void Regen_Pre(out long __state)
			{
				__state = Stopwatch.GetTimestamp();
			}

			[HarmonyPostfix]
			[HarmonyPriority(200)]
			[HarmonyPatch(typeof(Heightmap), "Regenerate")]
			private static void Regen_Post(long __state)
			{
				RollFrame();
				_frameRegenTicks += Stopwatch.GetTimestamp() - __state;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(TerrainLod), "ResetMeshes")]
			private static void ResetMeshes_Prefix(TerrainLod __instance)
			{
				_lodDone.Remove(__instance);
			}
		}

		private static readonly Dictionary<TerrainLod, HashSet<int>> _lodDone = new Dictionary<TerrainLod, HashSet<int>>();

		private const double RegenBudgetMs = 3.0;

		private const int MaxDeferredPerFrame = 4;

		private static readonly double TickToMs = 1000.0 / (double)Stopwatch.Frequency;

		private static int _frame = -1;

		private static long _frameRegenTicks;

		private static int _frameDeferredRuns;

		public static int ReadyCap()
		{
			return 64;
		}

		public static void BuilderSleep(int ms)
		{
			HeightmapBuilder instance = HeightmapBuilder.m_instance;
			object obj = instance?.m_lock;
			if (obj != null)
			{
				bool flag;
				lock (obj)
				{
					flag = instance.m_toBuild.Count > 0;
				}
				if (flag)
				{
					Thread.Sleep(0);
					return;
				}
			}
			Thread.Sleep(ms);
		}

		private static void RollFrame()
		{
			int frameCount = Time.frameCount;
			if (frameCount != _frame)
			{
				_frame = frameCount;
				_frameRegenTicks = 0L;
				_frameDeferredRuns = 0;
			}
		}

		private static bool AllowDeferred()
		{
			RollFrame();
			if (_frameDeferredRuns == 0 || ((double)_frameRegenTicks * TickToMs < 3.0 && _frameDeferredRuns < 4))
			{
				_frameDeferredRuns++;
				return true;
			}
			return false;
		}
	}
	internal static class WorldGenFix
	{
		[HarmonyPatch]
		internal static class Hooks
		{
			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZoneSystem), "SpawnZone")]
			private static void SpawnZone_Prefix()
			{
				SpawningZones++;
			}

			[HarmonyFinalizer]
			[HarmonyPatch(typeof(ZoneSystem), "SpawnZone")]
			private static void SpawnZone_Finalizer()
			{
				if (SpawningZones > 0)
				{
					SpawningZones--;
				}
			}
		}

		internal static int SpawningZones;
	}
	internal static class ZoneSmooth
	{
		private sealed class Job
		{
			public DungeonGenerator Gen;

			public int Next;

			public long Born;
		}

		private sealed class Tear
		{
			public GameObject Root;

			public List<GameObject> Parts = new List<GameObject>();

			public List<int> Cost = new List<int>();

			public int Next;
		}

		[HarmonyPatch]
		internal static class Hooks
		{
			private static float _ttlPending;

			private static int _ttlSkips;

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNetScene), "RemoveObjects")]
			private static bool RemoveObjects_Prefix(ZNetScene __instance, List<ZDO> currentNearObjects, List<ZDO> currentDistantObjects)
			{
				if (InLoading())
				{
					return true;
				}
				byte b = (byte)(Time.frameCount & 0xFF);
				foreach (ZDO currentNearObject in currentNearObjects)
				{
					currentNearObject.TempRemoveEarmark = b;
				}
				foreach (ZDO currentDistantObject in currentDistantObjects)
				{
					currentDistantObject.TempRemoveEarmark = b;
				}
				List<ZNetView> tempRemoved = __instance.m_tempRemoved;
				tempRemoved.Clear();
				foreach (ZNetView value in __instance.m_instances.Values)
				{
					if (value.GetZDO().TempRemoveEarmark != b)
					{
						tempRemoved.Add(value);
					}
				}
				int count = tempRemoved.Count;
				if (count == 0)
				{
					return false;
				}
				int num = Math.Min(Math.Max(48, count / 10), count);
				int num2 = 0;
				for (int i = 0; i < num; i++)
				{
					ZNetView val = tempRemoved[i];
					ZDO zDO = val.GetZDO();
					val.ResetZDO();
					if ((Object)(object)val != (Object)null)
					{
						GameObject gameObject = ((Component)val).gameObject;
						if (!TryDeferDestroy(gameObject))
						{
							num2 += gameObject.transform.hierarchyCount;
							Object.Destroy((Object)(object)gameObject);
						}
					}
					if (!zDO.Persistent && zDO.IsOwner())
					{
						ZDOMan.instance.DestroyZDO(zDO);
					}
					__instance.m_instances.Remove(zDO);
					if (num2 >= 900)
					{
						break;
					}
				}
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(DungeonGenerator), "OnRoomLoaded")]
			private static bool OnRoomLoaded_Prefix(DungeonGenerator __instance, LoadResult result, ref int ___m_roomsToLoad)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				if (InLoading())
				{
					return true;
				}
				if ((int)result == 0 && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).gameObject == (Object)null))
				{
					___m_roomsToLoad--;
					if (___m_roomsToLoad <= 0)
					{
						Jobs.Add(new Job
						{
							Gen = __instance,
							Next = 0,
							Born = Stopwatch.GetTimestamp()
						});
					}
				}
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZoneSystem), "UpdateTTL")]
			private static bool UpdateTTL_Prefix(ref float dt)
			{
				if (!InLoading() && FrameLoad.Busy && _ttlSkips < 4)
				{
					_ttlPending += dt;
					_ttlSkips++;
					return false;
				}
				dt += _ttlPending;
				_ttlPending = 0f;
				_ttlSkips = 0;
				return true;
			}
		}

		private static readonly double TicksPerMs = (double)Stopwatch.Frequency / 1000.0;

		private static readonly List<Job> Jobs = new List<Job>();

		private static long _nextRoomAllowed;

		private static int _roomDeferrals;

		private static readonly List<Tear> Tears = new List<Tear>();

		private static int _tearDeferrals;

		private const int BigLocation = 400;

		private const int MaxPart = 250;

		private const int TearBudget = 500;

		private static bool InLoading()
		{
			ZNetScene instance = ZNetScene.instance;
			if (!((Object)(object)instance == (Object)null) && !instance.InLoadingScreen())
			{
				return (Object)(object)ZNet.instance == (Object)null;
			}
			return true;
		}

		internal static void Update_()
		{
			try
			{
				if (Tears.Count > 0)
				{
					UpdateTears();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("ZoneSmooth teardown failed, finishing at once: " + ex.Message));
				FlushTears();
			}
			if (Jobs.Count > 0)
			{
				UpdateRooms();
			}
		}

		private static void UpdateRooms()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			long timestamp = Stopwatch.GetTimestamp();
			bool flag = InLoading();
			if (!flag && timestamp - Jobs[0].Born <= (long)(800.0 * TicksPerMs))
			{
				if (timestamp < _nextRoomAllowed)
				{
					return;
				}
				if (FrameLoad.Busy && _roomDeferrals < 4)
				{
					_roomDeferrals++;
					return;
				}
			}
			_roomDeferrals = 0;
			for (int i = 0; i < Jobs.Count; i++)
			{
				Job job = Jobs[i];
				DungeonGenerator gen = job.Gen;
				if ((Object)(object)gen == (Object)null)
				{
					Jobs.RemoveAt(i--);
					continue;
				}
				try
				{
					RoomPlacementData[] loadedRooms = gen.m_loadedRooms;
					int num = ((loadedRooms != null) ? loadedRooms.Length : 0);
					while (job.Next < num)
					{
						RoomPlacementData val = loadedRooms[job.Next++];
						long timestamp2 = Stopwatch.GetTimestamp();
						gen.PlaceRoom(val.m_roomData, val.m_position, val.m_rotation, (RoomConnection)null, (SpawnMode)1);
						if (!flag)
						{
							long timestamp3 = Stopwatch.GetTimestamp();
							_nextRoomAllowed = timestamp3 + Math.Max((timestamp3 - timestamp2) * 2, (long)(5.0 * TicksPerMs));
							break;
						}
					}
					if (job.Next >= num)
					{
						SnapToGround.SnappAll();
						gen.m_loadedRooms = null;
						gen.ReleaseHeldReferences();
						Jobs.RemoveAt(i--);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("ZoneSmooth dungeon job failed: " + ex.Message));
					try
					{
						gen.ReleaseHeldReferences();
					}
					catch
					{
					}
					Jobs.RemoveAt(i--);
				}
				if (!flag)
				{
					break;
				}
			}
		}

		private static void Partition(Transform t, Tear tear)
		{
			for (int i = 0; i < t.childCount; i++)
			{
				Transform child = t.GetChild(i);
				int hierarchyCount = child.hierarchyCount;
				if (hierarchyCount > 250 && child.childCount > 0)
				{
					Partition(child, tear);
				}
				tear.Parts.Add(((Component)child).gameObject);
				tear.Cost.Add((hierarchyCount > 250) ? 1 : hierarchyCount);
			}
		}

		private static bool TryDeferDestroy(GameObject go)
		{
			try
			{
				if ((Object)(object)go.GetComponent<LocationProxy>() == (Object)null)
				{
					return false;
				}
				if (go.transform.hierarchyCount < 400)
				{
					return false;
				}
				Tear tear = new Tear
				{
					Root = go
				};
				Partition(go.transform, tear);
				if (tear.Parts.Count < 2)
				{
					return false;
				}
				Tears.Add(tear);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static void UpdateTears()
		{
			bool flag = InLoading();
			if (!flag && FrameLoad.Busy && _tearDeferrals < 3)
			{
				_tearDeferrals++;
				return;
			}
			_tearDeferrals = 0;
			for (int i = 0; i < Tears.Count; i++)
			{
				Tear tear = Tears[i];
				if ((Object)(object)tear.Root == (Object)null)
				{
					Tears.RemoveAt(i--);
					continue;
				}
				int num = 0;
				while (tear.Next < tear.Parts.Count && (flag || num < 500))
				{
					GameObject val = tear.Parts[tear.Next];
					num += tear.Cost[tear.Next];
					tear.Next++;
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
				if (tear.Next >= tear.Parts.Count)
				{
					Object.Destroy((Object)(object)tear.Root);
					Tears.RemoveAt(i--);
				}
				if (!flag)
				{
					break;
				}
			}
		}

		private static void FlushTears()
		{
			Tear[] array = Tears.ToArray();
			foreach (Tear tear in array)
			{
				try
				{
					if ((Object)(object)tear.Root != (Object)null)
					{
						Object.Destroy((Object)(object)tear.Root);
					}
				}
				catch
				{
				}
			}
			Tears.Clear();
		}

		internal static void Shutdown()
		{
			Job[] array = Jobs.ToArray();
			foreach (Job job in array)
			{
				try
				{
					if ((Object)(object)job.Gen != (Object)null)
					{
						job.Gen.ReleaseHeldReferences();
					}
				}
				catch
				{
				}
			}
			Jobs.Clear();
			FlushTears();
		}
	}
	internal sealed class Fixed<T>
	{
		public readonly T Value;

		public Fixed(T v)
		{
			Value = v;
		}
	}
	internal static class Feat
	{
		public const bool DepthNormals = true;

		public const bool ShadowCull = true;

		public const bool SkyAlpha = true;

		public const bool Minimap = true;

		public const bool Terrain = true;

		public const bool Sync = true;

		public const bool TerrainStream = true;

		public const bool ObjectSpawn = true;

		public const bool AllocTrim = true;

		public const bool ZoneSmooth = true;
	}
	[BepInPlugin("dow.valheim.optimized", "ValheimOptimized", "1.1.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "dow.valheim.optimized";

		public const string Name = "ValheimOptimized";

		public const string Version = "1.1.1";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		internal static readonly Fixed<float> CShadowPiece = new Fixed<float>(80f);

		internal static readonly Fixed<float> CShadowSmall = new Fixed<float>(35f);

		internal static readonly Fixed<float> CShadowCharacter = new Fixed<float>(50f);

		internal static readonly Fixed<float> CShadowItem = new Fixed<float>(25f);

		internal static readonly Fixed<float> CShadowVehicle = new Fixed<float>(80f);

		internal static readonly Fixed<float> CSkyMove = new Fixed<float>(12f);

		internal static readonly Fixed<float> CSkyVertical = new Fixed<float>(10f);

		internal static readonly Fixed<float> CSkyMaxInterval = new Fixed<float>(10f);

		internal static readonly Fixed<float> CObjectBudget = new Fixed<float>(1f);

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("dow.valheim.optimized");
			PatchGroup(typeof(SkyAlphaThrottle.Hooks));
			PatchGroup(typeof(MinimapUpload.Hooks));
			PatchGroup(typeof(TerrainAsync.Hooks));
			PatchGroup(typeof(SyncCoalesce.Hooks));
			PatchGroup(typeof(TerrainStream.Hooks));
			PatchGroup(typeof(TerrainMeshAsync.Hooks));
			PatchGroup(typeof(ObjectSpawn.Hooks));
			PatchGroup(typeof(AllocTrim.Hooks));
			PatchGroup(typeof(ZoneSmooth.Hooks));
			PatchGroup(typeof(WorldGenFix.Hooks));
			Log.LogInfo((object)"ValheimOptimized 1.1.1 loaded.");
		}

		private void PatchGroup(Type t)
		{
			try
			{
				_harmony.PatchAll(t);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Patch group {t.FullName} FAILED (that optimization is inactive): {arg}");
			}
		}

		private void LateUpdate()
		{
			FrameLoad.Tick();
			DepthNormalsFix.Tick();
			ShadowCull.Tick();
			TerrainAsync.Tick();
			TerrainMeshAsync.Tick();
			ZoneSmooth.Update_();
		}

		private void OnDestroy()
		{
			TerrainAsync.CompleteAll();
			TerrainMeshAsync.Shutdown();
			ZoneSmooth.Shutdown();
		}
	}
}