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(); private static readonly Dictionary _real = new Dictionary(); private static readonly List _remove = new List(); 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 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 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 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 list = new List(); try { EmployeeManager instance = NetworkSingleton.Instance; if ((Object)(object)instance != (Object)null) { List 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(); 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 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(); } } internal static class GameTrash { internal static TrashManager TrashManagerOrNull() { try { return NetworkSingleton.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 _saved = new Dictionary(); private static bool _applied; internal static void Apply(int mult) { mult = Mathf.Clamp(mult, 1, 1000); List 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 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 _settling = new Dictionary(); private static readonly HashSet _tracked = new HashSet(); private static readonly List _doneSettling = new List(); private static readonly List _destroyQueue = new List(); 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 _distinctPub = new HashSet(); private static readonly HashSet _distinctPriv = new HashSet(); 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(); } 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 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 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 _done = new HashSet(); private static readonly HashSet _boosted = new HashSet(); private static readonly Dictionary _generated = new Dictionary(); private static readonly Dictionary _deferred = new Dictionary(); 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 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(); 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 _pendingTypes = new List(); private static int _cursor; private static int _typeFrames; private static readonly List _probes = new List(); private static readonly List _spawnY = new List(); private static readonly List _caps = new List(); 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(); 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 list = new List(_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 _idx = new List(); private static readonly List _items = new List(); private static readonly List _start = new List(); private static readonly List _startRot = new List(); 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 dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); 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 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 _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[] _typeBuckets; private static readonly Dictionary _typeIndex = new Dictionary(); 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 _groundCache = new Dictionary(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> _grid = new Dictionary>(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 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)(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(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(1024))).Add(count); if (_batch == null) { _batch = new Il2CppStructArray(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.Resize(ref _py, num); Array.Resize(ref _vy, num); Array.Resize(ref _restY, num); Array.Resize(ref _qx, num); Array.Resize(ref _qy, num); Array.Resize(ref _qz, num); Array.Resize(ref _qw, num); Array.Resize(ref _type, num); Array.Resize(ref _settled, num); Array.Resize(ref _hidden, num); Array.Resize(ref _dead, num); Array.Resize(ref _realized, num); Array.Resize(ref _matrices, num); _capacity = num; } } private static void EnsureBuckets() { int num = ((_types != null) ? _types.Length : 0); if (_typeBuckets == null) { _typeBuckets = new List[Math.Max(8, num)]; } else if (_typeBuckets.Length < num) { Array.Resize(ref _typeBuckets, num); } } private static void RebuildBuckets() { EnsureBuckets(); for (int i = 0; i < _typeBuckets.Length; i++) { _typeBuckets[i]?.Clear(); } for (int j = 0; j < _count; j++) { if (!_dead[j]) { int num = _type[j]; if (num >= 0 && num < _typeBuckets.Length) { (_typeBuckets[num] ?? (_typeBuckets[num] = new List(1024))).Add(j); } } } } private static int CellOf(float v) { return Mathf.FloorToInt(v / 8f); } private static long CellKey(int cx, int cz) { return (long)(((ulong)(uint)cx << 32) | (uint)cz); } private static bool ActorCandidate(int i) { if (!_dead[i] && !_hidden[i] && !_realized[i]) { return _settled[i]; } return false; } internal static void BuildGrid() { foreach (KeyValuePair> item in _grid) { item.Value.Clear(); } for (int i = 0; i < _count; i++) { if (!_dead[i]) { long key = CellKey(CellOf(_px[i]), CellOf(_pz[i])); if (!_grid.TryGetValue(key, out var value)) { value = new List(8); _grid[key] = value; } value.Add(i); } } } internal static int QueryGrid(float x, float z, float radius, int[] outIdx, int max) { if (_px == null) { return 0; } float num = radius * radius; int num2 = Mathf.CeilToInt(radius / 8f); int num3 = CellOf(x); int num4 = CellOf(z); int num5 = 0; for (int i = num3 - num2; i <= num3 + num2; i++) { if (num5 >= max) { break; } for (int j = num4 - num2; j <= num4 + num2; j++) { if (num5 >= max) { break; } if (!_grid.TryGetValue(CellKey(i, j), out var value)) { continue; } for (int k = 0; k < value.Count; k++) { if (num5 >= max) { break; } int num6 = value[k]; if (ActorCandidate(num6)) { float num7 = _px[num6] - x; float num8 = _pz[num6] - z; if (num7 * num7 + num8 * num8 <= num) { outIdx[num5++] = num6; } } } } } return num5; } private static int BruteNear(float x, float z, float radius, int[] outIdx, int max) { float num = radius * radius; int num2 = 0; for (int i = 0; i < _count; i++) { if (num2 >= max) { break; } if (ActorCandidate(i)) { float num3 = _px[i] - x; float num4 = _pz[i] - z; if (num3 * num3 + num4 * num4 <= num) { outIdx[num2++] = i; } } } return num2; } internal static void GridSelfTest() { if (_count <= 0) { Instance log = Core.Log; if (log != null) { log.Warning("[grid] no field; spawn (tv inst) or route first"); } return; } BuildGrid(); Random random = new Random(777); int[] array = new int[16384]; int[] array2 = new int[16384]; int num = 16; int num2 = 0; int num3 = 0; for (int i = 0; i < num; i++) { int num4 = random.Next(_count); float num5 = _px[num4] + (float)(random.NextDouble() * 30.0 - 15.0); float num6 = _pz[num4] + (float)(random.NextDouble() * 30.0 - 15.0); float num7 = 6f + (float)(random.NextDouble() * 26.0); int num8 = QueryGrid(num5, num6, num7, array, array.Length); int num9 = BruteNear(num5, num6, num7, array2, array2.Length); if (num8 > num3) { num3 = num8; } bool flag = num8 == num9; if (flag) { Array.Sort(array, 0, num8); Array.Sort(array2, 0, num9); for (int j = 0; j < num8; j++) { if (array[j] != array2[j]) { flag = false; break; } } } if (flag) { num2++; continue; } Instance log2 = Core.Log; if (log2 != null) { log2.Warning($"[grid] MISMATCH at ({num5:F0},{num6:F0}) r={num7:F0}: grid={num8} brute={num9}"); } } Instance log3 = Core.Log; if (log3 != null) { log3.Msg($"[grid] SELF-TEST {((num2 == num) ? "PASS" : "FAIL")}: {num2}/{num} query points match brute-force (cell={8f}m, field={_count}, maxHits={num3})."); } } private static Ground SampleGround(float x, float z, float fallbackY) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0073: 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_0084: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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) long key = ((long)Mathf.FloorToInt(x / 5f) << 32) ^ (uint)Mathf.FloorToInt(z / 5f); if (_groundCache.TryGetValue(key, out var value)) { return value; } value.Y = fallbackY; value.N = Vector3.up; value.Hit = false; try { NavMeshHit val = default(NavMeshHit); if (NavMesh.SamplePosition(new Vector3(x, fallbackY + 3f, z), ref val, 25f, -1)) { Vector3 position = ((NavMeshHit)(ref val)).position; if (!float.IsNaN(position.y) && Mathf.Abs(position.y - fallbackY) < 200f) { value.Y = position.y; Vector3 normal = ((NavMeshHit)(ref val)).normal; if (((Vector3)(ref normal)).sqrMagnitude > 0.01f && normal.y > 0.3f) { value.N = ((Vector3)(ref normal)).normalized; } value.Hit = true; RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(new Vector3(x, value.Y + 1.5f, z), Vector3.down, ref val2, 4f, GroundRayMask, (QueryTriggerInteraction)1)) { value.Y = ((RaycastHit)(ref val2)).point.y; if (((RaycastHit)(ref val2)).normal.y > 0.3f) { Vector3 normal2 = ((RaycastHit)(ref val2)).normal; value.N = ((Vector3)(ref normal2)).normalized; } } } } } catch { } _groundCache[key] = value; return value; } private static bool InRange(int i) { if (_px != null && i >= 0) { return i < _count; } return false; } internal static Vector3 GetPosition(int i) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!InRange(i)) { return Vector3.zero; } return new Vector3(_px[i], _py[i], _pz[i]); } internal static Quaternion GetRotation(int i) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!InRange(i)) { return Quaternion.identity; } return new Quaternion(_qx[i], _qy[i], _qz[i], _qw[i]); } internal static string GetTypeId(int i) { if (!InRange(i) || _types == null) { return null; } return _types[_type[i]].Id; } internal static bool IsSettled(int i) { if (InRange(i)) { return _settled[i]; } return false; } internal static void SetRealized(int i, bool v) { if (InRange(i)) { _realized[i] = v; } } internal static void Hide(int i) { if (InRange(i)) { _hidden[i] = true; } } internal static void Restore(int i, Vector3 pos, Quaternion rot) { //IL_0027: 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_0041: 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_0067: 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_0081: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00b3: 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) //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_00ca: Unknown result type (might be due to invalid IL or missing references) if (InRange(i)) { _hidden[i] = false; _realized[i] = false; _settled[i] = true; _px[i] = pos.x; _py[i] = pos.y; _pz[i] = pos.z; _restY[i] = pos.y; _vy[i] = 0f; _qx[i] = rot.x; _qy[i] = rot.y; _qz[i] = rot.z; _qw[i] = rot.w; _matrices[i] = BuildRootMatrix(pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, rot.w); } } internal static void Kill(int i) { if (InRange(i)) { _dead[i] = true; _hidden[i] = true; _realized[i] = false; } } internal static int CollectNear(Vector3 p, float radius, int[] outIdx, int max) { //IL_0046: 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) if (_count <= 0 || _px == null) { return 0; } float num = radius * radius; int num2 = 0; for (int i = 0; i < _count; i++) { if (num2 >= max) { break; } if (!_dead[i] && !_hidden[i] && !_realized[i] && _settled[i]) { float num3 = _px[i] - p.x; float num4 = _pz[i] - p.z; if (num3 * num3 + num4 * num4 <= num) { outIdx[num2++] = i; } } } return num2; } internal static int CountInBox(float cx, float cz, float halfX, float halfZ, int cap) { if (_count <= 0 || _px == null || cap <= 0) { return 0; } int num = 0; for (int i = 0; i < _count; i++) { if (_dead[i]) { continue; } float num2 = _px[i] - cx; if (num2 < 0f) { num2 = 0f - num2; } if (!(num2 > halfX)) { float num3 = _pz[i] - cz; if (num3 < 0f) { num3 = 0f - num3; } if (!(num3 > halfZ) && ++num >= cap) { break; } } } return num; } internal static int CollectWithinRadius(Vector3 p, float radius, int[] outIdx, int max, out int totalInRadius) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) totalInRadius = 0; int num = 0; if (_count <= 0 || _px == null) { return 0; } float num2 = radius * radius; for (int i = 0; i < _count; i++) { if (_dead[i] || !_settled[i]) { continue; } float num3 = _px[i] - p.x; float num4 = _pz[i] - p.z; if (!(num3 * num3 + num4 * num4 > num2)) { totalInRadius++; if (!_realized[i] && !_hidden[i] && num < max) { outIdx[num++] = i; } } } return num; } internal static int CollectVisible(float[] cur, float[] pred, Vector3 backCenter, Vector3 p, float backRadius, float viewDist, float margin, int[] outIdx, int max) { //IL_004e: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (_count <= 0 || _px == null) { return 0; } float num = backRadius * backRadius; float num2 = viewDist * viewDist; int num3 = 0; for (int i = 0; i < _count; i++) { if (num3 >= max) { break; } if (!_dead[i] && !_hidden[i] && !_realized[i] && _settled[i]) { float num4 = _px[i] - backCenter.x; float num5 = _pz[i] - backCenter.z; if (num4 * num4 + num5 * num5 <= num) { outIdx[num3++] = i; } } } for (int j = 0; j < _count; j++) { if (num3 >= max) { break; } if (_dead[j] || _hidden[j] || _realized[j] || !_settled[j]) { continue; } float num6 = _px[j] - backCenter.x; float num7 = _pz[j] - backCenter.z; if (!(num6 * num6 + num7 * num7 <= num)) { float num8 = _px[j] - p.x; float num9 = _pz[j] - p.z; if (!(num8 * num8 + num9 * num9 > num2) && (Frustum.Contains(cur, _px[j], _py[j], _pz[j], margin) || Frustum.Contains(pred, _px[j], _py[j], _pz[j], margin))) { outIdx[num3++] = j; } } } return num3; } private static Matrix4x4 BuildRootMatrix(float tx, float ty, float tz, float qx, float qy, float qz, float qw) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) float num = qx * qx; float num2 = qy * qy; float num3 = qz * qz; float num4 = qx * qy; float num5 = qx * qz; float num6 = qy * qz; float num7 = qw * qx; float num8 = qw * qy; float num9 = qw * qz; return new Matrix4x4 { m00 = 1f - 2f * (num2 + num3), m01 = 2f * (num4 - num9), m02 = 2f * (num5 + num8), m03 = tx, m10 = 2f * (num4 + num9), m11 = 1f - 2f * (num + num3), m12 = 2f * (num6 - num7), m13 = ty, m20 = 2f * (num5 - num8), m21 = 2f * (num6 + num7), m22 = 1f - 2f * (num + num2), m23 = tz, m33 = 1f }; } private static Matrix4x4 Mul(in Matrix4x4 a, in Matrix4x4 b) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) return new Matrix4x4 { m00 = a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30, m01 = a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31, m02 = a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22 + a.m03 * b.m32, m03 = a.m00 * b.m03 + a.m01 * b.m13 + a.m02 * b.m23 + a.m03 * b.m33, m10 = a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20 + a.m13 * b.m30, m11 = a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31, m12 = a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32, m13 = a.m10 * b.m03 + a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33, m20 = a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20 + a.m23 * b.m30, m21 = a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31, m22 = a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32, m23 = a.m20 * b.m03 + a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33, m30 = a.m30 * b.m00 + a.m31 * b.m10 + a.m32 * b.m20 + a.m33 * b.m30, m31 = a.m30 * b.m01 + a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31, m32 = a.m30 * b.m02 + a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32, m33 = a.m30 * b.m03 + a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 }; } private static float ComputeClearance(TType ty, Quaternion restRot) { //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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_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_006e: 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_0086: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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) if (ty == null || ty.Parts == null || ty.Parts.Length == 0) { return 0.1f; } Matrix4x4 val = Matrix4x4.Rotate(restRot); float num = float.MaxValue; for (int i = 0; i < ty.Parts.Length; i++) { Part part = ty.Parts[i]; if ((Object)(object)part.Mesh == (Object)null) { continue; } Bounds bounds = part.Mesh.bounds; Matrix4x4 val2 = val * part.Local; Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val3 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(new Vector3(center.x + (float)j * extents.x, center.y + (float)k * extents.y, center.z + (float)l * extents.z)); if (val3.y < num) { num = val3.y; } } } } } if (num == float.MaxValue || float.IsNaN(num)) { return 0.1f; } return Mathf.Clamp(0f - num, -0.2f, 1f); } private static bool EnsurePalette() { TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { return false; } if (!string.IsNullOrEmpty(OnlyType)) { if (_types != null && _types.Length == 1 && _types[0].Id == OnlyType) { return true; } TType tType = BuildType(val, OnlyType, 1f); if (tType == null) { Instance log = Core.Log; if (log != null) { log.Warning("[inst] onlytype '" + OnlyType + "' has no mesh."); } return false; } DestroyPaletteMaterials(); _types = new TType[1] { tType }; Instance log2 = Core.Log; if (log2 != null) { log2.Msg($"[inst] type '{tType.Id}' parts={tType.Parts.Length} (ONLYTYPE)"); } return true; } int num = Mathf.Clamp(MaxTypes, 1, Palette.Length); if (_types != null && _types.Length == num) { return true; } List list = new List(num); for (int i = 0; i < Palette.Length; i++) { if (list.Count >= num) { break; } TType tType2 = BuildType(val, Palette[i].id, Palette[i].w); if (tType2 != null) { list.Add(tType2); } } if (list.Count == 0) { TType tType3 = BuildFirstUsable(val); if (tType3 != null) { list.Add(tType3); } } if (list.Count == 0) { return false; } DestroyPaletteMaterials(); _types = list.ToArray(); TType[] types = _types; foreach (TType tType4 in types) { Instance log3 = Core.Log; if (log3 != null) { log3.Msg($"[inst] type '{tType4.Id}' parts={tType4.Parts.Length} w={tType4.Weight}"); } } return true; } private static TType BuildType(TrashManager tm, string id, float weight) { try { TrashItem trashPrefab = tm.GetTrashPrefab(id); if ((Object)(object)trashPrefab == (Object)null) { return null; } return BuildFromPrefab(trashPrefab, weight); } catch { return null; } } private static TType BuildFirstUsable(TrashManager tm) { try { Il2CppReferenceArray trashPrefabs = tm.TrashPrefabs; if (trashPrefabs == null) { return null; } for (int i = 0; i < ((Il2CppArrayBase)(object)trashPrefabs).Length; i++) { TType tType = BuildFromPrefab(((Il2CppArrayBase)(object)trashPrefabs)[i], 1f); if (tType != null) { return tType; } } } catch { } return null; } private static TType BuildFromPrefab(TrashItem prefab, float weight) { //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_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown if ((Object)(object)prefab == (Object)null) { return null; } GameObject gameObject = ((Component)prefab).gameObject; Il2CppArrayBase componentsInChildren = gameObject.GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return null; } Matrix4x4 worldToLocalMatrix = gameObject.transform.worldToLocalMatrix; Dictionary dictionary = new Dictionary(); for (int i = 0; i < componentsInChildren.Length; i++) { MeshFilter val = componentsInChildren[i]; if ((Object)(object)val == (Object)null) { continue; } Mesh sharedMesh = val.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { continue; } MeshRenderer component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((Renderer)component).sharedMaterial == (Object)null)) { string key = StripLod(((Object)sharedMesh).name); int num = ParseLod(((Object)sharedMesh).name); if (!dictionary.TryGetValue(key, out var value) || num < value.Item4 || (num == value.Item4 && sharedMesh.vertexCount > value.Item5)) { dictionary[key] = (val, sharedMesh, component, num, sharedMesh.vertexCount); } } } if (dictionary.Count == 0) { return null; } List list = new List(dictionary.Count); foreach (KeyValuePair item2 in dictionary) { (MeshFilter, Mesh, MeshRenderer, int, int) value2 = item2.Value; Mesh item = value2.Item2; int num2 = Mathf.Max(1, item.subMeshCount); Il2CppArrayBase val2 = null; try { val2 = (Il2CppArrayBase)(object)((Renderer)value2.Item3).sharedMaterials; } catch { } int num3 = val2?.Length ?? 0; Material[] array = (Material[])(object)new Material[num2]; for (int j = 0; j < num2; j++) { Material val3 = null; if (num3 > 0) { val3 = val2[(j < num3) ? j : (num3 - 1)]; } if ((Object)(object)val3 == (Object)null) { val3 = ((Renderer)value2.Item3).sharedMaterial; } Material val4 = new Material(val3); val4.enableInstancing = true; array[j] = val4; } list.Add(new Part { Mesh = item, Mats = array, Local = worldToLocalMatrix * ((Component)value2.Item1).transform.localToWorldMatrix }); } return new TType { Id = prefab.ID, Parts = list.ToArray(), Weight = weight }; } private static string StripLod(string name) { if (string.IsNullOrEmpty(name)) { return name; } int num = name.LastIndexOf("_LOD", StringComparison.OrdinalIgnoreCase); if (num > 0 && num < name.Length - 4) { bool flag = true; for (int i = num + 4; i < name.Length; i++) { if (!char.IsDigit(name[i])) { flag = false; break; } } if (flag) { return name.Substring(0, num); } } return name; } private static int ParseLod(string name) { if (string.IsNullOrEmpty(name)) { return 0; } int num = name.LastIndexOf("_LOD", StringComparison.OrdinalIgnoreCase); if (num > 0 && num < name.Length - 4) { int num2 = 0; bool flag = false; bool flag2 = true; for (int i = num + 4; i < name.Length; i++) { if (char.IsDigit(name[i])) { num2 = num2 * 10 + (name[i] - 48); flag = true; continue; } flag2 = false; break; } if (flag2 && flag) { return num2; } } return 0; } internal static void DumpMeshParts() { //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: 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) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { Instance log = Core.Log; if (log != null) { log.Warning("[meshdiag] no TrashManager"); } return; } (string, float)[] palette = Palette; for (int i = 0; i < palette.Length; i++) { (string, float) tuple = palette[i]; TrashItem val2 = null; try { val2 = val.GetTrashPrefab(tuple.Item1); } catch { } if ((Object)(object)val2 == (Object)null) { Instance log2 = Core.Log; if (log2 != null) { log2.Msg("[meshdiag] '" + tuple.Item1 + "': prefab NULL"); } continue; } GameObject gameObject = ((Component)val2).gameObject; Il2CppArrayBase componentsInChildren = gameObject.GetComponentsInChildren(true); TType tType = BuildFromPrefab(val2, 1f); string value = "(none)"; if (tType != null && tType.Parts != null) { string[] array = new string[tType.Parts.Length]; for (int j = 0; j < tType.Parts.Length; j++) { array[j] = (((Object)(object)tType.Parts[j].Mesh != (Object)null) ? ((Object)tType.Parts[j].Mesh).name : "?"); } value = string.Join(" + ", array); Part[] parts = tType.Parts; foreach (Part part in parts) { if (part == null || part.Mats == null) { continue; } Material[] mats = part.Mats; foreach (Material val3 in mats) { if ((Object)(object)val3 != (Object)null) { try { Object.Destroy((Object)(object)val3); } catch { } } } } } Il2CppArrayBase componentsInChildren2 = gameObject.GetComponentsInChildren(true); Instance log3 = Core.Log; if (log3 != null) { log3.Msg($"[meshdiag] '{tuple.Item1}': {componentsInChildren?.Length ?? 0} meshfilters, {componentsInChildren2?.Length ?? 0} renderers -> instancer renders [{value}]"); } if (componentsInChildren2 == null) { continue; } for (int m = 0; m < componentsInChildren2.Length; m++) { Renderer val4 = componentsInChildren2[m]; if ((Object)(object)val4 == (Object)null) { continue; } string value2 = "Renderer"; Mesh val5 = null; SkinnedMeshRenderer val6 = ((Il2CppObjectBase)val4).TryCast(); if ((Object)(object)val6 != (Object)null) { value2 = "SKINNED"; val5 = val6.sharedMesh; } else { MeshFilter component = ((Component)val4).GetComponent(); if ((Object)(object)component != (Object)null) { value2 = "mesh"; val5 = component.sharedMesh; } } Vector3 val7; if (!((Object)(object)val5 != (Object)null)) { val7 = Vector3.zero; } else { Bounds bounds = val5.bounds; val7 = Vector3.Scale(((Bounds)(ref bounds)).size, ((Component)val4).transform.lossyScale); } Vector3 val8 = val7; Instance log4 = Core.Log; if (log4 != null) { log4.Msg($" [{m}] {value2} '{(((Object)(object)val5 != (Object)null) ? ((Object)val5).name : "null")}' verts={(((Object)(object)val5 != (Object)null) ? val5.vertexCount : 0)} size=({val8.x:F2},{val8.y:F2},{val8.z:F2}) enabled={val4.enabled}"); } Il2CppArrayBase val9 = null; try { val9 = (Il2CppArrayBase)(object)val4.sharedMaterials; } catch { } if (val9 == null) { continue; } for (int n = 0; n < val9.Length; n++) { Material val10 = val9[n]; if ((Object)(object)val10 == (Object)null) { Instance log5 = Core.Log; if (log5 != null) { log5.Msg($" submat[{n}] NULL"); } continue; } string value3 = "?"; int num = -1; float num2 = -1f; bool flag = false; try { value3 = (((Object)(object)val10.shader != (Object)null) ? ((Object)val10.shader).name : "null"); } catch { } try { num = val10.renderQueue; } catch { } try { if (val10.HasProperty("_Surface")) { num2 = val10.GetFloat("_Surface"); } } catch { } try { if (val10.HasProperty("_Cull")) { flag = val10.GetFloat("_Cull") == 0f; } } catch { } string value4 = ((num >= 2900 || num2 == 1f) ? "TRANSPARENT" : "opaque"); Instance log6 = Core.Log; if (log6 != null) { log6.Msg($" submat[{n}] '{((Object)val10).name}' shader='{value3}' queue={num} surface={num2} {value4}{(flag ? " TWO-SIDED" : "")}"); } } } } } internal static void Clear() { _count = 0; _active = 0; _capacity = 0; _pending = false; RoutedDataPresent = false; Calibration.Reset(); _px = (_pz = (_py = (_vy = (_restY = (_qx = (_qy = (_qz = (_qw = null)))))))); _type = null; _settled = (_hidden = (_dead = (_realized = null))); _matrices = null; if (_typeBuckets != null) { for (int i = 0; i < _typeBuckets.Length; i++) { _typeBuckets[i]?.Clear(); } } _typeIndex.Clear(); } internal static void ResetPalette() { DestroyPaletteMaterials(); _types = null; _groundCache.Clear(); } private static void DestroyPaletteMaterials() { if (_types == null) { return; } TType[] types = _types; foreach (TType tType in types) { if (tType == null || tType.Parts == null) { continue; } Part[] parts = tType.Parts; foreach (Part part in parts) { if (part == null || part.Mats == null) { continue; } Material[] mats = part.Mats; foreach (Material val in mats) { if ((Object)(object)val != (Object)null) { try { Object.Destroy((Object)(object)val); } catch { } } } } } } } internal static class SaveBlob { private static string BlobPath() { try { LoadManager instance = Singleton.Instance; string text = (((Object)(object)instance != (Object)null) ? instance.LoadedGameFolderPath : null); if (string.IsNullOrEmpty(text)) { return null; } text = text.Replace('\\', '/').TrimEnd('/'); string[] array = text.Split('/'); string text2 = ((array.Length >= 2) ? (array[^2] + "_" + array[^1]) : array[^1]); char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text2 = text2.Replace(oldChar, '_'); } string text3 = Path.Combine(Application.persistentDataPath, "Litterally", "saves"); Directory.CreateDirectory(text3); return Path.Combine(text3, text2 + ".tvb"); } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[blob] path resolve failed: " + ex.Message); } return null; } } internal static void Save() { if (!InstancedTrash.RoutedDataPresent) { return; } string text = BlobPath(); if (text == null) { Instance log = Core.Log; if (log != null) { log.Warning("[blob] no save path; routed trash NOT persisted this save"); } return; } try { int value = InstancedTrash.WriteBlob(text); Instance log2 = Core.Log; if (log2 != null) { log2.Msg($"[blob] persisted {value} routed instanced items -> {text}"); } try { string path = text + ".gen"; if (File.Exists(path)) { File.Delete(path); } } catch { } } catch (Exception ex) { Instance log3 = Core.Log; if (log3 != null) { log3.Warning("[blob] save failed: " + ex.Message); } } } internal static void Load() { InstancedTrash.Clear(); string text = BlobPath(); if (text == null || !File.Exists(text)) { return; } try { int num = InstancedTrash.ReadBlob(text); Instance log = Core.Log; if (log != null) { log.Msg($"[blob] restored {num} routed instanced items from {text}"); } if (num > 0) { RouteHook.Active = true; } } catch (Exception ex) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[blob] load failed: " + ex.Message); } } } } internal static class Virtualizer { private sealed class Real { public TrashItem Item; public Rigidbody Rb; public Il2CppArrayBase Rends; public bool Diverged; public int OutFrames; public int Age; } internal static bool Enabled = true; internal static bool Collide = false; internal static float ViewDist = 32f; internal static int MaxReal = 200; internal static int NewPerFrame = 100; private static float _matRadius = 32f; private const float MinMatRadius = 3f; private const float RadiusShrink = 0.95f; private const float RadiusGrow = 1.04f; private const int DemoteDelayFrames = 20; private const float DemoteVel2 = 0.06f; private const float SettleGraceFrames = 10f; private const float DivergePos2 = 0.0025f; private static readonly Dictionary _real = new Dictionary(); private static readonly int[] _scan = new int[4096]; private static readonly List _remove = new List(); internal static float MatRadius => _matRadius; internal static int RealCount => _real.Count; private static string NextId() { return Guid.NewGuid().ToString(); } internal static int CopyRealIndices(int[] buf) { if (buf == null) { return 0; } int num = 0; foreach (KeyValuePair 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 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 int AwakeRealCount() { int num = 0; foreach (KeyValuePair item in _real) { Rigidbody val = ((item.Value != null) ? item.Value.Rb : null); if (!((Object)(object)val != (Object)null)) { continue; } try { if (!val.IsSleeping()) { num++; } } catch { } } return num; } internal static void Tick() { //IL_00ae: 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_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_00ea: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: 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_022d: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0332: 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 || !GameTrash.TryGetPlayerPosition(out var pos)) { return; } float num = _matRadius + 1.5f; float num2 = num * num; _remove.Clear(); foreach (KeyValuePair item2 in _real) { int key = item2.Key; Real value = item2.Value; TrashItem item = value.Item; if ((Object)(object)item == (Object)null) { InstancedTrash.Kill(key); _remove.Add(key); continue; } value.Age++; try { Vector3 position = ((Component)item).transform.position; Vector3 velocity; if (!value.Diverged) { Vector3 position2 = InstancedTrash.GetPosition(key); float num3 = position.x - position2.x; float num4 = position.y - position2.y; float num5 = position.z - position2.z; if (num3 * num3 + num4 * num4 + num5 * num5 > 0.0025f) { goto IL_013b; } if ((Object)(object)value.Rb != (Object)null) { velocity = value.Rb.velocity; if (((Vector3)(ref velocity)).sqrMagnitude > 0.06f) { goto IL_013b; } } } goto IL_0198; IL_013b: value.Diverged = true; if (value.Rends != null) { for (int i = 0; i < value.Rends.Length; i++) { if ((Object)(object)value.Rends[i] != (Object)null) { value.Rends[i].enabled = true; } } } InstancedTrash.Hide(key); goto IL_0198; IL_0222: InstancedTrash.Restore(key, position, ((Component)item).transform.rotation); item.DestroyTrash(); _remove.Add(key); goto end_IL_00a7; IL_0198: float num6 = position.x - pos.x; float num7 = position.z - pos.z; if (num6 * num6 + num7 * num7 <= num2) { value.OutFrames = 0; continue; } value.OutFrames++; if (value.OutFrames >= 20 && (float)value.Age >= 10f) { if ((Object)(object)value.Rb == (Object)null) { goto IL_0222; } velocity = value.Rb.velocity; if (((Vector3)(ref velocity)).sqrMagnitude <= 0.06f) { goto IL_0222; } } end_IL_00a7:; } catch { InstancedTrash.Kill(key); _remove.Add(key); } } for (int j = 0; j < _remove.Count; j++) { _real.Remove(_remove[j]); } if (!InstancedTrash.Ready) { return; } int max = ((_real.Count < MaxReal) ? _scan.Length : 0); int totalInRadius; int num8 = InstancedTrash.CollectWithinRadius(pos, _matRadius, _scan, max, out totalInRadius); int num9 = 0; for (int k = 0; k < num8; k++) { if (_real.Count >= MaxReal) { break; } if (num9 >= NewPerFrame) { break; } int num10 = _scan[k]; if (_real.ContainsKey(num10)) { continue; } try { Vector3 position3 = InstancedTrash.GetPosition(num10); Quaternion rotation = InstancedTrash.GetRotation(num10); RouteHook.Suppress = true; TrashItem val2; try { val2 = val.CreateTrashItem(InstancedTrash.GetTypeId(num10), position3, rotation, Vector3.zero, NextId(), !Collide); } finally { RouteHook.Suppress = false; } if (!((Object)(object)val2 != (Object)null)) { continue; } InstancedTrash.MarkRealCreated(); InstancedTrash.SetRealized(num10, v: true); bool collide = Collide; if (collide) { InstancedTrash.Hide(num10); } Il2CppArrayBase val3 = null; try { val3 = ((Component)val2).GetComponentsInChildren(true); if (val3 != null) { for (int l = 0; l < val3.Length; l++) { if (!((Object)(object)val3[l] == (Object)null)) { if (!InstancedTrash.Shadows) { val3[l].shadowCastingMode = (ShadowCastingMode)0; } val3[l].enabled = collide; } } } } catch { } Rigidbody rb = null; try { rb = ((Component)val2).GetComponentInChildren(); } catch { } _real[num10] = new Real { Item = val2, Rb = rb, Rends = val3, Diverged = collide, OutFrames = 0, Age = 0 }; num9++; } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[virt] materialize error: " + ex.Message); } } } if (totalInRadius > MaxReal) { _matRadius = Mathf.Max(3f, _matRadius * 0.95f); } else if ((float)totalInRadius < (float)MaxReal * 0.9f) { _matRadius = Mathf.Min(ViewDist, _matRadius * 1.04f); } } internal static void ClearAll() { //IL_0044: 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) foreach (KeyValuePair item in _real) { TrashItem val = ((item.Value != null) ? item.Value.Item : null); if ((Object)(object)val != (Object)null) { try { InstancedTrash.Restore(item.Key, ((Component)val).transform.position, ((Component)val).transform.rotation); val.DestroyTrash(); } catch { InstancedTrash.Kill(item.Key); } } else { InstancedTrash.Kill(item.Key); } } _real.Clear(); _matRadius = ViewDist; } } } namespace Litterally.Config { internal static class Preferences { private const string CategoryId = "Litterally_01_Main"; private static MelonPreferences_Category _category; private static MelonPreferences_Entry _enablePerf; private static MelonPreferences_Entry _enableInMp; private static MelonPreferences_Entry _maxRealItems; private static MelonPreferences_Entry _materializeDistance; private static MelonPreferences_Entry _renderDistance; private static MelonPreferences_Entry _trashMultiplier; private static MelonPreferences_Entry _activePhysics; private static MelonPreferences_Entry _showFps; private static MelonPreferences_Entry _showActiveItems; private static MelonPreferences_Entry _showStatsPanel; private static MelonPreferences_Entry _showRanges; internal static bool EnablePerformanceLayer => _enablePerf?.Value ?? true; internal static bool EnableInMultiplayer => _enableInMp?.Value ?? false; internal static int MaxRealItems => Mathf.Clamp(_maxRealItems?.Value ?? 200, 50, 2000); internal static float MaterializeDistance => Mathf.Clamp(_materializeDistance?.Value ?? 32f, 8f, 80f); internal static float RenderDistance => Mathf.Clamp(_renderDistance?.Value ?? 150f, 40f, 600f); internal static int TrashMultiplier => Mathf.Clamp(_trashMultiplier?.Value ?? 1, 1, 1000); internal static bool ActivePhysics => _activePhysics?.Value ?? false; internal static bool ShowFpsCounter => _showFps?.Value ?? false; internal static bool ShowActiveItems => _showActiveItems?.Value ?? false; internal static bool ShowStatsPanel => _showStatsPanel?.Value ?? false; internal static bool ShowRanges => _showRanges?.Value ?? false; internal static void Initialize() { if (_category == null) { _category = MelonPreferences.CreateCategory("Litterally_01_Main", "Litterally (Trash Performance)"); _enablePerf = Create("EnablePerformanceLayer", def: true, "Enable performance layer", "Master switch for the trash performance layer. When ON (default), the game's own generated trash is absorbed into a lightweight instanced field so the world can hold far more trash with little cost. Turn OFF to run fully vanilla (no routing, no instancing)."); _enableInMp = Create("EnableInMultiplayer", def: false, "Enable in multiplayer (experimental)", "OFF (default): the performance layer auto-disables in a multiplayer session because the instanced field is local-only and would desync between players. ON: force-enable it in multiplayer for testing - expect visual desync between clients. Leave OFF unless you are testing."); _maxRealItems = Create("MaxRealItems", 200, "Max real (interactable) items", "How many trash items are materialised as real, pickup-able objects around you at once (default 200). Higher = a larger interactable radius around you, at a small per-item cost. Clamped 50-2000.", (ValueValidator)(object)new ValueRange(50, 2000)); _materializeDistance = Create("MaterializeDistance", 32f, "Materialize distance (m)", "How far ahead of you trash becomes real/interactable (inside the view). Beyond this it is drawn cheaply as instanced data. Higher = interactable further out, at more cost. Clamped 8-80."); _renderDistance = Create("RenderDistance", 150f, "Render distance (m)", "How far away trash is DRAWN. Beyond this distant (tiny on-screen) trash is skipped - the big render saving when looking across open ground. Does not affect interaction (see Materialize distance). Lower = more FPS / a nearer trash horizon; higher = trash visible further. Clamped 40-600.", (ValueValidator)(object)new ValueRange(40f, 600f)); _trashMultiplier = Create("TrashMultiplier", 1, "Trash amount multiplier", "Multiplies the game's OWN trash density (vanilla 0.015/m2 x this). 1 = vanilla amount (default) - the mod then only makes the existing trash cheap to render, without adding any. Raise it if you WANT more litter: 10 is comfortable, 50 ~ 100,000, up to 1000 ~ 2,000,000 across the map (extreme; very high values cost FPS as dense areas fill). The performance layer absorbs it into a cheap instanced field and fills the world around you as you explore. Clamped 1-1000.", (ValueValidator)(object)new ValueRange(1, 1000)); _activePhysics = Create("ActivePhysics", def: false, "Materialized trash has active physics", "OFF (default) = trash near you is frozen at its resting pose (cheapest, and you cannot tell). ON = the real items materialized around you have live physics (they fall/settle and can be shoved). Applies live."); _showFps = Create("ShowFpsCounter", def: false, "Show FPS counter", "Shows a small on-screen FPS readout (top-right). OFF by default. Applies live."); _showActiveItems = Create("ShowActiveItems", def: false, "Debug: highlight active trash", "Marks the trash items that are currently REAL/interactable around you (green) and around cleaners (cyan), so you can see what the performance layer is materializing. OFF by default. Applies live."); _showStatsPanel = Create("ShowStatsPanel", def: false, "Debug: live stats panel", "Shows a small on-screen panel with the live performance-layer numbers (trash in field, real items, materialize radius, drawn/total, fps). OFF by default. Applies live."); _showRanges = Create("ShowRanges", def: false, "Debug: show materialize radius", "Draws a ring on the ground for the materialize radius (and the max distance) around you, so you can see how far trash becomes interactable. OFF by default. Applies live."); } } private static MelonPreferences_Entry Create(string id, T def, string name, string desc = null, ValueValidator validator = null) { if (validator != null) { return _category.CreateEntry(id, def, name, desc, false, false, validator); } return _category.CreateEntry(id, def, name, desc, false, false, (ValueValidator)null, (string)null); } } } namespace Litterally.Compat { internal static class Net { internal static bool IsMultiplayer() { try { Lobby instance = Singleton.Instance; if ((Object)(object)instance == (Object)null) { return false; } return instance.IsInLobby && instance.PlayerCount > 1; } catch { return false; } } } }