Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of Litterally v1.1.0
Litterally.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.Networking; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Trash; using Il2CppSystem.Collections.Generic; using Litterally; using Litterally.Compat; using Litterally.Config; using Litterally.Instanced; using Litterally.SaveGuard; using Litterally.Spawning; using Litterally.UI; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using S1API.Lifecycle; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "Litterally", "1.1.0", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Litterally")] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("DooDesch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © DooDesch")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+ad9b68373aed6ae1b046e8d5382a90216f6155dd")] [assembly: AssemblyProduct("Litterally")] [assembly: AssemblyTitle("Litterally")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Litterally { public sealed class Core : MelonMod { private bool _inWorld; private bool _perfApplied; private int _perfLogState = -1; private float _teleElapsed; private int _teleFrames; private float _teleMaxDt; public static Core Instance { get; private set; } public static Instance Log { get; private set; } [Conditional("DEBUG")] public static void LogDebug(string msg) { Instance log = Log; if (log != null) { log.Msg(msg); } } public override void OnInitializeMelon() { Instance = this; Log = ((MelonBase)this).LoggerInstance; Preferences.Initialize(); try { ((MelonBase)this).HarmonyInstance.PatchAll(); } catch (Exception ex) { Log.Warning("[Core] Harmony patch failed: " + ex.Message); } GameLifecycle.OnSaveStart += delegate { SaveBlob.Save(); SaveSafety.ForceClearForSave("save starting"); _perfApplied = false; }; GameLifecycle.OnPreSceneChange += delegate { SaveSafety.ForceClearForSave("scene changing"); }; GameLifecycle.OnLoadComplete += OnGameLoaded; GameLifecycle.OnLoadComplete += delegate { if (Preferences.EnablePerformanceLayer) { SaveBlob.Load(); } }; Log.Msg("Litterally v1.0.0 - trash performance layer active."); } private void OnGameLoaded() { _perfApplied = false; } private void ApplyPerformanceLayer() { _perfApplied = true; try { if (!Preferences.EnablePerformanceLayer) { DisableLayer(); if (_perfLogState != 0) { Log.Msg("[Core] Performance layer DISABLED via preferences - running vanilla trash."); _perfLogState = 0; } return; } if (Net.IsMultiplayer() && !Preferences.EnableInMultiplayer) { DisableLayer(); if (_perfLogState != 1) { Log.Msg("[Core] Multiplayer session detected - performance layer auto-DISABLED (set EnableInMultiplayer to force it on for testing)."); _perfLogState = 1; } return; } RouteHook.Active = true; Virtualizer.Enabled = true; CleanerActor.Enabled = true; int value = (TrashPopulator.Multiplier = Preferences.TrashMultiplier); Virtualizer.MaxReal = Preferences.MaxRealItems; Virtualizer.ViewDist = Preferences.MaterializeDistance; InstancedTrash.RenderDist = Preferences.RenderDistance; bool collide = Virtualizer.Collide; Virtualizer.Collide = Preferences.ActivePhysics; if (collide != Virtualizer.Collide) { Virtualizer.ClearAll(); } if (_perfLogState != 2) { Log.Msg($"[Core] Performance layer ACTIVE (maxReal={Preferences.MaxRealItems}, materializeDist={Preferences.MaterializeDistance}m, trashMult={value})."); _perfLogState = 2; } } catch (Exception ex) { Log.Warning("[Core] ApplyPerformanceLayer failed: " + ex.Message); } } private static void DisableLayer() { RouteHook.Active = false; Virtualizer.Enabled = false; CleanerActor.Enabled = false; TrashPopulator.Multiplier = 1; TrashPopulator.Reset(); InstancedTrash.Clear(); } private void TelemetryTick() { float unscaledDeltaTime = Time.unscaledDeltaTime; _teleElapsed += unscaledDeltaTime; _teleFrames++; if (unscaledDeltaTime > _teleMaxDt) { _teleMaxDt = unscaledDeltaTime; } if (_teleElapsed < 15f) { return; } try { float value = (float)_teleFrames / _teleElapsed; float value2 = ((_teleMaxDt > 0f) ? (1f / _teleMaxDt) : 0f); TrashManager val = GameTrash.TrashManagerOrNull(); int value3 = (((Object)(object)val != (Object)null) ? GameTrash.TrashItemCount(val) : (-1)); Log.Msg($"[telemetry] fps={value:F0} (min {value2:F0}) field-live={InstancedTrash.LiveCount} real-player={Virtualizer.RealCount} matR={Virtualizer.MatRadius:F1} real-cleaner={CleanerActor.RealCount} mgr={value3} absorbed={RouteHook.Absorbed}"); } catch { } finally { _teleElapsed = 0f; _teleFrames = 0; _teleMaxDt = 0f; } } private void OnSettingsSaved() { try { if (_inWorld && (Object)(object)GameTrash.TrashManagerOrNull() != (Object)null) { ApplyPerformanceLayer(); } } catch (Exception ex) { Log.Warning("[Core] live settings re-apply failed: " + ex.Message); } } public override void OnPreferencesSaved() { OnSettingsSaved(); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { _inWorld = sceneName == "Main"; } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { _inWorld = false; _perfApplied = false; SaveSafety.ForceClearForSave("scene unloaded"); InstancedTrash.Clear(); TrashPopulator.Reset(); } public override void OnUpdate() { if (_inWorld) { if (!_perfApplied && (Object)(object)GameTrash.TrashManagerOrNull() != (Object)null) { ApplyPerformanceLayer(); } RouteHook.Tick(); InstancedTrash.Tick(Time.deltaTime); Virtualizer.Tick(); CleanerActor.Tick(); TrashPopulator.Tick(Time.deltaTime); InstancedTrash.Render(); TelemetryTick(); } } public override void OnGUI() { if (_inWorld) { if (Preferences.ShowFpsCounter) { FpsCounter.Draw(); } if (Preferences.ShowStatsPanel) { StatsPanel.Draw(); } if (Preferences.ShowActiveItems || Preferences.ShowRanges) { DebugDraw.Draw(); } } } public override void OnApplicationQuit() { Teardown("application quit"); } public override void OnDeinitializeMelon() { Teardown("melon unload"); } private void Teardown(string reason) { try { SaveSafety.ForceClearForSave(reason); } catch { } } } } namespace Litterally.UI { internal static class DebugDraw { private static readonly Vector3[] _pos = (Vector3[])(object)new Vector3[2048]; private static GUIStyle _dot; private static GUIStyle Dot { get { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown if (_dot == null) { _dot = new GUIStyle(); _dot.normal.background = Texture2D.whiteTexture; } return _dot; } } internal static void Draw() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (Event.current != null && (int)Event.current.type != 7) { return; } Camera val = Frustum.Cam(); if (!((Object)(object)val == (Object)null)) { if (Preferences.ShowActiveItems) { int n = Virtualizer.CopyRealPositions(_pos); DrawDots(val, n, new Color(0.25f, 1f, 0.35f, 0.95f)); int n2 = CleanerActor.CopyRealPositions(_pos); DrawDots(val, n2, new Color(0.25f, 0.85f, 1f, 0.95f)); } if (Preferences.ShowRanges && GameTrash.TryGetPlayerPosition(out var pos)) { DrawRing(val, pos, Virtualizer.MatRadius, new Color(1f, 1f, 1f, 0.9f)); DrawRing(val, pos, Virtualizer.ViewDist, new Color(1f, 0.55f, 0.1f, 0.7f)); } } } private static void DrawDots(Camera cam, int n, Color col) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) GUI.color = col; float num = Screen.height; for (int i = 0; i < n; i++) { Vector3 val = cam.WorldToScreenPoint(_pos[i]); if (!(val.z <= 0f)) { GUI.Box(new Rect(val.x - 3f, num - val.y - 3f, 6f, 6f), GUIContent.none, Dot); } } GUI.color = Color.white; } private static void DrawRing(Camera cam, Vector3 center, float radius, Color col) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (radius <= 0f) { return; } GUI.color = col; float num = Screen.height; Vector3 val = default(Vector3); for (int i = 0; i < 56; i++) { float num2 = (float)i / 56f * (float)Math.PI * 2f; ((Vector3)(ref val))..ctor(center.x + Mathf.Cos(num2) * radius, center.y, center.z + Mathf.Sin(num2) * radius); Vector3 val2 = cam.WorldToScreenPoint(val); if (!(val2.z <= 0f)) { GUI.Box(new Rect(val2.x - 3f, num - val2.y - 3f, 6f, 6f), GUIContent.none, Dot); } } GUI.color = Color.white; } } internal static class FpsCounter { private static GUIStyle _style; internal static void Draw() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (Event.current == null || (int)Event.current.type == 7) { float smoothDeltaTime = Time.smoothDeltaTime; int num = ((smoothDeltaTime > 0f) ? Mathf.RoundToInt(1f / smoothDeltaTime) : 0); if (_style == null) { _style = new GUIStyle(GUI.skin.label) { fontSize = 22, fontStyle = (FontStyle)1, alignment = (TextAnchor)2 }; } _style.normal.textColor = (Color)((num >= 50) ? Color.green : ((num >= 30) ? Color.yellow : new Color(1f, 0.45f, 0.45f))); string text = num + " FPS"; Rect val = default(Rect); ((Rect)(ref val))..ctor((float)Screen.width - 140f, 6f, 132f, 28f); GUI.color = new Color(0f, 0f, 0f, 0.6f); GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), text, _style); GUI.color = Color.white; GUI.Label(val, text, _style); } } } internal static class StatsPanel { private static GUIStyle _label; private static GUIStyle _backdrop; private static string _text = ""; private static float _next; private static float _smoothFps; private static GUIStyle Backdrop { get { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown if (_backdrop == null) { _backdrop = new GUIStyle(); _backdrop.normal.background = Texture2D.whiteTexture; } return _backdrop; } } internal static void Draw() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (Event.current == null || (int)Event.current.type == 7) { float smoothDeltaTime = Time.smoothDeltaTime; float num = ((smoothDeltaTime > 0f) ? (1f / smoothDeltaTime) : 0f); _smoothFps = ((_smoothFps <= 0f) ? num : Mathf.Lerp(_smoothFps, num, 0.1f)); float unscaledTime = Time.unscaledTime; if (unscaledTime >= _next) { _next = unscaledTime + 0.1f; _text = Build(); } if (_label == null) { _label = new GUIStyle(GUI.skin.label) { fontSize = 13, fontStyle = (FontStyle)1, alignment = (TextAnchor)0, richText = false }; _label.normal.textColor = Color.white; } Rect val = default(Rect); ((Rect)(ref val))..ctor(10f, 70f, 232f, 174f); GUI.color = new Color(0f, 0f, 0f, 0.55f); GUI.Box(val, GUIContent.none, Backdrop); GUI.color = Color.white; GUI.Label(new Rect(((Rect)(ref val)).x + 9f, ((Rect)(ref val)).y + 7f, ((Rect)(ref val)).width - 14f, ((Rect)(ref val)).height - 12f), _text, _label); } } private static string Build() { int liveCount = InstancedTrash.LiveCount; int count = InstancedTrash.Count; int drawn = InstancedTrash.Drawn; int realCount = Virtualizer.RealCount; int realCount2 = CleanerActor.RealCount; float matRadius = Virtualizer.MatRadius; return "Litterally\n" + $"field-live {liveCount} / {count}\n" + $"drawn {drawn}\n" + $"real player {realCount}\n" + $"real cleaner {realCount2}\n" + $"awake {Virtualizer.AwakeRealCount()}\n" + $"matR {matRadius:F1} m\n" + $"absorbed {RouteHook.Absorbed}\n" + $"fps {Mathf.RoundToInt(_smoothFps)}"; } } } namespace Litterally.Spawning { internal static class CleanerActor { private sealed class Real { public TrashItem Item; public Vector3 Pos; public Quaternion Rot; } internal static bool Enabled = true; internal static float Range = 30f; internal static int PerCleaner = 6; private const int RebuildEvery = 30; private const int FindCleanersEvery = 120; private static int _frame; private static Cleaner[] _cleaners = Array.Empty<Cleaner>(); private static readonly Dictionary<int, Real> _real = new Dictionary<int, Real>(); private static readonly List<int> _remove = new List<int>(); private static readonly int[] _scan = new int[64]; private static float DemoteRange2 => (Range + 8f) * (Range + 8f); internal static int RealCount => _real.Count; internal static int CopyRealIndices(int[] buf) { if (buf == null) { return 0; } int num = 0; foreach (KeyValuePair<int, Real> item in _real) { if (num >= buf.Length) { break; } buf[num++] = item.Key; } return num; } internal static int CopyRealPositions(Vector3[] buf) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (buf == null) { return 0; } int num = 0; foreach (KeyValuePair<int, Real> item in _real) { if (num >= buf.Length) { break; } TrashItem val = ((item.Value != null) ? item.Value.Item : null); if (!((Object)(object)val == (Object)null)) { try { buf[num++] = ((Component)val).transform.position; } catch { } } } return num; } internal static void Tick() { //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || InstancedTrash.Count <= 0) { return; } TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { return; } if (_frame % 120 == 0) { _cleaners = FindCleaners(); } if (_frame % 30 == 0) { InstancedTrash.BuildGrid(); } _frame++; _remove.Clear(); foreach (KeyValuePair<int, Real> item in _real) { Real value = item.Value; if ((Object)(object)value.Item == (Object)null) { InstancedTrash.Kill(item.Key); _remove.Add(item.Key); continue; } Vector3 position; try { position = ((Component)value.Item).transform.position; } catch { InstancedTrash.Kill(item.Key); _remove.Add(item.Key); continue; } if (!NearAnyCleaner(position) && !IsAnyCleanerTarget(value.Item)) { try { InstancedTrash.Restore(item.Key, position, ((Component)value.Item).transform.rotation); value.Item.DestroyTrash(); } catch { InstancedTrash.Kill(item.Key); } _remove.Add(item.Key); } } for (int i = 0; i < _remove.Count; i++) { _real.Remove(_remove[i]); } if (_cleaners.Length == 0) { return; } int num = _cleaners.Length * PerCleaner - _real.Count; if (num <= 0) { return; } for (int j = 0; j < _cleaners.Length && num > 0; j++) { Cleaner val2 = _cleaners[j]; if ((Object)(object)val2 == (Object)null) { continue; } Vector3 position2; try { position2 = ((Component)val2).transform.position; } catch { continue; } int num2 = InstancedTrash.QueryGrid(position2.x, position2.z, Range, _scan, _scan.Length); for (int k = 0; k < num2; k++) { if (num <= 0) { break; } int num3 = _scan[k]; if (_real.ContainsKey(num3)) { continue; } string typeId = InstancedTrash.GetTypeId(num3); if (string.IsNullOrEmpty(typeId)) { continue; } Vector3 position3 = InstancedTrash.GetPosition(num3); Quaternion rotation = InstancedTrash.GetRotation(num3); TrashItem val3 = null; RouteHook.Suppress = true; try { val3 = val.CreateTrashItem(typeId, position3, rotation, Vector3.zero, Guid.NewGuid().ToString(), false); } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[cleaner] materialize: " + ex.Message); } } finally { RouteHook.Suppress = false; } if ((Object)(object)val3 == (Object)null) { continue; } try { val3.SetPhysicsActive(true); val3.RecheckProperty(); } catch (Exception ex2) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[cleaner] register: " + ex2.Message); } } InstancedTrash.MarkRealCreated(); InstancedTrash.SetRealized(num3, v: true); InstancedTrash.Hide(num3); _real[num3] = new Real { Item = val3, Pos = position3, Rot = rotation }; num--; } } } private static Cleaner[] FindCleaners() { List<Cleaner> list = new List<Cleaner>(); try { EmployeeManager instance = NetworkSingleton<EmployeeManager>.Instance; if ((Object)(object)instance != (Object)null) { List<Employee> employeesByType = instance.GetEmployeesByType((EEmployeeType)3); if (employeesByType != null) { for (int i = 0; i < employeesByType.Count; i++) { Employee val = employeesByType[i]; if (!((Object)(object)val == (Object)null)) { Cleaner val2 = ((Il2CppObjectBase)val).TryCast<Cleaner>(); if ((Object)(object)val2 != (Object)null) { list.Add(val2); } } } } } } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[cleaner] find: " + ex.Message); } } return list.ToArray(); } private static bool NearAnyCleaner(Vector3 p) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _cleaners.Length; i++) { Cleaner val = _cleaners[i]; if (!((Object)(object)val == (Object)null)) { Vector3 position; try { position = ((Component)val).transform.position; } catch { continue; } float num = p.x - position.x; float num2 = p.z - position.z; if (num * num + num2 * num2 <= DemoteRange2) { return true; } } } return false; } private static bool IsAnyCleanerTarget(TrashItem item) { for (int i = 0; i < _cleaners.Length; i++) { Cleaner val = _cleaners[i]; if ((Object)(object)val == (Object)null) { continue; } try { if ((Object)(object)val.PickUpTrashBehaviour != (Object)null && (Object)(object)val.PickUpTrashBehaviour.TargetTrash == (Object)(object)item) { return true; } } catch { } } return false; } internal static void Diagnose() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) try { Cleaner[] array = FindCleaners(); InstancedTrash.BuildGrid(); int[] array2 = new int[256]; Instance log = Core.Log; if (log != null) { log.Msg($"[cleaner] DIAG: {array.Length} cleaner(s) via EmployeeManager registry; field={InstancedTrash.Count} (live {InstancedTrash.LiveCount}); range={Range}m, perCleaner={PerCleaner}; materialised={_real.Count}"); } for (int i = 0; i < array.Length; i++) { Cleaner val = array[i]; if (!((Object)(object)val == (Object)null)) { Vector3 position = ((Component)val).transform.position; int value = InstancedTrash.QueryGrid(position.x, position.z, Range, array2, array2.Length); int value2 = InstancedTrash.QueryGrid(position.x, position.z, 50f, array2, array2.Length); Instance log2 = Core.Log; if (log2 != null) { log2.Msg($"[cleaner] #{i} at ({position.x:F0},{position.y:F0},{position.z:F0}): data within {Range}m={value}, within 50m={value2}"); } } } } catch (Exception ex) { Instance log3 = Core.Log; if (log3 != null) { log3.Warning("[cleaner] diag: " + ex.Message); } } } internal static void ClearAll() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair<int, Real> item in _real) { Real value = item.Value; if (value != null && (Object)(object)value.Item != (Object)null) { try { InstancedTrash.Restore(item.Key, ((Component)value.Item).transform.position, ((Component)value.Item).transform.rotation); value.Item.DestroyTrash(); } catch { InstancedTrash.Kill(item.Key); } } else { InstancedTrash.Kill(item.Key); } } _real.Clear(); _cleaners = Array.Empty<Cleaner>(); } } internal static class GameTrash { internal static TrashManager TrashManagerOrNull() { try { return NetworkSingleton<TrashManager>.Instance; } catch { return null; } } internal static int TrashItemCount(TrashManager tm) { try { return ((Object)(object)tm != (Object)null && tm.trashItems != null) ? tm.trashItems.Count : 0; } catch { return 0; } } internal static bool TryGetPlayerPosition(out Vector3 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) pos = Vector3.zero; try { Player local = Player.Local; if ((Object)(object)local == (Object)null) { return false; } pos = ((Component)local).transform.position; return true; } catch { return false; } } } internal static class GeneratorBoost { private static readonly Dictionary<TrashGenerator, int> _saved = new Dictionary<TrashGenerator, int>(); private static bool _applied; internal static void Apply(int mult) { mult = Mathf.Clamp(mult, 1, 1000); List<TrashGenerator> val = null; try { val = TrashGenerator.AllGenerators; } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[route] boost AllGenerators: " + ex.Message); } } if (val == null) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[route] boost: no generators"); } return; } int num = 0; for (int i = 0; i < val.Count; i++) { TrashGenerator val2 = val[i]; if ((Object)(object)val2 == (Object)null) { continue; } if (!_saved.ContainsKey(val2)) { try { _saved[val2] = val2.MaxTrashCount; } catch { continue; } } try { val2.MaxTrashCount = _saved[val2] * mult; num++; } catch { } } _applied = true; Instance log3 = Core.Log; if (log3 != null) { log3.Msg($"[route] boosted MaxTrashCount x{mult} on {num} generators. Walk into a fresh region or 'tv route burst' to see it."); } } internal static void Restore() { if (!_applied && _saved.Count == 0) { return; } foreach (KeyValuePair<TrashGenerator, int> item in _saved) { TrashGenerator key = item.Key; if (!((Object)(object)key == (Object)null)) { try { key.MaxTrashCount = item.Value; } catch { } } } _saved.Clear(); _applied = false; Instance log = Core.Log; if (log != null) { log.Msg("[route] generator MaxTrashCount restored."); } } } internal static class RouteHook { private sealed class SettleItem { public TrashItem Item; public Rigidbody Rb; public int Age; public int Rest; } internal static bool Active = false; internal static bool Probe = false; [ThreadStatic] internal static bool Suppress; internal static bool AbsorbAny = false; [ThreadStatic] internal static bool GeneratorActive; [ThreadStatic] private static int _genDepth; private static readonly Dictionary<int, SettleItem> _settling = new Dictionary<int, SettleItem>(); private static readonly HashSet<int> _tracked = new HashSet<int>(); private static readonly List<int> _doneSettling = new List<int>(); private static readonly List<TrashItem> _destroyQueue = new List<TrashItem>(); internal static int Absorbed; internal static int Skipped; internal static int AtCap; private const int SettleMinFrames = 6; private const int SettleMaxFrames = 150; private const float SettleVel2 = 0.01f; private const int SettleRestFrames = 8; private const int SettlingCap = 1200; internal static int PubCalls; internal static int PrivCalls; private static readonly HashSet<int> _distinctPub = new HashSet<int>(); private static readonly HashSet<int> _distinctPriv = new HashSet<int>(); private static int _logged; private const int GroundMask = -1025; private static int _heightLogged; internal static int SettlingCount => _settling.Count; internal static void EnterGenerator() { if (_genDepth++ == 0) { GeneratorActive = true; } } internal static void ExitGenerator() { if (--_genDepth <= 0) { _genDepth = 0; GeneratorActive = false; } } internal static void OnCreate(bool isPrivate, TrashItem result) { if (Suppress) { return; } if (Probe && !Active) { ProbeNote(isPrivate, result); } else { if (!Active || (Object)(object)result == (Object)null) { return; } if (!GeneratorActive && !AbsorbAny) { Skipped++; return; } int instanceID; try { instanceID = ((Object)result).GetInstanceID(); } catch { return; } if (_tracked.Add(instanceID)) { try { if (_settling.Count >= 1200) { Record(instanceID, result, groundSnap: true); } else { Rigidbody rb = null; try { rb = ((Component)result).GetComponentInChildren<Rigidbody>(); } catch { } _settling[instanceID] = new SettleItem { Item = result, Rb = rb, Age = 0 }; } return; } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[route] track: " + ex.Message); } _tracked.Remove(instanceID); return; } } Skipped++; } } private static void Record(int iid, TrashItem item, bool groundSnap) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)item == (Object)null) { _tracked.Remove(iid); return; } string iD = item.ID; Vector3 position = ((Component)item).transform.position; Quaternion rotation = ((Component)item).transform.rotation; RaycastHit val = default(RaycastHit); if (Physics.Raycast(position + Vector3.up * 0.5f, Vector3.down, ref val, 80f, -1025, (QueryTriggerInteraction)1)) { float num = position.y - ((RaycastHit)(ref val)).point.y; bool flag = num > 0.4f || num < -0.1f; if (_heightLogged < 10) { _heightLogged++; Instance log = Core.Log; if (log != null) { log.Msg($"[route] settled '{iD}' {num:F2}m vs ground{(flag ? " -> ground-snap" : "")}"); } } if (flag) { groundSnap = true; } } int num2 = InstancedTrash.AddOne(iD, position, rotation, groundSnap); if (num2 == -2) { AtCap++; _tracked.Remove(iid); } else if (num2 < 0) { _tracked.Remove(iid); } else { Absorbed++; _destroyQueue.Add(item); } } catch (Exception ex) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[route] record: " + ex.Message); } } finally { _tracked.Remove(iid); } } internal static void Tick() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (_settling.Count > 0) { _doneSettling.Clear(); foreach (KeyValuePair<int, SettleItem> item in _settling) { SettleItem value = item.Value; if ((Object)(object)value.Item == (Object)null) { _doneSettling.Add(item.Key); _tracked.Remove(item.Key); continue; } value.Age++; int num; if (!((Object)(object)value.Rb == (Object)null)) { Vector3 velocity = value.Rb.velocity; num = ((((Vector3)(ref velocity)).sqrMagnitude < 0.01f) ? 1 : 0); } else { num = 1; } bool flag = (byte)num != 0; value.Rest = (flag ? (value.Rest + 1) : 0); if (value.Age >= 150 || (value.Age >= 6 && value.Rest >= 8)) { Record(item.Key, value.Item, groundSnap: false); _doneSettling.Add(item.Key); } } for (int i = 0; i < _doneSettling.Count; i++) { _settling.Remove(_doneSettling[i]); } } if (_destroyQueue.Count <= 0) { return; } Suppress = true; try { for (int j = 0; j < _destroyQueue.Count; j++) { TrashItem val = _destroyQueue[j]; if ((Object)(object)val == (Object)null) { continue; } try { val.DestroyTrash(); } catch { } try { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } catch { } } } finally { Suppress = false; } _destroyQueue.Clear(); } internal static void ResetState() { _settling.Clear(); _tracked.Clear(); _doneSettling.Clear(); _destroyQueue.Clear(); _genDepth = 0; GeneratorActive = false; } private static void ProbeNote(bool isPrivate, TrashItem result) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) int item = 0; try { if ((Object)(object)result != (Object)null) { item = ((Object)result).GetInstanceID(); } } catch { } if (isPrivate) { PrivCalls++; if ((Object)(object)result != (Object)null) { _distinctPriv.Add(item); } } else { PubCalls++; if ((Object)(object)result != (Object)null) { _distinctPub.Add(item); } } if (_logged >= 16) { return; } _logged++; string text = "?"; Vector3 val = Vector3.zero; try { if ((Object)(object)result != (Object)null) { text = result.ID; val = ((Component)result).transform.position; } } catch { } Instance log = Core.Log; if (log != null) { log.Msg($"[route-probe] {(isPrivate ? "CreateAndReturnTrashItem" : "CreateTrashItem")} -> {(((Object)(object)result == (Object)null) ? "NULL" : text)} @({val.x:F0},{val.y:F0},{val.z:F0})"); } } internal static void ResetCounts() { PubCalls = (PrivCalls = (_logged = (_heightLogged = 0))); _distinctPub.Clear(); _distinctPriv.Clear(); Absorbed = (Skipped = (AtCap = 0)); } internal static void Command(string[] p) { switch ((p.Length > 2) ? p[2] : "stat") { case "on": { Active = true; Probe = false; ResetCounts(); Instance log9 = Core.Log; if (log9 != null) { log9.Msg("[route] routing ON: game-generated trash is absorbed into the instanced field."); } break; } case "off": { Active = false; Tick(); ResetState(); GeneratorBoost.Restore(); InstancedTrash.Clear(); Instance log2 = Core.Log; if (log2 != null) { log2.Msg("[route] routing OFF: generators restored, instanced field cleared."); } break; } case "boost": { GeneratorBoost.Apply((p.Length > 3 && int.TryParse(p[3], out var result2)) ? result2 : 20); break; } case "unboost": GeneratorBoost.Restore(); break; case "probe": { Probe = ((p.Length <= 3) ? (!Probe) : (p[3] == "on" || p[3] == "1")); Active = false; ResetCounts(); Instance log8 = Core.Log; if (log8 != null) { log8.Msg($"[route-probe] probe = {Probe} (log-only). tv route burst, then tv route stat."); } break; } case "burst": { Burst((p.Length > 3 && int.TryParse(p[3], out var result)) ? result : 30); break; } case "stat": { TrashManager val2 = GameTrash.TrashManagerOrNull(); int value = -1; try { if ((Object)(object)val2 != (Object)null) { value = GameTrash.TrashItemCount(val2); } } catch { } Instance log10 = Core.Log; if (log10 != null) { log10.Msg($"[route] STAT active={Active} absorbMode={(AbsorbAny ? "ANY (legacy)" : "generator-only (good-citizen)")} instanced={InstancedTrash.Count} realTrashItems(manager)={value} settling={_settling.Count} absorbed={Absorbed} skipped(echo+othermod)={Skipped} atCap={AtCap}"); } if (Probe) { Instance log11 = Core.Log; if (log11 != null) { log11.Msg($"[route-probe] public calls={PubCalls} distinct={_distinctPub.Count} private calls={PrivCalls} distinct={_distinctPriv.Count}"); } } break; } case "absorbany": { AbsorbAny = ((p.Length <= 3) ? (!AbsorbAny) : (p[3] == "on" || p[3] == "1" || p[3] == "true")); Instance log7 = Core.Log; if (log7 != null) { log7.Msg($"[route] absorbAny = {AbsorbAny} ({(AbsorbAny ? "absorb ALL trash incl. other mods' - legacy" : "absorb ONLY the game generator's trash - good-citizen default")})."); } break; } case "testlimit": try { Instance log5 = Core.Log; if (log5 != null) { log5.Msg($"[limit] TRASH_ITEM_LIMIT = {TrashManager.TRASH_ITEM_LIMIT} (READ-ONLY; writing it hard-crashes the game - verified)."); } break; } catch (Exception ex2) { Instance log6 = Core.Log; if (log6 != null) { log6.Warning("[limit] read threw: " + ex2.Message); } break; } case "clearreal": try { TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val != (Object)null) { val.DestroyAllTrash(); } Instance log3 = Core.Log; if (log3 != null) { log3.Msg("[route] DestroyAllTrash()"); } break; } catch (Exception ex) { Instance log4 = Core.Log; if (log4 != null) { log4.Warning("[route] clear failed: " + ex.Message); } break; } default: { Instance log = Core.Log; if (log != null) { log.Msg("[route] usage: tv route on|off | boost [mult] | unboost | burst [n] | stat | probe on|off | absorbany on|off | clearreal"); } break; } } } private static void Burst(int perGenerator) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (!GameTrash.TryGetPlayerPosition(out var pos)) { Instance log = Core.Log; if (log != null) { log.Warning("[route] no player"); } return; } List<TrashGenerator> val = null; try { val = TrashGenerator.AllGenerators; } catch (Exception ex) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[route] AllGenerators: " + ex.Message); } } if (val == null) { Instance log3 = Core.Log; if (log3 != null) { log3.Warning("[route] AllGenerators null"); } return; } int count = val.Count; int num = 0; int num2 = 0; for (int i = 0; i < count; i++) { TrashGenerator val2 = val[i]; if ((Object)(object)val2 == (Object)null) { continue; } float num3; try { num3 = Vector3.Distance(((Component)val2).transform.position, pos); } catch { continue; } if (num3 > 120f) { continue; } num++; try { val2.GenerateTrash(perGenerator); num2++; } catch (Exception ex2) { Instance log4 = Core.Log; if (log4 != null) { log4.Warning("[route] GenerateTrash: " + ex2.Message); } } } Instance log5 = Core.Log; if (log5 != null) { log5.Msg($"[route] burst: {count} generators, {num} within 120m, GenerateTrash({perGenerator}) on {num2}. tv route stat."); } } } [HarmonyPatch(typeof(TrashManager), "CreateAndReturnTrashItem", new Type[] { typeof(string), typeof(Vector3), typeof(Quaternion), typeof(Vector3), typeof(string), typeof(bool) })] internal static class TM_CreateAndReturnTrashItem_Patch { private static void Postfix(TrashItem __result) { try { RouteHook.OnCreate(isPrivate: true, __result); } catch { } } } [HarmonyPatch(typeof(TrashManager), "CreateTrashItem", new Type[] { typeof(string), typeof(Vector3), typeof(Quaternion), typeof(Vector3), typeof(string), typeof(bool) })] internal static class TM_CreateTrashItem_Patch { private static void Postfix(TrashItem __result) { try { RouteHook.OnCreate(isPrivate: false, __result); } catch { } } } [HarmonyPatch(typeof(TrashGenerator), "GenerateMaxTrash")] internal static class TG_GenerateMaxTrash_Patch { private static void Prefix() { RouteHook.EnterGenerator(); } private static Exception Finalizer(Exception __exception) { RouteHook.ExitGenerator(); return __exception; } } [HarmonyPatch(typeof(TrashGenerator), "GenerateTrash", new Type[] { typeof(int) })] internal static class TG_GenerateTrash_Patch { private static void Prefix() { RouteHook.EnterGenerator(); } private static Exception Finalizer(Exception __exception) { RouteHook.ExitGenerator(); return __exception; } } internal static class TrashPopulator { internal static bool Enabled = true; internal static int Multiplier = 1; internal static float Radius = 170f; private const int BatchPerGen = 30; private const int GensPerPass = 2; private const float PassEvery = 0.3f; private const float NoSpawnInView = 50f; private const int MaxDeferPasses = 12; private static float _timer; private static readonly float[] _planes = new float[24]; private static readonly HashSet<int> _done = new HashSet<int>(); private static readonly HashSet<int> _boosted = new HashSet<int>(); private static readonly Dictionary<int, int> _generated = new Dictionary<int, int>(); private static readonly Dictionary<int, int> _deferred = new Dictionary<int, int>(); internal static void Reset() { _done.Clear(); _boosted.Clear(); _generated.Clear(); _deferred.Clear(); _timer = 0f; } internal static void Tick(float dt) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) if (!Enabled || Multiplier <= 1) { return; } _timer += dt; if (_timer < 0.3f) { return; } _timer = 0f; if (!GameTrash.TryGetPlayerPosition(out var pos)) { return; } List<TrashGenerator> allGenerators; try { allGenerators = TrashGenerator.AllGenerators; } catch { return; } if (allGenerators == null) { return; } float[] array = (Frustum.Compute(Frustum.Cam(), _planes) ? _planes : null); float num = 2500f; float num2 = Radius * Radius; int num3 = 0; for (int i = 0; i < allGenerators.Count && num3 < 2; i++) { TrashGenerator val = allGenerators[i]; if ((Object)(object)val == (Object)null) { continue; } int instanceID; try { instanceID = ((Object)val).GetInstanceID(); } catch { continue; } if (_done.Contains(instanceID)) { continue; } Vector3 position; try { position = ((Component)val).transform.position; } catch { continue; } float num4 = position.x - pos.x; float num5 = position.z - pos.z; float num6 = num4 * num4 + num5 * num5; if (num6 > num2) { continue; } try { if (_boosted.Contains(instanceID)) { goto IL_01d2; } BoxCollider component = ((Component)val).GetComponent<BoxCollider>(); if (!((Object)(object)component == (Object)null)) { _boosted.Add(instanceID); val.TrashCountMultiplier = Multiplier; val.AutoCalculateTrashCount(); int maxTrashCount = val.MaxTrashCount; Bounds bounds = ((Collider)component).bounds; int num7 = ((maxTrashCount > 0) ? InstancedTrash.CountInBox(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.z, ((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.z, maxTrashCount) : 0); _generated[instanceID] = num7; if (maxTrashCount <= 0 || num7 < maxTrashCount) { goto IL_01d2; } _done.Add(instanceID); } goto end_IL_010b; IL_01d2: int maxTrashCount2 = val.MaxTrashCount; int value; int num8 = (_generated.TryGetValue(instanceID, out value) ? value : 0); if (maxTrashCount2 <= 0 || num8 >= maxTrashCount2) { _done.Add(instanceID); continue; } if (array == null || !(num6 < num) || !Frustum.Contains(array, position.x, position.y, position.z, 3f)) { goto IL_0268; } int value2; int num9 = ((!_deferred.TryGetValue(instanceID, out value2)) ? 1 : (value2 + 1)); _deferred[instanceID] = num9; if (num9 >= 12) { goto IL_0268; } goto end_IL_010b; IL_0268: int num10 = Math.Min(maxTrashCount2 - num8, 30); val.GenerateTrash(num10); _generated[instanceID] = num8 + num10; num3++; if (num8 + num10 >= maxTrashCount2) { _done.Add(instanceID); } end_IL_010b:; } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[populate] " + ex.Message); } _done.Add(instanceID); } } } } } namespace Litterally.SaveGuard { internal static class SaveSafety { internal static void ForceClearForSave(string reason) { RouteHook.Tick(); GeneratorBoost.Restore(); Virtualizer.ClearAll(); CleanerActor.ClearAll(); InstancedTrash.AbortCalibration(); InstancedTrash.AbortDrift(); } } } namespace Litterally.Instanced { internal static class Frustum { private static Camera _cam; internal static Camera Cam() { Camera main = Camera.main; if ((Object)(object)main != (Object)null) { _cam = main; } return _cam; } internal static bool Compute(Camera cam, float[] planes) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cam == (Object)null || planes == null || planes.Length < 24) { return false; } try { return ComputeFromVP(cam.projectionMatrix * cam.worldToCameraMatrix, planes); } catch { return false; } } internal static bool ComputeFromVP(Matrix4x4 m, float[] planes) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if (planes == null || planes.Length < 24) { return false; } Set(planes, 0, m.m30 + m.m00, m.m31 + m.m01, m.m32 + m.m02, m.m33 + m.m03); Set(planes, 1, m.m30 - m.m00, m.m31 - m.m01, m.m32 - m.m02, m.m33 - m.m03); Set(planes, 2, m.m30 + m.m10, m.m31 + m.m11, m.m32 + m.m12, m.m33 + m.m13); Set(planes, 3, m.m30 - m.m10, m.m31 - m.m11, m.m32 - m.m12, m.m33 - m.m13); Set(planes, 4, m.m30 + m.m20, m.m31 + m.m21, m.m32 + m.m22, m.m33 + m.m23); Set(planes, 5, m.m30 - m.m20, m.m31 - m.m21, m.m32 - m.m22, m.m33 - m.m23); return true; } internal static Matrix4x4 ViewProjection(Matrix4x4 projection, Vector3 pos, Quaternion rot) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = Matrix4x4.Scale(new Vector3(1f, 1f, -1f)); Matrix4x4 val2 = Matrix4x4.TRS(pos, rot, Vector3.one); Matrix4x4 val3 = val * ((Matrix4x4)(ref val2)).inverse; return projection * val3; } private static void Set(float[] pl, int k, float a, float b, float c, float d) { float num = Mathf.Sqrt(a * a + b * b + c * c); float num2 = ((num > 1E-06f) ? (1f / num) : 0f); int num3 = k << 2; pl[num3] = a * num2; pl[num3 + 1] = b * num2; pl[num3 + 2] = c * num2; pl[num3 + 3] = d * num2; } internal static bool Contains(float[] pl, float px, float py, float pz, float margin) { if (pl == null) { return true; } for (int i = 0; i < 6; i++) { int num = i << 2; if (pl[num] * px + pl[num + 1] * py + pl[num + 2] * pz + pl[num + 3] < 0f - margin) { return false; } } return true; } } internal static class InstancedTrash { private sealed class Part { public Mesh Mesh; public Material[] Mats; public Matrix4x4 Local = Matrix4x4.identity; } private struct Pose { public Quaternion Rot; public float Clearance; } private sealed class TType { public string Id; public Part[] Parts; public Pose[] Poses; public bool Calibrated; public float Weight = 1f; public int Start; public int Len; } private struct Ground { public float Y; public Vector3 N; public bool Hit; } private static class Calibration { private const int PosesPerType = 16; private const float ProbeSpacing = 4f; private const float ProbeDropHeight = 1f; private const int MinSettleFrames = 25; private const int TypeTimeoutFrames = 150; private const float SettleVel2 = 0.0025f; private const float MinDescent = 0.3f; private const float FlatNormalY = 0.985f; private static readonly List<TType> _pendingTypes = new List<TType>(); private static int _cursor; private static int _typeFrames; private static readonly List<TrashItem> _probes = new List<TrashItem>(); private static readonly List<float> _spawnY = new List<float>(); private static readonly List<Pose> _caps = new List<Pose>(); internal static bool Active { get; private set; } internal static int Outstanding { get; private set; } internal static bool Begin(TType[] types) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (Active) { return true; } _pendingTypes.Clear(); for (int i = 0; i < types.Length; i++) { if (!types[i].Calibrated) { _pendingTypes.Add(types[i]); } } if (_pendingTypes.Count == 0) { return false; } if ((Object)(object)GameTrash.TrashManagerOrNull() == (Object)null) { return false; } if (!GameTrash.TryGetPlayerPosition(out var pos)) { return false; } RaycastHit val = default(RaycastHit); if (Physics.Raycast(pos + Vector3.up, Vector3.down, ref val, 5f, GroundRayMask, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val)).normal.y < 0.99f) { Instance log = Core.Log; if (log != null) { log.Warning($"[inst] calibration ground not flat (normal.y={((RaycastHit)(ref val)).normal.y:F3}); stand on flat ground for best poses."); } } _cursor = 0; Active = true; Outstanding = _pendingTypes.Count; SpawnProbesFor(_pendingTypes[0]); return true; } private static bool SpawnProbesFor(TType ty) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) DestroyProbes(); _caps.Clear(); _typeFrames = 0; TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { return false; } if (!GameTrash.TryGetPlayerPosition(out var pos)) { return false; } for (int i = 0; i < 16; i++) { int num = i % 4; int num2 = i / 4; Vector3 val2 = pos + new Vector3(((float)num - 1.5f) * 4f, 1f, ((float)num2 - 1.5f) * 4f); TrashItem val3 = null; RouteHook.Suppress = true; try { val3 = val.CreateTrashItem(ty.Id, val2, Random.rotation, Vector3.zero, Guid.NewGuid().ToString(), false); } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[inst] probe spawn failed for " + ty.Id + ": " + ex.Message); } } finally { RouteHook.Suppress = false; } if ((Object)(object)val3 != (Object)null) { MarkRealCreated(); } _probes.Add(val3); _spawnY.Add(val2.y); } return true; } internal static bool Tick() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return true; } _typeFrames++; TType tType = ((_cursor < _pendingTypes.Count) ? _pendingTypes[_cursor] : null); if (tType == null) { Finish(); return true; } bool flag = _typeFrames >= 150; bool flag2 = true; for (int i = 0; i < _probes.Count; i++) { TrashItem val = _probes[i]; if ((Object)(object)val == (Object)null) { continue; } bool flag3 = false; if (_typeFrames >= 25) { try { float num = _spawnY[i] - ((Component)val).transform.position.y; Rigidbody componentInChildren = ((Component)val).GetComponentInChildren<Rigidbody>(); int num2; if (!((Object)(object)componentInChildren == (Object)null)) { Vector3 velocity = componentInChildren.velocity; num2 = ((((Vector3)(ref velocity)).sqrMagnitude < 0.0025f) ? 1 : 0); } else { num2 = 1; } bool flag4 = (byte)num2 != 0; if (num >= 0.3f && flag4) { flag3 = true; } } catch { flag3 = true; } } if (!flag3) { flag2 = false; continue; } CaptureProbe(tType, val, force: false); DestroyOne(val); _probes[i] = null; } if (flag2 || flag) { if (flag) { for (int j = 0; j < _probes.Count; j++) { if ((Object)(object)_probes[j] != (Object)null) { CaptureProbe(tType, _probes[j], force: true); DestroyOne(_probes[j]); _probes[j] = null; } } } FinalizeType(tType); _cursor++; if (_cursor < _pendingTypes.Count) { SpawnProbesFor(_pendingTypes[_cursor]); return false; } Finish(); return true; } return false; } private static void CaptureProbe(TType ty, TrashItem probe, bool force) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) try { Vector3 position = ((Component)probe).transform.position; float y = position.y; float num = 1f; RaycastHit val = default(RaycastHit); if (Physics.Raycast(position + Vector3.up * 0.6f, Vector3.down, ref val, 3f, GroundRayMask, (QueryTriggerInteraction)1)) { y = ((RaycastHit)(ref val)).point.y; num = ((RaycastHit)(ref val)).normal.y; } if (force || !(num < 0.985f)) { float clearance = Mathf.Clamp(position.y - y, -0.3f, 1.2f); _caps.Add(new Pose { Rot = ((Component)probe).transform.rotation, Clearance = clearance }); } } catch { } } private static void FinalizeType(TType ty) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) List<Pose> list = new List<Pose>(_caps.Count); for (int i = 0; i < _caps.Count; i++) { Vector3 val = Quaternion.Inverse(_caps[i].Rot) * Vector3.down; bool flag = false; for (int j = 0; j < list.Count; j++) { if (Vector3.Dot(Quaternion.Inverse(list[j].Rot) * Vector3.down, val) > 0.985f) { flag = true; break; } } if (!flag) { list.Add(_caps[i]); } } if (list.Count == 0) { list.Add(new Pose { Rot = Quaternion.identity, Clearance = ComputeClearance(ty, Quaternion.identity) }); } ty.Poses = list.ToArray(); ty.Calibrated = true; Outstanding = Math.Max(0, Outstanding - 1); Instance log = Core.Log; if (log != null) { log.Msg($"[inst] calibrated '{ty.Id}': {ty.Poses.Length} settled pose(s) from {_caps.Count} drop(s)" + ((ty.Poses.Length < 4) ? " (low variety - relying on random yaw)" : "")); } } private static void Finish() { DestroyProbes(); _caps.Clear(); Active = false; Outstanding = 0; _cursor = 0; } private static void DestroyOne(TrashItem pr) { if ((Object)(object)pr == (Object)null) { return; } try { pr.DestroyTrash(); } catch { } try { if ((Object)(object)pr != (Object)null) { Object.Destroy((Object)(object)((Component)pr).gameObject); } } catch { } } private static void DestroyProbes() { for (int i = 0; i < _probes.Count; i++) { DestroyOne(_probes[i]); } _probes.Clear(); _spawnY.Clear(); } internal static void Reset() { DestroyProbes(); _caps.Clear(); _pendingTypes.Clear(); Active = false; Outstanding = 0; _cursor = 0; _typeFrames = 0; } } private static class GroundDrift { private const float WaitSeconds = 5f; private const float SampleRadius = 18f; private const float DriftThreshold = 0.15f; private static readonly List<int> _idx = new List<int>(); private static readonly List<TrashItem> _items = new List<TrashItem>(); private static readonly List<Vector3> _start = new List<Vector3>(); private static readonly List<Quaternion> _startRot = new List<Quaternion>(); private static readonly int[] _scan = new int[512]; private static float _elapsed; internal static bool Active { get; private set; } internal static void Begin(int count) { //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) if (Active) { Instance log = Core.Log; if (log != null) { log.Msg("[drift] already running"); } return; } TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { Instance log2 = Core.Log; if (log2 != null) { log2.Warning("[drift] no TrashManager"); } return; } if (!GameTrash.TryGetPlayerPosition(out var pos)) { Instance log3 = Core.Log; if (log3 != null) { log3.Warning("[drift] no player"); } return; } if (!Ready || _count <= 0) { Instance log4 = Core.Log; if (log4 != null) { log4.Warning("[drift] no instanced field to sample"); } return; } _idx.Clear(); _items.Clear(); _start.Clear(); _startRot.Clear(); _elapsed = 0f; int num = CollectNear(pos, 18f, _scan, _scan.Length); if (num == 0) { Instance log5 = Core.Log; if (log5 != null) { log5.Warning("[drift] no settled instances within " + 18f + "m"); } return; } int num2 = Mathf.Clamp(count, 1, num); int num3 = Mathf.Max(1, num / num2); for (int i = 0; i < num; i += num3) { if (_idx.Count >= num2) { break; } int num4 = _scan[i]; string typeId = GetTypeId(num4); if (string.IsNullOrEmpty(typeId)) { continue; } Vector3 position = GetPosition(num4); Quaternion rotation = GetRotation(num4); TrashItem val2 = null; RouteHook.Suppress = true; try { val2 = val.CreateTrashItem(typeId, position, rotation, Vector3.zero, Guid.NewGuid().ToString(), false); } catch (Exception ex) { Instance log6 = Core.Log; if (log6 != null) { log6.Warning("[drift] spawn failed: " + ex.Message); } } finally { RouteHook.Suppress = false; } if (!((Object)(object)val2 == (Object)null)) { MarkRealCreated(); Hide(num4); _idx.Add(num4); _items.Add(val2); _start.Add(position); _startRot.Add(rotation); } } if (_idx.Count == 0) { Instance log7 = Core.Log; if (log7 != null) { log7.Warning("[drift] no probes materialized"); } return; } Active = true; Instance log8 = Core.Log; if (log8 != null) { log8.Msg($"[drift] activated {_idx.Count} DYNAMIC probe(s) within {18f:F0}m; measuring drift over {5f:F0}s..."); } } internal static void Tick(float dt) { if (Active) { _elapsed += dt; if (!(_elapsed < 5f)) { Measure(); Cleanup(); Active = false; } } } private static void Measure() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) int count = _idx.Count; float num = 0f; float num2 = 0f; float num3 = 0f; float num4 = 0f; int num5 = 0; int num6 = 0; int num7 = 0; Dictionary<string, int[]> dictionary = new Dictionary<string, int[]>(); Dictionary<string, float[]> dictionary2 = new Dictionary<string, float[]>(); for (int i = 0; i < count; i++) { TrashItem val = _items[i]; if ((Object)(object)val == (Object)null) { continue; } Vector3 val2 = _start[i]; Vector3 position; try { position = ((Component)val).transform.position; } catch { continue; } float num8 = position.x - val2.x; float num9 = position.y - val2.y; float num10 = position.z - val2.z; float num11 = Mathf.Sqrt(num8 * num8 + num9 * num9 + num10 * num10); if (num11 > 5f) { num7++; continue; } num6++; float num12 = Mathf.Sqrt(num8 * num8 + num10 * num10); float num13 = 0f - num9; num += num12; if (num12 > num2) { num2 = num12; } num3 += num13; if (Mathf.Abs(num13) > Mathf.Abs(num4)) { num4 = num13; } if (num11 > 0.15f) { num5++; } string key = GetTypeId(_idx[i]) ?? "?"; if (!dictionary.ContainsKey(key)) { dictionary[key] = new int[1]; dictionary2[key] = new float[3]; } dictionary[key][0]++; dictionary2[key][0] += num12; dictionary2[key][1] += num13; if (Mathf.Abs(num13) > Mathf.Abs(dictionary2[key][2])) { dictionary2[key][2] = num13; } } int num14 = Math.Max(1, num6); Instance log = Core.Log; if (log != null) { log.Msg($"[drift] RESULT n={num6} (lost {num7}) moved>{0.15f:F2}m: {num5}/{num6} horiz mean={num / (float)num14:F3} max={num2:F3} vert(drop+) mean={num3 / (float)num14:F3} max={num4:F3} (m)"); } foreach (KeyValuePair<string, int[]> item in dictionary) { string key2 = item.Key; int num15 = item.Value[0]; float[] array = dictionary2[key2]; Instance log2 = Core.Log; if (log2 != null) { log2.Msg($"[drift] {key2}: n={num15} horiz={array[0] / (float)num15:F3} drop(mean)={array[1] / (float)num15:F3} drop(maxAbs)={array[2]:F3}"); } } Instance log3 = Core.Log; if (log3 != null) { log3.Msg("[drift] read: drop>0 fell (floated above ground); drop<0 pushed up (penetrated); ~0 = resting correctly."); } } private static void Cleanup() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _idx.Count; i++) { TrashItem val = _items[i]; if ((Object)(object)val != (Object)null) { try { val.DestroyTrash(); } catch { } try { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } catch { } } Restore(_idx[i], _start[i], _startRot[i]); } _idx.Clear(); _items.Clear(); _start.Clear(); _startRot.Clear(); } internal static void Abort() { Cleanup(); Active = false; _elapsed = 0f; } } private const int BatchSize = 1023; private const float Gravity = -22f; private const float GroundCellSize = 5f; private const float NavSampleMaxDist = 25f; private static readonly int GroundRayMask = -1025; internal static bool Shadows = false; internal static int MaxTypes = 8; internal static string OnlyType = null; private static readonly (string id, float w)[] Palette = new(string, float)[8] { ("trashbag", 3f), ("glassbottle", 2f), ("waterbottle", 2f), ("coffeecup", 1.8f), ("energydrink", 1.5f), ("cigarettebox", 1.4f), ("litter1", 1.2f), ("soilbag", 1f) }; private static TType[] _types; private static Il2CppStructArray<Matrix4x4> _batch; private static readonly float[] _renderPlanes = new float[24]; private const float RenderCullMargin = 6f; internal static float RenderDist = 150f; private static int _lastDrawn; private static int _capacity; private static List<int>[] _typeBuckets; private static readonly Dictionary<string, int> _typeIndex = new Dictionary<string, int>(); internal const int CapacityCeiling = 2000000; internal static bool RoutedDataPresent; private static float[] _px; private static float[] _pz; private static float[] _py; private static float[] _vy; private static float[] _restY; private static float[] _qx; private static float[] _qy; private static float[] _qz; private static float[] _qw; private static byte[] _type; private static bool[] _settled; private static bool[] _hidden; private static bool[] _dead; private static bool[] _realized; private static Matrix4x4[] _matrices; private static int _count; private static int _active; private static readonly Dictionary<long, Ground> _groundCache = new Dictionary<long, Ground>(8192); private static bool _pending; private static int _pendingN; private static Vector3 _pendingCenter; private const int BlobMagic = 1414944305; private const float GridCell = 8f; private static readonly Dictionary<long, List<int>> _grid = new Dictionary<long, List<int>>(4096); internal static int Count => _count; internal static int LiveCount { get { if (_dead == null) { return _count; } int num = 0; for (int i = 0; i < _count; i++) { if (!_dead[i]) { num++; } } return num; } } internal static int Active => _active; internal static int Drawn => _lastDrawn; internal static int TypeCount { get { if (_types == null) { return 0; } return _types.Length; } } internal static bool Ready { get { if (_types != null) { return _types.Length != 0; } return false; } } internal static bool EverMaterialized { get; private set; } internal static bool DriftActive => GroundDrift.Active; internal static void MarkRealCreated() { EverMaterialized = true; } internal static void AbortCalibration() { Calibration.Reset(); _pending = false; } internal static void BeginDrift(int count) { GroundDrift.Begin(count); } internal static void DriftTick(float dt) { GroundDrift.Tick(dt); } internal static void AbortDrift() { GroundDrift.Abort(); } internal static bool Setup(int n, Vector3 center) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (n < 0) { n = 0; } Virtualizer.ClearAll(); _count = 0; _active = 0; if (!EnsurePalette()) { Instance log = Core.Log; if (log != null) { log.Warning("[inst] could not build a trash palette (no prefab meshes)."); } return false; } _pending = true; _pendingN = n; _pendingCenter = center; if (!Calibration.Begin(_types)) { BuildPending(); } else { Instance log2 = Core.Log; if (log2 != null) { log2.Msg($"[inst] calibrating resting pose for {Calibration.Outstanding} type(s) before spawning {n}..."); } } return true; } internal static void Tick(float dt) { if (Calibration.Active) { if (Calibration.Tick()) { BuildPending(); } } else { if (_active <= 0 || _count <= 0 || dt <= 0f) { return; } float num = -22f * dt; int num2 = 0; for (int i = 0; i < _count; i++) { if (!_settled[i] && !_hidden[i] && !_dead[i]) { _vy[i] += num; float num3 = _py[i] + _vy[i] * dt; if (num3 <= _restY[i]) { num3 = _restY[i]; _settled[i] = true; } else { num2++; } _py[i] = num3; _matrices[i].m13 = num3; } } _active = num2; } } internal static void Render() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) if (_count <= 0 || _types == null || _batch == null) { return; } try { ShadowCastingMode val = (ShadowCastingMode)(Shadows ? 1 : 0); Camera val2 = Frustum.Cam(); float[] array = (((Object)(object)val2 != (Object)null && Frustum.Compute(val2, _renderPlanes)) ? _renderPlanes : null); float num = 0f; float num2 = 0f; float num3 = 0f; if ((Object)(object)val2 != (Object)null && RenderDist > 0f) { Vector3 position = ((Component)val2).transform.position; num = position.x; num2 = position.z; num3 = RenderDist * RenderDist; } int num4 = 0; for (int i = 0; i < _types.Length; i++) { TType tType = _types[i]; List<int> list = ((_typeBuckets != null && i < _typeBuckets.Length) ? _typeBuckets[i] : null); if (tType.Parts == null || list == null || list.Count == 0) { continue; } int count = list.Count; for (int j = 0; j < tType.Parts.Length; j++) { Part part = tType.Parts[j]; if ((Object)(object)part.Mesh == (Object)null || part.Mats == null || part.Mats.Length == 0) { continue; } int num5 = part.Mats.Length; int num6 = 0; for (int k = 0; k < count; k++) { int num7 = list[k]; if (_hidden[num7] || _dead[num7]) { continue; } if (num3 > 0f) { float num8 = _px[num7] - num; float num9 = _pz[num7] - num2; if (num8 * num8 + num9 * num9 > num3) { continue; } } if (array != null && !Frustum.Contains(array, _px[num7], _py[num7], _pz[num7], 6f)) { continue; } if (j == 0) { num4++; } ((Il2CppArrayBase<Matrix4x4>)(object)_batch)[num6++] = Mul(in _matrices[num7], in part.Local); if (num6 != 1023) { continue; } for (int l = 0; l < num5; l++) { Material val3 = part.Mats[l]; if (!((Object)(object)val3 == (Object)null)) { Graphics.DrawMeshInstanced(part.Mesh, l, val3, _batch, num6, (MaterialPropertyBlock)null, val, Shadows, 0); } } num6 = 0; } if (num6 <= 0) { continue; } for (int m = 0; m < num5; m++) { Material val4 = part.Mats[m]; if (!((Object)(object)val4 == (Object)null)) { Graphics.DrawMeshInstanced(part.Mesh, m, val4, _batch, num6, (MaterialPropertyBlock)null, val, Shadows, 0); } } } } _lastDrawn = num4; } catch (Exception ex) { Instance log = Core.Log; if (log != null) { log.Warning("[inst] render error (disabling): " + ex.Message); } _count = 0; } } private static void BuildPending() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) if (!_pending) { return; } _pending = false; int pendingN = _pendingN; Vector3 pendingCenter = _pendingCenter; float num = Mathf.Clamp((float)Math.Sqrt(pendingN) * 0.5f, 20f, 220f); _px = new float[pendingN]; _pz = new float[pendingN]; _py = new float[pendingN]; _vy = new float[pendingN]; _restY = new float[pendingN]; _qx = new float[pendingN]; _qy = new float[pendingN]; _qz = new float[pendingN]; _qw = new float[pendingN]; _type = new byte[pendingN]; _settled = new bool[pendingN]; _hidden = new bool[pendingN]; _dead = new bool[pendingN]; _realized = new bool[pendingN]; _matrices = (Matrix4x4[])(object)new Matrix4x4[pendingN]; AssignTypeRanges(pendingN); Random random = new Random(12345); Stopwatch stopwatch = Stopwatch.StartNew(); int num2 = 0; for (int i = 0; i < _types.Length; i++) { TType tType = _types[i]; for (int j = 0; j < tType.Len; j++) { int num3 = tType.Start + j; _type[num3] = (byte)i; double num4 = random.NextDouble() * Math.PI * 2.0; double num5 = Math.Sqrt(random.NextDouble()) * (double)num; float num6 = pendingCenter.x + (float)(Math.Cos(num4) * num5); float num7 = pendingCenter.z + (float)(Math.Sin(num4) * num5); Ground ground = SampleGround(num6, num7, pendingCenter.y); if (ground.Hit) { num2++; } Pose pose = ((tType.Poses != null && tType.Poses.Length != 0) ? tType.Poses[random.Next(tType.Poses.Length)] : new Pose { Rot = Quaternion.identity, Clearance = 0.1f }); float num8 = ground.Y + pose.Clearance; Quaternion val = Quaternion.AngleAxis((float)(random.NextDouble() * 360.0), Vector3.up) * pose.Rot; float num9 = 8f + (float)(random.NextDouble() * 26.0); _px[num3] = num6; _pz[num3] = num7; _restY[num3] = num8; _py[num3] = num8 + num9; _vy[num3] = 0f; _qx[num3] = val.x; _qy[num3] = val.y; _qz[num3] = val.z; _qw[num3] = val.w; _matrices[num3] = BuildRootMatrix(num6, _py[num3], num7, val.x, val.y, val.z, val.w); } } stopwatch.Stop(); _count = pendingN; _active = pendingN; _capacity = pendingN; RebuildBuckets(); if (_batch == null) { _batch = new Il2CppStructArray<Matrix4x4>(1023L); } Instance log = Core.Log; if (log != null) { log.Msg($"[inst] {pendingN} falling instances across {_types.Length} type(s), radius={num:F0}, ground: {num2}/{pendingN} navmesh hits, sampled in {stopwatch.ElapsedMilliseconds}ms (cache={_groundCache.Count})."); } } private static void AssignTypeRanges(int n) { float num = 0f; for (int i = 0; i < _types.Length; i++) { num += _types[i].Weight; } int num2 = 0; for (int j = 0; j < _types.Length; j++) { int num3 = ((j == _types.Length - 1) ? (n - num2) : Mathf.RoundToInt((float)n * (_types[j].Weight / num))); if (num3 < 0) { num3 = 0; } if (num2 + num3 > n) { num3 = n - num2; } _types[j].Start = num2; _types[j].Len = num3; num2 += num3; } } internal static int AddOne(string id, Vector3 pos, Quaternion rot, bool groundSnap = false) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(id)) { return -1; } int num = TypeIndexFor(id); if (num < 0) { return -1; } if (_count >= 2000000) { return -2; } EnsureCapacity(_count + 1); int count = _count; float num2 = pos.y; if (groundSnap) { float y = pos.y; RaycastHit val = default(RaycastHit); if (Physics.Raycast(pos + Vector3.up * 0.5f, Vector3.down, ref val, 60f, GroundRayMask, (QueryTriggerInteraction)1)) { y = ((RaycastHit)(ref val)).point.y; } num2 = y + ComputeClearance(_types[num], rot); } _type[count] = (byte)num; _px[count] = pos.x; _py[count] = num2; _pz[count] = pos.z; _restY[count] = num2; _vy[count] = 0f; _qx[count] = rot.x; _qy[count] = rot.y; _qz[count] = rot.z; _qw[count] = rot.w; _settled[count] = true; bool[] hidden = _hidden; bool flag; _dead[count] = (flag = (_realized[count] = false)); hidden[count] = flag; _matrices[count] = BuildRootMatrix(pos.x, num2, pos.z, rot.x, rot.y, rot.z, rot.w); _count++; _active = _count; RoutedDataPresent = true; (_typeBuckets[num] ?? (_typeBuckets[num] = new List<int>(1024))).Add(count); if (_batch == null) { _batch = new Il2CppStructArray<Matrix4x4>(1023L); } return num; } internal static int WriteBlob(string path) { using FileStream output = new FileStream(path, FileMode.Create, FileAccess.Write); using BinaryWriter binaryWriter = new BinaryWriter(output); binaryWriter.Write(1414944305); binaryWriter.Write(1); int num = ((_types != null) ? _types.Length : 0); binaryWriter.Write(num); for (int i = 0; i < num; i++) { binaryWriter.Write(_types[i].Id ?? ""); } int num2 = 0; for (int j = 0; j < _count; j++) { if (!_dead[j]) { num2++; } } binaryWriter.Write(num2); for (int k = 0; k < _count; k++) { if (!_dead[k]) { binaryWriter.Write(_type[k]); binaryWriter.Write(_px[k]); binaryWriter.Write(_py[k]); binaryWriter.Write(_pz[k]); binaryWriter.Write(_qx[k]); binaryWriter.Write(_qy[k]); binaryWriter.Write(_qz[k]); binaryWriter.Write(_qw[k]); } } return num2; } internal static int ReadBlob(string path) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read); using BinaryReader binaryReader = new BinaryReader(input); if (binaryReader.ReadInt32() != 1414944305) { return 0; } binaryReader.ReadInt32(); int num = binaryReader.ReadInt32(); string[] array = new string[num]; for (int i = 0; i < num; i++) { array[i] = binaryReader.ReadString(); } int num2 = binaryReader.ReadInt32(); int num3 = 0; for (int j = 0; j < num2; j++) { byte b = binaryReader.ReadByte(); float num4 = binaryReader.ReadSingle(); float num5 = binaryReader.ReadSingle(); float num6 = binaryReader.ReadSingle(); float num7 = binaryReader.ReadSingle(); float num8 = binaryReader.ReadSingle(); float num9 = binaryReader.ReadSingle(); float num10 = binaryReader.ReadSingle(); string text = ((b < array.Length) ? array[b] : null); if (!string.IsNullOrEmpty(text) && AddOne(text, new Vector3(num4, num5, num6), new Quaternion(num7, num8, num9, num10)) >= 0) { num3++; } } return num3; } private static int TypeIndexFor(string id) { if (_typeIndex.TryGetValue(id, out var value)) { return value; } TrashManager val = GameTrash.TrashManagerOrNull(); if ((Object)(object)val == (Object)null) { return -1; } TType tType = BuildType(val, id, 1f); if (tType == null) { _typeIndex[id] = -1; return -1; } int num = ((_types != null) ? _types.Length : 0); if (_types == null) { _types = new TType[1] { tType }; } else { Array.Resize(ref _types, _types.Length + 1); _types[num] = tType; } EnsureBuckets(); _typeIndex[id] = num; Instance log = Core.Log; if (log != null) { log.Msg($"[route] new instanced type '{id}' (#{num}, parts={tType.Parts.Length})"); } return num; } private static void EnsureCapacity(int need) { if (_px == null || need > _capacity) { int num = ((_px != null) ? (_capacity + 65536) : Math.Max(65536, need)); if (num < need) { num = need; } if (num > 2000000) { num = 2000000; } Array.Resize(ref _px, num); Array.Resize(ref _pz, num); Array.Res