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.1
V81ErrorFix.dll
Decompiled 21 hours 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [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 static class NullRefGuard { private const int MaxWarningsPerKey = 5; private static readonly Dictionary<string, int> WarningCounts = new Dictionary<string, int>(); internal static Exception Suppress(Exception exception, string key) { if (!(exception is NullReferenceException)) { return exception; } WarningCounts.TryGetValue(key, out var value); if (value < 5) { value++; WarningCounts[key] = value; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"Suppressed NullReferenceException in {key} ({value}/{5}); the object will safely retry on later updates."); } } return null; } } internal sealed class ParticleMeshShapeGuard : MonoBehaviour { private sealed class ParticleMeshWarningBatch { internal readonly string MeshName; internal readonly string Reason; internal readonly HashSet<string> ParticleSystemNames = new HashSet<string>(); internal ParticleMeshWarningBatch(string meshName, string reason) { MeshName = meshName; Reason = reason; } } private sealed class CachedMeshInspection { internal readonly Mesh Mesh; internal readonly string InvalidReason; internal CachedMeshInspection(Mesh mesh, string invalidReason) { Mesh = mesh; InvalidReason = invalidReason; } } private const float ScanInterval = 5f; private const int ScanBatchSize = 64; private const int MeshInspectionCacheCleanupThreshold = 256; private float _nextScanTime; private ParticleSystem[] _scanQueue; private int _scanIndex; private readonly HashSet<int> _patchedParticleSystems = new HashSet<int>(); 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>(); internal static void EnsureCreated() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)Object.FindObjectOfType<ParticleMeshShapeGuard>() != (Object)null)) { GameObject val = new GameObject("V81ErrorFix.ParticleMeshShapeGuard"); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<ParticleMeshShapeGuard>(); } } private void Update() { if (_scanQueue != null) { ContinueParticleSystemScan(); } else if (!(Time.realtimeSinceStartup < _nextScanTime)) { _nextScanTime = Time.realtimeSinceStartup + 5f; BeginParticleSystemScan(); ContinueParticleSystemScan(); } } 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); while (_scanIndex < num) { TryPatchParticleSystem(_scanQueue[_scanIndex]); _scanIndex++; } if (_scanIndex >= _scanQueue.Length) { _scanQueue = null; _scanIndex = 0; FlushParticleMeshWarnings(); } } } private void TryPatchParticleSystem(ParticleSystem particleSystem) { //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_0041: 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.Contains(instanceID)) { return; } try { ShapeModule shape = particleSystem.shape; if (((ShapeModule)(ref shape)).enabled && TryGetShapeMesh(shape, out var mesh) && !((Object)(object)mesh == (Object)null)) { string invalidMeshReasonCached = GetInvalidMeshReasonCached(mesh); if (invalidMeshReasonCached != null) { ((ShapeModule)(ref shape)).enabled = false; _patchedParticleSystems.Add(instanceID); QueueParticleMeshWarning(((Object)mesh).name, invalidMeshReasonCached, ((Object)particleSystem).name); } } } catch (Exception ex) { _patchedParticleSystems.Add(instanceID); QueueParticleMeshWarning("inspection", "could not be inspected safely: " + ex.GetType().Name, ((Object)particleSystem).name); } } private void QueueParticleMeshWarning(string meshName, string reason, string particleSystemName) { string key = meshName + "|" + reason; if (_warnings.CanWarn(key)) { if (!_pendingWarnings.TryGetValue(key, out var value)) { value = new ParticleMeshWarningBatch(meshName, reason); _pendingWarnings[key] = value; } value.ParticleSystemNames.Add(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); return "Disabled mesh shape because mesh '" + warningBatch.MeshName + "' " + warningBatch.Reason + " on particle systems: " + text + "."; }); } } private string GetInvalidMeshReasonCached(Mesh mesh) { int instanceID = ((Object)mesh).GetInstanceID(); if (_meshInspectionCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Mesh == (Object)(object)mesh) { return value.InvalidReason; } string invalidMeshReason = GetInvalidMeshReason(mesh); _meshInspectionCache[instanceID] = new CachedMeshInspection(mesh, invalidMeshReason); 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 static string GetInvalidMeshReason(Mesh mesh) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (!mesh.isReadable) { return "is not readable"; } try { Vector3[] vertices = mesh.vertices; int[] triangles = mesh.triangles; if (vertices == null || triangles == null || vertices.Length == 0 || triangles.Length < 3) { return "has zero surface area"; } double num = 0.0; for (int i = 0; i + 2 < triangles.Length; i += 3) { Vector3 val = vertices[triangles[i]]; Vector3 val2 = vertices[triangles[i + 1]]; Vector3 val3 = vertices[triangles[i + 2]]; double num2 = num; Vector3 val4 = Vector3.Cross(val2 - val, val3 - val); num = num2 + (double)((Vector3)(ref val4)).magnitude * 0.5; if (num > 0.0001) { return null; } } } catch { return "could not be inspected safely"; } return "has zero surface area"; } } internal sealed class WarningLimiter { private readonly int _maxWarnings; private readonly Dictionary<string, int> _warningCounts = new Dictionary<string, int>(); internal WarningLimiter(int maxWarnings = 5) { _maxWarnings = maxWarnings; } 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(key, out var value); return value < _maxWarnings; } private bool TryIncrement(string key, out int warningCount) { _warningCounts.TryGetValue(key, out warningCount); if (warningCount >= _maxWarnings) { return false; } warningCount++; _warningCounts[key] = warningCount; return true; } } [HarmonyPatch] internal static class DisabledAudioSourcePlayGuardPatch { [CompilerGenerated] private sealed class <TargetMethods>d__2 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private MethodInfo[] <>s__1; private int <>s__2; private MethodInfo <method>5__3; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = null; <method>5__3 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00a4; } <>1__state = -1; <>s__1 = typeof(AudioSource).GetMethods(BindingFlags.Instance | BindingFlags.Public); <>s__2 = 0; goto IL_00ba; IL_00a4: <method>5__3 = null; <>s__2++; goto IL_00ba; IL_00ba: if (<>s__2 < <>s__1.Length) { <method>5__3 = <>s__1[<>s__2]; if (<method>5__3.DeclaringType == typeof(AudioSource) && IsPlaybackMethod(<method>5__3)) { <>2__current = <method>5__3; <>1__state = 1; return true; } goto IL_00a4; } <>s__1 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__2(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); [IteratorStateMachine(typeof(<TargetMethods>d__2))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__2(-2); } 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 { [CompilerGenerated] private sealed class <TargetMethods>d__2 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(AudioSource), "PlayOneShot", new Type[1] { typeof(AudioClip) }, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(AudioSource), "PlayOneShot", new Type[2] { typeof(AudioClip), typeof(float) }, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__2(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } private static readonly WarningLimiter Warnings = new WarningLimiter(); private static readonly WarningLimiter GuardFailureWarnings = new WarningLimiter(); [IteratorStateMachine(typeof(<TargetMethods>d__2))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__2(-2); } 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 is NullReferenceException) { try { if ((Object)(object)__instance != (Object)null) { ((EnemyAI)__instance).targetPlayer = null; ((EnemyAI)__instance).movingTowardsTargetPlayer = false; } } catch { } } return NullRefGuard.Suppress(__exception, "BushWolfEnemy.Update"); } } [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(Exception __exception) { return NullRefGuard.Suppress(__exception, "BushWolfEnemy.LateUpdate"); } } [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(Exception __exception) { return NullRefGuard.Suppress(__exception, "DocileLocustBeesAI.Update"); } } [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 is NullReferenceException && (Object)(object)__instance != (Object)null) { try { ((EnemyAI)__instance).movingTowardsTargetPlayer = false; } catch { } } return NullRefGuard.Suppress(__exception, "CrawlerAI.Update"); } } [HarmonyPatch(typeof(EntranceTeleport), "Update")] internal static class EntranceTeleportUpdatePatch { private static readonly FieldInfo TriggerScriptField = AccessTools.Field(typeof(EntranceTeleport), "triggerScript"); private static readonly FieldInfo CheckForEnemiesIntervalField = AccessTools.Field(typeof(EntranceTeleport), "checkForEnemiesInterval"); private static readonly FieldInfo EnemyNearLastCheckField = AccessTools.Field(typeof(EntranceTeleport), "enemyNearLastCheck"); private static readonly FieldInfo GotExitPointField = AccessTools.Field(typeof(EntranceTeleport), "gotExitPoint"); private static bool Prefix(EntranceTeleport __instance) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { return false; } if (!__instance.isEntranceToBuilding) { return false; } if ((Object)(object)RoundManager.Instance == (Object)null) { return false; } InteractTrigger val = (InteractTrigger)TriggerScriptField.GetValue(__instance); if ((Object)(object)val == (Object)null) { return false; } float num = (float)CheckForEnemiesIntervalField.GetValue(__instance); if (num > 0f) { CheckForEnemiesIntervalField.SetValue(__instance, num - Time.deltaTime); return false; } if (!(bool)GotExitPointField.GetValue(__instance)) { if (__instance.FindExitPoint()) { GotExitPointField.SetValue(__instance, true); } return false; } if (((Object)(object)__instance.exitScript == (Object)null || (Object)(object)__instance.exitScript.entrancePoint == (Object)null) && !__instance.FindExitPoint()) { return false; } CheckForEnemiesIntervalField.SetValue(__instance, 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; } if (Vector3.Distance(((Component)spawnedEnemy).transform.position, __instance.exitScript.entrancePoint.position) < 7.7f) { flag = true; break; } } } } bool flag2 = (bool)EnemyNearLastCheckField.GetValue(__instance); if (flag && !flag2) { EnemyNearLastCheckField.SetValue(__instance, true); val.hoverTip = "[Near activity detected!]"; } else if (!flag && flag2) { EnemyNearLastCheckField.SetValue(__instance, false); val.hoverTip = "Enter: [LMB]"; } return false; } private static Exception Finalizer(Exception __exception) { return NullRefGuard.Suppress(__exception, "EntranceTeleport.Update"); } } [HarmonyPatch(typeof(RoundManager), "FindMainEntrancePosition")] internal static class RoundManagerFindMainEntrancePositionPatch { private const int MaxWarnings = 5; private static int _warningCount; private static bool Prefix(bool getTeleportPosition, bool getOutsideEntrance, ref Vector3 __result) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>(false); EntranceTeleport val = null; EntranceTeleport val2 = null; foreach (EntranceTeleport val3 in array) { if (!((Object)(object)val3 == (Object)null)) { if (val == null) { val = val3; } if (val3.entranceId == 0 && val2 == null) { val2 = val3; } if (val3.entranceId == 0 && val3.isEntranceToBuilding == getOutsideEntrance) { __result = GetEntrancePosition(val3, getTeleportPosition); return false; } } } EntranceTeleport val4 = val2 ?? val; if ((Object)(object)val4 != (Object)null) { __result = GetEntrancePosition(val4, 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 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) { if (_warningCount < 5) { _warningCount++; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({_warningCount}/{5})"); } } } } [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(Exception __exception) { if (__exception is NullReferenceException) { 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 bool Prefix(HUDManager __instance) { 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(Exception __exception) { if (__exception is NullReferenceException) { HUDManagerAddChatMessagePatch.Warn("Suppressed HUDManager.AddTextMessageClientRpc NullReferenceException while chat HUD was not ready."); return null; } return __exception; } } [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 bool Prefix(InteractTrigger __instance, int playerNum) { 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(Exception __exception) { if (__exception is NullReferenceException) { 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})"); } } } } [HarmonyPatch(typeof(RadMechAI), "SetExplosion")] internal static class RadMechAISetExplosionPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(Exception __exception) { return SuppressKnownException(__exception, "RadMechAI.SetExplosion", Warnings); } internal static Exception SuppressKnownException(Exception exception, string key, WarningLimiter warnings) { if (exception is NullReferenceException) { warnings.Warn(key, "Suppressed " + key + " NullReferenceException."); return null; } return exception; } } [HarmonyPatch(typeof(RadMechAI), "SetExplosionClientRpc")] internal static class RadMechAISetExplosionClientRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(Exception __exception) { return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "RadMechAI.SetExplosionClientRpc", Warnings); } } [HarmonyPatch(typeof(JetpackItem), "DeactivateJetpack")] internal static class JetpackItemDeactivateJetpackPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(Exception __exception) { return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "JetpackItem.DeactivateJetpack", Warnings); } } [HarmonyPatch(typeof(JetpackItem), "ItemActivate")] internal static class JetpackItemItemActivatePatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(Exception __exception) { return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "JetpackItem.ItemActivate", Warnings); } } [HarmonyPatch(typeof(GrabbableObject), "ActivateItemRpc")] internal static class GrabbableObjectActivateItemRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(GrabbableObject __instance, Exception __exception) { if (!(__instance is JetpackItem)) { return __exception; } return RadMechAISetExplosionPatch.SuppressKnownException(__exception, "GrabbableObject.ActivateItemRpc", Warnings); } } [HarmonyPatch(typeof(LobbySlot), "SetModdedIcon")] internal static class LobbySlotSetModdedIconPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(LobbySlot __instance, ModdedState moddedState) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null) { Warnings.Warn("null-slot", "Skipped LobbySlot.SetModdedIcon because the lobby slot was null."); return false; } if ((int)moddedState == 0 && (Object)(object)__instance.modStateUnknownIcon == (Object)null) { Warnings.Warn("missing-unknown-icon", "Skipped LobbySlot.SetModdedIcon because modStateUnknownIcon was missing."); return false; } if ((int)moddedState == 2 && (Object)(object)__instance.modStateTrueIcon == (Object)null) { Warnings.Warn("missing-modded-icon", "Skipped LobbySlot.SetModdedIcon because modStateTrueIcon was missing."); return false; } return true; } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("finalizer-null-reference", "Suppressed LobbySlot.SetModdedIcon NullReferenceException."); return null; } return __exception; } } [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; } Traverse val = Traverse.Create((object)__instance); string value = val.Field("_device").GetValue<string>(); if (IsValidMicrophoneDevice(value) && Microphone.IsRecording(value)) { Microphone.End(value); } 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)); val.Field("_device").SetValue((object)micDevice); val.Field("_clipRecord").SetValue((object)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); val.Field("_clipRecord").SetValue((object)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 value = Traverse.Create((object)__instance).Field("_device").GetValue<string>(); if (DisplayPlayerMicVolumeInitMicPatch.IsValidMicrophoneDevice(value) && Microphone.IsRecording(value)) { Microphone.End(value); } } 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 { AudioClip value = Traverse.Create((object)__instance).Field("_clipRecord").GetValue<AudioClip>(); return (Object)(object)value != (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 ((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 (!((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 (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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); for (int i = 0; i < SampleRadii.Length; i++) { if (NavMesh.SamplePosition(position, ref val, SampleRadii[i], 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 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 { [CompilerGenerated] private sealed class <TargetMethods>d__4 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__4(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Object), "Destroy", new Type[2] { typeof(Object), typeof(float) }, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__4(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } private const float WarningInterval = 5f; 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(); [IteratorStateMachine(typeof(<TargetMethods>d__4))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__4(-2); } 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; } 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; } private static void WarnBlockedDestroy(NetworkObject networkObject) { float realtimeSinceStartup = Time.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."); } } } [HarmonyPatch] internal static class NetworkObjectParentChangedPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return TargetMethod() != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(NetworkObject), "OnTransformParentChanged", (Type[])null, (Type[])null); } private static bool Prefix(NetworkObject __instance) { if ((Object)(object)__instance == (Object)null || __instance.IsSpawned) { return true; } Warnings.Warn(GetWarningKey(__instance), () => "Skipped NetworkObject.OnTransformParentChanged for unspawned object '" + GetObjectName(__instance) + "' to avoid invalid reparent handling."); return false; } 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 static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return TargetMethod() != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("EnemyHealthBars.Scripts.HealthBar"); return OptionalPatchTargetResolver.FindMethod(type, "LateUpdate", false, typeof(void)); } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("EnemyHealthBars.HealthBar.LateUpdate", "Suppressed EnemyHealthBars.HealthBar.LateUpdate NullReferenceException."); return null; } return __exception; } } [HarmonyPatch] internal static class ShipLootPlusUiHelperPatch { [CompilerGenerated] private sealed class <TargetMethods>d__2 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private Type <uiHelperType>5__1; private HashSet<MethodBase> <yieldedMethods>5__2; private MethodBase <calculateLootValue>5__3; private MethodBase <refreshElementValues>5__4; private Type[] <>s__5; private int <>s__6; private Type <nestedType>5__7; private MethodInfo[] <>s__8; private int <>s__9; private MethodInfo <method>5__10; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <uiHelperType>5__1 = null; <yieldedMethods>5__2 = null; <calculateLootValue>5__3 = null; <refreshElementValues>5__4 = null; <>s__5 = null; <nestedType>5__7 = null; <>s__8 = null; <method>5__10 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <uiHelperType>5__1 = AccessTools.TypeByName("ShipLootPlus.Utils.UiHelper"); if (<uiHelperType>5__1 == null) { return false; } <yieldedMethods>5__2 = new HashSet<MethodBase>(); <calculateLootValue>5__3 = OptionalPatchTargetResolver.FindMethod(<uiHelperType>5__1, "CalculateLootValue", true, null, typeof(List<GrabbableObject>), typeof(string)); if (<calculateLootValue>5__3 != null && <yieldedMethods>5__2.Add(<calculateLootValue>5__3)) { <>2__current = <calculateLootValue>5__3; <>1__state = 1; return true; } goto IL_00e4; case 1: <>1__state = -1; goto IL_00e4; case 2: <>1__state = -1; goto IL_014e; case 3: { <>1__state = -1; <method>5__10 = null; goto IL_020a; } IL_0218: if (<>s__9 < <>s__8.Length) { <method>5__10 = <>s__8[<>s__9]; if (!ShouldPatchGeneratedMethod(<nestedType>5__7, <method>5__10) || !<yieldedMethods>5__2.Add(<method>5__10)) { goto IL_020a; } <>2__current = <method>5__10; <>1__state = 3; return true; } <>s__8 = null; <nestedType>5__7 = null; <>s__6++; goto IL_0248; IL_014e: <>s__5 = <uiHelperType>5__1.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); <>s__6 = 0; goto IL_0248; IL_0248: if (<>s__6 < <>s__5.Length) { <nestedType>5__7 = <>s__5[<>s__6]; <>s__8 = <nestedType>5__7.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); <>s__9 = 0; goto IL_0218; } <>s__5 = null; return false; IL_020a: <>s__9++; goto IL_0218; IL_00e4: <refreshElementValues>5__4 = OptionalPatchTargetResolver.FindMethod(<uiHelperType>5__1, "RefreshElementValues", true, typeof(void)); if (<refreshElementValues>5__4 != null && <yieldedMethods>5__2.Add(<refreshElementValues>5__4)) { <>2__current = <refreshElementValues>5__4; <>1__state = 2; return true; } goto IL_014e; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__2(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } private static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return AccessTools.TypeByName("ShipLootPlus.Utils.UiHelper") != null; } [IteratorStateMachine(typeof(<TargetMethods>d__2))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__2(-2); } private static Exception Finalizer(MethodBase __originalMethod, Exception __exception) { if (__exception is NullReferenceException) { string text = ((__originalMethod != null) ? __originalMethod.Name : "unknown"); Warnings.Warn("ShipLootPlus.UiHelper." + text, "Compatibility guard handled ShipLootPlus.UiHelper." + text + " NullReferenceException while refreshing loot UI."); return null; } return __exception; } private static bool ShouldPatchGeneratedMethod(Type nestedType, MethodInfo method) { if (nestedType == null || method == null) { return false; } return method.ReturnType == typeof(bool) && (method.Name.Contains("<CalculateLootValue>") || (method.Name == "MoveNext" && nestedType.Name.Contains("<UpdateDatapoints>"))); } } [HarmonyPatch] internal static class NightVisionInsideLightingPostfixPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return TargetMethod() != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("NightVision.Patches.NightVisionOutdoors"); return OptionalPatchTargetResolver.FindMethod(type, "InsideLightingPostfix", true, typeof(void), typeof(TimeOfDay)); } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("NightVision.InsideLightingPostfix", "Compatibility guard handled NightVision outdoors lighting NullReferenceException while inside lighting changed."); return null; } return __exception; } } [HarmonyPatch] internal static class ChatCommandApiStartHostPostfixPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); [HarmonyPrepare] private static bool Prepare() { return TargetMethod() != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ChatCommandAPI.Patches.GameNetworkManager_StartHost"); return OptionalPatchTargetResolver.FindMethod(type, "Postfix", true, typeof(void)); } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("ChatCommandAPI.GameNetworkManager_StartHost.Postfix", "Compatibility guard handled ChatCommandAPI StartHost Postfix NullReferenceException while hosting a lobby."); return null; } return __exception; } } internal static class OptionalPatchTargetResolver { internal static MethodBase FindMethod(Type type, string methodName, bool isStatic, Type returnType, params Type[] parameterTypes) { if (type == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, methodName, parameterTypes, (Type[])null); if (methodInfo == null || methodInfo.IsStatic != isStatic || (returnType != null && methodInfo.ReturnType != returnType)) { return null; } return methodInfo; } } [HarmonyPatch(typeof(PlayerControllerB), "NearOtherPlayers")] internal static class PlayerControllerBNearOtherPlayersPatch { private static bool Prefix(PlayerControllerB __instance, float checkRadius, ref bool __result) { try { return CheckNearOtherPlayersSafely(__instance, checkRadius, ref __result); } catch (Exception exception) { __result = false; return NullRefGuard.Suppress(exception, "PlayerControllerB.NearOtherPlayers") != null; } } private static bool CheckNearOtherPlayersSafely(PlayerControllerB __instance, float checkRadius, ref bool __result) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).transform == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { __result = false; return false; } float num = checkRadius * checkRadius; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)__instance) && val.isPlayerControlled && !((Object)(object)((Component)val).transform == (Object)null)) { Vector3 val2 = ((Component)__instance).transform.position - ((Component)val).transform.position; if (((Vector3)(ref val2)).sqrMagnitude < num) { __result = true; return false; } } } __result = false; return false; } } [HarmonyPatch(typeof(PlayerControllerB), "PlayJumpAudio")] internal static class PlayerControllerBPlayJumpAudioPatch { private const int MaxWarnings = 5; private static int _warningCount; private static bool Prefix(PlayerControllerB __instance) { try { PlayJumpAudioSafely(__instance); } catch (Exception ex) { Warn("Skipped PlayerControllerB.PlayJumpAudio because the guard failed safely: " + ex.GetType().Name + "."); } return false; } private static void PlayJumpAudioSafely(PlayerControllerB player) { if ((Object)(object)player == (Object)null || (Object)(object)player.movementAudio == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { Warn("Skipped PlayerControllerB.PlayJumpAudio because audio dependencies were not ready."); return; } string missingDependency; AudioClip val = TryGetSuitJumpAudio(player, out missingDependency) ?? TryGetDefaultJumpAudio(ref missingDependency); if ((Object)(object)val == (Object)null) { Warn("Skipped PlayerControllerB.PlayJumpAudio because no jump audio clip was available: " + missingDependency + "."); return; } if (!string.IsNullOrEmpty(missingDependency)) { Warn("Used default jump audio because suit jump audio was not available: " + missingDependency + "."); } player.movementAudio.PlayOneShot(val); } private static Exception Finalizer(Exception __exception) { if (__exception is ArgumentOutOfRangeException || __exception is NullReferenceException) { Warn("Suppressed PlayerControllerB.PlayJumpAudio " + __exception.GetType().Name + "."); return null; } return __exception; } private static AudioClip TryGetSuitJumpAudio(PlayerControllerB player, out string missingDependency) { missingDependency = string.Empty; if ((Object)(object)StartOfRound.Instance.unlockablesList == (Object)null || StartOfRound.Instance.unlockablesList.unlockables == null) { missingDependency = "StartOfRound.Instance.unlockablesList"; return null; } if (player.currentSuitID < 0 || player.currentSuitID >= StartOfRound.Instance.unlockablesList.unlockables.Count) { missingDependency = $"currentSuitID {player.currentSuitID} outside unlockables count {StartOfRound.Instance.unlockablesList.unlockables.Count}"; return null; } UnlockableItem val = StartOfRound.Instance.unlockablesList.unlockables[player.currentSuitID]; if (val == null) { missingDependency = $"unlockables[{player.currentSuitID}]"; return null; } AudioClip jumpAudio = val.jumpAudio; if ((Object)(object)jumpAudio == (Object)null) { missingDependency = $"unlockables[{player.currentSuitID}].jumpAudio"; } return jumpAudio; } private static AudioClip TryGetDefaultJumpAudio(ref string missingDependency) { if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.playerJumpSFX == (Object)null) { missingDependency = (string.IsNullOrEmpty(missingDependency) ? "StartOfRound.Instance.playerJumpSFX" : (missingDependency + "; StartOfRound.Instance.playerJumpSFX")); return null; } return StartOfRound.Instance.playerJumpSFX; } 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(PlayerControllerB), "PlayerJumpedClientRpc")] internal static class PlayerControllerBPlayerJumpedClientRpcPatch { private static Exception Finalizer(Exception __exception) { if (__exception is ArgumentOutOfRangeException || __exception is NullReferenceException) { PlayerControllerBPlayJumpAudioPatch.Warn("Suppressed PlayerControllerB.PlayerJumpedClientRpc " + __exception.GetType().Name + " from jump audio playback."); return null; } return __exception; } } [HarmonyPatch(typeof(PlayerControllerB), "ThrowObjectClientRpc")] internal static class PlayerControllerBThrowObjectClientRpcPatch { private const int MaxWarnings = 5; private static readonly Dictionary<string, int> WarningCounts = new Dictionary<string, int>(); private static readonly FieldInfo RpcExecStageField = AccessTools.Field(typeof(NetworkBehaviour), "__rpc_exec_stage"); private static readonly FieldInfo ThrowingObjectField = AccessTools.Field(typeof(PlayerControllerB), "throwingObject"); private static readonly object RpcExecStageSend = ((RpcExecStageField != null) ? Enum.Parse(RpcExecStageField.FieldType, "Send") : null); private static bool Prefix(PlayerControllerB __instance, bool droppedInElevator, bool droppedInShipRoom, Vector3 targetFloorPosition, NetworkObjectReference grabbedObject, int floorYRot) { //IL_0018: 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 (!IsExecutingClientRpc(__instance)) { return true; } try { HandleThrowObjectClientRpcSafely(__instance, droppedInElevator, droppedInShipRoom, targetFloorPosition, grabbedObject, floorYRot); } catch (Exception ex) { Warn("guard-failed", "Suppressed ThrowObjectClientRpc because the guard failed safely: " + ex.GetType().Name + "."); SetRpcExecStageSend(__instance); if ((Object)(object)__instance != (Object)null && ((NetworkBehaviour)__instance).IsOwner) { SetThrowingObject(__instance, value: false); } } return false; } private static void HandleThrowObjectClientRpcSafely(PlayerControllerB player, bool droppedInElevator, bool droppedInShipRoom, Vector3 targetFloorPosition, NetworkObjectReference grabbedObject, int floorYRot) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)((NetworkBehaviour)player).NetworkManager == (Object)null || !((NetworkBehaviour)player).NetworkManager.IsListening || (!((NetworkBehaviour)player).NetworkManager.IsClient && !((NetworkBehaviour)player).NetworkManager.IsHost)) { return; } SetRpcExecStageSend(player); NetworkObject val = default(NetworkObject); if (((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && (Object)(object)val != (Object)null) { GrabbableObject component = ((Component)val).GetComponent<GrabbableObject>(); if ((Object)(object)component == (Object)null) { Warn($"missing-grabbable|{player.playerClientId}", $"Skipped ThrowObjectClientRpc for player #{player.playerClientId} because the NetworkObject had no GrabbableObject."); FinishThrowingIfOwner(player); return; } if (!((NetworkBehaviour)player).IsOwner) { player.SetObjectAsNoLongerHeld(droppedInElevator, droppedInShipRoom, targetFloorPosition, component, floorYRot); } if ((Object)(object)component.itemProperties == (Object)null || !component.itemProperties.syncDiscardFunction) { component.playerHeldBy = null; } if ((Object)(object)component == (Object)(object)player.currentlyHeldObjectServer) { player.currentlyHeldObjectServer = null; } else { Warn($"held-mismatch|{player.playerClientId}", $"Suppressed ThrowObjectClientRpc held-object mismatch for player #{player.playerClientId}; currentlyHeldObjectServer was {GetHeldObjectName(player.currentlyHeldObjectServer)}."); } } else { Warn($"missing-network-object|{player.playerClientId}", $"Suppressed ThrowObjectClientRpc because the server object reference was missing for player #{player.playerClientId}."); } FinishThrowingIfOwner(player); } private static bool IsExecutingClientRpc(PlayerControllerB player) { if ((Object)(object)player == (Object)null || RpcExecStageField == null) { return false; } object value = RpcExecStageField.GetValue(player); return value != null && value.ToString() == "Execute"; } private static string GetHeldObjectName(GrabbableObject heldObject) { if ((Object)(object)heldObject == (Object)null) { return "null"; } return ((Object)(object)((Component)heldObject).gameObject != (Object)null) ? ((Object)((Component)heldObject).gameObject).name : "missing GameObject"; } private static void SetRpcExecStageSend(PlayerControllerB player) { if ((Object)(object)player != (Object)null && RpcExecStageField != null && RpcExecStageSend != null) { RpcExecStageField.SetValue(player, RpcExecStageSend); } } private static void FinishThrowingIfOwner(PlayerControllerB player) { if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).IsOwner) { SetThrowingObject(player, value: false); } } private static void SetThrowingObject(PlayerControllerB player, bool value) { if ((Object)(object)player != (Object)null && ThrowingObjectField != null) { ThrowingObjectField.SetValue(player, value); } } private static void Warn(string key, string message) { WarningCounts.TryGetValue(key, out var value); if (value < 5) { value++; WarningCounts[key] = value; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({value}/{5})"); } } } } [HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")] internal static class PlayerControllerBGrabObjectClientRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(PlayerControllerB __instance, Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("GrabObjectClientRpc|" + GetPlayerId(__instance), "Suppressed PlayerControllerB.GrabObjectClientRpc NullReferenceException for player #" + GetPlayerId(__instance) + "."); return null; } return __exception; } private static string GetPlayerId(PlayerControllerB player) { return ((Object)(object)player != (Object)null) ? player.playerClientId.ToString() : "unknown"; } } [HarmonyPatch(typeof(QuicksandTrigger), "OnExit")] internal static class QuicksandTriggerOnExitPatch { private const int MaxWarnings = 5; private static readonly Dictionary<string, int> WarningCounts = new Dictionary<string, int>(); private static bool Prefix(QuicksandTrigger __instance, Collider other) { try { HandleExitSafely(__instance, other); } catch (Exception ex) { Warn("exception", "Suppressed QuicksandTrigger.OnExit failure safely: " + ex.GetType().Name + "."); } return false; } private static void HandleExitSafely(QuicksandTrigger quicksandTrigger, Collider other) { if ((Object)(object)quicksandTrigger == (Object)null || (Object)(object)other == (Object)null) { Warn("missing-trigger-or-collider", "Skipped QuicksandTrigger.OnExit because the trigger or collider was missing."); return; } PlayerControllerB val = TryGetPlayer(other); if ((Object)(object)val == (Object)null) { if (((Component)other).CompareTag("Player")) { Warn("missing-player", "Skipped QuicksandTrigger.OnExit for '" + ((Object)other).name + "' because no PlayerControllerB was found."); } return; } if ((Object)(object)GameNetworkManager.Instance == (Object)null) { Warn("missing-network-manager", "Skipped QuicksandTrigger.OnExit because GameNetworkManager.Instance was missing."); return; } PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (!quicksandTrigger.sinkingLocalPlayer) { if (quicksandTrigger.isWater && (Object)(object)val != (Object)(object)localPlayerController) { val.isUnderwater = false; } } else if ((Object)(object)val == (Object)(object)localPlayerController) { quicksandTrigger.StopSinkingLocalPlayer(val); } } private static PlayerControllerB TryGetPlayer(Collider other) { if ((Object)(object)other == (Object)null || (Object)(object)((Component)other).gameObject == (Object)null) { return null; } return ((Component)other).gameObject.GetComponent<PlayerControllerB>() ?? ((Component)other).GetComponentInParent<PlayerControllerB>(); } private static void Warn(string key, string message) { WarningCounts.TryGetValue(key, out var value); if (value < 5) { value++; WarningCounts[key] = value; ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)$"{message} ({value}/{5})"); } } } } [HarmonyPatch(typeof(RedLocustBees), "IsHiveMissing")] internal static class RedLocustBeesIsHiveMissingPatch { private static bool Prefix(RedLocustBees __instance, ref bool __result) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)((EnemyAI)__instance).eye == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { __result = false; return false; } if ((Object)(object)__instance.hive == (Object)null) { __result = true; return false; } float num = Vector3.Distance(((EnemyAI)__instance).eye.position, __instance.lastKnownHivePosition); if (!Traverse.Create((object)__instance).Field("syncedLastKnownHivePosition").GetValue<bool>()) { __result = false; return false; } bool flag = num < 8f && !Physics.Linecast(((EnemyAI)__instance).eye.position, __instance.lastKnownHivePosition, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); if (num < 4f || flag) { if ((Vector3.Distance(((Component)__instance.hive).transform.position, __instance.lastKnownHivePosition) > 6f && !IsHivePlacedAndInLOS(__instance)) || __instance.hive.isHeld) { __result = true; return false; } __instance.lastKnownHivePosition = ((Component)__instance.hive).transform.position + Vector3.up * 0.5f; } __result = false; return false; } private static Exception Finalizer(Exception __exception) { return NullRefGuard.Suppress(__exception, "RedLocustBees.IsHiveMissing"); } private static bool IsHivePlacedAndInLOS(RedLocustBees bees) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bees.hive == (Object)null || (Object)(object)((EnemyAI)bees).eye == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || bees.hive.isHeld) { return false; } return Vector3.Distance(((EnemyAI)bees).eye.position, ((Component)bees.hive).transform.position) <= 9f && !Physics.Linecast(((EnemyAI)bees).eye.position, ((Component)bees.hive).transform.position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); } } [HarmonyPatch(typeof(RedLocustBees), "IsHivePlacedAndInLOS")] internal static class RedLocustBeesIsHivePlacedAndInLOSPatch { private static bool Prefix(RedLocustBees __instance, ref bool __result) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.hive == (Object)null || (Object)(object)((EnemyAI)__instance).eye == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || __instance.hive.isHeld) { __result = false; return false; } __result = Vector3.Distance(((EnemyAI)__instance).eye.position, ((Component)__instance.hive).transform.position) <= 9f && !Physics.Linecast(((EnemyAI)__instance).eye.position, ((Component)__instance.hive).transform.position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); return false; } private static Exception Finalizer(Exception __exception) { return NullRefGuard.Suppress(__exception, "RedLocustBees.IsHivePlacedAndInLOS"); } } [HarmonyPatch(typeof(RedLocustBees), "DoAIInterval")] internal static class RedLocustBeesDoAIIntervalPatch { private static bool Prefix(RedLocustBees __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } if (!Traverse.Create((object)__instance).Field("hasSpawnedHive").GetValue<bool>() || (Object)(object)__instance.hive != (Object)null) { return true; } ((EnemyAI)__instance).targetPlayer = null; ((EnemyAI)__instance).movingTowardsTargetPlayer = false; if (((EnemyAI)__instance).currentBehaviourStateIndex != 2) { ((EnemyAI)__instance).SwitchToBehaviourState(2); } return false; } private static Exception Finalizer(Exception __exception) { return NullRefGuard.Suppress(__exception, "RedLocustBees.DoAIInterval"); } } [HarmonyPatch(typeof(RedLocustBees), "Update")] internal static class RedLocustBeesUpdatePatch { private static bool Prefix(RedLocustBees __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)__instance.beeParticles == (Object)null || (Object)(object)__instance.beeParticlesTarget == (Object)null) { return false; } return true; } private static Exception Finalizer(Exception __exception) { return NullRefGuard.Suppress(__exception, "RedLocustBees.Update"); } } [HarmonyPatch(typeof(SandSpiderAI), "PlayerLeaveWebClientRpc")] internal static class SandSpiderAIPlayerLeaveWebClientRpcPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static Exception Finalizer(int trapID, int playerNum, Exception __exception) { if (__exception is ArgumentOutOfRangeException) { Warnings.Warn($"PlayerLeaveWebClientRpc|trap:{trapID}|player:{playerNum}", $"Suppressed SandSpiderAI.PlayerLeaveWebClientRpc ArgumentOutOfRangeException for trap {trapID}, player {playerNum}."); return null; } return __exception; } } [HarmonyPatch(typeof(GrabbableObjectPhysicsTrigger), "OnTriggerEnter")] internal static class GrabbableObjectPhysicsTriggerOnTriggerEnterPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(GrabbableObjectPhysicsTrigger __instance, Collider other) { if ((Object)(object)__instance?.itemScript != (Object)null && (Object)(object)((other != null) ? ((Component)other).gameObject : null) != (Object)null) { return true; } Warnings.Warn("missing-trigger-dependency", "Skipped GrabbableObjectPhysicsTrigger.OnTriggerEnter because itemScript or collider was missing."); return false; } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("nre", "Suppressed GrabbableObjectPhysicsTrigger.OnTriggerEnter NullReferenceException."); return null; } return __exception; } } [HarmonyPatch(typeof(SoccerBallProp), "ActivatePhysicsTrigger")] internal static class SoccerBallPropActivatePhysicsTriggerPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(SoccerBallProp __instance, Collider other) { //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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)((other != null) ? ((Component)other).gameObject : null) == (Object)null) { Warnings.Warn("missing-trigger", "Skipped SoccerBallProp.ActivatePhysicsTrigger because the ball or collider was missing."); return false; } GameObject gameObject = ((Component)other).gameObject; if (!IsPlayerOrEnemy(gameObject)) { return false; } if ((Object)(object)StartOfRound.Instance == (Object)null) { Warnings.Warn("missing-startofround", "Skipped SoccerBallProp.ActivatePhysicsTrigger because StartOfRound was not ready."); return false; } Vector3 val = gameObject.transform.position + Vector3.up; Vector3 val2 = ((Component)__instance).transform.position + Vector3.up * 0.5f; if (!Physics.Linecast(val, val2, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1)) { __instance.BeginKickBall(val, gameObject.CompareTag("Enemy")); } return false; } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("nre", "Suppressed SoccerBallProp.ActivatePhysicsTrigger NullReferenceException."); return null; } return __exception; } private static bool IsPlayerOrEnemy(GameObject gameObject) { return (Object)(object)gameObject != (Object)null && (gameObject.CompareTag("Player") || gameObject.CompareTag("Enemy")); } } [HarmonyPatch(typeof(SoccerBallProp), "BeginKickBall")] internal static class SoccerBallPropBeginKickBallPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(SoccerBallProp __instance, bool hitByEnemy) { if ((Object)(object)__instance != (Object)null && ((hitByEnemy && !((NetworkBehaviour)__instance).IsServer) || ((GrabbableObject)__instance).isHeld || (Object)(object)((GrabbableObject)__instance).parentObject != (Object)null)) { return false; } if (HasRequiredKickDependencies(__instance)) { return true; } Warnings.Warn("missing-kick-dependency", "Skipped SoccerBallProp.BeginKickBall because required ball, round, player, or ship references were missing."); return false; } private static Exception Finalizer(Exception __exception) { if (__exception is NullReferenceException) { Warnings.Warn("nre", "Suppressed SoccerBallProp.BeginKickBall NullReferenceException."); return null; } return __exception; } private static bool HasRequiredKickDependencies(SoccerBallProp ball) { if ((Object)(object)ball == (Object)null || (Object)(object)((Component)ball).transform == (Object)null || (Object)(object)((GrabbableObject)ball).itemProperties == (Object)null) { return false; } StartOfRound instance = StartOfRound.Instance; RoundManager instance2 = RoundManager.Instance; GameNetworkManager instance3 = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3?.localPlayerController == (Object)null) { return false; } return (Object)(object)instance.elevatorTransform != (Object)null && (Object)(object)instance.propsContainer != (Object)null && (Object)(object)instance.shipBounds != (Object)null && (Object)(object)instance.shipInnerRoomBounds != (Object)null && (Object)(object)instance2.spawnedScrapContainer != (Object)null; } } [HarmonyPatch(typeof(SoundManager), "PlayAmbienceClipLocal")] internal static class SoundManagerPlayAmbienceClipLocalPatch { private static readonly WarningLimiter Warnings = new WarningLimiter(); private static bool Prefix(SoundManager __instance, int soundType, int clipIndex, float soundVolume, bool playInsanitySounds) { try { return IsAmbienceClipValid(__instance, soundType, clipIndex, playInsanitySounds); } catch (Exception ex) { Warnings.Warn("guard-failed", "SoundManager.PlayAmbienceClipLocal guard failed safely and allowed original playback: " + ex.GetType().Name + "."); return true; } } private static Exception Finalizer(int soundType, int clipIndex, bool playInsanitySounds, Exception __exception) { if (__exception is IndexOutOfRangeException) { Warnings.Warn($"index-exception|{soundType}|{playInsanitySounds}", $"Suppressed SoundManager.PlayAmbienceClipLocal IndexOutOfRangeException for soundType {soundType}, clipIndex {clipIndex}, playInsanitySounds={playInsanitySounds}."); return null; } return __exception; } private static bool IsAmbienceClipValid(SoundManager soundManager, int soundType, int clipIndex, bool playInsanitySounds) { if ((Object)(object)soundManager == (Object)null || (Object)(object)soundManager.currentLevelAmbience == (Object)null) { Warnings.Warn("missing-ambience", "Skipped SoundManager.PlayAmbienceClipLocal because currentLevelAmbience was missing."); return false; } if (clipIndex < 0) { Warnings.Warn($"negative-index|{soundType}|{playInsanitySounds}", $"Skipped SoundManager.PlayAmbienceClipLocal because clipIndex {clipIndex} was negative for soundType {soundType}."); return false; } LevelAmbienceLibrary currentLevelAmbience = soundManager.currentLevelAmbience; if (playInsanitySounds) { return IsInsanityClipValid(currentLevelAmbience, soundType, clipIndex); } return IsNormalClipValid(currentLevelAmbience, soundType, clipIndex); } private static bool IsNormalClipValid(LevelAmbienceLibrary ambience, int soundType, int clipIndex) { if (1 == 0) { } AudioClip[] array = soundType switch { 0 => ambience.insideAmbience, 1 => ambience.outsideAmbience, 2 => ambience.shipAmbience, _ => null, }; if (1 == 0) { } AudioClip[] array2 = array; if (array2 != null && clipIndex < array2.Length && (Object)(object)array2[clipIndex] != (Object)null) { return true; } WarnInvalidIndex(soundType, clipIndex, playInsanitySounds: false, (array2 != null) ? array2.Length : 0); return false; } private static bool IsInsanityClipValid(LevelAmbienceLibrary ambience, int soundType, int clipIndex) { if (1 == 0) { } RandomAudioClip[] array = soundType switch { 0 => ambience.insideAmbienceInsanity, 1 => ambience.outsideAmbienceInsanity, 2 => ambience.shipAmbienceInsanity, _ => null, }; if (1 == 0) { } RandomAudioClip[] array2 = array; if (array2 != null && clipIndex < array2.Length && array2[clipIndex] != null && (Object)(object)array2[clipIndex].audioClip != (Object)null) { return true; } WarnInvalidIndex(soundType, clipIndex, playInsanitySounds: