Decompiled source of Litterally v1.1.0

Litterally.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Employees;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Trash;
using Il2CppSystem.Collections.Generic;
using Litterally;
using Litterally.Compat;
using Litterally.Config;
using Litterally.Instanced;
using Litterally.SaveGuard;
using Litterally.Spawning;
using Litterally.UI;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using S1API.Lifecycle;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Litterally", "1.1.0", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Litterally")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+ad9b68373aed6ae1b046e8d5382a90216f6155dd")]
[assembly: AssemblyProduct("Litterally")]
[assembly: AssemblyTitle("Litterally")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.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;
		}
	}
}
namespace Litterally
{
	public sealed class Core : MelonMod
	{
		private bool _inWorld;

		private bool _perfApplied;

		private int _perfLogState = -1;

		private float _teleElapsed;

		private int _teleFrames;

		private float _teleMaxDt;

		public static Core Instance { get; private set; }

		public static Instance Log { get; private set; }

		[Conditional("DEBUG")]
		public static void LogDebug(string msg)
		{
			Instance log = Log;
			if (log != null)
			{
				log.Msg(msg);
			}
		}

		public override void OnInitializeMelon()
		{
			Instance = this;
			Log = ((MelonBase)this).LoggerInstance;
			Preferences.Initialize();
			try
			{
				((MelonBase)this).HarmonyInstance.PatchAll();
			}
			catch (Exception ex)
			{
				Log.Warning("[Core] Harmony patch failed: " + ex.Message);
			}
			GameLifecycle.OnSaveStart += delegate
			{
				SaveBlob.Save();
				SaveSafety.ForceClearForSave("save starting");
				_perfApplied = false;
			};
			GameLifecycle.OnPreSceneChange += delegate
			{
				SaveSafety.ForceClearForSave("scene changing");
			};
			GameLifecycle.OnLoadComplete += OnGameLoaded;
			GameLifecycle.OnLoadComplete += delegate
			{
				if (Preferences.EnablePerformanceLayer)
				{
					SaveBlob.Load();
				}
			};
			Log.Msg("Litterally v1.0.0 - trash performance layer active.");
		}

		private void OnGameLoaded()
		{
			_perfApplied = false;
		}

		private void ApplyPerformanceLayer()
		{
			_perfApplied = true;
			try
			{
				if (!Preferences.EnablePerformanceLayer)
				{
					DisableLayer();
					if (_perfLogState != 0)
					{
						Log.Msg("[Core] Performance layer DISABLED via preferences - running vanilla trash.");
						_perfLogState = 0;
					}
					return;
				}
				if (Net.IsMultiplayer() && !Preferences.EnableInMultiplayer)
				{
					DisableLayer();
					if (_perfLogState != 1)
					{
						Log.Msg("[Core] Multiplayer session detected - performance layer auto-DISABLED (set EnableInMultiplayer to force it on for testing).");
						_perfLogState = 1;
					}
					return;
				}
				RouteHook.Active = true;
				Virtualizer.Enabled = true;
				CleanerActor.Enabled = true;
				int value = (TrashPopulator.Multiplier = Preferences.TrashMultiplier);
				Virtualizer.MaxReal = Preferences.MaxRealItems;
				Virtualizer.ViewDist = Preferences.MaterializeDistance;
				InstancedTrash.RenderDist = Preferences.RenderDistance;
				bool collide = Virtualizer.Collide;
				Virtualizer.Collide = Preferences.ActivePhysics;
				if (collide != Virtualizer.Collide)
				{
					Virtualizer.ClearAll();
				}
				if (_perfLogState != 2)
				{
					Log.Msg($"[Core] Performance layer ACTIVE (maxReal={Preferences.MaxRealItems}, materializeDist={Preferences.MaterializeDistance}m, trashMult={value}).");
					_perfLogState = 2;
				}
			}
			catch (Exception ex)
			{
				Log.Warning("[Core] ApplyPerformanceLayer failed: " + ex.Message);
			}
		}

		private static void DisableLayer()
		{
			RouteHook.Active = false;
			Virtualizer.Enabled = false;
			CleanerActor.Enabled = false;
			TrashPopulator.Multiplier = 1;
			TrashPopulator.Reset();
			InstancedTrash.Clear();
		}

		private void TelemetryTick()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			_teleElapsed += unscaledDeltaTime;
			_teleFrames++;
			if (unscaledDeltaTime > _teleMaxDt)
			{
				_teleMaxDt = unscaledDeltaTime;
			}
			if (_teleElapsed < 15f)
			{
				return;
			}
			try
			{
				float value = (float)_teleFrames / _teleElapsed;
				float value2 = ((_teleMaxDt > 0f) ? (1f / _teleMaxDt) : 0f);
				TrashManager val = GameTrash.TrashManagerOrNull();
				int value3 = (((Object)(object)val != (Object)null) ? GameTrash.TrashItemCount(val) : (-1));
				Log.Msg($"[telemetry] fps={value:F0} (min {value2:F0})  field-live={InstancedTrash.LiveCount}  real-player={Virtualizer.RealCount}  matR={Virtualizer.MatRadius:F1}  real-cleaner={CleanerActor.RealCount}  mgr={value3}  absorbed={RouteHook.Absorbed}");
			}
			catch
			{
			}
			finally
			{
				_teleElapsed = 0f;
				_teleFrames = 0;
				_teleMaxDt = 0f;
			}
		}

		private void OnSettingsSaved()
		{
			try
			{
				if (_inWorld && (Object)(object)GameTrash.TrashManagerOrNull() != (Object)null)
				{
					ApplyPerformanceLayer();
				}
			}
			catch (Exception ex)
			{
				Log.Warning("[Core] live settings re-apply failed: " + ex.Message);
			}
		}

		public override void OnPreferencesSaved()
		{
			OnSettingsSaved();
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			_inWorld = sceneName == "Main";
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			_inWorld = false;
			_perfApplied = false;
			SaveSafety.ForceClearForSave("scene unloaded");
			InstancedTrash.Clear();
			TrashPopulator.Reset();
		}

		public override void OnUpdate()
		{
			if (_inWorld)
			{
				if (!_perfApplied && (Object)(object)GameTrash.TrashManagerOrNull() != (Object)null)
				{
					ApplyPerformanceLayer();
				}
				RouteHook.Tick();
				InstancedTrash.Tick(Time.deltaTime);
				Virtualizer.Tick();
				CleanerActor.Tick();
				TrashPopulator.Tick(Time.deltaTime);
				InstancedTrash.Render();
				TelemetryTick();
			}
		}

		public override void OnGUI()
		{
			if (_inWorld)
			{
				if (Preferences.ShowFpsCounter)
				{
					FpsCounter.Draw();
				}
				if (Preferences.ShowStatsPanel)
				{
					StatsPanel.Draw();
				}
				if (Preferences.ShowActiveItems || Preferences.ShowRanges)
				{
					DebugDraw.Draw();
				}
			}
		}

		public override void OnApplicationQuit()
		{
			Teardown("application quit");
		}

		public override void OnDeinitializeMelon()
		{
			Teardown("melon unload");
		}

		private void Teardown(string reason)
		{
			try
			{
				SaveSafety.ForceClearForSave(reason);
			}
			catch
			{
			}
		}
	}
}
namespace Litterally.UI
{
	internal static class DebugDraw
	{
		private static readonly Vector3[] _pos = (Vector3[])(object)new Vector3[2048];

		private static GUIStyle _dot;

		private static GUIStyle Dot
		{
			get
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				if (_dot == null)
				{
					_dot = new GUIStyle();
					_dot.normal.background = Texture2D.whiteTexture;
				}
				return _dot;
			}
		}

		internal static void Draw()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if (Event.current != null && (int)Event.current.type != 7)
			{
				return;
			}
			Camera val = Frustum.Cam();
			if (!((Object)(object)val == (Object)null))
			{
				if (Preferences.ShowActiveItems)
				{
					int n = Virtualizer.CopyRealPositions(_pos);
					DrawDots(val, n, new Color(0.25f, 1f, 0.35f, 0.95f));
					int n2 = CleanerActor.CopyRealPositions(_pos);
					DrawDots(val, n2, new Color(0.25f, 0.85f, 1f, 0.95f));
				}
				if (Preferences.ShowRanges && GameTrash.TryGetPlayerPosition(out var pos))
				{
					DrawRing(val, pos, Virtualizer.MatRadius, new Color(1f, 1f, 1f, 0.9f));
					DrawRing(val, pos, Virtualizer.ViewDist, new Color(1f, 0.55f, 0.1f, 0.7f));
				}
			}
		}

		private static void DrawDots(Camera cam, int n, Color col)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			GUI.color = col;
			float num = Screen.height;
			for (int i = 0; i < n; i++)
			{
				Vector3 val = cam.WorldToScreenPoint(_pos[i]);
				if (!(val.z <= 0f))
				{
					GUI.Box(new Rect(val.x - 3f, num - val.y - 3f, 6f, 6f), GUIContent.none, Dot);
				}
			}
			GUI.color = Color.white;
		}

		private static void DrawRing(Camera cam, Vector3 center, float radius, Color col)
		{
			//IL_0009: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if (radius <= 0f)
			{
				return;
			}
			GUI.color = col;
			float num = Screen.height;
			Vector3 val = default(Vector3);
			for (int i = 0; i < 56; i++)
			{
				float num2 = (float)i / 56f * (float)Math.PI * 2f;
				((Vector3)(ref val))..ctor(center.x + Mathf.Cos(num2) * radius, center.y, center.z + Mathf.Sin(num2) * radius);
				Vector3 val2 = cam.WorldToScreenPoint(val);
				if (!(val2.z <= 0f))
				{
					GUI.Box(new Rect(val2.x - 3f, num - val2.y - 3f, 6f, 6f), GUIContent.none, Dot);
				}
			}
			GUI.color = Color.white;
		}
	}
	internal static class FpsCounter
	{
		private static GUIStyle _style;

		internal static void Draw()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0064: Expected O, but got Unknown
			//IL_0095: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_008e: 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)
			if (Event.current == null || (int)Event.current.type == 7)
			{
				float smoothDeltaTime = Time.smoothDeltaTime;
				int num = ((smoothDeltaTime > 0f) ? Mathf.RoundToInt(1f / smoothDeltaTime) : 0);
				if (_style == null)
				{
					_style = new GUIStyle(GUI.skin.label)
					{
						fontSize = 22,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)2
					};
				}
				_style.normal.textColor = (Color)((num >= 50) ? Color.green : ((num >= 30) ? Color.yellow : new Color(1f, 0.45f, 0.45f)));
				string text = num + " FPS";
				Rect val = default(Rect);
				((Rect)(ref val))..ctor((float)Screen.width - 140f, 6f, 132f, 28f);
				GUI.color = new Color(0f, 0f, 0f, 0.6f);
				GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), text, _style);
				GUI.color = Color.white;
				GUI.Label(val, text, _style);
			}
		}
	}
	internal static class StatsPanel
	{
		private static GUIStyle _label;

		private static GUIStyle _backdrop;

		private static string _text = "";

		private static float _next;

		private static float _smoothFps;

		private static GUIStyle Backdrop
		{
			get
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				if (_backdrop == null)
				{
					_backdrop = new GUIStyle();
					_backdrop.normal.background = Texture2D.whiteTexture;
				}
				return _backdrop;
			}
		}

		internal static void Draw()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (Event.current == null || (int)Event.current.type == 7)
			{
				float smoothDeltaTime = Time.smoothDeltaTime;
				float num = ((smoothDeltaTime > 0f) ? (1f / smoothDeltaTime) : 0f);
				_smoothFps = ((_smoothFps <= 0f) ? num : Mathf.Lerp(_smoothFps, num, 0.1f));
				float unscaledTime = Time.unscaledTime;
				if (unscaledTime >= _next)
				{
					_next = unscaledTime + 0.1f;
					_text = Build();
				}
				if (_label == null)
				{
					_label = new GUIStyle(GUI.skin.label)
					{
						fontSize = 13,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)0,
						richText = false
					};
					_label.normal.textColor = Color.white;
				}
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(10f, 70f, 232f, 174f);
				GUI.color = new Color(0f, 0f, 0f, 0.55f);
				GUI.Box(val, GUIContent.none, Backdrop);
				GUI.color = Color.white;
				GUI.Label(new Rect(((Rect)(ref val)).x + 9f, ((Rect)(ref val)).y + 7f, ((Rect)(ref val)).width - 14f, ((Rect)(ref val)).height - 12f), _text, _label);
			}
		}

		private static string Build()
		{
			int liveCount = InstancedTrash.LiveCount;
			int count = InstancedTrash.Count;
			int drawn = InstancedTrash.Drawn;
			int realCount = Virtualizer.RealCount;
			int realCount2 = CleanerActor.RealCount;
			float matRadius = Virtualizer.MatRadius;
			return "Litterally\n" + $"field-live   {liveCount} / {count}\n" + $"drawn        {drawn}\n" + $"real player  {realCount}\n" + $"real cleaner {realCount2}\n" + $"awake        {Virtualizer.AwakeRealCount()}\n" + $"matR         {matRadius:F1} m\n" + $"absorbed     {RouteHook.Absorbed}\n" + $"fps          {Mathf.RoundToInt(_smoothFps)}";
		}
	}
}
namespace Litterally.Spawning
{
	internal static class CleanerActor
	{
		private sealed class Real
		{
			public TrashItem Item;

			public Vector3 Pos;

			public Quaternion Rot;
		}

		internal static bool Enabled = true;

		internal static float Range = 30f;

		internal static int PerCleaner = 6;

		private const int RebuildEvery = 30;

		private const int FindCleanersEvery = 120;

		private static int _frame;

		private static Cleaner[] _cleaners = Array.Empty<Cleaner>();

		private static readonly Dictionary<int, Real> _real = new Dictionary<int, Real>();

		private static readonly List<int> _remove = new List<int>();

		private static readonly int[] _scan = new int[64];

		private static float DemoteRange2 => (Range + 8f) * (Range + 8f);

		internal static int RealCount => _real.Count;

		internal static int CopyRealIndices(int[] buf)
		{
			if (buf == null)
			{
				return 0;
			}
			int num = 0;
			foreach (KeyValuePair<int, Real> item in _real)
			{
				if (num >= buf.Length)
				{
					break;
				}
				buf[num++] = item.Key;
			}
			return num;
		}

		internal static int CopyRealPositions(Vector3[] buf)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (buf == null)
			{
				return 0;
			}
			int num = 0;
			foreach (KeyValuePair<int, Real> item in _real)
			{
				if (num >= buf.Length)
				{
					break;
				}
				TrashItem val = ((item.Value != null) ? item.Value.Item : null);
				if (!((Object)(object)val == (Object)null))
				{
					try
					{
						buf[num++] = ((Component)val).transform.position;
					}
					catch
					{
					}
				}
			}
			return num;
		}

