Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Error Fix v0.0.4
V81ErrorFix.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; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance.Integrations.Unity_NFGO; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.AI.Navigation; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 V81ErrorFix { internal enum PatchEnableMode { Auto, Enabled, Disabled } internal static class ErrorFixConfig { internal static ConfigEntry<bool> EnableGlobalDestroyGuard; internal static ConfigEntry<PatchEnableMode> GlobalDestroyGuardMode; internal static ConfigEntry<bool> AllowDestroyDuringSceneUnload; internal static ConfigEntry<float> LifecycleDestroyWindowSeconds; internal static ConfigEntry<bool> LogBlockedDestroyStackTraceOnce; internal static ConfigEntry<PatchEnableMode> AudioSourcePlaybackGuardMode; internal static ConfigEntry<PatchEnableMode> KnownUnityWarningFilterMode; internal static ConfigEntry<PatchEnableMode> PlayerRagdollGlobalTagGuardMode; internal static ConfigEntry<PatchEnableMode> ParticleMeshShapeGuardMode; internal static ConfigEntry<bool> ParticleMeshShapeGuardDryRun; internal static ConfigEntry<PatchEnableMode> EntranceTeleportUpdateGuardMode; internal static ConfigEntry<PatchEnableMode> FindMainEntrancePositionFallbackMode; internal static ConfigEntry<PatchEnableMode> ThrowObjectClientRpcGuardMode; internal static ConfigEntry<PatchEnableMode> VoiceRefreshFallbackMode; internal static ConfigEntry<PatchEnableMode> UnlockableSuitGuardMode; internal static ConfigEntry<PatchEnableMode> NetworkObjectParentGuardMode; internal static ConfigEntry<PatchEnableMode> SteamValveDamageTriggerSpawnGuardMode; internal static ConfigEntry<PatchEnableMode> EnemyHealthBarsLateUpdateGuardMode; internal static ConfigEntry<PatchEnableMode> ShipLootPlusUiHelperGuardMode; internal static ConfigEntry<PatchEnableMode> NightVisionInsideLightingPostfixGuardMode; internal static ConfigEntry<PatchEnableMode> ChatCommandsStartHostPostfixGuardMode; internal static ConfigEntry<bool> EnableEnemyAINavMeshGuard; internal static ConfigEntry<bool> AllowEnemyAIWarp; internal static ConfigEntry<float> EnemyAINavMeshMaxWarpRadius; internal static ConfigEntry<bool> EnemyAINavMeshHostServerOnly; internal static void Bind(ConfigFile config) { EnableGlobalDestroyGuard = config.Bind<bool>("NetworkObjectDestroy", "EnableGlobalDestroyGuard", true, "Legacy switch for the global Destroy guard. GlobalDestroyGuardMode can also disable this patch."); GlobalDestroyGuardMode = config.Bind<PatchEnableMode>("NetworkObjectDestroy", "GlobalDestroyGuardMode", PatchEnableMode.Disabled, "Only Enabled installs the global UnityEngine.Object.Destroy hook. Auto is treated as disabled for this global hook to avoid upgrade-time performance surprises. Requires restart."); AllowDestroyDuringSceneUnload = config.Bind<bool>("NetworkObjectDestroy", "AllowDestroyDuringSceneUnload", true, "Allows Destroy during network shutdown, ship scene unload, or lobby transitions."); LifecycleDestroyWindowSeconds = config.Bind<float>("NetworkObjectDestroy", "LifecycleDestroyWindowSeconds", 3f, "Seconds after scene load/unload/active-scene changes where lifecycle Destroy calls are allowed. Values are clamped from 0 to 15."); LogBlockedDestroyStackTraceOnce = config.Bind<bool>("NetworkObjectDestroy", "LogBlockedDestroyStackTraceOnce", true, "Logs one stack trace for the first blocked spawned ragdoll Destroy call."); AudioSourcePlaybackGuardMode = config.Bind<PatchEnableMode>("Performance", "AudioSourcePlaybackGuardMode", PatchEnableMode.Disabled, "Only Enabled installs global AudioSource.Play* hooks. Auto is treated as disabled for this global hook. Requires restart."); KnownUnityWarningFilterMode = config.Bind<PatchEnableMode>("Performance", "KnownUnityWarningFilterMode", PatchEnableMode.Enabled, "Enabled by default to suppress high-frequency Unity log spam for missing audio spatializer plugin setup, BoxCollider negative scale/size asset warnings, the SteamValve(Clone) custom-filter AudioSource warning, and duplicate Static Lighting Sky baking warnings. This is log-only and does not repair the underlying audio plugin, collider geometry, AudioSource setup, or lighting setup. It filters only those exact warning prefixes, does not filter Netcode NetworkVariable lifecycle warnings, and requires restart."); PlayerRagdollGlobalTagGuardMode = config.Bind<PatchEnableMode>("Performance", "PlayerRagdollGlobalTagGuardMode", PatchEnableMode.Disabled, "Only Enabled installs global GameObject/Component tag lookup, CompareTag, and tag setter guards. Auto is treated as disabled for these global hooks. The targeted DeadBodyInfo ragdoll guard remains active. Requires restart."); ParticleMeshShapeGuardMode = config.Bind<PatchEnableMode>("Performance", "ParticleMeshShapeGuardMode", PatchEnableMode.Disabled, "Only Enabled starts ParticleSystem mesh shape scans after scene load. Auto is treated as disabled for this scene scan. Requires restart."); ParticleMeshShapeGuardDryRun = config.Bind<bool>("Performance", "ParticleMeshShapeGuardDryRun", false, "When true, ParticleMeshShapeGuard logs invalid particle mesh shapes without disabling them. Requires restart."); EntranceTeleportUpdateGuardMode = config.Bind<PatchEnableMode>("EntranceTeleport", "EntranceTeleportUpdateGuardMode", PatchEnableMode.Auto, "Auto enables the guarded EntranceTeleport.Update replacement only for the verified game assembly."); FindMainEntrancePositionFallbackMode = config.Bind<PatchEnableMode>("EntranceTeleport", "FindMainEntrancePositionFallbackMode", PatchEnableMode.Auto, "Auto enables the guarded RoundManager.FindMainEntrancePosition fallback only for the verified game assembly. Disabled preserves vanilla origin fallback."); ThrowObjectClientRpcGuardMode = config.Bind<PatchEnableMode>("PlayerControllerB", "ThrowObjectClientRpcGuardMode", PatchEnableMode.Auto, "Auto enables the ThrowObjectClientRpc guard only for the verified game assembly. Enabled forces it on; Disabled turns it off."); VoiceRefreshFallbackMode = config.Bind<PatchEnableMode>("Voice", "VoiceRefreshFallbackMode", PatchEnableMode.Auto, "Auto enables the voice refresh fallback only for the verified game assembly. Enabled forces it on; Disabled turns it off."); UnlockableSuitGuardMode = config.Bind<PatchEnableMode>("UnlockableSuit", "UnlockableSuitGuardMode", PatchEnableMode.Auto, "Auto enables suit/unlockable sync guards only for the verified game assembly. Enabled forces them on; Disabled turns them off."); NetworkObjectParentGuardMode = config.Bind<PatchEnableMode>("NetworkObjectParent", "NetworkObjectParentGuardMode", PatchEnableMode.Auto, "Auto suppresses only the known Netcode unspawned reparent SpawnStateException on the verified game assembly. Enabled forces it on; Disabled turns it off."); SteamValveDamageTriggerSpawnGuardMode = config.Bind<PatchEnableMode>("SteamValve", "SteamValveDamageTriggerSpawnGuardMode", PatchEnableMode.Disabled, "Disabled by default because the Netcode warning \"damageTrigger is disabled! Netcode for GameObjects does not support spawning disabled NetworkBehaviours\" is usually a one-time spawn lifecycle warning, not a performance issue. Only Enabled installs the experimental SteamValveHazard damageTrigger spawn guard, which temporarily activates the inactive damageTrigger InteractTrigger during Netcode spawn and then restores it inactive. Auto is treated as disabled for this guard to avoid changing object activation unless a SteamValve damageTrigger gameplay issue is confirmed. Requires restart."); EnemyHealthBarsLateUpdateGuardMode = config.Bind<PatchEnableMode>("OptionalCompatibility", "EnemyHealthBarsLateUpdateGuardMode", PatchEnableMode.Auto, "Auto enables the EnemyHealthBars HealthBar.LateUpdate compatibility guard only on a verified game assembly when the expected target signature is present. Enabled forces it on; Disabled turns it off."); ShipLootPlusUiHelperGuardMode = config.Bind<PatchEnableMode>("OptionalCompatibility", "ShipLootPlusUiHelperGuardMode", PatchEnableMode.Auto, "Auto enables the ShipLootPlus UiHelper compatibility guard only on a verified game assembly when at least one expected target signature is present. Enabled forces it on; Disabled turns it off."); NightVisionInsideLightingPostfixGuardMode = config.Bind<PatchEnableMode>("OptionalCompatibility", "NightVisionInsideLightingPostfixGuardMode", PatchEnableMode.Auto, "Auto enables the ToggleableNightVision InsideLightingPostfix compatibility guard only on a verified game assembly when the expected target signature is present. Enabled forces it on; Disabled turns it off."); ChatCommandsStartHostPostfixGuardMode = config.Bind<PatchEnableMode>("OptionalCompatibility", "ChatCommandsStartHostPostfixGuardMode", PatchEnableMode.Auto, "Auto enables the ChatCommands StartHost postfix compatibility guard only on a verified game assembly when the expected target signature is present. Enabled forces it on; Disabled turns it off."); EnableEnemyAINavMeshGuard = config.Bind<bool>("EnemyAI.NavMesh", "EnableEnemyAINavMeshGuard", true, "Suppresses known EnemyAI SetDestination errors when an agent is off the NavMesh."); AllowEnemyAIWarp = config.Bind<bool>("EnemyAI.NavMesh", "AllowEnemyAIWarp", false, "Allows the guard to warp an off-mesh enemy back to a nearby valid NavMesh point."); EnemyAINavMeshMaxWarpRadius = config.Bind<float>("EnemyAI.NavMesh", "EnemyAINavMeshMaxWarpRadius", 16f, "Maximum radius used when looking for a nearby NavMesh recovery point."); EnemyAINavMeshHostServerOnly = config.Bind<bool>("EnemyAI.NavMesh", "EnemyAINavMeshHostServerOnly", true, "Only allows active EnemyAI NavMesh recovery on host/server. Non-authority clients only suppress the unsafe tick."); } } internal static class GameAssemblyIdentity { internal const string VerifiedAssemblySha256 = "5f7db5538b78dc408845a3002907619785ac9f9c6b6059d13dc9a602d9b65731"; internal const string VerifiedAssemblyMvid = "aca1e98d-6f84-4d3f-85cd-22b6f7be2f9b"; internal static string CurrentAssemblySha256 { get; private set; } internal static string CurrentAssemblyMvid { get; private set; } internal static bool IsVerified { get; private set; } internal static void Initialize() { Assembly assembly = typeof(StartOfRound).Assembly; CurrentAssemblyMvid = assembly.ManifestModule.ModuleVersionId.ToString(); CurrentAssemblySha256 = TryComputeSha256(assembly.Location); IsVerified = string.Equals(CurrentAssemblyMvid, "aca1e98d-6f84-4d3f-85cd-22b6f7be2f9b", StringComparison.OrdinalIgnoreCase) && string.Equals(CurrentAssemblySha256, "5f7db5538b78dc408845a3002907619785ac9f9c6b6059d13dc9a602d9b65731", StringComparison.OrdinalIgnoreCase); } private static string TryComputeSha256(string path) { try { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return null; } using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); byte[] array = sHA.ComputeHash(inputStream); return BitConverter.ToString(array).Replace("-", string.Empty).ToLowerInvariant(); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Could not compute Assembly-CSharp SHA256: " + ex.GetType().Name + ".")); } return null; } } } internal static class NullRefGuard { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly HashSet<string> LoggedExceptionDetails = new HashSet<string>(); internal static Exception Suppress(Exception exception, string key, Func<bool> isKnownSafeCase) { if (exception == null) { return null; } if (!(exception is NullReferenceException)) { return exception; } if (!IsKnownSafeCase(key, isKnownSafeCase)) { return exception; } Warnings.Warn(key, () => LoggedExceptionDetails.Add(key) ? $"Suppressed known NullReferenceException in {key}. First exception detail: {exception}" : ("Suppressed known NullReferenceException in " + key + "; the object will safely retry on later updates.")); return null; } internal static void Clear() { Warnings.Clear(); LoggedExceptionDetails.Clear(); } private static bool IsKnownSafeCase(string key, Func<bool> isKnownSafeCase) { if (isKnownSafeCase == null) { return false; } try { return isKnownSafeCase(); } catch (Exception ex) { Warnings.Warn("classifier-failed|" + key, "NullRefGuard classifier failed for " + key + "; returning original exception: " + ex.GetType().Name + "."); return false; } } } internal sealed class ParticleMeshShapeGuard : MonoBehaviour { private sealed class ParticleMeshWarningBatch { internal readonly string MeshName; internal readonly string Reason; internal readonly bool DryRun; internal readonly HashSet<string> ParticleSystemNames = new HashSet<string>(); internal int OmittedParticleSystemCount; internal ParticleMeshWarningBatch(string meshName, string reason, bool dryRun) { MeshName = meshName; Reason = reason; DryRun = dryRun; } internal void AddParticleSystemName(string particleSystemName) { if (ParticleSystemNames.Count < 16) { ParticleSystemNames.Add(particleSystemName); } else if (!ParticleSystemNames.Contains(particleSystemName)) { OmittedParticleSystemCount++; } } } private sealed class CachedMeshInspection { internal readonly Mesh Mesh; internal readonly MeshInspectionStatus Status; internal readonly string InvalidReason; internal CachedMeshInspection(Mesh mesh, MeshInspectionStatus status, string invalidReason) { Mesh = mesh; Status = status; InvalidReason = invalidReason; } } private sealed class MeshInspectionProgress { internal readonly Mesh Mesh; internal readonly int VertexCount; internal readonly int SubMeshCount; internal readonly int SubMeshIndex; internal readonly int TriangleIndex; internal readonly double Area; internal MeshInspectionProgress(Mesh mesh, int vertexCount, int subMeshCount, int subMeshIndex, int triangleIndex, double area) { Mesh = mesh; VertexCount = vertexCount; SubMeshCount = subMeshCount; SubMeshIndex = subMeshIndex; TriangleIndex = triangleIndex; Area = area; } } private enum MeshInspectionStatus { Valid, Invalid, Incomplete } private const int ScanBatchSize = 64; private const float ScanFrameBudgetSeconds = 0.0025f; private const int MeshInspectionCacheCleanupThreshold = 256; private const int MaxFullAreaScanVertices = 32768; private const int MaxFullAreaScanIndices = 98304; private const int MaxPendingWarningBatches = 64; private const int MaxParticleSystemNamesPerWarning = 16; private static ParticleMeshShapeGuard _instance; private bool _scanRequested; private ParticleSystem[] _scanQueue; private int _scanIndex; private readonly Dictionary<int, ParticleSystem> _patchedParticleSystems = new Dictionary<int, ParticleSystem>(); private readonly WarningLimiter _warnings = new WarningLimiter(); private readonly Dictionary<string, ParticleMeshWarningBatch> _pendingWarnings = new Dictionary<string, ParticleMeshWarningBatch>(); private readonly Dictionary<int, CachedMeshInspection> _meshInspectionCache = new Dictionary<int, CachedMeshInspection>(); private readonly Dictionary<int, MeshInspectionProgress> _meshInspectionProgress = new Dictionary<int, MeshInspectionProgress>(); private List<Vector3> _meshVertices = new List<Vector3>(); private List<int> _meshTriangles = new List<int>(); internal static void EnsureCreated() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ParticleMeshShapeGuard particleMeshShapeGuard = Object.FindObjectOfType<ParticleMeshShapeGuard>(); if ((Object)(object)particleMeshShapeGuard != (Object)null) { _instance = particleMeshShapeGuard; _instance.RequestSceneScan(); return; } GameObject val = new GameObject("V81ErrorFix.ParticleMeshShapeGuard"); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; _instance = val.AddComponent<ParticleMeshShapeGuard>(); _instance.RequestSceneScan(); } internal static void NotifySceneLoaded() { if (!((Object)(object)_instance == (Object)null)) { _instance.RequestSceneScan(); } } internal static void NotifySceneUnloaded() { if (!((Object)(object)_instance == (Object)null)) { _instance.ClearSceneCaches(); } } private void Awake() { _instance = this; } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void Update() { if (_scanQueue != null) { ContinueParticleSystemScan(); } else if (_scanRequested) { _scanRequested = false; BeginParticleSystemScan(); ContinueParticleSystemScan(); } } private void RequestSceneScan() { _scanRequested = true; } private void BeginParticleSystemScan() { _pendingWarnings.Clear(); _scanQueue = Object.FindObjectsOfType<ParticleSystem>(true); _scanIndex = 0; } private void ContinueParticleSystemScan() { if (_scanQueue != null) { int num = Math.Min(_scanIndex + 64, _scanQueue.Length); float num2 = Time.realtimeSinceStartup + 0.0025f; while (_scanIndex < num && Time.realtimeSinceStartup < num2) { TryPatchParticleSystem(_scanQueue[_scanIndex], num2); _scanIndex++; } if (_scanIndex >= _scanQueue.Length) { _scanQueue = null; _scanIndex = 0; FlushParticleMeshWarnings(); } } } private void TryPatchParticleSystem(ParticleSystem particleSystem, float scanDeadline) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) if ((Object)(object)particleSystem == (Object)null) { return; } int instanceID = ((Object)particleSystem).GetInstanceID(); if (_patchedParticleSystems.TryGetValue(instanceID, out var value) && (Object)(object)value == (Object)(object)particleSystem) { return; } try { ShapeModule shape = particleSystem.shape; if (!((ShapeModule)(ref shape)).enabled || !TryGetShapeMesh(shape, out var mesh) || (Object)(object)mesh == (Object)null) { return; } string invalidReason; switch (GetInvalidMeshReasonCached(mesh, scanDeadline, out invalidReason)) { case MeshInspectionStatus.Incomplete: _scanIndex--; return; case MeshInspectionStatus.Valid: return; } if (!IsDryRun()) { ((ShapeModule)(ref shape)).enabled = false; } _patchedParticleSystems[instanceID] = particleSystem; QueueParticleMeshWarning(((Object)mesh).name, invalidReason, ((Object)particleSystem).name, IsDryRun()); } catch (Exception ex) { _patchedParticleSystems[instanceID] = particleSystem; QueueParticleMeshWarning("inspection", "could not be inspected safely: " + ex.GetType().Name, ((Object)particleSystem).name); } } private void ClearSceneCaches() { _scanQueue = null; _scanIndex = 0; _scanRequested = false; _pendingWarnings.Clear(); _patchedParticleSystems.Clear(); _meshInspectionCache.Clear(); _meshInspectionProgress.Clear(); _warnings.Clear(); } private void QueueParticleMeshWarning(string meshName, string reason, string particleSystemName, bool dryRun = false) { string key = $"{meshName}|{reason}|{dryRun}"; if (!_warnings.CanWarn(key)) { return; } if (!_pendingWarnings.TryGetValue(key, out var value)) { if (_pendingWarnings.Count >= 64) { return; } value = new ParticleMeshWarningBatch(meshName, reason, dryRun); _pendingWarnings[key] = value; } value.AddParticleSystemName(particleSystemName); } private void FlushParticleMeshWarnings() { foreach (KeyValuePair<string, ParticleMeshWarningBatch> pendingWarning in _pendingWarnings) { ParticleMeshWarningBatch warningBatch = pendingWarning.Value; _warnings.Warn(pendingWarning.Key, delegate { string text = string.Join(", ", warningBatch.ParticleSystemNames); if (warningBatch.OmittedParticleSystemCount > 0) { text = $"{text}, and {warningBatch.OmittedParticleSystemCount} more"; } string text2 = (warningBatch.DryRun ? "Would disable" : "Disabled"); return text2 + " mesh shape because mesh '" + warningBatch.MeshName + "' " + warningBatch.Reason + " on particle systems: " + text + "."; }); } } private MeshInspectionStatus GetInvalidMeshReasonCached(Mesh mesh, float scanDeadline, out string invalidReason) { invalidReason = null; int instanceID = ((Object)mesh).GetInstanceID(); if (_meshInspectionCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Mesh == (Object)(object)mesh) { invalidReason = value.InvalidReason; return value.Status; } MeshInspectionStatus invalidMeshReason = GetInvalidMeshReason(mesh, instanceID, scanDeadline, out invalidReason); if (invalidMeshReason == MeshInspectionStatus.Incomplete) { return invalidMeshReason; } _meshInspectionProgress.Remove(instanceID); _meshInspectionCache[instanceID] = new CachedMeshInspection(mesh, invalidMeshReason, invalidReason); CleanupMeshInspectionCacheIfNeeded(); return invalidMeshReason; } private void CleanupMeshInspectionCacheIfNeeded() { if (_meshInspectionCache.Count < 256) { return; } List<int> list = null; foreach (KeyValuePair<int, CachedMeshInspection> item in _meshInspectionCache) { if (!((Object)(object)item.Value.Mesh != (Object)null)) { if (list == null) { list = new List<int>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { _meshInspectionCache.Remove(list[i]); } } } private static bool TryGetShapeMesh(ShapeModule shape, out Mesh mesh) { //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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 mesh = null; ParticleSystemShapeType shapeType = ((ShapeModule)(ref shape)).shapeType; ParticleSystemShapeType val = shapeType; if ((int)val != 6) { if ((int)val != 13) { if ((int)val == 14) { mesh = (((Object)(object)((ShapeModule)(ref shape)).skinnedMeshRenderer != (Object)null) ? ((ShapeModule)(ref shape)).skinnedMeshRenderer.sharedMesh : null); return (Object)(object)mesh != (Object)null; } return false; } object obj; if (!((Object)(object)((ShapeModule)(ref shape)).meshRenderer != (Object)null)) { obj = null; } else { MeshFilter component = ((Component)((ShapeModule)(ref shape)).meshRenderer).GetComponent<MeshFilter>(); obj = ((component != null) ? component.sharedMesh : null); } mesh = (Mesh)obj; return (Object)(object)mesh != (Object)null; } mesh = ((ShapeModule)(ref shape)).mesh; return (Object)(object)mesh != (Object)null; } private MeshInspectionStatus GetInvalidMeshReason(Mesh mesh, int meshId, float scanDeadline, out string invalidReason) { //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024c: 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_0258: Unknown result type (might be due to invalid IL or missing references) invalidReason = null; if (!mesh.isReadable) { invalidReason = "is not readable"; return MeshInspectionStatus.Invalid; } int vertexCount = mesh.vertexCount; int subMeshCount = mesh.subMeshCount; if (vertexCount == 0 || subMeshCount <= 0) { invalidReason = "has zero surface area"; return MeshInspectionStatus.Invalid; } try { bool flag = false; ulong num = 0uL; for (int i = 0; i < subMeshCount; i++) { uint indexCount = mesh.GetIndexCount(i); if (indexCount >= 3) { flag = true; } num += indexCount; } if (!flag) { invalidReason = "has zero surface area"; return MeshInspectionStatus.Invalid; } if (vertexCount > 32768 || num > 98304) { return MeshInspectionStatus.Valid; } MeshInspectionProgress meshInspectionProgress = null; if (_meshInspectionProgress.TryGetValue(meshId, out var value) && (Object)(object)value.Mesh == (Object)(object)mesh && value.VertexCount == vertexCount && value.SubMeshCount == subMeshCount) { meshInspectionProgress = value; } _meshVertices.Clear(); _meshTriangles.Clear(); mesh.GetVertices(_meshVertices); int num2 = Math.Min(meshInspectionProgress?.SubMeshIndex ?? 0, subMeshCount - 1); for (int j = num2; j < subMeshCount; j++) { _meshTriangles.Clear(); mesh.GetTriangles(_meshTriangles, j); if (_meshTriangles.Count < 3) { continue; } double num3 = ((j != num2) ? 0.0 : (meshInspectionProgress?.Area ?? 0.0)); int num4 = ((j == num2) ? (meshInspectionProgress?.TriangleIndex ?? 0) : 0); num4 -= num4 % 3; for (int k = num4; k + 2 < _meshTriangles.Count; k += 3) { Vector3 val = _meshVertices[_meshTriangles[k]]; Vector3 val2 = _meshVertices[_meshTriangles[k + 1]]; Vector3 val3 = _meshVertices[_meshTriangles[k + 2]]; double num5 = num3; Vector3 val4 = Vector3.Cross(val2 - val, val3 - val); num3 = num5 + (double)((Vector3)(ref val4)).magnitude * 0.5; if (num3 > 0.0001) { return MeshInspectionStatus.Valid; } if (Time.realtimeSinceStartup >= scanDeadline) { _meshInspectionProgress[meshId] = new MeshInspectionProgress(mesh, vertexCount, subMeshCount, j, Math.Min(k + 3, _meshTriangles.Count), num3); return MeshInspectionStatus.Incomplete; } } } } catch { invalidReason = "could not be inspected safely"; return MeshInspectionStatus.Invalid; } finally { TrimMeshScratchLists(); } invalidReason = "has zero surface area"; return MeshInspectionStatus.Invalid; } private void TrimMeshScratchLists() { if (_meshVertices.Capacity > 65536) { _meshVertices = new List<Vector3>(); } else { _meshVertices.Clear(); } if (_meshTriangles.Capacity > 65536) { _meshTriangles = new List<int>(); } else { _meshTriangles.Clear(); } } private static bool IsDryRun() { return ErrorFixConfig.ParticleMeshShapeGuardDryRun != null && ErrorFixConfig.ParticleMeshShapeGuardDryRun.Value; } } internal sealed class WarningLimiter { private const string OverflowKey = "__overflow__"; private static readonly List<WarningLimiter> SceneScopedLimiters = new List<WarningLimiter>(); private readonly int _maxWarnings; private readonly int _maxKeyCount; private readonly Dictionary<string, int> _warningCounts = new Dictionary<string, int>(); internal WarningLimiter(int maxWarnings = 5, int maxKeyCount = 512, bool clearOnSceneChange = true) { _maxWarnings = maxWarnings; _maxKeyCount = Math.Max(1, maxKeyCount); if (clearOnSceneChange) { SceneScopedLimiters.Add(this); } } internal void Warn(string key, string message) { if (TryIncrement(key, out var warningCount)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({warningCount}/{_maxWarnings})"); } } } internal void Warn(string key, Func<string> messageFactory) { if (TryIncrement(key, out var warningCount)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{messageFactory()} ({warningCount}/{_maxWarnings})"); } } } internal bool CanWarn(string key) { _warningCounts.TryGetValue(GetEffectiveKeyForRead(NormalizeKey(key)), out var value); return value < _maxWarnings; } internal int KeyCount() { return _warningCounts.Count; } internal void Clear() { _warningCounts.Clear(); } internal void ClearPrefix(string prefix) { if (string.IsNullOrEmpty(prefix) || _warningCounts.Count == 0) { return; } List<string> list = null; foreach (string key in _warningCounts.Keys) { if (key.StartsWith(prefix, StringComparison.Ordinal)) { if (list == null) { list = new List<string>(); } list.Add(key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { _warningCounts.Remove(list[i]); } } } internal static void ClearSceneScopedLimiters() { for (int i = 0; i < SceneScopedLimiters.Count; i++) { SceneScopedLimiters[i]?.Clear(); } } private bool TryIncrement(string key, out int warningCount) { key = NormalizeKey(key); key = ApplyKeyLimit(key); _warningCounts.TryGetValue(key, out warningCount); if (warningCount >= _maxWarnings) { return false; } warningCount++; _warningCounts[key] = warningCount; return true; } private string ApplyKeyLimit(string incomingKey) { if (_warningCounts.ContainsKey(incomingKey) || _warningCounts.Count < _maxKeyCount) { return incomingKey; } if (_warningCounts.ContainsKey("__overflow__") || _warningCounts.Count < _maxKeyCount + 1) { return "__overflow__"; } string text = null; foreach (string key in _warningCounts.Keys) { if (key == "__overflow__") { continue; } text = key; break; } if (text != null) { _warningCounts.Remove(text); } return "__overflow__"; } private string GetEffectiveKeyForRead(string incomingKey) { if (_warningCounts.ContainsKey(incomingKey) || _warningCounts.Count < _maxKeyCount) { return incomingKey; } return "__overflow__"; } private static string NormalizeKey(string key) { return string.IsNullOrEmpty(key) ? "unknown" : key; } } [HarmonyPatch] internal static class DisabledAudioSourcePlayGuardPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return PatchModeUtility.IsExplicitlyEnabled(ErrorFixConfig.AudioSourcePlaybackGuardMode); } [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { MethodInfo[] methods = typeof(AudioSource).GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo method in methods) { if (method.DeclaringType == typeof(AudioSource) && IsPlaybackMethod(method)) { yield return method; } } } private static bool Prefix(AudioSource __instance, MethodBase __originalMethod) { try { return ShouldAllowPlayback(__instance, __originalMethod); } catch (Exception ex) { GuardFailureWarnings.Warn("guard-failure", "Disabled AudioSource guard failed safely and allowed original playback: " + ex.GetType().Name + "."); return true; } } private static bool ShouldAllowPlayback(AudioSource audioSource, MethodBase originalMethod) { if ((Object)(object)audioSource == (Object)null || ((Behaviour)audioSource).isActiveAndEnabled) { return true; } string methodName = originalMethod?.Name ?? "Play"; string key = $"{((Object)audioSource).GetInstanceID()}|{methodName}"; Warnings.Warn(key, delegate { string transformPath = GetTransformPath(((Component)audioSource).transform); return $"Suppressed disabled AudioSource {methodName} on '{transformPath}' because AudioSource.enabled={((Behaviour)audioSource).enabled}, activeInHierarchy={(Object)(object)((Component)audioSource).gameObject != (Object)null && ((Component)audioSource).gameObject.activeInHierarchy}."; }); return false; } private static bool IsPlaybackMethod(MethodInfo method) { return method.ReturnType == typeof(void) && (method.Name == "Play" || method.Name == "PlayDelayed" || method.Name == "PlayScheduled" || method.Name == "PlayOneShot"); } internal static string GetTransformPath(Transform transform) { if ((Object)(object)transform == (Object)null) { return "unknown"; } string text = ((Object)transform).name; Transform parent = transform.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } } [HarmonyPatch] internal static class AudioSourcePlayOneShotNullClipGuardPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return PatchModeUtility.IsExplicitlyEnabled(ErrorFixConfig.AudioSourcePlaybackGuardMode); } [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { MethodInfo playOneShot = AccessTools.Method(typeof(AudioSource), "PlayOneShot", new Type[1] { typeof(AudioClip) }, (Type[])null); if (playOneShot != null) { yield return playOneShot; } MethodInfo playOneShotWithScale = AccessTools.Method(typeof(AudioSource), "PlayOneShot", new Type[2] { typeof(AudioClip), typeof(float) }, (Type[])null); if (playOneShotWithScale != null) { yield return playOneShotWithScale; } } private static bool Prefix(AudioSource __instance, AudioClip __0) { try { if ((Object)(object)__0 != (Object)null) { return true; } WarnNullClip(__instance); return false; } catch (Exception ex) { GuardFailureWarnings.Warn("guard-failure", "AudioSource null AudioClip guard failed safely and allowed original PlayOneShot: " + ex.GetType().Name + "."); return true; } } private static void WarnNullClip(AudioSource audioSource) { string key = (((Object)(object)audioSource != (Object)null) ? $"null-clip|{((Object)audioSource).GetInstanceID()}" : "null-clip|unknown"); Warnings.Warn(key, delegate { string text = (((Object)(object)audioSource != (Object)null) ? DisabledAudioSourcePlayGuardPatch.GetTransformPath(((Component)audioSource).transform) : "unknown"); return "Suppressed AudioSource.PlayOneShot on '" + text + "' because AudioClip was null."; }); } } [HarmonyPatch(typeof(BushWolfEnemy), "Update")] internal static class BushWolfEnemyUpdatePatch { private static bool Prefix(BushWolfEnemy __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } if ((Object)(object)((EnemyAI)__instance).agent == (Object)null || (Object)(object)((EnemyAI)__instance).creatureAnimator == (Object)null || (Object)(object)__instance.animationContainer == (Object)null) { return false; } return true; } private static Exception Finalizer(BushWolfEnemy __instance, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } if ((Object)(object)__instance != (Object)null) { try { ((EnemyAI)__instance).targetPlayer = null; ((EnemyAI)__instance).movingTowardsTargetPlayer = false; } catch { } } return NullRefGuard.Suppress(__exception, "BushWolfEnemy.Update", () => (Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)((EnemyAI)__instance).agent == (Object)null || (Object)(object)((EnemyAI)__instance).creatureAnimator == (Object)null || (Object)(object)__instance.animationContainer == (Object)null); } } [HarmonyPatch(typeof(BushWolfEnemy), "LateUpdate")] internal static class BushWolfEnemyLateUpdatePatch { private static bool Prefix(BushWolfEnemy __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } if ((Object)(object)__instance.tongue == (Object)null || (Object)(object)__instance.tongueStartPoint == (Object)null || (Object)(object)__instance.animationContainer == (Object)null || (Object)(object)__instance.bendHeadBack == (Object)null || __instance.proceduralBodyTargets == null || __instance.IKTargetContainers == null || __instance.IKTargetContainers.Length < __instance.proceduralBodyTargets.Length) { return false; } return true; } private static Exception Finalizer(BushWolfEnemy __instance, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } return NullRefGuard.Suppress(__exception, "BushWolfEnemy.LateUpdate", () => (Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)__instance.tongue == (Object)null || (Object)(object)__instance.tongueStartPoint == (Object)null || (Object)(object)__instance.animationContainer == (Object)null || (Object)(object)__instance.bendHeadBack == (Object)null || __instance.proceduralBodyTargets == null || __instance.IKTargetContainers == null || __instance.IKTargetContainers.Length < __instance.proceduralBodyTargets.Length); } } [HarmonyPatch(typeof(DocileLocustBeesAI), "Update")] internal static class DocileLocustBeesAIUpdatePatch { private static bool Prefix(DocileLocustBeesAI __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.activeCamera == (Object)null || (Object)(object)__instance.bugsEffect == (Object)null || (Object)(object)((EnemyAI)__instance).creatureVoice == (Object)null || (Object)(object)__instance.scanNode == (Object)null) { return false; } if (((EnemyAI)__instance).currentBehaviourStateIndex == 1 && ((Object)(object)((EnemyAI)__instance).creatureSFX == (Object)null || (Object)(object)((EnemyAI)__instance).enemyType == (Object)null || ((EnemyAI)__instance).enemyType.audioClips == null || ((EnemyAI)__instance).enemyType.audioClips.Length == 0 || (Object)(object)RoundManager.Instance == (Object)null)) { return false; } return true; } private static Exception Finalizer(DocileLocustBeesAI __instance, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } return NullRefGuard.Suppress(__exception, "DocileLocustBeesAI.Update", () => (Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.activeCamera == (Object)null || (Object)(object)__instance.bugsEffect == (Object)null || (Object)(object)((EnemyAI)__instance).creatureVoice == (Object)null || (Object)(object)__instance.scanNode == (Object)null || (((EnemyAI)__instance).currentBehaviourStateIndex == 1 && ((Object)(object)((EnemyAI)__instance).creatureSFX == (Object)null || (Object)(object)((EnemyAI)__instance).enemyType == (Object)null || ((EnemyAI)__instance).enemyType.audioClips == null || ((EnemyAI)__instance).enemyType.audioClips.Length == 0 || (Object)(object)RoundManager.Instance == (Object)null))); } } [HarmonyPatch(typeof(CrawlerAI), "Update")] internal static class CrawlerAIUpdatePatch { private static bool Prefix(CrawlerAI __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } if ((Object)(object)((EnemyAI)__instance).agent == (Object)null || (Object)(object)((EnemyAI)__instance).creatureAnimator == (Object)null || (Object)(object)((Component)__instance).transform == (Object)null || __instance.searchForPlayers == null) { return false; } return true; } private static Exception Finalizer(CrawlerAI __instance, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } if ((Object)(object)__instance != (Object)null) { try { ((EnemyAI)__instance).movingTowardsTargetPlayer = false; } catch { } } return NullRefGuard.Suppress(__exception, "CrawlerAI.Update", () => (Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null || (Object)(object)((EnemyAI)__instance).agent == (Object)null || (Object)(object)((EnemyAI)__instance).creatureAnimator == (Object)null || (Object)(object)((Component)__instance).transform == (Object)null || __instance.searchForPlayers == null); } } [HarmonyPatch(typeof(EntranceTeleport), "Update")] internal static class EntranceTeleportUpdatePatch { private sealed class HoverTipState { internal string DefaultHoverTip; } private const float EnemyNearDistanceSqr = 59.289997f; private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly ConditionalWeakTable<EntranceTeleport, HoverTipState> HoverTipStates = new ConditionalWeakTable<EntranceTeleport, HoverTipState>(); private static bool Prefix(EntranceTeleport __instance) { //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) if (!IsPatchEnabled()) { return true; } if ((Object)(object)__instance == (Object)null || !__instance.isEntranceToBuilding || (Object)(object)RoundManager.Instance == (Object)null) { return false; } InteractTrigger triggerScript = __instance.triggerScript; if ((Object)(object)triggerScript == (Object)null) { Warnings.Warn("missing-trigger", "Skipped EntranceTeleport.Update guard because triggerScript was missing."); return false; } if (__instance.checkForEnemiesInterval > 0f) { __instance.checkForEnemiesInterval -= Time.deltaTime; return false; } if (!__instance.gotExitPoint) { if (__instance.FindExitPoint()) { __instance.gotExitPoint = true; } else { Warnings.Warn("missing-exit|" + GetEntranceName(__instance), "Skipped EntranceTeleport.Update for '" + GetEntranceName(__instance) + "' because no exit point was found."); } return false; } if (((Object)(object)__instance.exitScript == (Object)null || (Object)(object)__instance.exitScript.entrancePoint == (Object)null) && !__instance.FindExitPoint()) { Warnings.Warn("missing-exit-point|" + GetEntranceName(__instance), "Skipped EntranceTeleport.Update for '" + GetEntranceName(__instance) + "' because exitScript or entrancePoint was missing."); return false; } __instance.checkForEnemiesInterval = 1f; bool flag = false; if (RoundManager.Instance.SpawnedEnemies != null) { foreach (EnemyAI spawnedEnemy in RoundManager.Instance.SpawnedEnemies) { if (!((Object)(object)spawnedEnemy == (Object)null) && !((Object)(object)((Component)spawnedEnemy).transform == (Object)null) && !spawnedEnemy.isEnemyDead) { if ((Object)(object)__instance.exitScript == (Object)null || (Object)(object)__instance.exitScript.entrancePoint == (Object)null) { break; } Vector3 val = ((Component)spawnedEnemy).transform.position - __instance.exitScript.entrancePoint.position; if (((Vector3)(ref val)).sqrMagnitude < 59.289997f) { flag = true; break; } } } } if (flag && !__instance.enemyNearLastCheck) { __instance.enemyNearLastCheck = true; SaveDefaultHoverTip(__instance, triggerScript); triggerScript.hoverTip = "[Near activity detected!]"; } else if (!flag && __instance.enemyNearLastCheck) { __instance.enemyNearLastCheck = false; triggerScript.hoverTip = GetDefaultHoverTip(__instance, triggerScript); } return false; } private static Exception Finalizer(EntranceTeleport __instance, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } return NullRefGuard.Suppress(__exception, "EntranceTeleport.Update", () => IsPatchEnabled() && ((Object)(object)__instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null || (Object)(object)__instance.triggerScript == (Object)null || (Object)(object)__instance.exitScript == (Object)null || (Object)(object)__instance.exitScript.entrancePoint == (Object)null)); } private static bool IsPatchEnabled() { return PatchModeUtility.IsEnabled(ErrorFixConfig.EntranceTeleportUpdateGuardMode); } private static void SaveDefaultHoverTip(EntranceTeleport entrance, InteractTrigger trigger) { if (!((Object)(object)entrance == (Object)null) && !((Object)(object)trigger == (Object)null)) { HoverTipState orCreateValue = HoverTipStates.GetOrCreateValue(entrance); if (!string.Equals(trigger.hoverTip, "[Near activity detected!]", StringComparison.Ordinal)) { orCreateValue.DefaultHoverTip = trigger.hoverTip; } } } private static string GetDefaultHoverTip(EntranceTeleport entrance, InteractTrigger trigger) { if ((Object)(object)entrance != (Object)null && HoverTipStates.TryGetValue(entrance, out var value) && !string.IsNullOrEmpty(value.DefaultHoverTip)) { return value.DefaultHoverTip; } return ((Object)(object)trigger != (Object)null) ? trigger.hoverTip : string.Empty; } private static string GetEntranceName(EntranceTeleport entrance) { return ((Object)(object)entrance != (Object)null && (Object)(object)((Component)entrance).gameObject != (Object)null) ? ((Object)((Component)entrance).gameObject).name : "unknown"; } } [HarmonyPatch(typeof(RoundManager), "FindMainEntrancePosition")] internal static class RoundManagerFindMainEntrancePositionPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static EntranceTeleport[] cachedEntrances; private static int cachedSceneHandle = int.MinValue; [HarmonyPrepare] private static bool Prepare() { return PatchModeUtility.IsEnabled(ErrorFixConfig.FindMainEntrancePositionFallbackMode); } private static bool Prefix(bool getTeleportPosition, bool getOutsideEntrance, ref Vector3 __result) { //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) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) EntranceTeleport[] array = GetCachedEntrances(); EntranceTeleport fallbackEntrance = null; EntranceTeleport fallbackMainEntrance = null; if (TryFindEntrance(array, getTeleportPosition, getOutsideEntrance, ref __result, ref fallbackEntrance, ref fallbackMainEntrance)) { return false; } if ((Object)(object)fallbackEntrance == (Object)null && array.Length != 0) { array = RefreshEntranceCache(); if (TryFindEntrance(array, getTeleportPosition, getOutsideEntrance, ref __result, ref fallbackEntrance, ref fallbackMainEntrance)) { return false; } } EntranceTeleport val = fallbackMainEntrance ?? fallbackEntrance; if ((Object)(object)val != (Object)null) { __result = GetEntrancePosition(val, getTeleportPosition); Warn("Main entrance position was missing; using the first available EntranceTeleport instead of origin."); return false; } __result = Vector3.zero; if (!IsCompanyLevel()) { Warn("Main entrance position was missing and no EntranceTeleport fallback existed; returning origin."); } return false; } private static bool TryFindEntrance(EntranceTeleport[] entrances, bool getTeleportPosition, bool getOutsideEntrance, ref Vector3 result, ref EntranceTeleport fallbackEntrance, ref EntranceTeleport fallbackMainEntrance) { //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) foreach (EntranceTeleport val in entrances) { if (!((Object)(object)val == (Object)null)) { if (fallbackEntrance == null) { fallbackEntrance = val; } if (val.entranceId == 0 && fallbackMainEntrance == null) { fallbackMainEntrance = val; } if (val.entranceId == 0 && val.isEntranceToBuilding == getOutsideEntrance) { result = GetEntrancePosition(val, getTeleportPosition); return true; } } } return false; } private static EntranceTeleport[] GetCachedEntrances() { //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) Scene activeScene = SceneManager.GetActiveScene(); int handle = ((Scene)(ref activeScene)).handle; if (cachedEntrances == null || cachedSceneHandle != handle || cachedEntrances.Length == 0) { return RefreshEntranceCache(handle); } return cachedEntrances; } private static EntranceTeleport[] RefreshEntranceCache() { //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) Scene activeScene = SceneManager.GetActiveScene(); return RefreshEntranceCache(((Scene)(ref activeScene)).handle); } private static EntranceTeleport[] RefreshEntranceCache(int activeSceneHandle) { cachedEntrances = Object.FindObjectsOfType<EntranceTeleport>(false); cachedSceneHandle = activeSceneHandle; return cachedEntrances; } internal static void ClearCache() { cachedEntrances = null; cachedSceneHandle = int.MinValue; Warnings.Clear(); } private static Vector3 GetEntrancePosition(EntranceTeleport entrance, bool getTeleportPosition) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0048: 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) if ((Object)(object)entrance == (Object)null) { return Vector3.zero; } if (getTeleportPosition && (Object)(object)entrance.entrancePoint != (Object)null) { return entrance.entrancePoint.position; } return ((Object)(object)((Component)entrance).transform != (Object)null) ? ((Component)entrance).transform.position : Vector3.zero; } private static bool IsCompanyLevel() { SelectableLevel val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.currentLevel : null); if ((Object)(object)val == (Object)null) { return false; } return val.levelID == 3 || string.Equals(val.sceneName, "CompanyBuilding", StringComparison.OrdinalIgnoreCase) || (val.PlanetName != null && val.PlanetName.IndexOf("company", StringComparison.OrdinalIgnoreCase) >= 0); } private static void Warn(string message) { Warnings.Warn("FindMainEntrancePosition", message); } } [HarmonyPatch(typeof(HUDManager), "AddChatMessage")] internal static class HUDManagerAddChatMessagePatch { private const int MaxWarnings = 5; private static int _warningCount; private static bool Prefix(HUDManager __instance) { if (IsHudChatReady(__instance, out var missingDependency)) { return true; } Warn("Skipped HUDManager.AddChatMessage because chat HUD was not ready: " + missingDependency + "."); return false; } private static Exception Finalizer(HUDManager __instance, Exception __exception) { if (__exception is NullReferenceException && !IsHudChatReady(__instance, out var _)) { Warn("Suppressed HUDManager.AddChatMessage NullReferenceException while chat HUD was not ready."); return null; } return __exception; } internal static bool IsHudChatReady(HUDManager hudManager, out string missingDependency) { if ((Object)(object)hudManager == (Object)null) { missingDependency = "HUDManager"; return false; } if (hudManager.Chat == null) { missingDependency = "HUDManager.Chat"; return false; } if ((Object)(object)hudManager.chatText == (Object)null) { missingDependency = "HUDManager.chatText"; return false; } if (hudManager.ChatMessageHistory == null) { missingDependency = "HUDManager.ChatMessageHistory"; return false; } if ((Object)(object)GameNetworkManager.Instance == (Object)null) { missingDependency = "GameNetworkManager.Instance"; return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { missingDependency = "GameNetworkManager.Instance.localPlayerController"; return false; } if ((Object)(object)StartOfRound.Instance == (Object)null) { missingDependency = "StartOfRound.Instance"; return false; } if (StartOfRound.Instance.allPlayerScripts == null || StartOfRound.Instance.allPlayerScripts.Length < 4) { missingDependency = "StartOfRound.Instance.allPlayerScripts"; return false; } int num = Math.Min(4, StartOfRound.Instance.allPlayerScripts.Length); for (int i = 0; i < num; i++) { if ((Object)(object)StartOfRound.Instance.allPlayerScripts[i] == (Object)null) { missingDependency = $"StartOfRound.Instance.allPlayerScripts[{i}]"; return false; } } missingDependency = string.Empty; return true; } internal static void Warn(string message) { if (_warningCount < 5) { _warningCount++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({_warningCount}/{5})"); } } } } [HarmonyPatch(typeof(HUDManager), "AddTextMessageClientRpc")] internal static class HUDManagerAddTextMessageClientRpcPatch { private static readonly WarningLimiter FinalizerWarnings = new WarningLimiter(1); private static bool Prefix(HUDManager __instance) { if (!IsExecutingClientRpc(__instance)) { return true; } if (HUDManagerAddChatMessagePatch.IsHudChatReady(__instance, out var missingDependency)) { return true; } HUDManagerAddChatMessagePatch.Warn("Skipped HUDManager.AddTextMessageClientRpc because chat HUD was not ready: " + missingDependency + "."); return false; } private static Exception Finalizer(HUDManager __instance, Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } if (!RpcExecStageUtility.ShouldAllowClientRpcSuppression((NetworkBehaviour)(object)__instance, "HUDManager.AddTextMessageClientRpc", __exception, FinalizerWarnings)) { return __exception; } if (!HUDManagerAddChatMessagePatch.IsHudChatReady(__instance, out var _)) { HUDManagerAddChatMessagePatch.Warn("Suppressed HUDManager.AddTextMessageClientRpc NullReferenceException while chat HUD was not ready."); return null; } return __exception; } private static bool IsExecutingClientRpc(HUDManager hudManager) { bool isExecuting; return RpcExecStageUtility.TryIsExecuting((NetworkBehaviour)(object)hudManager, out isExecuting) && isExecuting; } } [HarmonyPatch(typeof(HUDManager), "SyncAllPlayerLevelsServerRpc", new Type[] { })] internal static class HUDManagerSyncAllPlayerLevelsServerRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(HUDManager __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)((NetworkBehaviour)__instance).NetworkManager == (Object)null || !((NetworkBehaviour)__instance).NetworkManager.IsListening) { return false; } if ((((NetworkBehaviour)__instance).NetworkManager.IsClient || ((NetworkBehaviour)__instance).NetworkManager.IsHost) && ((NetworkBehaviour)__instance).OwnerClientId != ((NetworkBehaviour)__instance).NetworkManager.LocalClientId) { Warnings.Warn("not-owner", "Skipped HUDManager.SyncAllPlayerLevelsServerRpc because the local client does not own HUDManager."); return false; } return true; } } [HarmonyPatch(typeof(InteractTrigger), "UpdateUsedByPlayerClientRpc")] internal static class InteractTriggerUpdateUsedByPlayerClientRpcPatch { private const int MaxWarnings = 5; private static int _warningCount; private static readonly WarningLimiter FinalizerWarnings = new WarningLimiter(1); private static bool Prefix(InteractTrigger __instance, int playerNum) { if (!IsExecutingClientRpc(__instance)) { return true; } if (IsInteractRpcReady(__instance, playerNum, out var missingDependency)) { return true; } Warn($"Skipped InteractTrigger.UpdateUsedByPlayerClientRpc for player {playerNum} because dependencies were not ready: {missingDependency}."); return false; } private static Exception Finalizer(InteractTrigger __instance, int playerNum, Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } if (!RpcExecStageUtility.ShouldAllowClientRpcSuppression((NetworkBehaviour)(object)__instance, "InteractTrigger.UpdateUsedByPlayerClientRpc", __exception, FinalizerWarnings)) { return __exception; } if (!IsInteractRpcReady(__instance, playerNum, out var _)) { Warn("Suppressed InteractTrigger.UpdateUsedByPlayerClientRpc NullReferenceException while trigger dependencies were not ready."); return null; } return __exception; } private static bool IsInteractRpcReady(InteractTrigger trigger, int playerNum, out string missingDependency) { if ((Object)(object)trigger == (Object)null) { missingDependency = "InteractTrigger"; return false; } if (trigger.onInteractEarlyOtherClients == null) { missingDependency = GetTriggerName(trigger) + ".onInteractEarlyOtherClients"; return false; } if (!TryGetPlayer(playerNum, out var player, out missingDependency)) { return false; } if ((Object)(object)GameNetworkManager.Instance == (Object)null) { missingDependency = "GameNetworkManager.Instance"; return false; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null || (Object)(object)((Component)localPlayerController).transform == (Object)null) { missingDependency = "GameNetworkManager.Instance.localPlayerController"; return false; } if (trigger.specialCharacterAnimation && trigger.setVehicleAnimation && (Object)(object)player.gameplayCamera == (Object)null) { missingDependency = $"player {playerNum} gameplayCamera"; return false; } missingDependency = string.Empty; return true; } private static bool TryGetPlayer(int playerNum, out PlayerControllerB player, out string missingDependency) { player = null; if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null || playerNum < 0 || playerNum >= StartOfRound.Instance.allPlayerScripts.Length) { missingDependency = "StartOfRound.Instance.allPlayerScripts"; return false; } player = StartOfRound.Instance.allPlayerScripts[playerNum]; if ((Object)(object)player == (Object)null || (Object)(object)((Component)player).transform == (Object)null) { missingDependency = $"StartOfRound.Instance.allPlayerScripts[{playerNum}]"; return false; } missingDependency = string.Empty; return true; } private static string GetTriggerName(InteractTrigger trigger) { return ((Object)(object)trigger != (Object)null && (Object)(object)((Component)trigger).gameObject != (Object)null) ? ((Object)((Component)trigger).gameObject).name : "unknown trigger"; } private static void Warn(string message) { if (_warningCount < 5) { _warningCount++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({_warningCount}/{5})"); } } } private static bool IsExecutingClientRpc(InteractTrigger trigger) { bool isExecuting; return RpcExecStageUtility.TryIsExecuting((NetworkBehaviour)(object)trigger, out isExecuting) && isExecuting; } } [HarmonyPatch(typeof(RadMechAI), "SetExplosion")] internal static class RadMechAISetExplosionPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(RadMechAI __instance, Exception __exception) { return SuppressKnownException(__exception, "RadMechAI.SetExplosion", Warnings, () => HasKnownMissingExplosionDependency(__instance)); } internal static Exception SuppressKnownException(Exception exception, string key, WarningLimiter warnings, Func<bool> isKnownSafeCase) { if (!(exception is NullReferenceException) || isKnownSafeCase == null) { return exception; } bool flag; try { flag = isKnownSafeCase(); } catch (Exception ex) { warnings.Warn(key + "|classifier-failed", "Known dependency classifier failed for " + key + "; returning original NullReferenceException: " + ex.GetType().Name + "."); return exception; } if (flag) { warnings.Warn(key, "Suppressed " + key + " NullReferenceException for a known missing dependency."); return null; } return exception; } internal static bool HasKnownMissingExplosionDependency(RadMechAI mech) { return (Object)(object)mech == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null || (Object)(object)((Component)GameNetworkManager.Instance.localPlayerController).transform == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)mech.explosionAudio == (Object)null || mech.largeExplosionSFX == null; } } [HarmonyPatch(typeof(RadMechAI), "SetExplosionClientRpc")] internal static class RadMechAISetExplosionClientRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter NonExecuteStageWarnings = new WarningLimiter(1); private static Exception Finalizer(RadMechAI __instance, Exception __exception) { if (__exception is NullReferenceException && !RpcExecStageUtility.ShouldAllowClientRpcSuppression((NetworkBehaviour)(object)__instance, "RadMechAI.SetExplosionClientRpc", __exception, NonExecuteStageWarnings)) { return __exception; } return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "RadMechAI.SetExplosionClientRpc", Warnings, () => RadMechAISetExplosionPatch.HasKnownMissingExplosionDependency(__instance)); } } [HarmonyPatch(typeof(JetpackItem), "DeactivateJetpack")] internal static class JetpackItemDeactivateJetpackPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(JetpackItem __instance, Exception __exception) { return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "JetpackItem.DeactivateJetpack", Warnings, () => JetpackItemKnownDependencyGuard.HasKnownMissingDeactivateDependency(__instance)); } } [HarmonyPatch(typeof(JetpackItem), "ItemActivate")] internal static class JetpackItemItemActivatePatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(JetpackItem __instance, Exception __exception) { return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "JetpackItem.ItemActivate", Warnings, () => JetpackItemKnownDependencyGuard.HasKnownMissingActivateDependency(__instance)); } } [HarmonyPatch(typeof(GrabbableObject), "ActivateItemRpc")] internal static class GrabbableObjectActivateItemRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(GrabbableObject __instance, Exception __exception) { JetpackItem jetpack = (JetpackItem)(object)((__instance is JetpackItem) ? __instance : null); if (jetpack == null) { return __exception; } return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "GrabbableObject.ActivateItemRpc", Warnings, () => JetpackItemKnownDependencyGuard.HasKnownMissingActivateDependency(jetpack)); } } internal static class JetpackItemKnownDependencyGuard { internal static bool HasKnownMissingDeactivateDependency(JetpackItem jetpack) { return (Object)(object)jetpack == (Object)null || (Object)(object)jetpack.previousPlayerHeldBy == (Object)null || (Object)(object)jetpack.jetpackBeepsAudio == (Object)null || (Object)(object)jetpack.jetpackAudio == (Object)null || (Object)(object)jetpack.smokeTrailParticle == (Object)null; } internal static bool HasKnownMissingActivateDependency(JetpackItem jetpack) { return (Object)(object)jetpack == (Object)null || (Object)(object)((GrabbableObject)jetpack).playerHeldBy == (Object)null || (Object)(object)jetpack.jetpackAudio == (Object)null || (Object)(object)jetpack.smokeTrailParticle == (Object)null || (jetpack.streamlineJetpack && ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)); } } [HarmonyPatch(typeof(LobbySlot), "SetModdedIcon")] internal static class LobbySlotSetModdedIconPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(LobbySlot __instance, ModdedState moddedState) { //IL_0002: 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) if (IsKnownMissingIcon(__instance, moddedState, out var reason)) { Warnings.Warn($"missing-icon|{moddedState}|{reason}", "Skipped LobbySlot.SetModdedIcon because " + reason + "."); return false; } return true; } private static Exception Finalizer(LobbySlot __instance, ModdedState moddedState, Exception __exception) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } string reason; return NullRefGuard.Suppress(__exception, "LobbySlot.SetModdedIcon", () => IsKnownMissingIcon(__instance, moddedState, out reason)); } private static bool IsKnownMissingIcon(LobbySlot slot, ModdedState moddedState, out string reason) { //IL_0018: 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_003c: Invalid comparison between Unknown and I4 if ((Object)(object)slot == (Object)null) { reason = "slot was null"; return true; } if ((int)moddedState == 0 && (Object)(object)slot.modStateUnknownIcon == (Object)null) { reason = "modStateUnknownIcon was missing"; return true; } if ((int)moddedState == 2 && (Object)(object)slot.modStateTrueIcon == (Object)null) { reason = "modStateTrueIcon was missing"; return true; } reason = string.Empty; return false; } } [HarmonyPatch(typeof(DisplayPlayerMicVolume), "InitMic")] internal static class DisplayPlayerMicVolumeInitMicPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(DisplayPlayerMicVolume __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)IngamePlayerSettings.Instance == (Object)null || IngamePlayerSettings.Instance.unsavedSettings == null) { return false; } IngamePlayerSettings.Instance.RefreshAndDisplayCurrentMicrophone(false); string micDevice = IngamePlayerSettings.Instance.unsavedSettings.micDevice; if (!IsValidMicrophoneDevice(micDevice)) { return false; } string device = __instance._device; if (IsValidMicrophoneDevice(device) && Microphone.IsRecording(device)) { Microphone.End(device); } try { int num = default(int); int num2 = default(int); Microphone.GetDeviceCaps(micDevice, ref num, ref num2); int num3 = ((num2 <= 0) ? 44100 : Mathf.Clamp(44100, Mathf.Max(num, 1), num2)); __instance._device = micDevice; __instance._clipRecord = Microphone.Start(micDevice, true, 1, num3); } catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { Warn("Skipping microphone preview for unavailable device '" + micDevice + "': " + ex.Message); __instance._clipRecord = null; } return false; } internal static void Warn(string message) { Warnings.Warn("DisplayPlayerMicVolume", message); } internal static bool IsValidMicrophoneDevice(string device) { if (string.IsNullOrWhiteSpace(device) || device == "none" || device == "LCNoMic" || Microphone.devices == null) { return false; } return Array.IndexOf(Microphone.devices, device) >= 0; } } [HarmonyPatch(typeof(DisplayPlayerMicVolume), "StopMicrophone")] internal static class DisplayPlayerMicVolumeStopMicrophonePatch { private static bool Prefix(DisplayPlayerMicVolume __instance) { if ((Object)(object)__instance == (Object)null) { return false; } try { string device = __instance._device; if (DisplayPlayerMicVolumeInitMicPatch.IsValidMicrophoneDevice(device) && Microphone.IsRecording(device)) { Microphone.End(device); } } catch (Exception ex) { DisplayPlayerMicVolumeInitMicPatch.Warn("Skipping microphone stop because it failed safely: " + ex.GetType().Name); } return false; } } [HarmonyPatch(typeof(DisplayPlayerMicVolume), "LevelMax")] internal static class DisplayPlayerMicVolumeLevelMaxPatch { private static bool Prefix(DisplayPlayerMicVolume __instance, ref float __result) { __result = 0f; if ((Object)(object)__instance == (Object)null || (Object)(object)IngamePlayerSettings.Instance == (Object)null || IngamePlayerSettings.Instance.unsavedSettings == null) { return false; } string micDevice = IngamePlayerSettings.Instance.unsavedSettings.micDevice; if (!DisplayPlayerMicVolumeInitMicPatch.IsValidMicrophoneDevice(micDevice) || !Microphone.IsRecording(micDevice)) { return false; } try { return (Object)(object)__instance._clipRecord != (Object)null; } catch (Exception ex) { DisplayPlayerMicVolumeInitMicPatch.Warn("Skipping microphone level preview because it failed safely: " + ex.GetType().Name); return false; } } } [HarmonyPatch(typeof(NavMeshSurface), "CollectSources")] internal static class NavMeshSurfaceCollectSourcesPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); private static void Postfix(NavMeshSurface __instance, ref List<NavMeshBuildSource> __result) { try { FilterUnreadableMeshSources(__instance, __result); } catch (Exception ex) { GuardFailureWarnings.Warn("guard-failure", "NavMeshSurface source filter failed safely and left sources unchanged: " + ex.GetType().Name + "."); } } private static void FilterUnreadableMeshSources(NavMeshSurface surface, List<NavMeshBuildSource> sources) { //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_004f: Unknown result type (might be due to invalid IL or missing references) if (sources == null || sources.Count == 0) { return; } int num = 0; string surfaceName = GetSurfaceName(surface); bool flag = ShouldLog(surfaceName); HashSet<string> hashSet = (flag ? new HashSet<string>() : null); for (int num2 = sources.Count - 1; num2 >= 0; num2--) { NavMeshBuildSource source = sources[num2]; if (TryGetUnreadableMesh(source, out var mesh)) { sources.RemoveAt(num2); num++; hashSet?.Add(GetMeshName(mesh)); } } if (num > 0 && flag) { Warn(surfaceName, hashSet, num); } } private static bool TryGetUnreadableMesh(NavMeshBuildSource source, out Mesh mesh) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) mesh = null; if ((int)((NavMeshBuildSource)(ref source)).shape == 0) { Object sourceObject = ((NavMeshBuildSource)(ref source)).sourceObject; Mesh val = (Mesh)(object)((sourceObject is Mesh) ? sourceObject : null); if (val != null && !((Object)(object)val == (Object)null)) { mesh = val; return !val.isReadable; } } return false; } private static bool ShouldLog(string surfaceName) { string key = "unreadable-navmesh-sources|" + surfaceName; return Warnings.CanWarn(key); } private static void Warn(string surfaceName, HashSet<string> meshNames, int removedCount) { string key = "unreadable-navmesh-sources|" + surfaceName; Warnings.Warn(key, delegate { string arg = ((meshNames != null && meshNames.Count > 0) ? string.Join(", ", meshNames) : "unknown"); return $"Filtered {removedCount} unreadable mesh source(s) from NavMeshSurface '{surfaceName}' before runtime NavMesh build: {arg}."; }); } private static string GetSurfaceName(NavMeshSurface surface) { return ((Object)(object)surface != (Object)null && (Object)(object)((Component)surface).gameObject != (Object)null) ? ((Object)((Component)surface).gameObject).name : "unknown"; } private static string GetMeshName(Mesh mesh) { return ((Object)(object)mesh != (Object)null && !string.IsNullOrEmpty(((Object)mesh).name)) ? ((Object)mesh).name : "unnamed mesh"; } } [HarmonyPatch(typeof(EnemyAI), "DoAIInterval")] internal static class EnemyAINavMeshGuardPatch { private const float RecoveryAttemptCooldown = 0.5f; private const float RecoveryCacheCleanupInterval = 30f; private static readonly float[] SampleRadii = new float[5] { 2f, 4f, 8f, 16f, 32f }; private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly Dictionary<int, float> NextRecoveryAttemptTimes = new Dictionary<int, float>(); private static float _nextRecoveryCacheCleanupTime; private static bool Prefix(EnemyAI __instance) { try { return GuardEnemyAIInterval(__instance); } catch (Exception ex) { string enemyName = GetEnemyName(__instance); Warn(enemyName, "NavMesh guard failed safely for " + enemyName + ": " + ex.GetType().Name + "."); return true; } } private static bool GuardEnemyAIInterval(EnemyAI enemy) { if (ErrorFixConfig.EnableEnemyAINavMeshGuard != null && !ErrorFixConfig.EnableEnemyAINavMeshGuard.Value) { return true; } if ((Object)(object)enemy == (Object)null || enemy.inSpecialAnimation || (Object)(object)enemy.agent == (Object)null || !enemy.moveTowardsDestination || !((Behaviour)enemy.agent).enabled || enemy.agent.isOnNavMesh) { return true; } string enemyName = GetEnemyName(enemy); if (!CanAttemptRecovery(enemy)) { return false; } if (ShouldRestrictRecoveryToHostServer() && !IsHostOrServer()) { Warn(enemyName, "Suppressed non-host/client " + enemyName + " SetDestination while its NavMeshAgent is off the NavMesh."); return false; } if (!((NetworkBehaviour)enemy).IsOwner) { Warn(enemyName, "Suppressed non-owner " + enemyName + " SetDestination while its NavMeshAgent is off the NavMesh."); return false; } if (enemy.isEnemyDead) { enemy.moveTowardsDestination = false; TrySyncPositionToClients(enemy); Warn(enemyName, "Suppressed " + enemyName + " SetDestination while it is dead and its NavMeshAgent is off the NavMesh."); return false; } if (ShouldAllowWarp() && TryWarpToNearbyNavMesh(enemy)) { Warn(enemyName, "Recovered " + enemyName + " NavMeshAgent by warping it back onto the NavMesh."); return true; } enemy.moveTowardsDestination = false; TrySyncPositionToClients(enemy); Warn(enemyName, "Suppressed " + enemyName + " SetDestination while its NavMeshAgent is off the NavMesh and no nearby NavMesh point was found."); return false; } private static bool TryWarpToNearbyNavMesh(EnemyAI enemy) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) int areaMask = enemy.agent.areaMask; Vector3 position = ((Component)enemy).transform.position; if (TryWarpToNearbyNavMesh(enemy, position, areaMask)) { return true; } return areaMask != -1 && TryWarpToNearbyNavMesh(enemy, position, -1); } private static bool TryWarpToNearbyNavMesh(EnemyAI enemy, Vector3 position, int areaMask) { //IL_001d: 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_0041: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); for (int i = 0; i < SampleRadii.Length; i++) { float num = SampleRadii[i]; if (num > GetMaxWarpRadius()) { break; } if (NavMesh.SamplePosition(position, ref val, num, areaMask) && IsUsableRecoveryPoint(enemy, ((NavMeshHit)(ref val)).position, areaMask) && enemy.agent.Warp(((NavMeshHit)(ref val)).position)) { if (enemy.agent.isOnNavMesh) { enemy.agent.ResetPath(); } return true; } } return false; } private static bool ShouldAllowWarp() { return ErrorFixConfig.AllowEnemyAIWarp == null || ErrorFixConfig.AllowEnemyAIWarp.Value; } private static bool ShouldRestrictRecoveryToHostServer() { return ErrorFixConfig.EnemyAINavMeshHostServerOnly == null || ErrorFixConfig.EnemyAINavMeshHostServerOnly.Value; } private static bool IsHostOrServer() { NetworkManager singleton = NetworkManager.Singleton; return (Object)(object)singleton == (Object)null || singleton.IsHost || singleton.IsServer; } private static float GetMaxWarpRadius() { float num = ErrorFixConfig.EnemyAINavMeshMaxWarpRadius?.Value ?? 32f; return Mathf.Clamp(num, 0f, 64f); } private static bool IsUsableRecoveryPoint(EnemyAI enemy, Vector3 position, int areaMask) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_003a: 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) //IL_0030: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 if (enemy.destination == Vector3.zero) { return true; } NavMeshPath val = enemy.path1; if (val == null) { val = (enemy.path1 = new NavMeshPath()); } return NavMesh.CalculatePath(position, enemy.destination, areaMask, val) && (int)val.status != 2; } private static bool CanAttemptRecovery(EnemyAI enemy) { int instanceID = ((Object)enemy).GetInstanceID(); float realtimeSinceStartup = Time.realtimeSinceStartup; CleanupRecoveryCacheIfNeeded(realtimeSinceStartup); if (NextRecoveryAttemptTimes.TryGetValue(instanceID, out var value) && realtimeSinceStartup < value) { return false; } NextRecoveryAttemptTimes[instanceID] = realtimeSinceStartup + 0.5f; return true; } private static void Warn(string enemyName, string message) { Warnings.Warn(enemyName, message); } private static void CleanupRecoveryCacheIfNeeded(float now) { if (now < _nextRecoveryCacheCleanupTime || NextRecoveryAttemptTimes.Count < 128) { return; } _nextRecoveryCacheCleanupTime = now + 30f; List<int> list = null; foreach (KeyValuePair<int, float> nextRecoveryAttemptTime in NextRecoveryAttemptTimes) { if (!(nextRecoveryAttemptTime.Value >= now)) { if (list == null) { list = new List<int>(); } list.Add(nextRecoveryAttemptTime.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { NextRecoveryAttemptTimes.Remove(list[i]); } } } private static string GetEnemyName(EnemyAI enemy) { if ((Object)(object)enemy == (Object)null) { return "Unknown Enemy"; } if ((Object)(object)enemy.enemyType != (Object)null && !string.IsNullOrEmpty(enemy.enemyType.enemyName)) { return enemy.enemyType.enemyName; } return ((Object)enemy).name; } private static void TrySyncPositionToClients(EnemyAI enemy) { try { enemy.SyncPositionToClients(); } catch (Exception ex) { Warn(GetEnemyName(enemy), "Skipped EnemyAI position sync after NavMesh guard because it failed safely: " + ex.GetType().Name + "."); } } } [HarmonyPatch] internal static class NetworkObjectDestroyGuardPatch { private const float WarningInterval = 5f; private const float WarningCacheCleanupInterval = 30f; private static readonly Dictionary<ulong, float> LastWarningTimes = new Dictionary<ulong, float>(); private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); private static bool _loggedBlockedDestroyStackTrace; private static float _nextWarningCacheCleanupTime; [HarmonyPrepare] private static bool Prepare() { return ShouldPatch(ErrorFixConfig.GlobalDestroyGuardMode?.Value ?? PatchEnableMode.Disabled, ErrorFixConfig.EnableGlobalDestroyGuard?.Value ?? false); } [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { MethodInfo destroy = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null); if (destroy != null) { yield return destroy; } MethodInfo destroyDelayed = AccessTools.Method(typeof(Object), "Destroy", new Type[2] { typeof(Object), typeof(float) }, (Type[])null); if (destroyDelayed != null) { yield return destroyDelayed; } } private static bool Prefix(Object obj) { try { return ShouldAllowDestroy(obj); } catch (Exception ex) { GuardFailureWarnings.Warn("guard-failure", "NetworkObject destroy guard failed safely and allowed original Destroy: " + ex.GetType().Name + "."); return true; } } private static bool ShouldAllowDestroy(Object obj) { if (obj == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsServer) { return true; } if (ShouldAllowLifecycleDestroy()) { return true; } bool flag = obj is GameObject; GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { Component val2 = (Component)(object)((obj is Component) ? obj : null); if (val2 != null) { val = val2.gameObject; } } if ((Object)(object)val == (Object)null) { return true; } RagdollGrabbableObject val3 = val.GetComponent<RagdollGrabbableObject>() ?? val.GetComponentInParent<RagdollGrabbableObject>(); if ((Object)(object)val3 == (Object)null && flag) { val3 = val.GetComponentInChildren<RagdollGrabbableObject>(); } if ((Object)(object)val3 == (Object)null) { return true; } NetworkObject component = ((Component)val3).GetComponent<NetworkObject>(); if ((Object)(object)component == (Object)null || !component.IsSpawned) { return true; } WarnBlockedDestroy(component); return false; } internal static bool ShouldPatch(PatchEnableMode mode, bool legacySwitchEnabled) { return legacySwitchEnabled && mode == PatchEnableMode.Enabled; } internal static void ClearCaches() { LastWarningTimes.Clear(); Warnings.Clear(); GuardFailureWarnings.Clear(); _loggedBlockedDestroyStackTrace = false; } private static bool ShouldAllowLifecycleDestroy() { if (ErrorFixConfig.AllowDestroyDuringSceneUnload != null && !ErrorFixConfig.AllowDestroyDuringSceneUnload.Value) { return false; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.ShutdownInProgress || !singleton.IsListening) { return true; } if (SceneLifecycle.IsLifecycleDestroyAllowed) { return true; } StartOfRound instance = StartOfRound.Instance; return (Object)(object)instance == (Object)null || instance.shipIsLeaving || instance.inShipPhase; } private static void WarnBlockedDestroy(NetworkObject networkObject) { float realtimeSinceStartup = Time.realtimeSinceStartup; CleanupWarningCacheIfNeeded(realtimeSinceStartup); if (!LastWarningTimes.TryGetValue(networkObject.NetworkObjectId, out var value) || !(realtimeSinceStartup - value < 5f)) { LastWarningTimes[networkObject.NetworkObjectId] = realtimeSinceStartup; Warnings.Warn($"blocked-destroy|{networkObject.NetworkObjectId}", "Blocked client-side Destroy on spawned " + ((Object)networkObject).name + "; waiting for server despawn."); LogStackTraceOnceIfEnabled(); } } private static void CleanupWarningCacheIfNeeded(float now) { if (now < _nextWarningCacheCleanupTime || LastWarningTimes.Count < 128) { return; } _nextWarningCacheCleanupTime = now + 30f; List<ulong> list = null; foreach (KeyValuePair<ulong, float> lastWarningTime in LastWarningTimes) { if (!(now - lastWarningTime.Value < 5f)) { if (list == null) { list = new List<ulong>(); } list.Add(lastWarningTime.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { LastWarningTimes.Remove(list[i]); } } } private static void LogStackTraceOnceIfEnabled() { if (!_loggedBlockedDestroyStackTrace && ErrorFixConfig.LogBlockedDestroyStackTraceOnce != null && ErrorFixConfig.LogBlockedDestroyStackTraceOnce.Value) { _loggedBlockedDestroyStackTrace = true; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("First blocked spawned ragdoll Destroy stack trace: " + Environment.StackTrace)); } } } } [HarmonyPatch] internal static class NetworkObjectParentChangedPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return PatchModeUtility.IsEnabled(ErrorFixConfig.NetworkObjectParentGuardMode) && TargetMethod() != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(NetworkObject), "OnTransformParentChanged", (Type[])null, (Type[])null); } private static Exception Finalizer(NetworkObject __instance, Exception __exception) { if (IsKnownSpawnStateException(__exception)) { Warnings.Warn(GetWarningKey(__instance), () => "Suppressed NetworkObject reparent SpawnStateException for '" + GetObjectName(__instance) + "'."); return null; } return __exception; } private static bool IsKnownSpawnStateException(Exception exception) { return exception != null && exception.GetType().Name == "SpawnStateException" && exception.Message != null && exception.Message.Contains("NetworkObject can only be reparented after being spawned"); } private static string GetWarningKey(NetworkObject networkObject) { return ((Object)(object)networkObject != (Object)null) ? $"network-parent|{((Object)networkObject).GetInstanceID()}" : "network-parent|unknown"; } private static string GetObjectName(NetworkObject networkObject) { return ((Object)(object)networkObject != (Object)null) ? ((Object)networkObject).name : "unknown"; } } [HarmonyPatch] internal static class EnemyHealthBarsLateUpdatePatch { private const string TargetKey = "EnemyHealthBars.HealthBar.LateUpdate"; private const string TargetSignature = "EnemyHealthBars.Scripts.HealthBar::LateUpdate() : void instance"; private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter UnknownWarnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return OptionalCompatibilityUtility.ShouldResolveTarget(ErrorFixConfig.EnemyHealthBarsLateUpdateGuardMode, "EnemyHealthBars.Scripts.HealthBar::LateUpdate() : void instance") && OptionalCompatibilityUtility.ShouldPatchResolvedTarget(TargetMethod() != null, "EnemyHealthBars.HealthBar.LateUpdate", "EnemyHealthBars.Scripts.HealthBar::LateUpdate() : void instance"); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { Type typeByName = OptionalCompatibilityUtility.GetTypeByName("EnemyHealthBars.Scripts.HealthBar"); return OptionalPatchTargetResolver.FindMethod(typeByName, "LateUpdate", false, typeof(void)); } private static Exception Finalizer(object __instance, MethodBase __originalMethod, Exception __exception) { if (__exception == null) { return null; } if (!(__exception is NullReferenceException)) { return __exception; } return OptionalCompatibilityUtility.HandleNullReference("EnemyHealthBars.HealthBar.LateUpdate", __originalMethod, __exception, () => IsKnownSafeNullReference(__instance), Warnings, UnknownWarnings); } private static bool IsKnownSafeNullReference(object healthBar) { if (OptionalCompatibilityUtility.IsUnityObjectMissing(healthBar)) { return true; } if (!OptionalCompatibilityUtility.TryGetInstanceMemberValue("EnemyHealthBars.HealthBar.LateUpdate", healthBar, "CurLayout", out var value)) { return false; } if (OptionalCompatibilityUtility.IsUnityObjectMissing(value)) { return true; } Component val = (Component)((value is Component) ? value : null); return val != null && (Object)(object)val.gameObject == (Object)null; } } internal static class ShipLootPlusUiHelperPatchSupport { internal const string TargetKey = "ShipLootPlus.UiHelper"; private const string CalculateLootValueSignature = "ShipLootPlus.Utils.UiHelper::CalculateLootValue(List<GrabbableObject>|List<string>, string) : unknown static"; private const string GeneratedMethodsSignature = "ShipLootPlus.Utils.UiHelper generated CalculateLootValue/UpdateDatapoints methods"; private const string RefreshElementValuesSignature = "ShipLootPlus.Utils.UiHelper::RefreshElementValues() : void static"; private const double HeldScrapScanCacheSeconds = 0.25; private static readonly Type[] IgnoredLootListTypes = new Type[2] { typeof(List<GrabbableObject>), typeof(List<string>) }; internal static readonly WarningLimiter Warnings = new WarningLimiter(); internal static readonly WarningLimiter UnknownWarnings = new WarningLimiter(); private static readonly object HeldScrapScanLock = new object(); private static DateTime heldScrapLastScanUtc = DateTime.MinValue; private static bool heldScrapLastScanResult; private static MethodBase[] calculateLootValueTargets; private static MethodBase[] generatedTargets; private static bool refreshElementValuesTargetResolved; private static MethodBase refreshElementValuesTarget; internal static bool ShouldPatchCalculateLootValue() { return OptionalCompatibilityUtility.ShouldResolveTarget(ErrorFixConfig.ShipLootPlusUiHelperGuardMode, "ShipLootPlus.Utils.UiHelper::CalculateLootValue(List<GrabbableObject>|List<string>, string) : unknown static") && OptionalCompatibilityUtility.ShouldPatchResolvedTarget(GetCalculateLootValueTargets().Length != 0, "ShipLootPlus.UiHelper", "ShipLootPlus.Utils.UiHelper::CalculateLootValue(List<GrabbableObject>|List<string>, string) : unknown static"); } internal static bool ShouldPatchRefreshElementValues() { return OptionalCompatibilityUtility.ShouldResolveTarget(ErrorFixConfig.ShipLootPlusUiHelperGuardMode, "ShipLootPlus.Utils.UiHelper::RefreshElementValues() : void static") && OptionalCompatibilityUtility.ShouldPatchResolvedTarget(GetRefreshElementValuesTarget() != null, "ShipLootPlus.UiHelper", "ShipLootPlus.Utils.UiHelper::RefreshElementValues() : void static"); } internal static bool ShouldPatchGeneratedMethods() { return OptionalCompatibilityUtility.ShouldResolveTarget(ErrorFixConfig.ShipLootPlusUiHelperGuardMode, "ShipLootPlus.Utils.UiHelper generated CalculateLootValue/UpdateDatapoints methods") && OptionalCompatibilityUtility.ShouldPatchResolvedTarget(GetGeneratedTargets().Length != 0, "ShipLootPlus.UiHelper", "ShipLootPlus.Utils.UiHelper generated CalculateLootValue/UpdateDatapoints methods"); } internal static IEnumerable<MethodBase> ResolveCalculateLootValueTargets(bool logResolvedTargets) { MethodBase[] targets = GetCalculateLootValueTargets(); for (int i = 0; i < targets.Length; i++) { if (logResolvedTargets) { OptionalCompatibilityUtility.LogResolvedTarget("ShipLootPlus.UiHelper", targets[i]); } yield return targets[i]; } } internal static MethodBase ResolveRefreshElementValuesTarget(bool logResolvedTarget) { MethodBase methodBase = GetRefreshElementValuesTarget(); if (methodBase != null && logResolvedTarget) { OptionalCompatibilityUtility.LogResolvedTarget("ShipLootPlus.UiHelper", methodBase); } return methodBase; } internal static IEnumerable<MethodBase> ResolveGeneratedTargets(bool logResolvedTargets) { MethodBase[] targets = GetGeneratedTargets(); for (int i = 0; i < targets.Length; i++) { if (logResolvedTargets) { OptionalCompatibilityUtility.LogResolvedTarget("ShipLootPlus.UiHelper", targets[i]); } yield return targets[i]; } } private static MethodBase[] GetCalculateLootValueTargets() { if (calculateLootValueTargets != null) { return calculateLootValueTargets; } Type typeByName = OptionalCompatibilityUtility.GetTypeByName("ShipLootPlus.Utils.UiHelper"); if (typeByName == null) { calculateLootValueTargets = Array.Empty<MethodBase>(); return calculateLootValueTargets; } List<MethodBase> list = new List<MethodBase>(IgnoredLootListTypes.Length); HashSet<MethodBase> hashSet = new HashSet<MethodBase>(); for (int i = 0; i < IgnoredLootListTypes.Length; i++) { MethodBase methodBase = OptionalPatchTargetResolver.FindMethod(typeByName, "CalculateLootValue", true, null, IgnoredLootListTypes[i], typeof(string)); if (methodBase != null && hashSet.Add(methodBase)) { list.Add(methodBase); } } calculateLootValueTargets = list.ToArray(); return calculateLootValueTargets; } private static MethodBase GetRefreshElementValuesTarget() { if (refreshElementValuesTargetResolved) { return refreshElementValuesTarget; } refreshElementValuesTargetResolved = true; Type typeByName = OptionalCompatibilityUtility.GetTypeByName("ShipLootPlus.Utils.UiHelper"); refreshElementValuesTarget = ((typeByName != null) ? OptionalPatchTargetResolver.FindMethod(typeByName, "RefreshElementValues", true, typeof(void)) : null); return refreshElementValuesTarget; } private static MethodBase[] GetGeneratedTargets() { if (generatedTargets != null) { return generatedTargets; } Type typeByName = OptionalCompatibilityUtility.GetTypeByName("ShipLootPlus.Utils.UiHelper"); if (typeByName == null) { generatedTargets = Array.Empty<MethodBase>(); return generatedTargets; } List<MethodBase> list = new List<MethodBase>(); HashSet<MethodBase> hashSet = new HashSet<MethodBase>(); Type[] nestedTypes = typeByName.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); foreach (Type type in nestedTypes) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (ShouldPatchGeneratedMethod(type, methodInfo) && hashSet.Add(methodInfo)) { list.Add(methodInfo); } } } generatedTargets = list.ToArray(); return generatedTargets; } internal static bool IsKnownSafeCalculateLootValueNullReference(MethodBase originalMethod, object ignoredList, string ignoredCategory) { if (!string.Equals(originalMethod?.Name, "CalculateLootValue", StringComparison.Ordinal)) { return false; } if (ignoredList == null || string.IsNullOrEmpty(ignoredCategory)) { return true; } if (HasNullOrDestroyedLootEntry(ignoredList)) { return true; } return string.Equals(ignoredCategory, "Inv", StringComparison.OrdinalIgnoreCase) && HasHeldScrapWithoutHolder(); } internal static bool IsKnownSafeGeneratedNullReference(MethodBase originalMethod) { string text = ((originalMethod != null) ? originalMethod.Name : string.E