Decompiled source of BRUTALISTICKMP v0.3.7
Mods/Mods/BrutalistickMP.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BrutalistickMP; using BrutalistickMP.Core; using HarmonyLib; using Il2Cpp; using Il2CppActiveRagdoll; using Il2CppHexabodyVR.PlayerController; using Il2CppHurricaneVR.Framework.Core; using Il2CppHurricaneVR.Framework.Core.Grabbers; using Il2CppHurricaneVR.Framework.Weapons; using Il2CppHurricaneVR.Framework.Weapons.Guns; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(MultiplayerMod), "BrutalistickMP", "0.3.5", "BrutalistickMP contributors", null)] [assembly: MelonGame("Kubunautilus", "BrutalistickVR")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("BrutalistickMP")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BrutalistickMP")] [assembly: AssemblyTitle("BrutalistickMP")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte flag) { NullableFlags = new byte[1] { flag }; } public NullableAttribute(byte[] flags) { NullableFlags = flags; } } } namespace BrutalistickMP { internal static class DevAutoTest { private static float _menuSince = -1f; private static bool _missionStarted; private static float _levelSince = -1f; private static float _nextShot; private static float _itemStepAt = -1f; private static int _itemStep; private static HVRGunBase? _testGun; private static bool _clientGrabbed; private static float _levelAt = -1f; private static bool _pvpDone; private static bool _spawnDone; private static bool _sliceDone; private static bool _grabDone; private static bool _releaseDone; private static HVRHandGrabber? _grabHand; private static GameObject? _sliceCountRoot; private static bool _clientSliceCounted; private static float _sliceCountAt = -1f; public static bool Enabled => DevOptions.AutoTest.Length > 0; private static bool IsHost { get { string autoTest = DevOptions.AutoTest; if (autoTest == "host" || autoTest == "solo") { return true; } return false; } } public static MissionInfo TestMission => new MissionInfo { SceneName = "Farmland", WaveLength = 6, EnemyType = DevOptions.EnemyType, WaveType = 0, WaveDifficulty = 1 }; public static void OnSteamReady(Session session) { if (IsHost) { session.StartHosting(); } } public static void OnScene(string scene) { bool flag = ((scene == "MainMenuScene" || scene == "MainHub") ? true : false); _menuSince = (flag ? Time.unscaledTime : (-1f)); _levelSince = ((scene == TestMission.SceneName) ? Time.unscaledTime : (-1f)); } public static void AdjustPose(ref PoseData pose) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if (DevOptions.AutoTest != "client-bait") { return; } foreach (StickHealth item in Object.FindObjectsOfType<StickHealth>()) { GameObject gameObject = ((Component)((Component)item).transform.root).gameObject; if (!EnemySync.IsPuppet(gameObject) || item.isDead) { continue; } ColliderBridge val = null; foreach (ColliderBridge componentsInChild in gameObject.GetComponentsInChildren<ColliderBridge>()) { if (componentsInChild.damageRegion == "head") { val = componentsInChild; } } if (!((Object)(object)val == (Object)null)) { Vector3 vector = ((Component)val).transform.position.ToN() + new Vector3(1.2f, -0.6f, 0f) - pose.PelvisPos; pose.HeadPos += vector; pose.ChestPos += vector; pose.PelvisPos += vector; pose.LeftHandPos += vector; pose.RightHandPos += vector; pose.FeetPos += vector; break; } } } private static void ClientShoot(Session session) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) if (session.Role != Role.Client || Time.unscaledTime < _nextShot) { return; } _nextShot = Time.unscaledTime + 5f; foreach (StickHealth item in Object.FindObjectsOfType<StickHealth>()) { GameObject gameObject = ((Component)((Component)item).transform.root).gameObject; if (!EnemySync.IsPuppet(gameObject) || item.isDead) { continue; } ColliderBridge val = null; foreach (ColliderBridge componentsInChild in gameObject.GetComponentsInChildren<ColliderBridge>()) { if (componentsInChild.damageRegion == "head") { val = componentsInChild; } } if (!((Object)(object)val == (Object)null)) { Transform transform = ((Component)val).transform; MelonLogger.Msg($"[autotest] shooting '{((Object)gameObject).name}' in the head at {transform.position}"); BulletForce.Current = 20f; val.HitByBullet(40f, "9mm", transform.position, transform.forward, (transform.forward.ToN() * -1f).ToU(), 0.5f); break; } } } private static HVRHandGrabber? RightHand() { foreach (HVRHandGrabber item in Object.FindObjectsOfType<HVRHandGrabber>()) { if (!item.IsLeftHand && ((Behaviour)item).isActiveAndEnabled) { return item; } } return null; } private static void HostItemTest(Session session) { //IL_01c3: Unknown result type (might be due to invalid IL or missing references) if (_itemStepAt < 0f || Time.unscaledTime < _itemStepAt) { return; } HVRHandGrabber val = RightHand(); if ((Object)(object)val == (Object)null) { return; } switch (_itemStep) { case 0: { foreach (HVRGunBase item in Object.FindObjectsOfType<HVRGunBase>()) { if (((Object)item).name.StartsWith("9mmPistol")) { _testGun = item; } } HVRGrabbable val3 = (((Object)(object)_testGun != (Object)null) ? ((Component)_testGun).GetComponentInParent<HVRGrabbable>() : null); if ((Object)(object)val3 == (Object)null) { MelonLogger.Msg("[autotest] no pistol on the weapon wall"); _itemStepAt = -1f; break; } bool value = ((HVRGrabberBase)val).TryGrab(val3, true); MelonLogger.Msg($"[autotest] grabbing '{((Object)val3).name}': {value}, holding {(((Object)(object)((HVRGrabberBase)val).GrabbedTarget != (Object)null) ? ((Object)((HVRGrabberBase)val).GrabbedTarget).name : "nothing")}"); _itemStep = 1; _itemStepAt = Time.unscaledTime + 3f; break; } case 1: case 2: case 3: case 4: _itemStep++; _itemStepAt = Time.unscaledTime + 2f; if ((Object)(object)_testGun != (Object)null) { Transform val2 = (((Object)(object)_testGun.BulletOrigin != (Object)null) ? _testGun.BulletOrigin : ((Component)_testGun).transform); MelonLogger.Msg("[autotest] firing the pistol"); _testGun.FireBullet(val2.forward, -1); } break; case 5: MelonLogger.Msg("[autotest] dropping the pistol"); ((HVRGrabberBase)val).ForceRelease(); _itemStepAt = -1f; break; } } private static void ClientItemTest() { if (!_clientGrabbed) { HVRGrabbable val = ItemSync.FirstGrabbableCopy(); HVRHandGrabber val2 = RightHand(); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { _clientGrabbed = true; bool value = ((HVRGrabberBase)val2).TryGrab(val, true); MelonLogger.Msg($"[autotest] picking up our copy of '{((Object)val).name}': {value}"); } } } private static void ClientExtraTests(Session session) { //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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if (session.Role != Role.Client || _levelAt < 0f) { return; } CountSlicePieces(); float num = Time.unscaledTime - _levelAt; if (_sliceCountAt < 0f && !_clientSliceCounted && EnemySync.SeenSlice) { _clientSliceCounted = true; _sliceCountAt = Time.unscaledTime + 3f; } if (!_pvpDone && num > 12f) { Vector3? val = PvpSync.AnyChest(); if (val.HasValue) { Vector3 valueOrDefault = val.GetValueOrDefault(); Transform head = PlayerRig.Head; if (head != null) { _pvpDone = true; Vector3 vector = head.position.ToN() + new Vector3(0f, 0.3f, 0f); Vector3 vector2 = valueOrDefault.ToN() - vector; bool flag = PvpSync.Shoot((valueOrDefault.ToN() - Vector3.Normalize(vector2) * 0.6f).ToU(), vector2.ToU(), 30f); MelonLogger.Msg("[autotest] shooting the host's body: " + (flag ? "hit" : "missed")); } } } if (!_spawnDone && num > 16f) { Transform head2 = PlayerRig.Head; if (head2 != null) { _spawnDone = true; Vector3 position = head2.position.ToN() + new Vector3(3f, -1.5f, 0f); PacketWriter w = session.Begin(MsgType.EnemySpawnRequest); EnemySpawnRequestMsg enemySpawnRequestMsg = default(EnemySpawnRequestMsg); enemySpawnRequestMsg.Prefab = "Handgun"; enemySpawnRequestMsg.Position = position; enemySpawnRequestMsg.Yaw = 90f; enemySpawnRequestMsg.Write(w); session.SendToHost(reliable: true); MelonLogger.Msg("[autotest] asking the host to spawn a 'Handgun' enemy"); } } if (!_grabDone && num > 22f) { foreach (StickHealth item in Object.FindObjectsOfType<StickHealth>()) { GameObject gameObject = ((Component)((Component)item).transform.root).gameObject; if (!EnemySync.IsPuppet(gameObject) || item.isDead) { continue; } HVRGrabbable val2 = null; foreach (HVRGrabbable componentsInChild in gameObject.GetComponentsInChildren<HVRGrabbable>()) { if (((Object)componentsInChild).name == "UpperChest" || ((Object)componentsInChild).name == "Head") { val2 = componentsInChild; } } _grabHand = RightHand(); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)_grabHand == (Object)null)) { _grabDone = true; bool value = ((HVRGrabberBase)_grabHand).TryGrab(val2, true); MelonLogger.Msg($"[autotest] grabbing host enemy '{((Object)gameObject).name}' by '{((Object)val2).name}': {value}"); break; } } } if (_grabDone && !_releaseDone && num > 30f) { _releaseDone = true; HVRHandGrabber? grabHand = _grabHand; if (grabHand != null) { ((HVRGrabberBase)grabHand).ForceRelease(); } MelonLogger.Msg("[autotest] letting go of the enemy"); } } private static void CountSlicePieces() { if (_sliceCountAt < 0f || Time.unscaledTime < _sliceCountAt) { return; } _sliceCountAt = -1f; int num = 0; foreach (Rigidbody item in Object.FindObjectsOfType<Rigidbody>()) { if (!item.isKinematic && ((Object)item).name.Contains("Elbow")) { num++; } } MelonLogger.Msg($"[autotest] moving 'Elbow' pieces in the level after the slice: {num}"); } private static void HostExtraTests(Session session) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) CountSlicePieces(); if (session.Role != Role.Host || _levelAt < 0f || _sliceDone || Time.unscaledTime - _levelAt < 20f) { return; } foreach (SliceOnInputCustom item in Object.FindObjectsOfType<SliceOnInputCustom>()) { GameObject gameObject = ((Component)((Component)item).transform.root).gameObject; if (EnemySync.IsHostEnemy(gameObject) && !(((Object)item).name != "Elbow_R") && item.canSlice) { _sliceDone = true; Transform transform = ((Component)item).transform; int length = gameObject.GetComponentsInChildren<Transform>().Length; MelonLogger.Msg($"[autotest] slicing '{((Object)gameObject).name}' through '{((Object)transform).name}'"); try { item.InitiateSlicing(new Plane(transform.up, transform.position), transform.position, Vector3.zero, EnemySync.SliceDummy, new Il2CppReferenceArray<Collider>(0L), (Rigidbody)null, 0.3f, (Rigidbody)null); } catch (Exception ex) { MelonLogger.Msg("[autotest] slicing failed: " + ex.Message); } MelonLogger.Msg($"[autotest] '{((Object)gameObject).name}' had {length} parts"); _sliceCountRoot = gameObject; _sliceCountAt = Time.unscaledTime + 3f; break; } } } public static void Update(Session session) { if (_levelAt < 0f && MultiplayerMod.CurrentScene == TestMission.SceneName) { _levelAt = Time.unscaledTime; } if (DevOptions.AutoTest.StartsWith("client")) { ClientShoot(session); ClientItemTest(); ClientExtraTests(session); } if (IsHost) { HostItemTest(session); HostExtraTests(session); } if (Enabled && IsHost && _levelSince >= 0f && Time.unscaledTime - _levelSince > 6f) { _levelSince = -1f; foreach (EnemyWaveSpawner item in Object.FindObjectsOfType<EnemyWaveSpawner>()) { MelonLogger.Msg("[autotest] starting the wave"); item.spawnerActive = true; } _itemStep = 0; _itemStepAt = Time.unscaledTime + 4f; } if (!Enabled || !IsHost || _missionStarted || _menuSince < 0f || (!(DevOptions.AutoTest == "solo") && session.Peers.Count <= 0) || Time.unscaledTime - _menuSince < 8f) { return; } _menuSince = -1f; if (MultiplayerMod.CurrentScene != "MainHub") { MelonLogger.Msg("[autotest] going to the hub"); Il2CppArrayBase<MenuUIManager> val = Object.FindObjectsOfType<MenuUIManager>(true); if (val.Length > 0) { val[0].SelectScene("MainHub"); } } else { _missionStarted = true; MelonLogger.Msg("[autotest] starting test mission"); MissionSync.StartAsHost(TestMission); } } } internal static class DevOptions { public static int LocalSlot { get; } public static string AutoTest { get; } public static int EnemyType { get; } public static bool Probe { get; } static DevOptions() { AutoTest = ""; string[] commandLineArgs = Environment.GetCommandLineArgs(); foreach (string text in commandLineArgs) { int result2; if (text.StartsWith("--bmp-local=") && int.TryParse(text.AsSpan("--bmp-local=".Length), out var result)) { LocalSlot = result; } else if (text.StartsWith("--bmp-autotest=")) { AutoTest = text.Substring("--bmp-autotest=".Length); } else if (text.StartsWith("--bmp-enemytype=") && int.TryParse(text.AsSpan("--bmp-enemytype=".Length), out result2)) { EnemyType = result2; } else if (text == "--bmp-probe") { Probe = true; } } } } internal static class DevProbe { private static readonly HashSet<string> DumpedPrefabs = new HashSet<string>(); private static float _nextStatus; private static StickHealth? _hitTarget; private static float _hitAt; private static float _watchUntil; private static bool _hitDone; private static float _itemSurveyAt = -1f; private static void Log(string msg) { MelonLogger.Msg("[probe] " + msg); } public static void OnScene(string scene) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (!DevOptions.Probe) { return; } _hitTarget = null; _hitDone = false; foreach (EnemyWaveSpawner item in Object.FindObjectsOfType<EnemyWaveSpawner>(true)) { Log($"spawner '{Path(((Component)item).transform)}' active={((Behaviour)item).isActiveAndEnabled} waveType={item.waveType} difficulty={item.waveDifficulty} waveEnemyCount={item.waveEnemyCount} breach={item.breachEnemyCount} aliveAtOnce={item.enemiesAliveAtOnce} maxDead={item.maxDeadBodies} ranged={Names(item.rangedPrefabs)} melee={Names(item.meleePrefabs)} zombie={Names(item.zombiePrefabs)} dummy={(((Object)(object)item.dummyEnemyPrefab != (Object)null) ? ((Object)item.dummyEnemyPrefab).name : "-")}"); } Il2CppArrayBase<StickHealth> val = Object.FindObjectsOfType<StickHealth>(true); Log($"scene {scene}: {val.Length} StickHealth objects already in the scene"); foreach (StickHealth item2 in ((IEnumerable<StickHealth>)val).Take(5)) { Log($" pre-placed stick '{Path(((Component)item2).transform)}' active={((Component)item2).gameObject.activeInHierarchy}"); } foreach (PlayerDamageBridge item3 in Object.FindObjectsOfType<PlayerDamageBridge>(true)) { Collider component = ((Component)item3).GetComponent<Collider>(); Log($"player damage bridge '{Path(((Component)item3).transform)}' layer={LayerMask.LayerToName(((Component)item3).gameObject.layer)} collider={(((Object)(object)component != (Object)null) ? ((MemberInfo)((Object)component).GetIl2CppType()).Name : "-")} mult={item3.dmgMultiplier}"); } PlayerHealthManager val2 = ((IEnumerable<PlayerHealthManager>)Object.FindObjectsOfType<PlayerHealthManager>(true)).FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { Log($"player health {val2.health}/{val2.startHealth} on '{Path(((Component)val2).transform)}'"); } _itemSurveyAt = Time.unscaledTime + 10f; } private static void ItemSurvey() { //IL_074f: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_08e7: Unknown result type (might be due to invalid IL or missing references) //IL_08ed: Unknown result type (might be due to invalid IL or missing references) //IL_056e: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_0644: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Unknown result type (might be due to invalid IL or missing references) GameObject playerHexaPelvisStatic = PlayerStaticReferences.playerHexaPelvisStatic; if ((Object)(object)playerHexaPelvisStatic != (Object)null) { Log("player body under '" + Path(playerHexaPelvisStatic.transform) + "':"); foreach (Renderer componentsInChild in playerHexaPelvisStatic.GetComponentsInChildren<Renderer>(true)) { Transform transform = ((Component)componentsInChild).transform; MeshFilter component = ((Component)componentsInChild).GetComponent<MeshFilter>(); object obj2; if (!((Object)(object)component != (Object)null) || !((Object)(object)component.sharedMesh != (Object)null)) { SkinnedMeshRenderer obj = ((Il2CppObjectBase)componentsInChild).TryCast<SkinnedMeshRenderer>(); if (obj == null) { obj2 = null; } else { Mesh sharedMesh = obj.sharedMesh; obj2 = ((sharedMesh != null) ? ((Object)sharedMesh).name : null); } if (obj2 == null) { obj2 = "-"; } } else { obj2 = ((Object)component.sharedMesh).name; } string value = (string)obj2; string value2 = string.Join(",", ((IEnumerable<Material>)componentsInChild.sharedMaterials).Select((Material m) => (!((Object)(object)m != (Object)null)) ? "null" : ((Object)m).name)); Log($" {((MemberInfo)((Object)componentsInChild).GetIl2CppType()).Name} '{Path(transform)}' on={componentsInChild.enabled && ((Component)componentsInChild).gameObject.activeInHierarchy} layer={LayerMask.LayerToName(((Component)transform).gameObject.layer)} mesh={value} mats=[{value2}] pos={transform.position} scale={transform.lossyScale}"); } Transform root = playerHexaPelvisStatic.transform.root; int length = ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(true).Length; Log($" rig '{((Object)root).name}' has {((Component)root).GetComponentsInChildren<Renderer>(true).Length} renderers ({length} skinned)"); Dictionary<string, (int, int)> dictionary = new Dictionary<string, (int, int)>(); foreach (Renderer componentsInChild2 in ((Component)root).GetComponentsInChildren<Renderer>(true)) { string[] array = Path(((Component)componentsInChild2).transform).Split('/'); string key = string.Join("/", array.Take(Math.Min(4, array.Length - 1))); dictionary.TryGetValue(key, out var value3); dictionary[key] = (value3.Item1 + 1, value3.Item2 + ((componentsInChild2.enabled && ((Component)componentsInChild2).gameObject.activeInHierarchy) ? 1 : 0)); SkinnedMeshRenderer val = ((Il2CppObjectBase)componentsInChild2).TryCast<SkinnedMeshRenderer>(); if (val != null) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(42, 5); defaultInterpolatedStringHandler.AppendLiteral(" skinned '"); defaultInterpolatedStringHandler.AppendFormatted(Path(((Component)componentsInChild2).transform)); defaultInterpolatedStringHandler.AppendLiteral("' shown="); defaultInterpolatedStringHandler.AppendFormatted(componentsInChild2.enabled && ((Component)componentsInChild2).gameObject.activeInHierarchy); defaultInterpolatedStringHandler.AppendLiteral(" mesh="); Mesh sharedMesh2 = val.sharedMesh; defaultInterpolatedStringHandler.AppendFormatted((sharedMesh2 != null) ? ((Object)sharedMesh2).name : null); defaultInterpolatedStringHandler.AppendLiteral(" bones="); defaultInterpolatedStringHandler.AppendFormatted(((Il2CppArrayBase<Transform>)(object)val.bones)?.Length); defaultInterpolatedStringHandler.AppendLiteral(" rootBone="); defaultInterpolatedStringHandler.AppendFormatted(((Object)(object)val.rootBone != (Object)null) ? Path(val.rootBone) : "-"); Log(defaultInterpolatedStringHandler.ToStringAndClear()); } } foreach (var (value4, tuple2) in dictionary) { Log($" renderers under '{value4}': {tuple2.Item1} ({tuple2.Item2} shown)"); } StringBuilder stringBuilder = new StringBuilder("visible body parts:\n"); foreach (MeshRenderer componentsInChild3 in ((Component)root).GetComponentsInChildren<MeshRenderer>(false)) { if (!((Renderer)componentsInChild3).enabled) { continue; } string text2 = Path(((Component)componentsInChild3).transform); if (text2.Contains("PhysicalUpperbody") || text2.Contains("CameraRig") || text2.Contains("HandModel")) { MeshFilter component2 = ((Component)componentsInChild3).GetComponent<MeshFilter>(); Bounds bounds = ((Renderer)componentsInChild3).bounds; StringBuilder stringBuilder2 = stringBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(25, 5, stringBuilder2); handler.AppendLiteral(" "); handler.AppendFormatted(text2.Substring(((Object)root).name.Length)); handler.AppendLiteral(" mesh="); handler.AppendFormatted(((Object)(object)component2 != (Object)null && (Object)(object)component2.sharedMesh != (Object)null) ? ((Object)component2.sharedMesh).name : "-"); handler.AppendLiteral(" mats="); handler.AppendFormatted(string.Join(",", ((IEnumerable<Material>)((Renderer)componentsInChild3).sharedMaterials).Select((Material m) => (!((Object)(object)m != (Object)null)) ? "null" : ((Object)m).name))); handler.AppendLiteral(" size="); handler.AppendFormatted<Vector3>(((Bounds)(ref bounds)).size); handler.AppendLiteral(" at="); handler.AppendFormatted<Vector3>(((Component)componentsInChild3).transform.position); handler.AppendLiteral("\n"); stringBuilder2.Append(ref handler); } } Log(stringBuilder.ToString()); } List<SpawnableItemInfo> spawnableItems = SpawnGunManager.spawnableItems; Log($"items: catalog has {spawnableItems?.Count ?? (-1)} entries"); if (spawnableItems != null) { for (int num = 0; num < spawnableItems.Count; num += Math.Max(1, spawnableItems.Count / 12)) { SpawnableItemInfo val2 = spawnableItems[num]; Log($" catalog[{num}] '{val2.spawnableName}' {val2.spawnableType} prefab='{(((Object)(object)val2.itemPrefab != (Object)null) ? ((Object)val2.itemPrefab).name : "-")}' modded={val2.isModded}"); } } foreach (HVRHandGrabber item in Object.FindObjectsOfType<HVRHandGrabber>(true)) { Log($" hand '{Path(((Component)item).transform)}' left={item.IsLeftHand} active={((Behaviour)item).isActiveAndEnabled} holding={(((Object)(object)((HVRGrabberBase)item).GrabbedTarget != (Object)null) ? ((Object)((HVRGrabberBase)item).GrabbedTarget).name : "-")}"); } Transform head = PlayerRig.Head; int num2 = 0; foreach (HVRGrabbable item2 in Object.FindObjectsOfType<HVRGrabbable>()) { if ((Object)(object)head == (Object)null || num2 >= 25) { break; } if (!(Vector3.Distance(((Component)item2).transform.position, head.position) > 2.5f) && !((Object)((Component)item2).transform.root).name.Contains("Hexa")) { num2++; Rigidbody rigidbody = item2.Rigidbody; Collider componentInChildren = ((Component)item2).GetComponentInChildren<Collider>(); Log($" near player: '{Path(((Component)item2).transform)}' rb={(((Object)(object)rigidbody != (Object)null) ? $"kin={rigidbody.isKinematic}" : "-")} layer={LayerMask.LayerToName(((Component)item2).gameObject.layer)} col={(((Object)(object)componentInChildren != (Object)null) ? LayerMask.LayerToName(((Component)componentInChildren).gameObject.layer) : "-")} socketed={item2.IsSocketed}"); } } foreach (HVRGunBase item3 in ((IEnumerable<HVRGunBase>)Object.FindObjectsOfType<HVRGunBase>()).Take(5)) { Log($" gun '{Path(((Component)item3).transform)}' bullet={(((Object)(object)item3.BulletPrefab != (Object)null) ? ((Object)item3.BulletPrefab).name : "-")} speed={item3.BulletSpeed} origin={(((Object)(object)item3.BulletOrigin != (Object)null) ? ((Object)item3.BulletOrigin).name : "-")} sounds={(Object)(object)((Component)item3).GetComponent<HVRGunSounds>() != (Object)null}"); } } public static void Update() { if (!DevOptions.Probe) { return; } float unscaledTime = Time.unscaledTime; if (_itemSurveyAt > 0f && unscaledTime >= _itemSurveyAt) { _itemSurveyAt = -1f; try { ItemSurvey(); } catch (Exception ex) { Log("item survey failed: " + ex.Message); } } if (unscaledTime >= _nextStatus) { _nextStatus = unscaledTime + 3f; foreach (EnemyWaveSpawner item in Object.FindObjectsOfType<EnemyWaveSpawner>()) { List<StickHealth> stickHealthScripts = item.stickHealthScripts; KillCounterScript instanceOfThis = KillCounterScript.instanceOfThis; PlayerHealthManager val = ((IEnumerable<PlayerHealthManager>)Object.FindObjectsOfType<PlayerHealthManager>()).FirstOrDefault(); MissionComplete val2 = ((IEnumerable<MissionComplete>)Object.FindObjectsOfType<MissionComplete>()).FirstOrDefault(); Log($"wave[{MultiplayerMod.Session?.Role}]: hp={(((Object)(object)val != (Object)null) ? val.health : (-1f)):F0} complete={(Object)(object)val2 != (Object)null && val2.isMissionComplete} active={item.spawnerActive} current={item.waveEnemyCurrentCount}/{item.waveEnemyCount} alive={item.enemiesCurrentlyAlive} list={stickHealthScripts?.Count ?? (-1)} breach={item.breachEnemyCurrentCount}/{item.breachEnemyCount} dead={item.breachDeadBodiesCount} kills={(((Object)(object)instanceOfThis != (Object)null) ? instanceOfThis.killsCounted : (-1))}"); if ((Object)(object)_hitTarget == (Object)null && stickHealthScripts != null && stickHealthScripts.Count > 0) { _hitTarget = stickHealthScripts[0]; _hitAt = unscaledTime + 20f; } if (stickHealthScripts != null && stickHealthScripts.Count > 0) { LogTargets(stickHealthScripts[0]); } } } if ((Object)(object)_hitTarget != (Object)null && !_hitDone && unscaledTime >= _hitAt) { HitTest(_hitTarget); } if ((Object)(object)_hitTarget != (Object)null && _hitDone && unscaledTime < _watchUntil) { Log($" after: health={_hitTarget.StickCurrentHealth:F1} cp={_hitTarget.StickCurrentCP:F1} queue={_hitTarget.damageInfoList?.Count} dead={_hitTarget.isDead} enabled={((Behaviour)_hitTarget).enabled}"); } } private static void HitTest(StickHealth stick) { //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) _hitDone = true; _watchUntil = Time.unscaledTime + 0.5f; Il2CppArrayBase<ColliderBridge> componentsInChildren = ((Component)stick).GetComponentsInChildren<ColliderBridge>(true); ColliderBridge val = ((IEnumerable<ColliderBridge>)componentsInChildren).FirstOrDefault((Func<ColliderBridge, bool>)((ColliderBridge b) => (b.damageRegion ?? "").Contains("Head"))) ?? ((IEnumerable<ColliderBridge>)componentsInChildren).FirstOrDefault(); if ((Object)(object)val == (Object)null) { Log("hit test: no ColliderBridge"); return; } Log($"hit test on '{Path(((Component)val).transform)}' region={val.damageRegion} mult={val.damageMultiplier}: before health={stick.StickCurrentHealth:F1} cp={stick.StickCurrentCP:F1} queue={stick.damageInfoList?.Count}"); string text = ((val.bulletCalibers != null && val.bulletCalibers.Count > 0) ? val.bulletCalibers[0] : "9mm"); Transform transform = ((Component)val).transform; val.HitByBullet(40f, text, transform.position, transform.forward, -transform.forward, 0.5f); Log($" right after: health={stick.StickCurrentHealth:F1} queue={stick.damageInfoList?.Count}"); } public static void OnInstantiated(EnemyWaveSpawner spawner, int enemNum, GameObject enemy) { if (DevOptions.Probe && !((Object)(object)enemy == (Object)null)) { PrefabRef? prefabRef = EnemyCatalog.Identify(spawner, enemy); Log($"InstantiateEnemy({enemNum}) -> '{((Object)enemy).name}' prefab={prefabRef} active={enemy.activeSelf}"); string item = prefabRef?.ToString() ?? ((Object)enemy).name; if (DumpedPrefabs.Add(item)) { DumpHierarchy(enemy); } } } public static void OnSpawned(EnemyWaveSpawner spawner) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (DevOptions.Probe) { List<StickHealth> stickHealthScripts = spawner.stickHealthScripts; if (stickHealthScripts != null && stickHealthScripts.Count != 0) { StickHealth val = stickHealthScripts[stickHealthScripts.Count - 1]; DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(31, 3); defaultInterpolatedStringHandler.AppendLiteral("SpawnNewEnemy -> '"); defaultInterpolatedStringHandler.AppendFormatted(((Object)((Component)val).transform.root).name); defaultInterpolatedStringHandler.AppendLiteral("' at "); Transform pelvisTransform = val.pelvisTransform; defaultInterpolatedStringHandler.AppendFormatted((pelvisTransform != null) ? new Vector3?(pelvisTransform.position) : ((Vector3?)null)); defaultInterpolatedStringHandler.AppendLiteral(" health="); defaultInterpolatedStringHandler.AppendFormatted(val.StickCurrentHealth); Log(defaultInterpolatedStringHandler.ToStringAndClear()); LogTargets(val); } } } private static void LogTargets(StickHealth stick) { //IL_007e: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = ((Component)((Component)stick).transform.root).gameObject; Transform head = PlayerRig.Head; Transform val = (((Object)(object)stick.pelvisRb != (Object)null) ? ((Component)stick.pelvisRb).transform : null); if ((Object)(object)val != (Object)null && (Object)(object)head != (Object)null) { Log($" enemy '{((Object)gameObject).name}' pelvis {val.position} player head {head.position} dist {Vector3.Distance(val.position, head.position):F1} health={stick.StickCurrentHealth:F0} dead={stick.isDead}"); } MovementBasic componentInChildren = gameObject.GetComponentInChildren<MovementBasic>(true); if ((Object)(object)componentInChildren != (Object)null) { Log($" MovementBasic target={Describe(componentInChildren.targetObject)} playerPelvis={Describe(componentInChildren.playerPelvisObject)} targetTransform={Describe(componentInChildren.targetTransformObject)}"); } EnemyFOV componentInChildren2 = gameObject.GetComponentInChildren<EnemyFOV>(true); if ((Object)(object)componentInChildren2 != (Object)null) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(31, 3); defaultInterpolatedStringHandler.AppendLiteral(" EnemyFOV player="); defaultInterpolatedStringHandler.AppendFormatted(Describe(componentInChildren2.playerObject)); defaultInterpolatedStringHandler.AppendLiteral(" mask="); LayerMask layerMask = componentInChildren2.layerMask; defaultInterpolatedStringHandler.AppendFormatted(((LayerMask)(ref layerMask)).value); defaultInterpolatedStringHandler.AppendLiteral(" start="); defaultInterpolatedStringHandler.AppendFormatted(Describe(componentInChildren2.viewConeStartPosition)); Log(defaultInterpolatedStringHandler.ToStringAndClear()); } StickGunManager componentInChildren3 = gameObject.GetComponentInChildren<StickGunManager>(true); if ((Object)(object)componentInChildren3 != (Object)null) { DefaultInterpolatedStringHandler defaultInterpolatedStringHandler2 = new DefaultInterpolatedStringHandler(56, 5); defaultInterpolatedStringHandler2.AppendLiteral(" StickGunManager gunTarget="); defaultInterpolatedStringHandler2.AppendFormatted(Describe(componentInChildren3.gunTarget)); defaultInterpolatedStringHandler2.AppendLiteral(" head="); defaultInterpolatedStringHandler2.AppendFormatted(Describe(componentInChildren3.headTarget)); defaultInterpolatedStringHandler2.AppendLiteral(" rHand="); defaultInterpolatedStringHandler2.AppendFormatted(Describe(componentInChildren3.rHandTarget)); defaultInterpolatedStringHandler2.AppendLiteral(" lHand="); defaultInterpolatedStringHandler2.AppendFormatted(Describe(componentInChildren3.lHandTarget)); defaultInterpolatedStringHandler2.AppendLiteral(" bullet="); GameObject bulletPrefab = componentInChildren3.bulletPrefab; defaultInterpolatedStringHandler2.AppendFormatted((bulletPrefab != null) ? ((Object)bulletPrefab).name : null); Log(defaultInterpolatedStringHandler2.ToStringAndClear()); } EnemyMeleeManager componentInChildren4 = gameObject.GetComponentInChildren<EnemyMeleeManager>(true); if ((Object)(object)componentInChildren4 != (Object)null) { Log(" EnemyMeleeManager playerBodyPart=" + Describe(componentInChildren4.playerBodyPart)); } EnemyAIManager componentInChildren5 = gameObject.GetComponentInChildren<EnemyAIManager>(true); if ((Object)(object)componentInChildren5 != (Object)null) { Log($" EnemyAIManager type={componentInChildren5.enemyType} activated={componentInChildren5.isAIActivated}"); } } private static void DumpHierarchy(GameObject root) { StringBuilder sb = new StringBuilder(); StringBuilder stringBuilder = sb; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder); handler.AppendLiteral("hierarchy of '"); handler.AppendFormatted(((Object)root).name); handler.AppendLiteral("':"); stringBuilder.AppendLine(ref handler); Walk(root.transform, 1); Log(sb.ToString()); void Walk(Transform t, int depth) { GameObject gameObject = ((Component)t).gameObject; IEnumerable<string> values = from c in (IEnumerable<Component>)gameObject.GetComponents<Component>() where (Object)(object)c != (Object)null select ((MemberInfo)((Object)c).GetIl2CppType()).Name into n where n != "Transform" select n; Rigidbody component = gameObject.GetComponent<Rigidbody>(); Il2CppArrayBase<Collider> components = gameObject.GetComponents<Collider>(); sb.Append(' ', depth * 2).Append(((Object)gameObject).name).Append(gameObject.activeSelf ? "" : " (inactive)") .Append(" [") .Append(LayerMask.LayerToName(gameObject.layer)) .Append("] ") .Append(string.Join(",", values)); if ((Object)(object)component != (Object)null) { StringBuilder stringBuilder2 = sb; StringBuilder stringBuilder3 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler2 = new StringBuilder.AppendInterpolatedStringHandler(12, 2, stringBuilder2); handler2.AppendLiteral(" rb(kin="); handler2.AppendFormatted(component.isKinematic); handler2.AppendLiteral(",m="); handler2.AppendFormatted(component.mass, "F1"); handler2.AppendLiteral(")"); stringBuilder3.Append(ref handler2); } if (components.Length > 0) { StringBuilder stringBuilder2 = sb; StringBuilder stringBuilder4 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler2 = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2); handler2.AppendLiteral(" cols("); handler2.AppendFormatted(string.Join(",", ((IEnumerable<Collider>)components).Select((Collider c) => ((MemberInfo)((Object)c).GetIl2CppType()).Name + (c.isTrigger ? "*" : "")))); handler2.AppendLiteral(")"); stringBuilder4.Append(ref handler2); } ColliderBridge component2 = gameObject.GetComponent<ColliderBridge>(); if ((Object)(object)component2 != (Object)null) { StringBuilder stringBuilder2 = sb; StringBuilder stringBuilder5 = stringBuilder2; StringBuilder.AppendInterpolatedStringHandler handler2 = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2); handler2.AppendLiteral(" region="); handler2.AppendFormatted(component2.damageRegion); stringBuilder5.Append(ref handler2); } sb.AppendLine(); for (int num = 0; num < t.childCount; num++) { Walk(t.GetChild(num), depth + 1); } } } private static string Names(Il2CppReferenceArray<GameObject>? arr) { if (arr != null) { return "[" + string.Join(",", ((IEnumerable<GameObject>)arr).Select((GameObject g) => (!((Object)(object)g != (Object)null)) ? "null" : ((Object)g).name)) + "]"; } return "-"; } private static string Describe(GameObject? go) { if (!((Object)(object)go == (Object)null)) { return $"'{Path(go.transform)}'[{LayerMask.LayerToName(go.layer)}]"; } return "null"; } private static string Describe(Transform? t) { if (!((Object)(object)t == (Object)null)) { return Describe(((Component)t).gameObject); } return "null"; } public static string Path(Transform t) { List<string> list = new List<string>(); Transform val = t; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } } [HarmonyPatch(typeof(EnemyWaveSpawner), "InstantiateEnemy")] internal static class ProbeInstantiatePatch { private static bool Prepare() { return DevOptions.Probe; } private static void Postfix(EnemyWaveSpawner __instance, int enemNum, GameObject __result) { try { DevProbe.OnInstantiated(__instance, enemNum, __result); } catch (Exception value) { MelonLogger.Error($"[probe] {value}"); } } } [HarmonyPatch(typeof(EnemyWaveSpawner), "SpawnNewEnemy")] internal static class ProbeSpawnPatch { private static bool Prepare() { return DevOptions.Probe; } private static void Postfix(EnemyWaveSpawner __instance) { try { DevProbe.OnSpawned(__instance); } catch (Exception value) { MelonLogger.Error($"[probe] {value}"); } } } internal enum PrefabKind : byte { Ranged, Melee, Zombie, Dummy } internal readonly record struct PrefabRef(PrefabKind Kind, int Index) { public override string ToString() { return $"{Kind}[{Index}]"; } } internal static class EnemyCatalog { private static readonly Dictionary<int, string> PrefabSignatures = new Dictionary<int, string>(); public static PrefabRef? Identify(EnemyWaveSpawner spawner, GameObject enemy) { string text = Signature(enemy); for (byte b = 0; b <= 3; b++) { IReadOnlyList<GameObject> readOnlyList = List(spawner, (PrefabKind)b); for (int i = 0; i < readOnlyList.Count; i++) { GameObject val = readOnlyList[i]; if (!((Object)(object)val == (Object)null)) { int instanceID = ((Object)val).GetInstanceID(); if (!PrefabSignatures.TryGetValue(instanceID, out string value)) { value = (PrefabSignatures[instanceID] = Signature(val)); } if (value == text) { return new PrefabRef((PrefabKind)b, i); } } } } return null; } public static GameObject? Resolve(EnemyWaveSpawner spawner, PrefabRef r) { IReadOnlyList<GameObject> readOnlyList = List(spawner, r.Kind); if (r.Index < 0 || r.Index >= readOnlyList.Count) { return null; } return readOnlyList[r.Index]; } private static IReadOnlyList<GameObject?> List(EnemyWaveSpawner spawner, PrefabKind kind) { return kind switch { PrefabKind.Ranged => Wrap(spawner.rangedPrefabs), PrefabKind.Melee => Wrap(spawner.meleePrefabs), PrefabKind.Zombie => Wrap(spawner.zombiePrefabs), _ => (IReadOnlyList<GameObject?>)((!((Object)(object)spawner.dummyEnemyPrefab != (Object)null)) ? ((Array)Array.Empty<GameObject>()) : ((Array)new GameObject[1] { spawner.dummyEnemyPrefab })), }; } private static IReadOnlyList<GameObject?> Wrap(Il2CppReferenceArray<GameObject>? arr) { if (arr == null) { return Array.Empty<GameObject>(); } GameObject[] array = (GameObject[])(object)new GameObject[((Il2CppArrayBase<GameObject>)(object)arr).Length]; for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)arr).Length; i++) { array[i] = ((Il2CppArrayBase<GameObject>)(object)arr)[i]; } return array; } public static string Signature(GameObject root) { StringBuilder sb = new StringBuilder(); Walk(root.transform); return sb.ToString(); void Walk(Transform t) { for (int i = 0; i < t.childCount; i++) { Transform child = t.GetChild(i); if (!((Object)child).name.EndsWith("(Clone)")) { sb.Append(((Object)child).name).Append('|'); MeshFilter component = ((Component)child).GetComponent<MeshFilter>(); if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null) { sb.Append(((Object)component.sharedMesh).name).Append('|'); } Walk(child); } } } } public static int LookHash(GameObject root) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < root.transform.childCount; i++) { Transform child = root.transform.GetChild(i); if (((Component)child).gameObject.activeSelf) { stringBuilder.Append(((Object)child).name).Append('|'); } } foreach (Transform componentsInChild in root.GetComponentsInChildren<Transform>(true)) { if (((Object)componentsInChild).name.EndsWith("(Clone)")) { stringBuilder.Append(((Object)(object)componentsInChild.parent != (Object)null) ? ((Object)componentsInChild.parent).name : "").Append('>').Append(((Object)componentsInChild).name) .Append('|'); } } return SceneHash.Of(stringBuilder.ToString()); } public static string Extras(GameObject root) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (Transform componentsInChild in root.GetComponentsInChildren<Transform>(true)) { num++; if (((Object)componentsInChild).name.Contains("(Clone)")) { stringBuilder.Append(((Object)(object)componentsInChild.parent != (Object)null) ? ((Object)componentsInChild.parent).name : "").Append('>').Append(((Object)componentsInChild).name) .Append(' '); } } return $"{num} parts; extras: {stringBuilder}"; } } internal static class Guard { public static void Run(Action a, string where) { try { a(); } catch (Exception value) { MelonLogger.Error($"{where}: {value}"); } } public static bool Run(Func<bool> f, string where) { try { return f(); } catch (Exception value) { MelonLogger.Error($"{where}: {value}"); return true; } } } [HarmonyPatch(typeof(EnemyWaveSpawner), "InstantiateEnemy")] internal static class InstantiateEnemyPatch { private static void Prefix() { Guard.Run((Action)EnemySync.BeforeInstantiate, "InstantiateEnemy"); } private static void Postfix(int enemNum, GameObject __result) { Guard.Run(delegate { EnemySync.AfterInstantiate(enemNum, __result); }, "InstantiateEnemy"); } } [HarmonyPatch(typeof(EnemyWaveSpawner), "SpawnNewEnemy")] internal static class SpawnNewEnemyPatch { private static bool Prefix() { return EnemySync.AllowLocalSpawning(); } private static void Postfix(EnemyWaveSpawner __instance) { Guard.Run(delegate { EnemySync.AfterSpawn(__instance); }, "SpawnNewEnemy"); } } [HarmonyPatch(typeof(EnemyWaveSpawner), "SpawnNewAIEnemy")] internal static class SpawnNewAIEnemyPatch { private static bool Prefix() { return EnemySync.AllowLocalSpawning(); } private static void Postfix(EnemyWaveSpawner __instance) { Guard.Run(delegate { EnemySync.AfterSpawn(__instance); }, "SpawnNewAIEnemy"); } } [HarmonyPatch(typeof(StickHatOnStart), "Start")] internal static class HatStartPatch { private static void Prefix(StickHatOnStart __instance) { Guard.Run(delegate { EnemySync.BeforeCosmeticStart((Component)(object)__instance, 1191); }, "StickHatOnStart"); } } [HarmonyPatch(typeof(RandomClothesColorOnStart), "Start")] internal static class ClothesStartPatch { private static void Prefix(RandomClothesColorOnStart __instance) { Guard.Run(delegate { EnemySync.BeforeCosmeticStart((Component)(object)__instance, 451); }, "RandomClothesColorOnStart"); } } [HarmonyPatch(typeof(BulletManager), "BulletRaycast")] internal static class BulletRaycastPatch { private static void Prefix(BulletManager __instance) { BulletForce.Current = __instance.bulletHitForce; } } [HarmonyPatch(typeof(BulletManager), "OnCollisionEnter")] internal static class BulletCollisionPatch { private static void Prefix(BulletManager __instance) { BulletForce.Current = __instance.bulletHitForce; } } [HarmonyPatch(typeof(ColliderBridge), "HitByBullet")] internal static class BridgeHitByBulletPatch { private static void Prefix(ColliderBridge __instance, float damage, string caliber, Vector3 hitPosition, Vector3 rayDir, Vector3 hitNormal, float exitWoundGoreValue, out int __state) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) int queued = -1; Guard.Run(delegate { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) queued = EnemySync.BeforePuppetBullet(__instance, BulletEvent.Hit, damage, caliber, hitPosition, rayDir, hitNormal, exitWoundGoreValue); }, "HitByBullet"); __state = queued; } private static void Postfix(ColliderBridge __instance, float damage, string caliber, Vector3 hitPosition, Vector3 rayDir, Vector3 hitNormal, float exitWoundGoreValue, int __state) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Guard.Run(delegate { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) EnemySync.AfterPuppetBullet(__instance, __state); EnemySync.AfterHostBullet(__instance, BulletEvent.Hit, damage, caliber, hitPosition, rayDir, hitNormal, exitWoundGoreValue); }, "HitByBullet"); } } [HarmonyPatch(typeof(ColliderBridge), "ExitedBullet")] internal static class BridgeExitedBulletPatch { private static void Prefix(ColliderBridge __instance, Vector3 hitPosition, Vector3 hitNormal, string caliber, Vector3 exitDirection, float exitWoundGoreValue) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Guard.Run(delegate { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) EnemySync.BeforePuppetBullet(__instance, BulletEvent.Exit, 0f, caliber, hitPosition, exitDirection, hitNormal, exitWoundGoreValue); }, "ExitedBullet"); } private static void Postfix(ColliderBridge __instance, Vector3 hitPosition, Vector3 hitNormal, string caliber, Vector3 exitDirection, float exitWoundGoreValue) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Guard.Run(delegate { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) EnemySync.AfterHostBullet(__instance, BulletEvent.Exit, 0f, caliber, hitPosition, exitDirection, hitNormal, exitWoundGoreValue); }, "ExitedBullet"); } } [HarmonyPatch(typeof(ColliderBridge), "OnCollisionEnter")] internal static class BridgeCollisionPatch { private static void Postfix(ColliderBridge __instance, Collision collision) { Guard.Run(delegate { EnemySync.AfterPuppetCollision(__instance, collision); }, "ColliderBridge collision"); } } [HarmonyPatch(typeof(StickHealth), "HitByBullet")] internal static class StickHitByBulletPatch { private static bool Prefix(StickHealth __instance) { return Guard.Run(() => EnemySync.AllowStickReaction(__instance), "StickHealth.HitByBullet"); } } [HarmonyPatch(typeof(StickHealth), "StartStaggering")] internal static class StickStaggerPatch { private static bool Prefix(StickHealth __instance) { return Guard.Run(() => EnemySync.AllowStickReaction(__instance), "StickHealth.StartStaggering"); } } [HarmonyPatch(typeof(StickHealth), "StartFlailingOrProtecting")] internal static class StickFlailPatch { private static bool Prefix(StickHealth __instance) { return Guard.Run(() => EnemySync.AllowStickReaction(__instance), "StickHealth.StartFlailingOrProtecting"); } } [HarmonyPatch(typeof(StickHealth), "ForceUnbalance", new Type[] { })] internal static class StickUnbalancePatch { private static bool Prefix(StickHealth __instance) { return Guard.Run(() => EnemySync.AllowStickReaction(__instance), "StickHealth.ForceUnbalance"); } } [HarmonyPatch(typeof(StickHealth), "ForceUnbalance", new Type[] { typeof(bool) })] internal static class StickUnbalance2Patch { private static bool Prefix(StickHealth __instance) { return Guard.Run(() => EnemySync.AllowStickReaction(__instance), "StickHealth.ForceUnbalance"); } } internal static class PuppetAttack { public static bool Allow(Component c) { return !EnemySync.IsPuppet(((Component)c.transform.root).gameObject); } } [HarmonyPatch(typeof(EnemyMeleeManager), "OnCollisionEnter")] internal static class PuppetMeleePatch { private static bool Prefix(EnemyMeleeManager __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(ZombieAttackTrigger), "OnTriggerEnter")] internal static class PuppetZombieTriggerPatch { private static bool Prefix(ZombieAttackTrigger __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(ZombieAttackingManager), "PlayerEnteredTrigger")] internal static class PuppetZombieBitePatch { private static bool Prefix(ZombieAttackingManager __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(ZombieSwipeAttackManager), "PlayerEnteredTrigger")] internal static class PuppetZombieSwipePatch { private static bool Prefix(ZombieSwipeAttackManager __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(ZombieGrabScript), "OnTriggerEnter")] internal static class PuppetZombieGrabPatch { private static bool Prefix(ZombieGrabScript __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(GrabScript), "OnTriggerEnter")] internal static class PuppetGrabPatch { private static bool Prefix(GrabScript __instance) { return PuppetAttack.Allow((Component)(object)__instance); } } [HarmonyPatch(typeof(SliceOnInputCustom), "InitiateSlicing", new Type[] { typeof(Plane), typeof(Vector3), typeof(Vector3), typeof(Rigidbody), typeof(Il2CppReferenceArray<Collider>), typeof(Rigidbody), typeof(float), typeof(Rigidbody) })] internal static class SlicePatch { private static void Prefix(SliceOnInputCustom __instance, Plane slicePlaneWorld, Vector3 hitPoint, Vector3 worldVelocity, Rigidbody directlyConnectedRb, float reEnableCollisionDistance) { //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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_001c: Unknown result type (might be due to invalid IL or missing references) Guard.Run(delegate { //IL_0007: 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_0013: Unknown result type (might be due to invalid IL or missing references) EnemySync.BeforeSlice(__instance, slicePlaneWorld, hitPoint, worldVelocity, directlyConnectedRb, reEnableCollisionDistance); }, "SliceOnInputCustom.InitiateSlicing"); } } [HarmonyPatch(typeof(StickGunManager), "FireGun")] internal static class FireGunPatch { private static void Postfix(StickGunManager __instance) { Guard.Run(delegate { EnemySync.AfterHostShot(__instance); }, "FireGun"); } } [HarmonyPatch(typeof(PlayerDamageBridge), "HitByBullet")] internal static class ProxyBulletPatch { private static bool Prefix(PlayerDamageBridge __instance) { return Guard.Run(() => PlayerProxies.OnBridgeBullet(__instance), "PlayerDamageBridge.HitByBullet"); } } [HarmonyPatch(typeof(PlayerDamageBridge), "HitByZombie")] internal static class ProxyZombieHitPatch { private static bool Prefix(PlayerDamageBridge __instance, Vector3 hitPoint, float damage, Transform zombiePelvis, float hitForce) { //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) return Guard.Run(() => PlayerProxies.OnBridgeZombieHit(__instance, hitPoint, damage, zombiePelvis, hitForce), "PlayerDamageBridge.HitByZombie"); } } [HarmonyPatch(typeof(PlayerDamageBridge), "BittenByZombie")] internal static class ProxyBitePatch { private static bool Prefix(PlayerDamageBridge __instance, float damage) { return Guard.Run(() => PlayerProxies.OnBridgeBite(__instance, damage), "PlayerDamageBridge.BittenByZombie"); } } [HarmonyPatch(typeof(PlayerHealthManager), "HitDetected")] internal static class ProxyMeleePatch { private static bool Prefix(PlayerDamageBridge dmgBridge, Collision collision) { return Guard.Run(() => PlayerProxies.OnMeleeHit(dmgBridge, collision), "PlayerHealthManager.HitDetected"); } } [HarmonyPatch(typeof(MissionComplete), "ContinueMission")] internal static class ContinueMissionPatch { private static bool Prefix() { return Guard.Run((Func<bool>)MissionSync.OnLocalContinue, "ContinueMission"); } } [HarmonyPatch(typeof(MissionComplete), "ReturnToMainHub")] internal static class ReturnToHubPatch { private static void Prefix() { Guard.Run((Action)MissionSync.OnLocalReturnToHub, "ReturnToMainHub"); } } internal static class EnemySync { private sealed class HostEnemy { public ushort NetId; public GameObject Root; public StickHealth Health; public EnemySpawnMsg? Spawn; public float RegisteredAt; public Transform[] Bones = Array.Empty<Transform>(); public bool DeathSent; public bool CanReplicate; public int Seed; public int EnemNum; public string? Prefab; } private sealed class Puppet { public ushort NetId; public GameObject Root; public StickHealth? Health; public Transform?[] Bones = Array.Empty<Transform>(); public readonly SnapshotBuffer<BonePose[]> Buffer = new SnapshotBuffer<BonePose[]>(BonePoses.Lerp) { InterpolationDelay = 0.12f }; public Rigidbody[] Bodies = Array.Empty<Rigidbody>(); public float NextFreeze; public int LookHash; public float LookCheckAt; public bool Dead; public float NextImpulse; public bool[] HiddenByUs = Array.Empty<bool>(); } private sealed class LocalGrab { public ushort NetId; public int Root; } private sealed class RemoteGrab { public HostEnemy Enemy; public ConfigurableJoint? Joint; public GameObject Grip; public Rigidbody GripBody; public Vector3 Offset; public Vector3 TargetPos; public Quaternion TargetRot = Quaternion.Identity; public bool HasTarget; } private const float StateInterval = 0.05f; private const int MaxStatesBytes = 1100; private const float ManifestDelay = 0.25f; private static readonly Random Seeds = new Random(); private static readonly Dictionary<int, (int Seed, int EnemNum)> Origins = new Dictionary<int, (int, int)>(); private static int? _forcedSeed; private static int _seedInUse; private static readonly Dictionary<ushort, HostEnemy> HostEnemies = new Dictionary<ushort, HostEnemy>(); private static readonly Dictionary<int, HostEnemy> HostByRoot = new Dictionary<int, HostEnemy>(); private static ushort _nextNetId = 1; private static float _nextStates; private static int _statesTick; private static WaveStateMsg _lastWave; private static float _nextWaveCheck; private static readonly PacketWriter Scratch = new PacketWriter(1500); public const int SpawnSentToHost = -1; private static bool _replaying; private static readonly Dictionary<ushort, Puppet> Puppets = new Dictionary<ushort, Puppet>(); private static readonly Dictionary<int, Puppet> PuppetByRoot = new Dictionary<int, Puppet>(); private static bool _buildingPuppet; private static bool _applyingHostFx; private static readonly HashSet<string> PuppetDisables = new HashSet<string> { "StickHealth", "EnemyAIManager", "EnemyInfectionManager", "ZombieAttackingManager", "ZombieAttackTrigger", "ZombieSwipeAttackManager", "ZombieGrabScript", "GrabScript", "GrabRangeTrigger", "HandIKSmooth", "HeadIKSmooth", "StickBodyAnimator", "JointBreakerTreeManager", "EnemyVoiceManager", "MovementBasic", "EnemyFOV", "EnemyFOV2", "StickGunManager", "StickRifleManager", "EnemyMeleeManager", "ActRagJoint", "ActRagHipJoint", "ActRagJointWorld", "StickJointBreaker", "TimeStopManager", "FootStepManager", "EnemyDoorOpener", "EnemyListener", "EnemyPatrol", "IKLegMovement", "InverseKinematicsGecko", "DisableCollisionWithPlayer", "Animator", "NavMeshAgent", "HVRTriggerButtonEvents", "SpriteBillboardToMainCamera" }; private static float _nextProbeLog; private static EnemyWaveSpawner? _spawner; private static bool _replayingSlice; private static Rigidbody? _sliceDummy; private static readonly LocalGrab?[] MyGrabs = new LocalGrab[2]; private static float _nextHands; private static readonly Dictionary<(ulong Client, bool Left), RemoteGrab> Grabs = new Dictionary<(ulong, bool), RemoteGrab>(); private static Session? Session => MultiplayerMod.Session; private static bool IsHost { get { Session? session = Session; if (session == null) { return false; } return session.Role == Role.Host; } } private static bool IsClient { get { Session? session = Session; if (session == null) { return false; } return session.Role == Role.Client; } } public static int SharedCount => HostEnemies.Count; public static int PuppetCount => Puppets.Count; public static bool BuildingPuppet => _buildingPuppet; public static bool SeenSlice { get; private set; } public static Rigidbody SliceDummy { get { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0022: 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) if (PlayerRig.IsAlive((Object?)(object)_sliceDummy)) { return _sliceDummy; } GameObject val = new GameObject("BMP slice stand-in"); Object.DontDestroyOnLoad((Object)val); val.transform.position = new Vector3(0f, -10000f, 0f); _sliceDummy = val.AddComponent<Rigidbody>(); _sliceDummy.isKinematic = true; _sliceDummy.useGravity = false; _sliceDummy.mass = 2f; return _sliceDummy; } } public static void BeforeInstantiate() { _seedInUse = _forcedSeed ?? Seeds.Next(); Random.InitState(_seedInUse); } public static void AfterInstantiate(int enemNum, GameObject? enemy) { if ((Object)(object)enemy != (Object)null) { Origins[((Object)enemy).GetInstanceID()] = (_seedInUse, enemNum); } } public static void BeforeCosmeticStart(Component c, int salt) { if (Origins.TryGetValue(((Object)((Component)c.transform.root).gameObject).GetInstanceID(), out (int, int) value)) { Random.InitState(value.Item1 ^ salt); } } public static void AfterSpawn(EnemyWaveSpawner spawner) { if (!IsHost) { return; } List<StickHealth> stickHealthScripts = spawner.stickHealthScripts; if (stickHealthScripts == null) { return; } for (int i = 0; i < stickHealthScripts.Count; i++) { StickHealth val = stickHealthScripts[i]; if (!((Object)(object)val == (Object)null)) { GameObject gameObject = ((Component)((Component)val).transform.root).gameObject; if (!HostByRoot.ContainsKey(((Object)gameObject).GetInstanceID())) { Register(gameObject, val); } } } } public static bool BeforeSpawnGun(SpawnGunManager gun, out int seed) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) seed = 0; SpawnableItemInfo currentSpawnableItem = gun.currentSpawnableItem; if ((Object)(object)currentSpawnableItem == (Object)null || (int)currentSpawnableItem.spawnableType != 0 || (Object)(object)currentSpawnableItem.itemPrefab == (Object)null) { return true; } if (IsClient) { PacketWriter w = Session.Begin(MsgType.EnemySpawnRequest); EnemySpawnRequestMsg enemySpawnRequestMsg = default(EnemySpawnRequestMsg); enemySpawnRequestMsg.Prefab = ((Object)currentSpawnableItem.itemPrefab).name; enemySpawnRequestMsg.Position = gun.spawnableTargetPos.ToN(); enemySpawnRequestMsg.Yaw = gun.currentRotation; enemySpawnRequestMsg.Write(w); Session.SendToHost(reliable: true); MultiplayerMod.Toast("Spawning it in the host's game..."); seed = -1; return false; } seed = Seeds.Next(1, int.MaxValue); Random.InitState(seed); return true; } public static void AfterSpawnGun(SpawnGunManager gun, int seed) { if (seed <= 0 || !IsHost) { return; } List<GameObject> spawnedItems = gun.spawnedItems; if (spawnedItems != null && spawnedItems.Count != 0) { GameObject val = spawnedItems[spawnedItems.Count - 1]; SpawnableItemInfo currentSpawnableItem = gun.currentSpawnableItem; if ((Object)(object)val != (Object)null && (Object)(object)((currentSpawnableItem != null) ? currentSpawnableItem.itemPrefab : null) != (Object)null) { RegisterPrefabEnemy(val, ((Object)currentSpawnableItem.itemPrefab).name, seed); } } } private static void OnSpawnRequest(EnemySpawnRequestMsg m) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) GameObject val = ItemCatalog.Find(m.Prefab); if ((Object)(object)val == (Object)null) { MelonLogger.Warning("A friend tried to spawn '" + m.Prefab + "', which this game doesn't have"); return; } int num = Seeds.Next(1, int.MaxValue); Random.InitState(num); GameObject val2 = Object.Instantiate<GameObject>(val, m.Position.ToU(), Quaternion.Euler(0f, m.Yaw, 0f)); if (!val2.activeSelf) { val2.SetActive(true); } RegisterPrefabEnemy(val2, m.Prefab, num); } private static void RegisterPrefabEnemy(GameObject go, string prefab, int seed) { StickHealth componentInChildren = go.GetComponentInChildren<StickHealth>(true); if (!((Object)(object)componentInChildren == (Object)null) && !HostByRoot.ContainsKey(((Object)go).GetInstanceID())) { Origins[((Object)go).GetInstanceID()] = (seed, -1); Register(go, componentInChildren); HostByRoot[((Object)go).GetInstanceID()].Prefab = prefab; } } private static void Register(GameObject root, StickHealth stick) { HostEnemy hostEnemy = new HostEnemy { NetId = _nextNetId++, Root = root, Health = stick, RegisteredAt = Time.unscaledTime }; if (_nextNetId == 0) { _nextNetId = 1; } if (Origins.TryGetValue(((Object)root).GetInstanceID(), out (int, int) value)) { hostEnemy.CanReplicate = true; (hostEnemy.Seed, hostEnemy.EnemNum) = value; } else { MelonLogger.Warning("Enemy '" + ((Object)root).name + "' wasn't made by the wave spawner; friends won't see it"); } HostEnemies[hostEnemy.NetId] = hostEnemy; HostByRoot[((Object)root).GetInstanceID()] = hostEnemy; } private static void Announce(HostEnemy e) { List<Transform> list = new List<Transform>(); List<string> list2 = new List<string>(); foreach (Rigidbody componentsInChild in e.Root.GetComponentsInChildren<Rigidbody>(false)) { if (!((Object)(object)componentsInChild == (Object)null) && !componentsInChild.isKinematic) { list.Add(((Component)componentsInChild).transform); list2.Add(Paths.Of(((Component)componentsInChild).transform, e.Root.transform)); if (list.Count == 255) { break; } } } e.Bones = list.ToArray(); PrefabRef? prefabRef = null; EnemyWaveSpawner val = FindSpawner(); if ((Object)(object)val != (Object)null && e.Prefab == null) { prefabRef = EnemyCatalog.Identify(val, e.Root); } e.Spawn = new EnemySpawnMsg { NetId = e.NetId, Template = ((e.Prefab == null) ? EnemyTemplate.Spawner : EnemyTemplate.Prefab), ScenePath = (e.Prefab ?? ""), EnemNum = e.EnemNum, Seed = e.Seed, PrefabKind = (byte)(prefabRef?.Kind ?? ((PrefabKind)255)), PrefabIndex = (ushort)(prefabRef?.Index ?? 65535), LookHash = EnemyCatalog.LookHash(e.Root), Bones = list2.ToArray() }; MelonLogger.Msg($"Sharing enemy {e.NetId} '{((Object)e.Root).name}' ({list.Count} bodies)"); if (DevOptions.Probe) { MelonLogger.Msg($"[probe] host enemy {e.NetId} seed {e.Seed}: {EnemyCatalog.Extras(e.Root)}"); } SendSpawn(e, 0uL); } private static void SendSpawn(HostEnemy e, ulong onlyTo) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (e.Spawn != null) { PacketWriter w = Session.Begin(MsgType.FirstGameplay); e.Spawn.Write(w); Session.SendToClients(reliable: true, onlyTo); if (e.Health.isDead) { PacketWriter w2 = Session.Begin(MsgType.EnemyDied); EnemyDiedMsg enemyDiedMsg = default(EnemyDiedMsg); enemyDiedMsg.NetId = e.NetId; enemyDiedMsg.Cause = (byte)e.Health.causeOfDeath; enemyDiedMsg.Write(w2); Session.SendToClients(reliable: true, onlyTo); } } } public static void SendAllTo(ulong client) { if (!IsHost) { return; } foreach (HostEnemy value in HostEnemies.Values) { SendSpawn(value, client); } PacketWriter w = Session.Begin(MsgType.WaveState); _lastWave.Write(w); Session.SendToClients(reliable: true, client); ItemSync.SendAllTo(client); } private static void HostUpdate() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) float unscaledTime = Time.unscaledTime; UpdateGrabs(); List<HostEnemy> list = new List<HostEnemy>(); foreach (HostEnemy value in HostEnemies.Values) { if (!PlayerRig.IsAlive((Object?)(object)value.Root) || !value.Root.activeInHierarchy) { list.Add(value); continue; } if (value.Spawn == null && value.CanReplicate && unscaledTime - value.RegisteredAt >= 0.25f) { Announce(value); } if (value.Spawn != null && !value.DeathSent && value.Health.isDead) { value.DeathSent = true; PacketWriter w = Session.Begin(MsgType.EnemyDied); EnemyDiedMsg enemyDiedMsg = default(EnemyDiedMsg); enemyDiedMsg.NetId = value.NetId; enemyDiedMsg.Cause = (byte)value.Health.causeOfDeath; enemyDiedMsg.Write(w); Session.SendToClients(reliable: true, 0uL); } } foreach (HostEnemy item in list) { HostEnemies.Remove(item.NetId); HostByRoot.Remove(((Object)item.Root).GetInstanceID()); if (item.Spawn != null) { PacketWriter w2 = Session.Begin(MsgType.EnemyDespawn); EnemyDespawnMsg enemyDespawnMsg = default(EnemyDespawnMsg); enemyDespawnMsg.NetId = item.NetId; enemyDespawnMsg.Write(w2); Session.SendToClients(reliable: true, 0uL); } } if (Session.Peers.Count == 0) { return; } if (unscaledTime >= _nextStates) { _nextStates = unscaledTime + 0.05f; _statesTick++; SendStates(); } if (unscaledTime >= _nextWaveCheck) { _nextWaveCheck = unscaledTime + 0.5f; WaveStateMsg lastWave = ReadWave(); if (!lastWave.Equals(_lastWave)) { _lastWave = lastWave; PacketWriter w3 = Session.Begin(MsgType.WaveState); lastWave.Write(w3); Session.SendToClients(reliable: true, 0uL); } } } private static void SendStates() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) EnemyStatesMsg enemyStatesMsg = new EnemyStatesMsg { Time = MultiplayerMod.Now }; int num = 5; foreach (HostEnemy value in HostEnemies.Values) { if (value.Spawn == null || (value.Health.isDead && _statesTick % 4 != 0)) { continue; } EnemyState enemyState = new EnemyState { NetId = value.NetId, Flags = (value.Health.isDead ? EnemyFlags.Dead : EnemyFlags.None), Bones = new BonePose[value.Bones.Length] }; for (int i = 0; i < value.Bones.Length; i++) { Transform val = value.Bones[i]; if (PlayerRig.IsAlive((Object?)(object)val)) { enemyState.Bones[i] = new BonePose { Position = val.position.ToN(), Rotation = val.rotation.ToN(), Active = ((Component)val).gameObject.activeInHierarchy }; } } int num2 = EnemyStatesMsg.SizeOf(enemyState); if (num + num2 > 1100 && enemyStatesMsg.Enemies.Count > 0) { Flush(enemyStatesMsg); enemyStatesMsg = new EnemyStatesMsg { Time = enemyStatesMsg.Time }; num = 5; } enemyStatesMsg.Enemies.Add(enemyState); num += num2; } if (enemyStatesMsg.Enemies.Count > 0) { Flush(enemyStatesMsg); } static void Flush(EnemyStatesMsg m) { PacketWriter w = Session.Begin(MsgType.EnemyStates); m.Write(w); Session.SendToClients(reliable: false, 0uL); } } private static WaveStateMsg ReadWave() { KillCounterScript instanceOfThis = KillCounterScript.instanceOfThis; EnemyWaveSpawner val = FindSpawner(); if (!((Object)(object)instanceOfThis == (Object)null)) { return new WaveStateMsg { Kills = instanceOfThis.killsCounted, BallisticKills = instanceOfThis.ballisticKillsCounted, HeadshotKills = instanceOfThis.headshotKillsCounted, MeleeKills = instanceOfThis.meleeKillsCounted, DecapitationKills = instanceOfThis.decapitationKillsCounted, DismemberKills = instanceOfThis.dismemberKillsCounted, AllBreachEnemiesKilled = ((Object)(object)val != (Object)null && val.allBreachEnemiesKilled) }; } return default(WaveStateMsg); } private static void OnClientDamage(EnemyDamageMsg m) { if (!HostEnemies.TryGetValue(m.NetId, out HostEnemy value) || value.Health.isDead) { return; } if (DevOptions.Probe) { MelonLogger.Msg($"[probe] friend's damage on enemy {m.NetId}: {m.DamageType} {m.Amount} at {m.Region}"); } Transform? obj = Paths.Resolve(value.Root.transform, m.BridgePath); ColliderBridge val = ((obj != null) ? ((Component)obj).GetComponent<ColliderBridge>() : null); value.Health.ReceivedGeneralDamage(m.Amount, (DamageType)m.DamageType, m.Region, val); if (m.ConsciousnessAmount != 0f || m.ThroatSlit) { List<DamageInfo> damageInfoList = value.Health.damageInfoList; if (damageInfoList != null && damageInfoList.Count > 0) { DamageInfo val2 = damageInfoList[damageInfoList.Count - 1]; val2.consciousnessDamageAmount = m.ConsciousnessAmount; val2.isThroatSlit = m.ThroatSlit; damageInfoList[damageInfoList.Count - 1] = val2; } } } private static void OnClientBullet(ulong from, EnemyBulletMsg m) { //IL_00d9: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) if (!HostEnemies.TryGetValue(m.NetId, out HostEnemy value)) { return; } if (DevOptions.Probe) { MelonLogger.Msg($"[probe] friend's bullet {m.Event} on enemy {m.NetId} ({m.Damage} dmg), health before {value.Health.StickCurrentHealth}"); } Transform val = Paths.Resolve(value.Root.transform, m.BridgePath); ColliderBridge val2 = ((val != null) ? ((Component)val).GetComponent<ColliderBridge>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return; } Vector3 val3 = val.TransformPoint(m.LocalPosition.ToU()); Vector3 val4 = val.TransformDirection(m.LocalDirection.ToU()); Vector3 val5 = val.TransformDirection(m.LocalNormal.ToU()); _replaying = true; try { if (m.Event == BulletEvent.Hit) { val2.HitByBullet(m.Damage, m.Caliber, val3, val4, val5, m.Gore); Rigidbody val6 = ((Component)val2).GetComponent<Rigidbody>() ?? ((Component)val2).GetComponentInParent<Rigidbody>(); if ((Object)(object)val6 != (Object)null && m.Force > 0f) { val6.AddForceAtPosition((val4.ToN() * Math.Min(m.Force, 500f)).ToU(), val3, (ForceMode)1); } } else { val2.ExitedBullet(val3, val5, m.Caliber, val4, m.Gore); } } finally { _replaying = false; } PacketWriter w = Session.Begin(MsgType.EnemyBulletFx); m.Write(w); foreach (PeerState value2 in Session.Peers.Values) { if (value2.Direct && value2.Id != from) { Session.SendToClients(reliable: true, value2.Id); } } } private static void OnClientImpulse(EnemyImpulseMsg m) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!HostEnemies.TryGetValue(m.NetId, out HostEnemy value)) { return; } Transform val = Paths.Resolve(value.Root.transform, m.BonePath); Rigidbody val2 = ((val != null) ? ((Component)val).GetComponent<Rigidbody>() : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { Vector3 vector = m.Impulse; if (vector.Length() > 200f) { vector = Vector3.Normalize(vector) * 200f; } val2.AddForceAtPosition(vector.ToU(), val.TransformPoint(m.LocalPoint.ToU()), (ForceMode)1); } } public static void AfterHostBullet(ColliderBridge bridge, BulletEvent ev, float damage, string caliber, Vector3 pos, Vector3 dir, Vector3 normal, float gore) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (IsHost && !_replaying && Session.Peers.Count != 0 && HostByRoot.TryGetValue(((Object)((Component)((Component)bridge).transform.root).gameObject).GetInstanceID(), out HostEnemy value) && value.Spawn != null) { Transform transform = ((Component)bridge).transform; PacketWriter w = Session.Begin(MsgType.EnemyBulletFx); EnemyBulletMsg enemyBulletMsg = default(EnemyBulletMsg); enemyBulletMsg.NetId = value.NetId; enemyBulletMsg.BridgePath = Paths.Of(transform, value.Root.transform); enemyBulletMsg.Event = ev; enemyBulletMsg.Damage = damage; enemyBulletMsg.Caliber = caliber ?? ""; enemyBulletMsg.LocalPosition = transform.InverseTransformPoint(pos).ToN(); enemyBulletMsg.LocalDirection = transform.InverseTransformDirection(dir).ToN(); enemyBulletMsg.LocalNormal = transform.InverseTransformDirection(normal).ToN(); enemyBulletMsg.Gore = gore; enemyBulletMsg.Write(w); Session.SendToClients(reliable: true, 0uL); } } public static void AfterHostShot(StickGunManager gun) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (IsHost && Session.Peers.Count != 0 && !((Object)(object)gun.bulletSpawnTransform == (Object)null) && HostByRoot.TryGetValue(((Object)((Component)((Component)gun).transform.root).gameObject).GetInstanceID(), out HostEnemy value) && value.Spawn != null) { Transform bulletSpawnTransform = gun.bulletSpawnTransform; PacketWriter w = Session.Begin(MsgType.EnemyShot); EnemyShotMsg enemyShotMsg = default(EnemyShotMsg); enemyShotMsg.NetId = value.NetId; enemyShotMsg.Position = bulletSpawnTransform.position.ToN(); enemyShotMsg.Rotation = bulletSpawnTransform.rotation.ToN(); enemyShotMsg.Velocity = bulletSpawnTransform.forward.ToN() * gun.bulletSpeed; enemyShotMsg.Write(w); Session.SendToClients(reliable: false, 0uL); } } public static bool IsHostEnemy(GameObject root) { return HostByRoot.ContainsKey(((Object)root).GetInstanceID()); } public static IEnumerable<StickHealth> HostEnemyHealth() { foreach (HostEnemy value in HostEnemies.Values) { if (PlayerRig.IsAlive((Object?)(object)value.Health)) { yield return value.Health; } } } public static bool AllowLocalSpawning() { return !IsClient; } public static bool IsPuppet(GameObject root) { return PuppetByRoot.ContainsKey(((Object)root).GetInstanceID()); } private static void OnSpawn(EnemySpawnMsg m) { if (Puppets.ContainsKey(m.NetId)) { return; } EnemyWaveSpawner val = FindSpawner(); GameObject val2; if (m.Template == EnemyTemplate.Prefab) { if (MissionSync.HostScene != MultiplayerMod.CurrentScene) { return; } val2 = BuildFromPrefab(m); if ((Object)(object)val2 == (Object)null) { return; } } else { if ((Object)(object)val == (Object)null || m.Template != EnemyTemplate.Spawner) { return; } _forcedSeed = m.Seed; _buildingPuppet = true; try { val2 = val.InstantiateEnemy(m.EnemNum); } catch (Exception value) { MelonLogger.Error($"Couldn't build host enemy {m.NetId}: {value}"); return; } finally { _forcedSeed = null; _buildingPuppet = false; } if ((Object)(object)val2 == (Object)null) { return; } } if (m.PrefabKind != byte.MaxValue && (Object)(object)val != (Object)null) { PrefabRef? prefabRef = EnemyCatalog.Identify(val, val2); if (!prefabRef.HasValue || (uint)prefabRef.Value.Kind != m.PrefabKind || prefabRef.Value.Index != m.PrefabIndex) { MelonLogger.Warning($"Host enemy {m.NetId} is {m.PrefabKind}[{m.PrefabIndex}] but ours came out {prefabRef?.ToString() ?? "unknown"}"); } } Puppetize(val2); Puppet puppet = new Puppet { NetId = m.NetId, Root = val2, Health = val2.GetComponentInChildren<StickHealth>(true), Bodies = Il2CppArrayBase<Rigidbody>.op_Implicit(val2.GetComponentsInChildren<Rigidbody>(true)), LookHash = m.LookHash, LookCheckAt = Time.unscaledTime + 0.5f }; puppet.Bones = (Transform?[])(object)new Transform[m.Bones.Length]; int num = 0; for (int i = 0; i < m.Bones.Length; i++) { puppet.Bones[i] = Paths.Resolve(val2.transform, m.Bones[i]); if ((Object)(object)puppet.Bones[i] == (Object)null) { num++; } } puppet.HiddenByUs = new bool[puppet.Bones.Length]; ((Object)val2).name = $"BMP host enemy {m.NetId}"; Puppets[m.NetId] = puppet; PuppetByRoot[((Object)val2).GetInstanceID()] = puppet; if (m.Template == EnemyTemplate.Prefab) { Transform parent = val2.transform.parent; Random.InitState(m.Seed); val2.transform.SetParent((Transform)null, true); if ((Object)(object)parent != (Object)null) { Object.Destroy((Object)(object)((Component)parent).gameObject); } } val2.SetActive(true); MelonLogger.Msg($"Showing host enemy {m.NetId} ({m.Bones.Length} bodies{((num > 0) ? $", {num} not found on ours" : "")})"); } private static GameObject? BuildFromPrefab(EnemySpawnMsg m) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown GameObject val = ItemCatalog.Find(m.ScenePath); if ((Object)(object)val == (Object)null) { MelonLogger.Warning("The host spawned '" + m.ScenePath + "', which this game doesn't have"); return null; } GameObject val2 = new GameObject("BMP spawn holder"); val2.SetActive(false); GameObject val3 = Object.Instantiate<GameObject>(val, val2.transform); if (!val3.activeSelf) { val3.SetActive(true); } Origins[((Object)val3).GetInstanceID()] = (m.Seed, -1); return val3; } private static void Puppetize(GameObject root) { foreach (Component componentsInChild in root.GetComponentsInChildren<Component>(true)) { if (!((Object)(object)componentsInChild == (Object)null) && PuppetDisables.Contains(((MemberInfo)((Object)componentsInChild).GetIl2CppType()).Name)) { Behaviour val = ((Il2CppObjectBase)componentsInChild).TryCast<Behaviour>(); if ((Object)(object)val != (Object)null) { val.enabled = false; } } } foreach (Rigidbody componentsInChild2 in root.GetComponentsInChildren<Rigidbody>(true)) { componentsInChild2.isKinematic = true; componentsInChild2.interpolation = (RigidbodyInterpolation)0; } foreach (Canvas componentsInChild3 in root.GetComponentsInChildren<Canvas>(true)) { ((Component)componentsInChild3).gameObject.SetActive(false); } } private static void OnStates(EnemyStatesMsg m) { foreach (EnemyState enemy in m.Enemies) { if (Puppets.TryGetValue(enemy.NetId, out Puppet value) && enemy.Bones.Length == value.Bones.Length) { value.Buffer.Add(m.Time, in enemy.Bones); if ((enemy.Flags & EnemyFlags.Dead) != EnemyFlags.None && !value.Dead) { MarkDead(value, 0); } } } } private static void OnDied(EnemyDiedMsg m) { if (Puppets.TryGetValue(m.NetId, out Puppet value) && !value.Dead) { MarkDead(value, m.Cause); } } private static void MarkDead(Puppet p, byte cause) { p.Dead = true; if ((Object)(object)p.Health != (Object)null) { p.Health.isDead = true; } EnemyWaveSpawner val = FindSpawner(); if ((Object)(object)val == (Object)null) { return; } try { val.StickDeathRegen((DamageType)cause); } catch (Exception ex) { MelonLogger.Warning("Kill regen failed: " + ex.Message); } } private static void OnDespawn(EnemyDespawnMsg m) { if (Puppets.Remove(m.NetId, out Puppet value)) { PuppetByRoot.Remove(((Object)value.Root).GetInstanceID()); if (PlayerRig.IsAlive((Object?)(object)value.Root)) { Object.Destroy((Object)(object)value.Root); } } } private static void OnWaveState(WaveStateMsg m) { KillCounterScript instanceOfThis = KillCounterScript.instanceOfThis; if ((Object)(object)instanceOfThis != (Object)null) { instanceOfThis.killsCounted = m.Kills; instanceOfThis.ballisticKillsCounted = m.BallisticKills; instanceOfThis.headshotKillsCounted = m.HeadshotKills; instanceOfThis.meleeKillsCounted = m.MeleeKills; instanceOfThis.decapitationKillsCounted = m.DecapitationKills; instanceOfThis.dismemberKillsCounted = m.DismemberKills; } EnemyWaveSpawner val = FindSpawner(); if ((Object)(object)val != (Object)null) { val.allBreachEnemiesKilled = m.AllBreachEnemiesKilled; } } private static void OnBulletFx(EnemyBulletMsg m) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (!Puppets.TryGetValue(m.NetId, out Puppet value)) { return; } Transform val = Paths.Resolve(value.Root.transform, m.BridgePath); ColliderBridge val2 = ((val != null) ? ((Component)val).GetComponent<ColliderBridge>() : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return; } Vector3 val3 = val.TransformPoint(m.LocalPosition.ToU()); Vector3 val4 = val.TransformDirection(m.LocalDirection.ToU()); Vector3 val5 = val.TransformDirection(m.LocalNormal.ToU()); _applyingHostFx = true; try { if (m.Event == BulletEvent.Hit) { val2.HitByBullet(m.Damage, m.Caliber, val3, val4, val5, m.Gore); } else { val2.ExitedBullet(val3, val5, m.Caliber, val4, m.Gore); } } finally { _applyingHostFx = false; StickHealth? health = value.Health; if (health != null) { health.damageInfoList?.Clear(); } } } private static void OnShot(EnemyShotMsg m) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (!Puppets.TryGetValue(m.NetId, out Puppet value)) { return; } StickGunManager componentInChildren = value.Root.GetComponentInChildren<StickGunManager>(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.bulletPrefab == (Object)null) { return; } Vector3 val = m.Position.ToU(); Quaternion val2 = m.Rotation.ToU(); try { if ((Object)(object)componentInChildren.muzzleFlashParticles != (Object)null) { componentInChildren.muzzleFlashParticles.Play(); } Il2CppReferenceArray<AudioClip> fireSounds = componentInChildren.fireSounds; if ((Object)(object)componentInChildren.fireSoundSource != (Object)null && fireSounds != null && ((Il2CppArrayBase<AudioClip>)(object)fireSounds).Length > 0) { componentInChildren.fireSoundSource.PlayOneShot(((Il2CppArrayBase<AudioClip>)(object)fireSounds)[Random.Range(0, ((Il2CppArrayBase<AudioClip>)(object)fireSounds).Length)]); } } catch (Exception ex) { MelonLogger.Warning("Muzzle effects failed: " + ex.Message); } GameObject val3 = Object.Instantiate<GameObject>(componentInChildren.bulletPrefab, val, val2); if (DevOptions.Probe) { MelonLogger.Msg($"[probe] host enemy {m.NetId} fired; our copy fired '{((Object)val3).name}' from {val}"); } } private static void OnPlayerHit(PlayerHitMsg m) { PlayerDamage.ApplyFromHost(m); } private static void ClientUpdate(float dt) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) float unscaledTime = Time.unscaledTime; if (DevOptions.Probe && unscaledTime >= _nextProbeLog && Puppets.Count > 0) { _nextProbeLog = unscaledTime + 3f; foreach (Puppet value in Puppets.Values) { Transform val = ((value.Bones.Length != 0) ? value.Bones[0] : null); MelonLogger.Msg($"[probe] puppet {value.NetId}: snapshots={value.Buffer.Count} last={value.Buffer.TimeSinceLastSnapshot:F2}s ago dead={value.Dead} body0={(((Object)(object)val != (Object)null) ? ((object)val.position/*cast due to .constrained prefix*/).ToString() : "-")}"); } } foreach (Puppet value2 in Puppets.Values) { if (!PlayerRig.IsAlive((Object?)(object)value2.Root)) { continue; } if (value2.LookCheckAt > 0f && unscaledTime >= value2.LookCheckAt) { value2.LookCheckAt = 0f; if (EnemyCatalog.LookHash(value2.Root) != value2.LookHash) { MelonLogger.Warning($"Host enemy {value2.NetId} came out looking different here (armor or hats won't match)"); } if (DevOptions.Probe) { MelonLogger.Msg($"[probe] our copy of {value2.NetId}: {EnemyCatalog.Extras(value2.Root)}"); } else if (DevOptions.Probe) { MelonLogger.Msg($"[probe] puppet {value2.NetId} matches the host's enemy part for part"); } } if (unscaledTime >= value2.NextFreeze) { value2.NextFreeze = unscaledTime + 0.5f; Rigidbody[] bodies = value2.Bodies; foreach (Rigidbody val2 in bodies) { if ((Object)(object)val2 != (Object)null && !val2.isKinematic) { val2.isKinematic = true; } } } if (value2.Buffer.TrySample(dt, out BonePose[] state)) { for (int j = 0; j < state.Length && j < value2.Bones.Length; j++) { Transform val3 = value2.Bones[j]; if ((Object)(object)val3 == (Object)null) { continue; } GameObject gameObject = ((Component)val3).gameObject; if (!state[j].Active) { if (gameObject.activeSelf) { gameObject.SetActive(false); value2.HiddenByUs[j] = true; } continue; } if (!gameObject.activeSelf) { if (!value2.HiddenByUs[j]) { continue; } gameObject.SetActive(true); value2.HiddenByUs[j] = false; } val3.position = state[j].Position.ToU(); val3.rotation = state[j].Rotation.ToU(); } } ForwardQueuedDamage(value2); } SendGrabHands(unscaledTime); } private static void ForwardQueuedDamage(Puppet p) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_00d6: Unknown result type (might be due to invalid IL or missing references) StickHealth? health = p.Health; List<DamageInfo> val = ((health != null) ? health.damageInfoList : null); if (val == null || val.Count == 0) { return; } for (int num = 0; num < val.Count; num++) { DamageInfo val2 = val[num]; DamageType damageType = val2.damageType; if ((int)dam