		internal static void Tick()
		{
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: 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_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: 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_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: 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_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || InstancedTrash.Count <= 0)
			{
				return;
			}
			TrashManager val = GameTrash.TrashManagerOrNull();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (_frame % 120 == 0)
			{
				_cleaners = FindCleaners();
			}
			if (_frame % 30 == 0)
			{
				InstancedTrash.BuildGrid();
			}
			_frame++;
			_remove.Clear();
			foreach (KeyValuePair<int, Real> item in _real)
			{
				Real value = item.Value;
				if ((Object)(object)value.Item == (Object)null)
				{
					InstancedTrash.Kill(item.Key);
					_remove.Add(item.Key);
					continue;
				}
				Vector3 position;
				try
				{
					position = ((Component)value.Item).transform.position;
				}
				catch
				{
					InstancedTrash.Kill(item.Key);
					_remove.Add(item.Key);
					continue;
				}
				if (!NearAnyCleaner(position) && !IsAnyCleanerTarget(value.Item))
				{
					try
					{
						InstancedTrash.Restore(item.Key, position, ((Component)value.Item).transform.rotation);
						value.Item.DestroyTrash();
					}
					catch
					{
						InstancedTrash.Kill(item.Key);
					}
					_remove.Add(item.Key);
				}
			}
			for (int i = 0; i < _remove.Count; i++)
			{
				_real.Remove(_remove[i]);
			}
			if (_cleaners.Length == 0)
			{
				return;
			}
			int num = _cleaners.Length * PerCleaner - _real.Count;
			if (num <= 0)
			{
				return;
			}
			for (int j = 0; j < _cleaners.Length && num > 0; j++)
			{
				Cleaner val2 = _cleaners[j];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Vector3 position2;
				try
				{
					position2 = ((Component)val2).transform.position;
				}
				catch
				{
					continue;
				}
				int num2 = InstancedTrash.QueryGrid(position2.x, position2.z, Range, _scan, _scan.Length);
				for (int k = 0; k < num2; k++)
				{
					if (num <= 0)
					{
						break;
					}
					int num3 = _scan[k];
					if (_real.ContainsKey(num3))
					{
						continue;
					}
					string typeId = InstancedTrash.GetTypeId(num3);
					if (string.IsNullOrEmpty(typeId))
					{
						continue;
					}
					Vector3 position3 = InstancedTrash.GetPosition(num3);
					Quaternion rotation = InstancedTrash.GetRotation(num3);
					TrashItem val3 = null;
					RouteHook.Suppress = true;
					try
					{
						val3 = val.CreateTrashItem(typeId, position3, rotation, Vector3.zero, Guid.NewGuid().ToString(), false);
					}
					catch (Exception ex)
					{
						Instance log = Core.Log;
						if (log != null)
						{
							log.Warning("[cleaner] materialize: " + ex.Message);
						}
					}
					finally
					{
						RouteHook.Suppress = false;
					}
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					try
					{
						val3.SetPhysicsActive(true);
						val3.RecheckProperty();
					}
					catch (Exception ex2)
					{
						Instance log2 = Core.Log;
						if (log2 != null)
						{
							log2.Warning("[cleaner] register: " + ex2.Message);
						}
					}
					InstancedTrash.MarkRealCreated();
					InstancedTrash.SetRealized(num3, v: true);
					InstancedTrash.Hide(num3);
					_real[num3] = new Real
					{
						Item = val3,
						Pos = position3,
						Rot = rotation
					};
					num--;
				}
			}
		}

		private static Cleaner[] FindCleaners()
		{
			List<Cleaner> list = new List<Cleaner>();
			try
			{
				EmployeeManager instance = NetworkSingleton<EmployeeManager>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					List<Employee> employeesByType = instance.GetEmployeesByType((EEmployeeType)3);
					if (employeesByType != null)
					{
						for (int i = 0; i < employeesByType.Count; i++)
						{
							Employee val = employeesByType[i];
							if (!((Object)(object)val == (Object)null))
							{
								Cleaner val2 = ((Il2CppObjectBase)val).TryCast<Cleaner>();
								if ((Object)(object)val2 != (Object)null)
								{
									list.Add(val2);
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[cleaner] find: " + ex.Message);
				}
			}
			return list.ToArray();
		}

		private static bool NearAnyCleaner(Vector3 p)
		{
			//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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _cleaners.Length; i++)
			{
				Cleaner val = _cleaners[i];
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 position;
					try
					{
						position = ((Component)val).transform.position;
					}
					catch
					{
						continue;
					}
					float num = p.x - position.x;
					float num2 = p.z - position.z;
					if (num * num + num2 * num2 <= DemoteRange2)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsAnyCleanerTarget(TrashItem item)
		{
			for (int i = 0; i < _cleaners.Length; i++)
			{
				Cleaner val = _cleaners[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					if ((Object)(object)val.PickUpTrashBehaviour != (Object)null && (Object)(object)val.PickUpTrashBehaviour.TargetTrash == (Object)(object)item)
					{
						return true;
					}
				}
				catch
				{
				}
			}
			return false;
		}

		internal static void Diagnose()
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Cleaner[] array = FindCleaners();
				InstancedTrash.BuildGrid();
				int[] array2 = new int[256];
				Instance log = Core.Log;
				if (log != null)
				{
					log.Msg($"[cleaner] DIAG: {array.Length} cleaner(s) via EmployeeManager registry; field={InstancedTrash.Count} (live {InstancedTrash.LiveCount}); range={Range}m, perCleaner={PerCleaner}; materialised={_real.Count}");
				}
				for (int i = 0; i < array.Length; i++)
				{
					Cleaner val = array[i];
					if (!((Object)(object)val == (Object)null))
					{
						Vector3 position = ((Component)val).transform.position;
						int value = InstancedTrash.QueryGrid(position.x, position.z, Range, array2, array2.Length);
						int value2 = InstancedTrash.QueryGrid(position.x, position.z, 50f, array2, array2.Length);
						Instance log2 = Core.Log;
						if (log2 != null)
						{
							log2.Msg($"[cleaner]   #{i} at ({position.x:F0},{position.y:F0},{position.z:F0}): data within {Range}m={value}, within 50m={value2}");
						}
					}
				}
			}
			catch (Exception ex)
			{
				Instance log3 = Core.Log;
				if (log3 != null)
				{
					log3.Warning("[cleaner] diag: " + ex.Message);
				}
			}
		}

		internal static void ClearAll()
		{
			//IL_0040: 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)
			foreach (KeyValuePair<int, Real> item in _real)
			{
				Real value = item.Value;
				if (value != null && (Object)(object)value.Item != (Object)null)
				{
					try
					{
						InstancedTrash.Restore(item.Key, ((Component)value.Item).transform.position, ((Component)value.Item).transform.rotation);
						value.Item.DestroyTrash();
					}
					catch
					{
						InstancedTrash.Kill(item.Key);
					}
				}
				else
				{
					InstancedTrash.Kill(item.Key);
				}
			}
			_real.Clear();
			_cleaners = Array.Empty<Cleaner>();
		}
	}
	internal static class GameTrash
	{
		internal static TrashManager TrashManagerOrNull()
		{
			try
			{
				return NetworkSingleton<TrashManager>.Instance;
			}
			catch
			{
				return null;
			}
		}

		internal static int TrashItemCount(TrashManager tm)
		{
			try
			{
				return ((Object)(object)tm != (Object)null && tm.trashItems != null) ? tm.trashItems.Count : 0;
			}
			catch
			{
				return 0;
			}
		}

		internal static bool TryGetPlayerPosition(out Vector3 pos)
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			try
			{
				Player local = Player.Local;
				if ((Object)(object)local == (Object)null)
				{
					return false;
				}
				pos = ((Component)local).transform.position;
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class GeneratorBoost
	{
		private static readonly Dictionary<TrashGenerator, int> _saved = new Dictionary<TrashGenerator, int>();

		private static bool _applied;

		internal static void Apply(int mult)
		{
			mult = Mathf.Clamp(mult, 1, 1000);
			List<TrashGenerator> val = null;
			try
			{
				val = TrashGenerator.AllGenerators;
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[route] boost AllGenerators: " + ex.Message);
				}
			}
			if (val == null)
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Warning("[route] boost: no generators");
				}
				return;
			}
			int num = 0;
			for (int i = 0; i < val.Count; i++)
			{
				TrashGenerator val2 = val[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				if (!_saved.ContainsKey(val2))
				{
					try
					{
						_saved[val2] = val2.MaxTrashCount;
					}
					catch
					{
						continue;
					}
				}
				try
				{
					val2.MaxTrashCount = _saved[val2] * mult;
					num++;
				}
				catch
				{
				}
			}
			_applied = true;
			Instance log3 = Core.Log;
			if (log3 != null)
			{
				log3.Msg($"[route] boosted MaxTrashCount x{mult} on {num} generators. Walk into a fresh region or 'tv route burst' to see it.");
			}
		}

		internal static void Restore()
		{
			if (!_applied && _saved.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<TrashGenerator, int> item in _saved)
			{
				TrashGenerator key = item.Key;
				if (!((Object)(object)key == (Object)null))
				{
					try
					{
						key.MaxTrashCount = item.Value;
					}
					catch
					{
					}
				}
			}
			_saved.Clear();
			_applied = false;
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg("[route] generator MaxTrashCount restored.");
			}
		}
	}
	internal static class RouteHook
	{
		private sealed class SettleItem
		{
			public TrashItem Item;

			public Rigidbody Rb;

			public int Age;

			public int Rest;
		}

		internal static bool Active = false;

		internal static bool Probe = false;

		[ThreadStatic]
		internal static bool Suppress;

		internal static bool AbsorbAny = false;

		[ThreadStatic]
		internal static bool GeneratorActive;

		[ThreadStatic]
		private static int _genDepth;

		private static readonly Dictionary<int, SettleItem> _settling = new Dictionary<int, SettleItem>();

		private static readonly HashSet<int> _tracked = new HashSet<int>();

		private static readonly List<int> _doneSettling = new List<int>();

		private static readonly List<TrashItem> _destroyQueue = new List<TrashItem>();

		internal static int Absorbed;

		internal static int Skipped;

		internal static int AtCap;

		private const int SettleMinFrames = 6;

		private const int SettleMaxFrames = 150;

		private const float SettleVel2 = 0.01f;

		private const int SettleRestFrames = 8;

		private const int SettlingCap = 1200;

		internal static int PubCalls;

		internal static int PrivCalls;

		private static readonly HashSet<int> _distinctPub = new HashSet<int>();

		private static readonly HashSet<int> _distinctPriv = new HashSet<int>();

		private static int _logged;

		private const int GroundMask = -1025;

		private static int _heightLogged;

		internal static int SettlingCount => _settling.Count;

		internal static void EnterGenerator()
		{
			if (_genDepth++ == 0)
			{
				GeneratorActive = true;
			}
		}

		internal static void ExitGenerator()
		{
			if (--_genDepth <= 0)
			{
				_genDepth = 0;
				GeneratorActive = false;
			}
		}

		internal static void OnCreate(bool isPrivate, TrashItem result)
		{
			if (Suppress)
			{
				return;
			}
			if (Probe && !Active)
			{
				ProbeNote(isPrivate, result);
			}
			else
			{
				if (!Active || (Object)(object)result == (Object)null)
				{
					return;
				}
				if (!GeneratorActive && !AbsorbAny)
				{
					Skipped++;
					return;
				}
				int instanceID;
				try
				{
					instanceID = ((Object)result).GetInstanceID();
				}
				catch
				{
					return;
				}
				if (_tracked.Add(instanceID))
				{
					try
					{
						if (_settling.Count >= 1200)
						{
							Record(instanceID, result, groundSnap: true);
						}
						else
						{
							Rigidbody rb = null;
							try
							{
								rb = ((Component)result).GetComponentInChildren<Rigidbody>();
							}
							catch
							{
							}
							_settling[instanceID] = new SettleItem
							{
								Item = result,
								Rb = rb,
								Age = 0
							};
						}
						return;
					}
					catch (Exception ex)
					{
						Instance log = Core.Log;
						if (log != null)
						{
							log.Warning("[route] track: " + ex.Message);
						}
						_tracked.Remove(instanceID);
						return;
					}
				}
				Skipped++;
			}
		}

		private static void Record(int iid, TrashItem item, bool groundSnap)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)item == (Object)null)
				{
					_tracked.Remove(iid);
					return;
				}
				string iD = item.ID;
				Vector3 position = ((Component)item).transform.position;
				Quaternion rotation = ((Component)item).transform.rotation;
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(position + Vector3.up * 0.5f, Vector3.down, ref val, 80f, -1025, (QueryTriggerInteraction)1))
				{
					float num = position.y - ((RaycastHit)(ref val)).point.y;
					bool flag = num > 0.4f || num < -0.1f;
					if (_heightLogged < 10)
					{
						_heightLogged++;
						Instance log = Core.Log;
						if (log != null)
						{
							log.Msg($"[route] settled '{iD}' {num:F2}m vs ground{(flag ? " -> ground-snap" : "")}");
						}
					}
					if (flag)
					{
						groundSnap = true;
					}
				}
				int num2 = InstancedTrash.AddOne(iD, position, rotation, groundSnap);
				if (num2 == -2)
				{
					AtCap++;
					_tracked.Remove(iid);
				}
				else if (num2 < 0)
				{
					_tracked.Remove(iid);
				}
				else
				{
					Absorbed++;
					_destroyQueue.Add(item);
				}
			}
			catch (Exception ex)
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Warning("[route] record: " + ex.Message);
				}
			}
			finally
			{
				_tracked.Remove(iid);
			}
		}

		internal static void Tick()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (_settling.Count > 0)
			{
				_doneSettling.Clear();
				foreach (KeyValuePair<int, SettleItem> item in _settling)
				{
					SettleItem value = item.Value;
					if ((Object)(object)value.Item == (Object)null)
					{
						_doneSettling.Add(item.Key);
						_tracked.Remove(item.Key);
						continue;
					}
					value.Age++;
					int num;
					if (!((Object)(object)value.Rb == (Object)null))
					{
						Vector3 velocity = value.Rb.velocity;
						num = ((((Vector3)(ref velocity)).sqrMagnitude < 0.01f) ? 1 : 0);
					}
					else
					{
						num = 1;
					}
					bool flag = (byte)num != 0;
					value.Rest = (flag ? (value.Rest + 1) : 0);
					if (value.Age >= 150 || (value.Age >= 6 && value.Rest >= 8))
					{
						Record(item.Key, value.Item, groundSnap: false);
						_doneSettling.Add(item.Key);
					}
				}
				for (int i = 0; i < _doneSettling.Count; i++)
				{
					_settling.Remove(_doneSettling[i]);
				}
			}
			if (_destroyQueue.Count <= 0)
			{
				return;
			}
			Suppress = true;
			try
			{
				for (int j = 0; j < _destroyQueue.Count; j++)
				{
					TrashItem val = _destroyQueue[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					try
					{
						val.DestroyTrash();
					}
					catch
					{
					}
					try
					{
						if ((Object)(object)val != (Object)null)
						{
							Object.Destroy((Object)(object)((Component)val).gameObject);
						}
					}
					catch
					{
					}
				}
			}
			finally
			{
				Suppress = false;
			}
			_destroyQueue.Clear();
		}

		internal static void ResetState()
		{
			_settling.Clear();
			_tracked.Clear();
			_doneSettling.Clear();
			_destroyQueue.Clear();
			_genDepth = 0;
			GeneratorActive = false;
		}

		private static void ProbeNote(bool isPrivate, TrashItem result)
		{
			//IL_007c: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			int item = 0;
			try
			{
				if ((Object)(object)result != (Object)null)
				{
					item = ((Object)result).GetInstanceID();
				}
			}
			catch
			{
			}
			if (isPrivate)
			{
				PrivCalls++;
				if ((Object)(object)result != (Object)null)
				{
					_distinctPriv.Add(item);
				}
			}
			else
			{
				PubCalls++;
				if ((Object)(object)result != (Object)null)
				{
					_distinctPub.Add(item);
				}
			}
			if (_logged >= 16)
			{
				return;
			}
			_logged++;
			string text = "?";
			Vector3 val = Vector3.zero;
			try
			{
				if ((Object)(object)result != (Object)null)
				{
					text = result.ID;
					val = ((Component)result).transform.position;
				}
			}
			catch
			{
			}
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg($"[route-probe] {(isPrivate ? "CreateAndReturnTrashItem" : "CreateTrashItem")} -> {(((Object)(object)result == (Object)null) ? "NULL" : text)} @({val.x:F0},{val.y:F0},{val.z:F0})");
			}
		}

		internal static void ResetCounts()
		{
			PubCalls = (PrivCalls = (_logged = (_heightLogged = 0)));
			_distinctPub.Clear();
			_distinctPriv.Clear();
			Absorbed = (Skipped = (AtCap = 0));
		}

		internal static void Command(string[] p)
		{
			switch ((p.Length > 2) ? p[2] : "stat")
			{
			case "on":
			{
				Active = true;
				Probe = false;
				ResetCounts();
				Instance log9 = Core.Log;
				if (log9 != null)
				{
					log9.Msg("[route] routing ON: game-generated trash is absorbed into the instanced field.");
				}
				break;
			}
			case "off":
			{
				Active = false;
				Tick();
				ResetState();
				GeneratorBoost.Restore();
				InstancedTrash.Clear();
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Msg("[route] routing OFF: generators restored, instanced field cleared.");
				}
				break;
			}
			case "boost":
			{
				GeneratorBoost.Apply((p.Length > 3 && int.TryParse(p[3], out var result2)) ? result2 : 20);
				break;
			}
			case "unboost":
				GeneratorBoost.Restore();
				break;
			case "probe":
			{
				Probe = ((p.Length <= 3) ? (!Probe) : (p[3] == "on" || p[3] == "1"));
				Active = false;
				ResetCounts();
				Instance log8 = Core.Log;
				if (log8 != null)
				{
					log8.Msg($"[route-probe] probe = {Probe} (log-only). tv route burst, then tv route stat.");
				}
				break;
			}
			case "burst":
			{
				Burst((p.Length > 3 && int.TryParse(p[3], out var result)) ? result : 30);
				break;
			}
			case "stat":
			{
				TrashManager val2 = GameTrash.TrashManagerOrNull();
				int value = -1;
				try
				{
					if ((Object)(object)val2 != (Object)null)
					{
						value = GameTrash.TrashItemCount(val2);
					}
				}
				catch
				{
				}
				Instance log10 = Core.Log;
				if (log10 != null)
				{
					log10.Msg($"[route] STAT  active={Active}  absorbMode={(AbsorbAny ? "ANY (legacy)" : "generator-only (good-citizen)")}  instanced={InstancedTrash.Count}  realTrashItems(manager)={value}  settling={_settling.Count}  absorbed={Absorbed} skipped(echo+othermod)={Skipped} atCap={AtCap}");
				}
				if (Probe)
				{
					Instance log11 = Core.Log;
					if (log11 != null)
					{
						log11.Msg($"[route-probe]  public calls={PubCalls} distinct={_distinctPub.Count}  private calls={PrivCalls} distinct={_distinctPriv.Count}");
					}
				}
				break;
			}
			case "absorbany":
			{
				AbsorbAny = ((p.Length <= 3) ? (!AbsorbAny) : (p[3] == "on" || p[3] == "1" || p[3] == "true"));
				Instance log7 = Core.Log;
				if (log7 != null)
				{
					log7.Msg($"[route] absorbAny = {AbsorbAny} ({(AbsorbAny ? "absorb ALL trash incl. other mods' - legacy" : "absorb ONLY the game generator's trash - good-citizen default")}).");
				}
				break;
			}
			case "testlimit":
				try
				{
					Instance log5 = Core.Log;
					if (log5 != null)
					{
						log5.Msg($"[limit] TRASH_ITEM_LIMIT = {TrashManager.TRASH_ITEM_LIMIT} (READ-ONLY; writing it hard-crashes the game - verified).");
					}
					break;
				}
				catch (Exception ex2)
				{
					Instance log6 = Core.Log;
					if (log6 != null)
					{
						log6.Warning("[limit] read threw: " + ex2.Message);
					}
					break;
				}
			case "clearreal":
				try
				{
					TrashManager val = GameTrash.TrashManagerOrNull();
					if ((Object)(object)val != (Object)null)
					{
						val.DestroyAllTrash();
					}
					Instance log3 = Core.Log;
					if (log3 != null)
					{
						log3.Msg("[route] DestroyAllTrash()");
					}
					break;
				}
				catch (Exception ex)
				{
					Instance log4 = Core.Log;
					if (log4 != null)
					{
						log4.Warning("[route] clear failed: " + ex.Message);
					}
					break;
				}
			default:
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Msg("[route] usage: tv route on|off | boost [mult] | unboost | burst [n] | stat | probe on|off | absorbany on|off | clearreal");
				}
				break;
			}
			}
		}

		private static void Burst(int perGenerator)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!GameTrash.TryGetPlayerPosition(out var pos))
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[route] no player");
				}
				return;
			}
			List<TrashGenerator> val = null;
			try
			{
				val = TrashGenerator.AllGenerators;
			}
			catch (Exception ex)
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Warning("[route] AllGenerators: " + ex.Message);
				}
			}
			if (val == null)
			{
				Instance log3 = Core.Log;
				if (log3 != null)
				{
					log3.Warning("[route] AllGenerators null");
				}
				return;
			}
			int count = val.Count;
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < count; i++)
			{
				TrashGenerator val2 = val[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				float num3;
				try
				{
					num3 = Vector3.Distance(((Component)val2).transform.position, pos);
				}
				catch
				{
					continue;
				}
				if (num3 > 120f)
				{
					continue;
				}
				num++;
				try
				{
					val2.GenerateTrash(perGenerator);
					num2++;
				}
				catch (Exception ex2)
				{
					Instance log4 = Core.Log;
					if (log4 != null)
					{
						log4.Warning("[route] GenerateTrash: " + ex2.Message);
					}
				}
			}
			Instance log5 = Core.Log;
			if (log5 != null)
			{
				log5.Msg($"[route] burst: {count} generators, {num} within 120m, GenerateTrash({perGenerator}) on {num2}. tv route stat.");
			}
		}
	}
	[HarmonyPatch(typeof(TrashManager), "CreateAndReturnTrashItem", new Type[]
	{
		typeof(string),
		typeof(Vector3),
		typeof(Quaternion),
		typeof(Vector3),
		typeof(string),
		typeof(bool)
	})]
	internal static class TM_CreateAndReturnTrashItem_Patch
	{
		private static void Postfix(TrashItem __result)
		{
			try
			{
				RouteHook.OnCreate(isPrivate: true, __result);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(TrashManager), "CreateTrashItem", new Type[]
	{
		typeof(string),
		typeof(Vector3),
		typeof(Quaternion),
		typeof(Vector3),
		typeof(string),
		typeof(bool)
	})]
	internal static class TM_CreateTrashItem_Patch
	{
		private static void Postfix(TrashItem __result)
		{
			try
			{
				RouteHook.OnCreate(isPrivate: false, __result);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(TrashGenerator), "GenerateMaxTrash")]
	internal static class TG_GenerateMaxTrash_Patch
	{
		private static void Prefix()
		{
			RouteHook.EnterGenerator();
		}

		private static Exception Finalizer(Exception __exception)
		{
			RouteHook.ExitGenerator();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(TrashGenerator), "GenerateTrash", new Type[] { typeof(int) })]
	internal static class TG_GenerateTrash_Patch
	{
		private static void Prefix()
		{
			RouteHook.EnterGenerator();
		}

		private static Exception Finalizer(Exception __exception)
		{
			RouteHook.ExitGenerator();
			return __exception;
		}
	}
	internal static class TrashPopulator
	{
		internal static bool Enabled = true;

		internal static int Multiplier = 1;

		internal static float Radius = 170f;

		private const int BatchPerGen = 30;

		private const int GensPerPass = 2;

		private const float PassEvery = 0.3f;

		private const float NoSpawnInView = 50f;

		private const int MaxDeferPasses = 12;

		private static float _timer;

		private static readonly float[] _planes = new float[24];

		private static readonly HashSet<int> _done = new HashSet<int>();

		private static readonly HashSet<int> _boosted = new HashSet<int>();

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

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

		internal static void Reset()
		{
			_done.Clear();
			_boosted.Clear();
			_generated.Clear();
			_deferred.Clear();
			_timer = 0f;
		}

		internal static void Tick(float dt)
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_00e0: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled || Multiplier <= 1)
			{
				return;
			}
			_timer += dt;
			if (_timer < 0.3f)
			{
				return;
			}
			_timer = 0f;
			if (!GameTrash.TryGetPlayerPosition(out var pos))
			{
				return;
			}
			List<TrashGenerator> allGenerators;
			try
			{
				allGenerators = TrashGenerator.AllGenerators;
			}
			catch
			{
				return;
			}
			if (allGenerators == null)
			{
				return;
			}
			float[] array = (Frustum.Compute(Frustum.Cam(), _planes) ? _planes : null);
			float num = 2500f;
			float num2 = Radius * Radius;
			int num3 = 0;
			for (int i = 0; i < allGenerators.Count && num3 < 2; i++)
			{
				TrashGenerator val = allGenerators[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int instanceID;
				try
				{
					instanceID = ((Object)val).GetInstanceID();
				}
				catch
				{
					continue;
				}
				if (_done.Contains(instanceID))
				{
					continue;
				}
				Vector3 position;
				try
				{
					position = ((Component)val).transform.position;
				}
				catch
				{
					continue;
				}
				float num4 = position.x - pos.x;
				float num5 = position.z - pos.z;
				float num6 = num4 * num4 + num5 * num5;
				if (num6 > num2)
				{
					continue;
				}
				try
				{
					if (_boosted.Contains(instanceID))
					{
						goto IL_01d2;
					}
					BoxCollider component = ((Component)val).GetComponent<BoxCollider>();
					if (!((Object)(object)component == (Object)null))
					{
						_boosted.Add(instanceID);
						val.TrashCountMultiplier = Multiplier;
						val.AutoCalculateTrashCount();
						int maxTrashCount = val.MaxTrashCount;
						Bounds bounds = ((Collider)component).bounds;
						int num7 = ((maxTrashCount > 0) ? InstancedTrash.CountInBox(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.z, ((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.z, maxTrashCount) : 0);
						_generated[instanceID] = num7;
						if (maxTrashCount <= 0 || num7 < maxTrashCount)
						{
							goto IL_01d2;
						}
						_done.Add(instanceID);
					}
					goto end_IL_010b;
					IL_01d2:
					int maxTrashCount2 = val.MaxTrashCount;
					int value;
					int num8 = (_generated.TryGetValue(instanceID, out value) ? value : 0);
					if (maxTrashCount2 <= 0 || num8 >= maxTrashCount2)
					{
						_done.Add(instanceID);
						continue;
					}
					if (array == null || !(num6 < num) || !Frustum.Contains(array, position.x, position.y, position.z, 3f))
					{
						goto IL_0268;
					}
					int value2;
					int num9 = ((!_deferred.TryGetValue(instanceID, out value2)) ? 1 : (value2 + 1));
					_deferred[instanceID] = num9;
					if (num9 >= 12)
					{
						goto IL_0268;
					}
					goto end_IL_010b;
					IL_0268:
					int num10 = Math.Min(maxTrashCount2 - num8, 30);
					val.GenerateTrash(num10);
					_generated[instanceID] = num8 + num10;
					num3++;
					if (num8 + num10 >= maxTrashCount2)
					{
						_done.Add(instanceID);
					}
					end_IL_010b:;
				}
				catch (Exception ex)
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning("[populate] " + ex.Message);
					}
					_done.Add(instanceID);
				}
			}
		}
	}
}
namespace Litterally.SaveGuard
{
	internal static class SaveSafety
	{
		internal static void ForceClearForSave(string reason)
		{
			RouteHook.Tick();
			GeneratorBoost.Restore();
			Virtualizer.ClearAll();
			CleanerActor.ClearAll();
			InstancedTrash.AbortCalibration();
			InstancedTrash.AbortDrift();
		}
	}
}
namespace Litterally.Instanced
{
	internal static class Frustum
	{
		private static Camera _cam;

		internal static Camera Cam()
		{
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				_cam = main;
			}
			return _cam;
		}

		internal static bool Compute(Camera cam, float[] planes)
		{
			//IL_0017: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null || planes == null || planes.Length < 24)
			{
				return false;
			}
			try
			{
				return ComputeFromVP(cam.projectionMatrix * cam.worldToCameraMatrix, planes);
			}
			catch
			{
				return false;
			}
		}

		internal static bool ComputeFromVP(Matrix4x4 m, float[] planes)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00d2: 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_00df: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_0142: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (planes == null || planes.Length < 24)
			{
				return false;
			}
			Set(planes, 0, m.m30 + m.m00, m.m31 + m.m01, m.m32 + m.m02, m.m33 + m.m03);
			Set(planes, 1, m.m30 - m.m00, m.m31 - m.m01, m.m32 - m.m02, m.m33 - m.m03);
			Set(planes, 2, m.m30 + m.m10, m.m31 + m.m11, m.m32 + m.m12, m.m33 + m.m13);
			Set(planes, 3, m.m30 - m.m10, m.m31 - m.m11, m.m32 - m.m12, m.m33 - m.m13);
			Set(planes, 4, m.m30 + m.m20, m.m31 + m.m21, m.m32 + m.m22, m.m33 + m.m23);
			Set(planes, 5, m.m30 - m.m20, m.m31 - m.m21, m.m32 - m.m22, m.m33 - m.m23);
			return true;
		}

		internal static Matrix4x4 ViewProjection(Matrix4x4 projection, Vector3 pos, Quaternion rot)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			Matrix4x4 val = Matrix4x4.Scale(new Vector3(1f, 1f, -1f));
			Matrix4x4 val2 = Matrix4x4.TRS(pos, rot, Vector3.one);
			Matrix4x4 val3 = val * ((Matrix4x4)(ref val2)).inverse;
			return projection * val3;
		}

		private static void Set(float[] pl, int k, float a, float b, float c, float d)
		{
			float num = Mathf.Sqrt(a * a + b * b + c * c);
			float num2 = ((num > 1E-06f) ? (1f / num) : 0f);
			int num3 = k << 2;
			pl[num3] = a * num2;
			pl[num3 + 1] = b * num2;
			pl[num3 + 2] = c * num2;
			pl[num3 + 3] = d * num2;
		}

		internal static bool Contains(float[] pl, float px, float py, float pz, float margin)
		{
			if (pl == null)
			{
				return true;
			}
			for (int i = 0; i < 6; i++)
			{
				int num = i << 2;
				if (pl[num] * px + pl[num + 1] * py + pl[num + 2] * pz + pl[num + 3] < 0f - margin)
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class InstancedTrash
	{
		private sealed class Part
		{
			public Mesh Mesh;

			public Material[] Mats;

			public Matrix4x4 Local = Matrix4x4.identity;
		}

		private struct Pose
		{
			public Quaternion Rot;

			public float Clearance;
		}

		private sealed class TType
		{
			public string Id;

			public Part[] Parts;

			public Pose[] Poses;

			public bool Calibrated;

			public float Weight = 1f;

			public int Start;

			public int Len;
		}

		private struct Ground
		{
			public float Y;

			public Vector3 N;

			public bool Hit;
		}

		private static class Calibration
		{
			private const int PosesPerType = 16;

			private const float ProbeSpacing = 4f;

			private const float ProbeDropHeight = 1f;

			private const int MinSettleFrames = 25;

			private const int TypeTimeoutFrames = 150;

			private const float SettleVel2 = 0.0025f;

			private const float MinDescent = 0.3f;

			private const float FlatNormalY = 0.985f;

			private static readonly List<TType> _pendingTypes = new List<TType>();

			private static int _cursor;

			private static int _typeFrames;

			private static readonly List<TrashItem> _probes = new List<TrashItem>();

			private static readonly List<float> _spawnY = new List<float>();

			private static readonly List<Pose> _caps = new List<Pose>();

			internal static bool Active { get; private set; }

			internal static int Outstanding { get; private set; }

			internal static bool Begin(TType[] types)
			{
				//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_0066: 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_0086: 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)
				if (Active)
				{
					return true;
				}
				_pendingTypes.Clear();
				for (int i = 0; i < types.Length; i++)
				{
					if (!types[i].Calibrated)
					{
						_pendingTypes.Add(types[i]);
					}
				}
				if (_pendingTypes.Count == 0)
				{
					return false;
				}
				if ((Object)(object)GameTrash.TrashManagerOrNull() == (Object)null)
				{
					return false;
				}
				if (!GameTrash.TryGetPlayerPosition(out var pos))
				{
					return false;
				}
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(pos + Vector3.up, Vector3.down, ref val, 5f, GroundRayMask, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val)).normal.y < 0.99f)
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning($"[inst] calibration ground not flat (normal.y={((RaycastHit)(ref val)).normal.y:F3}); stand on flat ground for best poses.");
					}
				}
				_cursor = 0;
				Active = true;
				Outstanding = _pendingTypes.Count;
				SpawnProbesFor(_pendingTypes[0]);
				return true;
			}

			private static bool SpawnProbesFor(TType ty)
			{
				//IL_0041: 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_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0101: 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_0082: 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)
				DestroyProbes();
				_caps.Clear();
				_typeFrames = 0;
				TrashManager val = GameTrash.TrashManagerOrNull();
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				if (!GameTrash.TryGetPlayerPosition(out var pos))
				{
					return false;
				}
				for (int i = 0; i < 16; i++)
				{
					int num = i % 4;
					int num2 = i / 4;
					Vector3 val2 = pos + new Vector3(((float)num - 1.5f) * 4f, 1f, ((float)num2 - 1.5f) * 4f);
					TrashItem val3 = null;
					RouteHook.Suppress = true;
					try
					{
						val3 = val.CreateTrashItem(ty.Id, val2, Random.rotation, Vector3.zero, Guid.NewGuid().ToString(), false);
					}
					catch (Exception ex)
					{
						Instance log = Core.Log;
						if (log != null)
						{
							log.Warning("[inst] probe spawn failed for " + ty.Id + ": " + ex.Message);
						}
					}
					finally
					{
						RouteHook.Suppress = false;
					}
					if ((Object)(object)val3 != (Object)null)
					{
						MarkRealCreated();
					}
					_probes.Add(val3);
					_spawnY.Add(val2.y);
				}
				return true;
			}

			internal static bool Tick()
			{
				//IL_0094: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
				if (!Active)
				{
					return true;
				}
				_typeFrames++;
				TType tType = ((_cursor < _pendingTypes.Count) ? _pendingTypes[_cursor] : null);
				if (tType == null)
				{
					Finish();
					return true;
				}
				bool flag = _typeFrames >= 150;
				bool flag2 = true;
				for (int i = 0; i < _probes.Count; i++)
				{
					TrashItem val = _probes[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					bool flag3 = false;
					if (_typeFrames >= 25)
					{
						try
						{
							float num = _spawnY[i] - ((Component)val).transform.position.y;
							Rigidbody componentInChildren = ((Component)val).GetComponentInChildren<Rigidbody>();
							int num2;
							if (!((Object)(object)componentInChildren == (Object)null))
							{
								Vector3 velocity = componentInChildren.velocity;
								num2 = ((((Vector3)(ref velocity)).sqrMagnitude < 0.0025f) ? 1 : 0);
							}
							else
							{
								num2 = 1;
							}
							bool flag4 = (byte)num2 != 0;
							if (num >= 0.3f && flag4)
							{
								flag3 = true;
							}
						}
						catch
						{
							flag3 = true;
						}
					}
					if (!flag3)
					{
						flag2 = false;
						continue;
					}
					CaptureProbe(tType, val, force: false);
					DestroyOne(val);
					_probes[i] = null;
				}
				if (flag2 || flag)
				{
					if (flag)
					{
						for (int j = 0; j < _probes.Count; j++)
						{
							if ((Object)(object)_probes[j] != (Object)null)
							{
								CaptureProbe(tType, _probes[j], force: true);
								DestroyOne(_probes[j]);
								_probes[j] = null;
							}
						}
					}
					FinalizeType(tType);
					_cursor++;
					if (_cursor < _pendingTypes.Count)
					{
						SpawnProbesFor(_pendingTypes[_cursor]);
						return false;
					}
					Finish();
					return true;
				}
				return false;
			}

			private static void CaptureProbe(TType ty, TrashItem probe, bool force)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: 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)
				try
				{
					Vector3 position = ((Component)probe).transform.position;
					float y = position.y;
					float num = 1f;
					RaycastHit val = default(RaycastHit);
					if (Physics.Raycast(position + Vector3.up * 0.6f, Vector3.down, ref val, 3f, GroundRayMask, (QueryTriggerInteraction)1))
					{
						y = ((RaycastHit)(ref val)).point.y;
						num = ((RaycastHit)(ref val)).normal.y;
					}
					if (force || !(num < 0.985f))
					{
						float clearance = Mathf.Clamp(position.y - y, -0.3f, 1.2f);
						_caps.Add(new Pose
						{
							Rot = ((Component)probe).transform.rotation,
							Clearance = clearance
						});
					}
				}
				catch
				{
				}
			}

			private static void FinalizeType(TType ty)
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: 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_00b8: 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_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				List<Pose> list = new List<Pose>(_caps.Count);
				for (int i = 0; i < _caps.Count; i++)
				{
					Vector3 val = Quaternion.Inverse(_caps[i].Rot) * Vector3.down;
					bool flag = false;
					for (int j = 0; j < list.Count; j++)
					{
						if (Vector3.Dot(Quaternion.Inverse(list[j].Rot) * Vector3.down, val) > 0.985f)
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						list.Add(_caps[i]);
					}
				}
				if (list.Count == 0)
				{
					list.Add(new Pose
					{
						Rot = Quaternion.identity,
						Clearance = ComputeClearance(ty, Quaternion.identity)
					});
				}
				ty.Poses = list.ToArray();
				ty.Calibrated = true;
				Outstanding = Math.Max(0, Outstanding - 1);
				Instance log = Core.Log;
				if (log != null)
				{
					log.Msg($"[inst] calibrated '{ty.Id}': {ty.Poses.Length} settled pose(s) from {_caps.Count} drop(s)" + ((ty.Poses.Length < 4) ? " (low variety - relying on random yaw)" : ""));
				}
			}

			private static void Finish()
			{
				DestroyProbes();
				_caps.Clear();
				Active = false;
				Outstanding = 0;
				_cursor = 0;
			}

			private static void DestroyOne(TrashItem pr)
			{
				if ((Object)(object)pr == (Object)null)
				{
					return;
				}
				try
				{
					pr.DestroyTrash();
				}
				catch
				{
				}
				try
				{
					if ((Object)(object)pr != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)pr).gameObject);
					}
				}
				catch
				{
				}
			}

			private static void DestroyProbes()
			{
				for (int i = 0; i < _probes.Count; i++)
				{
					DestroyOne(_probes[i]);
				}
				_probes.Clear();
				_spawnY.Clear();
			}

			internal static void Reset()
			{
				DestroyProbes();
				_caps.Clear();
				_pendingTypes.Clear();
				Active = false;
				Outstanding = 0;
				_cursor = 0;
				_typeFrames = 0;
			}
		}

		private static class GroundDrift
		{
			private const float WaitSeconds = 5f;

			private const float SampleRadius = 18f;

			private const float DriftThreshold = 0.15f;

			private static readonly List<int> _idx = new List<int>();

			private static readonly List<TrashItem> _items = new List<TrashItem>();

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

			private static readonly List<Quaternion> _startRot = new List<Quaternion>();

			private static readonly int[] _scan = new int[512];

			private static float _elapsed;

			internal static bool Active { get; private set; }

			internal static void Begin(int count)
			{
				//IL_01db: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e7: 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_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Unknown result type (might be due to invalid IL or missing references)
				//IL_0147: Unknown result type (might be due to invalid IL or missing references)
				//IL_0155: 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_0159: Unknown result type (might be due to invalid IL or missing references)
				if (Active)
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Msg("[drift] already running");
					}
					return;
				}
				TrashManager val = GameTrash.TrashManagerOrNull();
				if ((Object)(object)val == (Object)null)
				{
					Instance log2 = Core.Log;
					if (log2 != null)
					{
						log2.Warning("[drift] no TrashManager");
					}
					return;
				}
				if (!GameTrash.TryGetPlayerPosition(out var pos))
				{
					Instance log3 = Core.Log;
					if (log3 != null)
					{
						log3.Warning("[drift] no player");
					}
					return;
				}
				if (!Ready || _count <= 0)
				{
					Instance log4 = Core.Log;
					if (log4 != null)
					{
						log4.Warning("[drift] no instanced field to sample");
					}
					return;
				}
				_idx.Clear();
				_items.Clear();
				_start.Clear();
				_startRot.Clear();
				_elapsed = 0f;
				int num = CollectNear(pos, 18f, _scan, _scan.Length);
				if (num == 0)
				{
					Instance log5 = Core.Log;
					if (log5 != null)
					{
						log5.Warning("[drift] no settled instances within " + 18f + "m");
					}
					return;
				}
				int num2 = Mathf.Clamp(count, 1, num);
				int num3 = Mathf.Max(1, num / num2);
				for (int i = 0; i < num; i += num3)
				{
					if (_idx.Count >= num2)
					{
						break;
					}
					int num4 = _scan[i];
					string typeId = GetTypeId(num4);
					if (string.IsNullOrEmpty(typeId))
					{
						continue;
					}
					Vector3 position = GetPosition(num4);
					Quaternion rotation = GetRotation(num4);
					TrashItem val2 = null;
					RouteHook.Suppress = true;
					try
					{
						val2 = val.CreateTrashItem(typeId, position, rotation, Vector3.zero, Guid.NewGuid().ToString(), false);
					}
					catch (Exception ex)
					{
						Instance log6 = Core.Log;
						if (log6 != null)
						{
							log6.Warning("[drift] spawn failed: " + ex.Message);
						}
					}
					finally
					{
						RouteHook.Suppress = false;
					}
					if (!((Object)(object)val2 == (Object)null))
					{
						MarkRealCreated();
						Hide(num4);
						_idx.Add(num4);
						_items.Add(val2);
						_start.Add(position);
						_startRot.Add(rotation);
					}
				}
				if (_idx.Count == 0)
				{
					Instance log7 = Core.Log;
					if (log7 != null)
					{
						log7.Warning("[drift] no probes materialized");
					}
					return;
				}
				Active = true;
				Instance log8 = Core.Log;
				if (log8 != null)
				{
					log8.Msg($"[drift] activated {_idx.Count} DYNAMIC probe(s) within {18f:F0}m; measuring drift over {5f:F0}s...");
				}
			}

			internal static void Tick(float dt)
			{
				if (Active)
				{
					_elapsed += dt;
					if (!(_elapsed < 5f))
					{
						Measure();
						Cleanup();
						Active = false;
					}
				}
			}

			private static void Measure()
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				int count = _idx.Count;
				float num = 0f;
				float num2 = 0f;
				float num3 = 0f;
				float num4 = 0f;
				int num5 = 0;
				int num6 = 0;
				int num7 = 0;
				Dictionary<string, int[]> dictionary = new Dictionary<string, int[]>();
				Dictionary<string, float[]> dictionary2 = new Dictionary<string, float[]>();
				for (int i = 0; i < count; i++)
				{
					TrashItem val = _items[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Vector3 val2 = _start[i];
					Vector3 position;
					try
					{
						position = ((Component)val).transform.position;
					}
					catch
					{
						continue;
					}
					float num8 = position.x - val2.x;
					float num9 = position.y - val2.y;
					float num10 = position.z - val2.z;
					float num11 = Mathf.Sqrt(num8 * num8 + num9 * num9 + num10 * num10);
					if (num11 > 5f)
					{
						num7++;
						continue;
					}
					num6++;
					float num12 = Mathf.Sqrt(num8 * num8 + num10 * num10);
					float num13 = 0f - num9;
					num += num12;
					if (num12 > num2)
					{
						num2 = num12;
					}
					num3 += num13;
					if (Mathf.Abs(num13) > Mathf.Abs(num4))
					{
						num4 = num13;
					}
					if (num11 > 0.15f)
					{
						num5++;
					}
					string key = GetTypeId(_idx[i]) ?? "?";
					if (!dictionary.ContainsKey(key))
					{
						dictionary[key] = new int[1];
						dictionary2[key] = new float[3];
					}
					dictionary[key][0]++;
					dictionary2[key][0] += num12;
					dictionary2[key][1] += num13;
					if (Mathf.Abs(num13) > Mathf.Abs(dictionary2[key][2]))
					{
						dictionary2[key][2] = num13;
					}
				}
				int num14 = Math.Max(1, num6);
				Instance log = Core.Log;
				if (log != null)
				{
					log.Msg($"[drift] RESULT n={num6} (lost {num7})  moved>{0.15f:F2}m: {num5}/{num6}  horiz mean={num / (float)num14:F3} max={num2:F3}  vert(drop+) mean={num3 / (float)num14:F3} max={num4:F3} (m)");
				}
				foreach (KeyValuePair<string, int[]> item in dictionary)
				{
					string key2 = item.Key;
					int num15 = item.Value[0];
					float[] array = dictionary2[key2];
					Instance log2 = Core.Log;
					if (log2 != null)
					{
						log2.Msg($"[drift]   {key2}: n={num15} horiz={array[0] / (float)num15:F3} drop(mean)={array[1] / (float)num15:F3} drop(maxAbs)={array[2]:F3}");
					}
				}
				Instance log3 = Core.Log;
				if (log3 != null)
				{
					log3.Msg("[drift] read: drop>0 fell (floated above ground); drop<0 pushed up (penetrated); ~0 = resting correctly.");
				}
			}

			private static void Cleanup()
			{
				//IL_004f: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < _idx.Count; i++)
				{
					TrashItem val = _items[i];
					if ((Object)(object)val != (Object)null)
					{
						try
						{
							val.DestroyTrash();
						}
						catch
						{
						}
						try
						{
							if ((Object)(object)val != (Object)null)
							{
								Object.Destroy((Object)(object)((Component)val).gameObject);
							}
						}
						catch
						{
						}
					}
					Restore(_idx[i], _start[i], _startRot[i]);
				}
				_idx.Clear();
				_items.Clear();
				_start.Clear();
				_startRot.Clear();
			}

			internal static void Abort()
			{
				Cleanup();
				Active = false;
				_elapsed = 0f;
			}
		}

		private const int BatchSize = 1023;

		private const float Gravity = -22f;

		private const float GroundCellSize = 5f;

		private const float NavSampleMaxDist = 25f;

		private static readonly int GroundRayMask = -1025;

		internal static bool Shadows = false;

		internal static int MaxTypes = 8;

		internal static string OnlyType = null;

		private static readonly (string id, float w)[] Palette = new(string, float)[8]
		{
			("trashbag", 3f),
			("glassbottle", 2f),
			("waterbottle", 2f),
			("coffeecup", 1.8f),
			("energydrink", 1.5f),
			("cigarettebox", 1.4f),
			("litter1", 1.2f),
			("soilbag", 1f)
		};

		private static TType[] _types;

		private static Il2CppStructArray<Matrix4x4> _batch;

		private static readonly float[] _renderPlanes = new float[24];

		private const float RenderCullMargin = 6f;

		internal static float RenderDist = 150f;

		private static int _lastDrawn;

		private static int _capacity;

		private static List<int>[] _typeBuckets;

		private static readonly Dictionary<string, int> _typeIndex = new Dictionary<string, int>();

		internal const int CapacityCeiling = 2000000;

		internal static bool RoutedDataPresent;

		private static float[] _px;

		private static float[] _pz;

		private static float[] _py;

		private static float[] _vy;

		private static float[] _restY;

		private static float[] _qx;

		private static float[] _qy;

		private static float[] _qz;

		private static float[] _qw;

		private static byte[] _type;

		private static bool[] _settled;

		private static bool[] _hidden;

		private static bool[] _dead;

		private static bool[] _realized;

		private static Matrix4x4[] _matrices;

		private static int _count;

		private static int _active;

		private static readonly Dictionary<long, Ground> _groundCache = new Dictionary<long, Ground>(8192);

		private static bool _pending;

		private static int _pendingN;

		private static Vector3 _pendingCenter;

		private const int BlobMagic = 1414944305;

		private const float GridCell = 8f;

		private static readonly Dictionary<long, List<int>> _grid = new Dictionary<long, List<int>>(4096);

		internal static int Count => _count;

		internal static int LiveCount
		{
			get
			{
				if (_dead == null)
				{
					return _count;
				}
				int num = 0;
				for (int i = 0; i < _count; i++)
				{
					if (!_dead[i])
					{
						num++;
					}
				}
				return num;
			}
		}

		internal static int Active => _active;

		internal static int Drawn => _lastDrawn;

		internal static int TypeCount
		{
			get
			{
				if (_types == null)
				{
					return 0;
				}
				return _types.Length;
			}
		}

		internal static bool Ready
		{
			get
			{
				if (_types != null)
				{
					return _types.Length != 0;
				}
				return false;
			}
		}

		internal static bool EverMaterialized { get; private set; }

		internal static bool DriftActive => GroundDrift.Active;

		internal static void MarkRealCreated()
		{
			EverMaterialized = true;
		}

		internal static void AbortCalibration()
		{
			Calibration.Reset();
			_pending = false;
		}

		internal static void BeginDrift(int count)
		{
			GroundDrift.Begin(count);
		}

		internal static void DriftTick(float dt)
		{
			GroundDrift.Tick(dt);
		}

		internal static void AbortDrift()
		{
			GroundDrift.Abort();
		}

		internal static bool Setup(int n, Vector3 center)
		{
			//IL_0042: 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 (n < 0)
			{
				n = 0;
			}
			Virtualizer.ClearAll();
			_count = 0;
			_active = 0;
			if (!EnsurePalette())
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[inst] could not build a trash palette (no prefab meshes).");
				}
				return false;
			}
			_pending = true;
			_pendingN = n;
			_pendingCenter = center;
			if (!Calibration.Begin(_types))
			{
				BuildPending();
			}
			else
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Msg($"[inst] calibrating resting pose for {Calibration.Outstanding} type(s) before spawning {n}...");
				}
			}
			return true;
		}

		internal static void Tick(float dt)
		{
			if (Calibration.Active)
			{
				if (Calibration.Tick())
				{
					BuildPending();
				}
			}
			else
			{
				if (_active <= 0 || _count <= 0 || dt <= 0f)
				{
					return;
				}
				float num = -22f * dt;
				int num2 = 0;
				for (int i = 0; i < _count; i++)
				{
					if (!_settled[i] && !_hidden[i] && !_dead[i])
					{
						_vy[i] += num;
						float num3 = _py[i] + _vy[i] * dt;
						if (num3 <= _restY[i])
						{
							num3 = _restY[i];
							_settled[i] = true;
						}
						else
						{
							num2++;
						}
						_py[i] = num3;
						_matrices[i].m13 = num3;
					}
				}
				_active = num2;
			}
		}

		internal static void Render()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			if (_count <= 0 || _types == null || _batch == null)
			{
				return;
			}
			try
			{
				ShadowCastingMode val = (ShadowCastingMode)(Shadows ? 1 : 0);
				Camera val2 = Frustum.Cam();
				float[] array = (((Object)(object)val2 != (Object)null && Frustum.Compute(val2, _renderPlanes)) ? _renderPlanes : null);
				float num = 0f;
				float num2 = 0f;
				float num3 = 0f;
				if ((Object)(object)val2 != (Object)null && RenderDist > 0f)
				{
					Vector3 position = ((Component)val2).transform.position;
					num = position.x;
					num2 = position.z;
					num3 = RenderDist * RenderDist;
				}
				int num4 = 0;
				for (int i = 0; i < _types.Length; i++)
				{
					TType tType = _types[i];
					List<int> list = ((_typeBuckets != null && i < _typeBuckets.Length) ? _typeBuckets[i] : null);
					if (tType.Parts == null || list == null || list.Count == 0)
					{
						continue;
					}
					int count = list.Count;
					for (int j = 0; j < tType.Parts.Length; j++)
					{
						Part part = tType.Parts[j];
						if ((Object)(object)part.Mesh == (Object)null || part.Mats == null || part.Mats.Length == 0)
						{
							continue;
						}
						int num5 = part.Mats.Length;
						int num6 = 0;
						for (int k = 0; k < count; k++)
						{
							int num7 = list[k];
							if (_hidden[num7] || _dead[num7])
							{
								continue;
							}
							if (num3 > 0f)
							{
								float num8 = _px[num7] - num;
								float num9 = _pz[num7] - num2;
								if (num8 * num8 + num9 * num9 > num3)
								{
									continue;
								}
							}
							if (array != null && !Frustum.Contains(array, _px[num7], _py[num7], _pz[num7], 6f))
							{
								continue;
							}
							if (j == 0)
							{
								num4++;
							}
							((Il2CppArrayBase<Matrix4x4>)(object)_batch)[num6++] = Mul(in _matrices[num7], in part.Local);
							if (num6 != 1023)
							{
								continue;
							}
							for (int l = 0; l < num5; l++)
							{
								Material val3 = part.Mats[l];
								if (!((Object)(object)val3 == (Object)null))
								{
									Graphics.DrawMeshInstanced(part.Mesh, l, val3, _batch, num6, (MaterialPropertyBlock)null, val, Shadows, 0);
								}
							}
							num6 = 0;
						}
						if (num6 <= 0)
						{
							continue;
						}
						for (int m = 0; m < num5; m++)
						{
							Material val4 = part.Mats[m];
							if (!((Object)(object)val4 == (Object)null))
							{
								Graphics.DrawMeshInstanced(part.Mesh, m, val4, _batch, num6, (MaterialPropertyBlock)null, val, Shadows, 0);
							}
						}
					}
				}
				_lastDrawn = num4;
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[inst] render error (disabling): " + ex.Message);
				}
				_count = 0;
			}
		}

		private static void BuildPending()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_020e: 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_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: 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_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			if (!_pending)
			{
				return;
			}
			_pending = false;
			int pendingN = _pendingN;
			Vector3 pendingCenter = _pendingCenter;
			float num = Mathf.Clamp((float)Math.Sqrt(pendingN) * 0.5f, 20f, 220f);
			_px = new float[pendingN];
			_pz = new float[pendingN];
			_py = new float[pendingN];
			_vy = new float[pendingN];
			_restY = new float[pendingN];
			_qx = new float[pendingN];
			_qy = new float[pendingN];
			_qz = new float[pendingN];
			_qw = new float[pendingN];
			_type = new byte[pendingN];
			_settled = new bool[pendingN];
			_hidden = new bool[pendingN];
			_dead = new bool[pendingN];
			_realized = new bool[pendingN];
			_matrices = (Matrix4x4[])(object)new Matrix4x4[pendingN];
			AssignTypeRanges(pendingN);
			Random random = new Random(12345);
			Stopwatch stopwatch = Stopwatch.StartNew();
			int num2 = 0;
			for (int i = 0; i < _types.Length; i++)
			{
				TType tType = _types[i];
				for (int j = 0; j < tType.Len; j++)
				{
					int num3 = tType.Start + j;
					_type[num3] = (byte)i;
					double num4 = random.NextDouble() * Math.PI * 2.0;
					double num5 = Math.Sqrt(random.NextDouble()) * (double)num;
					float num6 = pendingCenter.x + (float)(Math.Cos(num4) * num5);
					float num7 = pendingCenter.z + (float)(Math.Sin(num4) * num5);
					Ground ground = SampleGround(num6, num7, pendingCenter.y);
					if (ground.Hit)
					{
						num2++;
					}
					Pose pose = ((tType.Poses != null && tType.Poses.Length != 0) ? tType.Poses[random.Next(tType.Poses.Length)] : new Pose
					{
						Rot = Quaternion.identity,
						Clearance = 0.1f
					});
					float num8 = ground.Y + pose.Clearance;
					Quaternion val = Quaternion.AngleAxis((float)(random.NextDouble() * 360.0), Vector3.up) * pose.Rot;
					float num9 = 8f + (float)(random.NextDouble() * 26.0);
					_px[num3] = num6;
					_pz[num3] = num7;
					_restY[num3] = num8;
					_py[num3] = num8 + num9;
					_vy[num3] = 0f;
					_qx[num3] = val.x;
					_qy[num3] = val.y;
					_qz[num3] = val.z;
					_qw[num3] = val.w;
					_matrices[num3] = BuildRootMatrix(num6, _py[num3], num7, val.x, val.y, val.z, val.w);
				}
			}
			stopwatch.Stop();
			_count = pendingN;
			_active = pendingN;
			_capacity = pendingN;
			RebuildBuckets();
			if (_batch == null)
			{
				_batch = new Il2CppStructArray<Matrix4x4>(1023L);
			}
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg($"[inst] {pendingN} falling instances across {_types.Length} type(s), radius={num:F0}, ground: {num2}/{pendingN} navmesh hits, sampled in {stopwatch.ElapsedMilliseconds}ms (cache={_groundCache.Count}).");
			}
		}

		private static void AssignTypeRanges(int n)
		{
			float num = 0f;
			for (int i = 0; i < _types.Length; i++)
			{
				num += _types[i].Weight;
			}
			int num2 = 0;
			for (int j = 0; j < _types.Length; j++)
			{
				int num3 = ((j == _types.Length - 1) ? (n - num2) : Mathf.RoundToInt((float)n * (_types[j].Weight / num)));
				if (num3 < 0)
				{
					num3 = 0;
				}
				if (num2 + num3 > n)
				{
					num3 = n - num2;
				}
				_types[j].Start = num2;
				_types[j].Len = num3;
				num2 += num3;
			}
		}

		internal static int AddOne(string id, Vector3 pos, Quaternion rot, bool groundSnap = false)
		{
			//IL_0038: 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_00b8: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: 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_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(id))
			{
				return -1;
			}
			int num = TypeIndexFor(id);
			if (num < 0)
			{
				return -1;
			}
			if (_count >= 2000000)
			{
				return -2;
			}
			EnsureCapacity(_count + 1);
			int count = _count;
			float num2 = pos.y;
			if (groundSnap)
			{
				float y = pos.y;
				RaycastHit val = default(RaycastHit);
				if (Physics.Raycast(pos + Vector3.up * 0.5f, Vector3.down, ref val, 60f, GroundRayMask, (QueryTriggerInteraction)1))
				{
					y = ((RaycastHit)(ref val)).point.y;
				}
				num2 = y + ComputeClearance(_types[num], rot);
			}
			_type[count] = (byte)num;
			_px[count] = pos.x;
			_py[count] = num2;
			_pz[count] = pos.z;
			_restY[count] = num2;
			_vy[count] = 0f;
			_qx[count] = rot.x;
			_qy[count] = rot.y;
			_qz[count] = rot.z;
			_qw[count] = rot.w;
			_settled[count] = true;
			bool[] hidden = _hidden;
			bool flag;
			_dead[count] = (flag = (_realized[count] = false));
			hidden[count] = flag;
			_matrices[count] = BuildRootMatrix(pos.x, num2, pos.z, rot.x, rot.y, rot.z, rot.w);
			_count++;
			_active = _count;
			RoutedDataPresent = true;
			(_typeBuckets[num] ?? (_typeBuckets[num] = new List<int>(1024))).Add(count);
			if (_batch == null)
			{
				_batch = new Il2CppStructArray<Matrix4x4>(1023L);
			}
			return num;
		}

		internal static int WriteBlob(string path)
		{
			using FileStream output = new FileStream(path, FileMode.Create, FileAccess.Write);
			using BinaryWriter binaryWriter = new BinaryWriter(output);
			binaryWriter.Write(1414944305);
			binaryWriter.Write(1);
			int num = ((_types != null) ? _types.Length : 0);
			binaryWriter.Write(num);
			for (int i = 0; i < num; i++)
			{
				binaryWriter.Write(_types[i].Id ?? "");
			}
			int num2 = 0;
			for (int j = 0; j < _count; j++)
			{
				if (!_dead[j])
				{
					num2++;
				}
			}
			binaryWriter.Write(num2);
			for (int k = 0; k < _count; k++)
			{
				if (!_dead[k])
				{
					binaryWriter.Write(_type[k]);
					binaryWriter.Write(_px[k]);
					binaryWriter.Write(_py[k]);
					binaryWriter.Write(_pz[k]);
					binaryWriter.Write(_qx[k]);
					binaryWriter.Write(_qy[k]);
					binaryWriter.Write(_qz[k]);
					binaryWriter.Write(_qw[k]);
				}
			}
			return num2;
		}

		internal static int ReadBlob(string path)
		{
			//IL_00c8: 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)
			using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read);
			using BinaryReader binaryReader = new BinaryReader(input);
			if (binaryReader.ReadInt32() != 1414944305)
			{
				return 0;
			}
			binaryReader.ReadInt32();
			int num = binaryReader.ReadInt32();
			string[] array = new string[num];
			for (int i = 0; i < num; i++)
			{
				array[i] = binaryReader.ReadString();
			}
			int num2 = binaryReader.ReadInt32();
			int num3 = 0;
			for (int j = 0; j < num2; j++)
			{
				byte b = binaryReader.ReadByte();
				float num4 = binaryReader.ReadSingle();
				float num5 = binaryReader.ReadSingle();
				float num6 = binaryReader.ReadSingle();
				float num7 = binaryReader.ReadSingle();
				float num8 = binaryReader.ReadSingle();
				float num9 = binaryReader.ReadSingle();
				float num10 = binaryReader.ReadSingle();
				string text = ((b < array.Length) ? array[b] : null);
				if (!string.IsNullOrEmpty(text) && AddOne(text, new Vector3(num4, num5, num6), new Quaternion(num7, num8, num9, num10)) >= 0)
				{
					num3++;
				}
			}
			return num3;
		}

		private static int TypeIndexFor(string id)
		{
			if (_typeIndex.TryGetValue(id, out var value))
			{
				return value;
			}
			TrashManager val = GameTrash.TrashManagerOrNull();
			if ((Object)(object)val == (Object)null)
			{
				return -1;
			}
			TType tType = BuildType(val, id, 1f);
			if (tType == null)
			{
				_typeIndex[id] = -1;
				return -1;
			}
			int num = ((_types != null) ? _types.Length : 0);
			if (_types == null)
			{
				_types = new TType[1] { tType };
			}
			else
			{
				Array.Resize(ref _types, _types.Length + 1);
				_types[num] = tType;
			}
			EnsureBuckets();
			_typeIndex[id] = num;
			Instance log = Core.Log;
			if (log != null)
			{
				log.Msg($"[route] new instanced type '{id}' (#{num}, parts={tType.Parts.Length})");
			}
			return num;
		}

		private static void EnsureCapacity(int need)
		{
			if (_px == null || need > _capacity)
			{
				int num = ((_px != null) ? (_capacity + 65536) : Math.Max(65536, need));
				if (num < need)
				{
					num = need;
				}
				if (num > 2000000)
				{
					num = 2000000;
				}
				Array.Resize(ref _px, num);
				Array.Resize(ref _pz, num);
				Array.Res