using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Users; using UnityEngine.InputSystem.Utilities; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CouchCrew")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0")] [assembly: AssemblyProduct("CouchCrew")] [assembly: AssemblyTitle("CouchCrew")] [assembly: AssemblyVersion("0.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CouchCrew { public enum CreditCorner { TopLeft, TopRight, BottomLeft, BottomRight } internal static class CouchCredit { private static GameObject _go; private static RawImage _raw; private static RectTransform _rt; private static Canvas _canvas; private static Texture2D _tex; private static bool _created; private static bool _failed; private static CreditCorner _appliedCorner = (CreditCorner)(-1); private static float _appliedWidth = float.NaN; private static Type _shiftMgrType; private static FieldInfo _fPhase; private static Object _shiftMgr; private static bool _reflTried; private static float _nextPhaseCheck; private static float _nextCamCheck; private static bool _inShift; private static MethodInfo _miUiCam; private static bool _uiCamTried; internal static void Tick() { if (_failed) { return; } if (Plugin.ShowTwitchCredit == null || !Plugin.ShowTwitchCredit.Value) { if ((Object)(object)_go != (Object)null && _go.activeSelf) { _go.SetActive(false); } return; } try { if (!_created) { Create(); } if (!((Object)(object)_go == (Object)null)) { MaintainCamera(); ApplyCorner(); UpdatePhase(); bool flag = !_inShift; if (_go.activeSelf != flag) { _go.SetActive(flag); } } } catch (Exception ex) { _failed = true; Plugin.Log.LogWarning((object)("[credit] " + ex.Message)); } } private static void Create() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) _created = true; _tex = LoadPng(); if ((Object)(object)_tex == (Object)null) { _failed = true; Plugin.Log.LogWarning((object)"[credit] credit.png not found next to the DLL — credit disabled."); return; } _go = new GameObject("CouchCrew.CreditCanvas"); Object.DontDestroyOnLoad((Object)(object)_go); _canvas = _go.AddComponent(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 29500; _go.AddComponent().uiScaleMode = (ScaleMode)0; GameObject val = new GameObject("Image"); val.transform.SetParent(_go.transform, false); _raw = val.AddComponent(); _raw.texture = (Texture)(object)_tex; ((Graphic)_raw).raycastTarget = false; _rt = ((Graphic)_raw).rectTransform; SetLayerRecursive(_go.transform, 5); Plugin.Log.LogInfo((object)("[credit] canvas created (credit.png " + ((Texture)_tex).width + "x" + ((Texture)_tex).height + ").")); } private static void MaintainCamera() { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Invalid comparison between Unknown and I4 if ((Object)(object)_canvas == (Object)null || Time.unscaledTime < _nextCamCheck) { return; } _nextCamCheck = Time.unscaledTime + 1f; if (!_uiCamTried) { _uiCamTried = true; Type type = AccessTools.TypeByName("GameUtil"); _miUiCam = ((type != null) ? AccessTools.Method(type, "get_uiCamera", (Type[])null, (Type[])null) : null); } Camera val = null; try { val = (Camera)((_miUiCam != null) ? /*isinst with value type is only supported in some contexts*/: null); } catch { } if ((Object)(object)val != (Object)null) { if ((Object)(object)_canvas.worldCamera != (Object)(object)val || (int)_canvas.renderMode != 1) { _canvas.renderMode = (RenderMode)1; _canvas.worldCamera = val; _canvas.planeDistance = Mathf.Max(val.nearClipPlane + 0.5f, 1f); } } else if ((int)_canvas.renderMode != 0) { _canvas.renderMode = (RenderMode)0; _canvas.worldCamera = null; } } private static void UpdatePhase() { if (Time.unscaledTime < _nextPhaseCheck) { return; } _nextPhaseCheck = Time.unscaledTime + 1f; if (!_reflTried) { _reflTried = true; _shiftMgrType = AccessTools.TypeByName("ShiftManager"); _fPhase = ((_shiftMgrType != null) ? AccessTools.Field(_shiftMgrType, "_shiftPhase") : null); } if (_fPhase == null) { _inShift = false; return; } try { if (_shiftMgr == (Object)null) { _shiftMgr = Object.FindObjectOfType(_shiftMgrType); } _inShift = _shiftMgr != (Object)null && Convert.ToInt32(_fPhase.GetValue(_shiftMgr)) == 3; } catch { _inShift = false; } } private static Texture2D LoadPng() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown try { string directoryName = Path.GetDirectoryName(typeof(Plugin).Assembly.Location); string text = (string.IsNullOrEmpty(directoryName) ? null : Path.Combine(directoryName, "credit.png")); if (text == null || !File.Exists(text)) { return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, File.ReadAllBytes(text))) { return null; } ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; return val; } catch { return null; } } private static void ApplyCorner() { //IL_00b0: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_rt == (Object)null) && !((Object)(object)_tex == (Object)null)) { CreditCorner creditCorner = ((Plugin.CreditCornerCfg != null) ? Plugin.CreditCornerCfg.Value : CreditCorner.TopLeft); float num = ((Plugin.CreditWidth != null) ? Plugin.CreditWidth.Value : 320f); if (creditCorner != _appliedCorner || num != _appliedWidth) { _appliedCorner = creditCorner; _appliedWidth = num; bool flag = creditCorner == CreditCorner.TopLeft || creditCorner == CreditCorner.BottomLeft; bool flag2 = creditCorner == CreditCorner.TopLeft || creditCorner == CreditCorner.TopRight; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(flag ? 0f : 1f, flag2 ? 1f : 0f); RectTransform rt = _rt; RectTransform rt2 = _rt; Vector2 val2 = (_rt.pivot = val); Vector2 anchorMin = (rt2.anchorMax = val2); rt.anchorMin = anchorMin; float num2 = 12f; _rt.anchoredPosition = new Vector2(flag ? num2 : (0f - num2), flag2 ? (0f - num2) : num2); _rt.sizeDelta = new Vector2(num, num * (float)((Texture)_tex).height / (float)Mathf.Max(1, ((Texture)_tex).width)); } } } private static void SetLayerRecursive(Transform t, int layer) { ((Component)t).gameObject.layer = layer; for (int i = 0; i < t.childCount; i++) { SetLayerRecursive(t.GetChild(i), layer); } } } internal static class CouchMenu { private class Item { public string label; public ConfigEntry cfg; public Action action; } internal static bool IsOpen; private static Item[] _items; private static GameObject _go; private static object _text; private static object _shadow; private static bool _ready; private static bool _failed; private static Type _tmpType; private static Type _imgType; private static PropertyInfo _fontProp; private static object _font; private static int _sel; private static ConfigEntry _capTarget; private static string _capLabel; private static bool _prevUp; private static bool _prevDown; private static bool _prevA; private static bool _capWait; private static bool _stateLogged; private static MethodInfo _miUiCam; private static bool _uiCamTried; private static void BuildItems() { if (_items == null) { _items = new Item[11] { new Item { label = "Resume", action = Close }, new Item { label = "Change Color", action = CouchCoop.CycleCouchColor }, new Item { label = "Brake/Reverse", cfg = Plugin.P2BrakeButton }, new Item { label = "Drift", cfg = Plugin.P2DriftButton }, new Item { label = "Boost", cfg = Plugin.P2BoostButton }, new Item { label = "Grab/Throw", cfg = Plugin.P2GrabButton }, new Item { label = "Lift/Lower", cfg = Plugin.P2LiftButton }, new Item { label = "Use Tool", cfg = Plugin.P2ToolButton }, new Item { label = "Beep", cfg = Plugin.P2BeepButton }, new Item { label = "Place Station", cfg = Plugin.P2PlaceButton }, new Item { label = "Leave Game", action = delegate { Close(); CouchCoop.LeaveCouch(); } } }; } } internal static void HandleStartPress() { if (!IsOpen) { Open(); } else if (_capTarget != null) { _capTarget = null; Redraw(); } else { Close(); } } internal static void Open() { DestroyUi(); if (EnsureUi()) { BuildItems(); IsOpen = true; _sel = 0; _capTarget = null; _prevUp = (_prevDown = true); _prevA = true; _stateLogged = false; _go.SetActive(true); Redraw(); NetworkIdentity localPlayer = NetworkClient.localPlayer; Plugin.Log.LogInfo((object)("[p2menu] opened (fresh UI). localPlayer=" + (((Object)(object)localPlayer != (Object)null) ? (((Object)localPlayer).name + "#" + localPlayer.netId) : "null") + " isCouch=" + ((Object)(object)localPlayer != (Object)null && CouchCoop.CouchBodies.Contains(localPlayer)) + ".")); } } private static void DestroyUi() { if (!((Object)(object)_go == (Object)null)) { try { Object.Destroy((Object)(object)_go); } catch { } _go = null; _text = null; _shadow = null; _ready = false; } } private static void LogOpenState() { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: 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) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) if (_stateLogged || (Object)(object)_go == (Object)null) { return; } _stateLogged = true; try { Canvas component = _go.GetComponent(); StringBuilder stringBuilder = new StringBuilder("[p2menu] live state: "); stringBuilder.Append("screen=").Append(Screen.width).Append("x") .Append(Screen.height); if ((Object)(object)component != (Object)null) { stringBuilder.Append(" mode=").Append(component.renderMode).Append(" display=") .Append(component.targetDisplay) .Append(" scaleFactor=") .Append(component.scaleFactor.ToString("0.00")) .Append(" pixelRect=") .Append(((object)component.pixelRect/*cast due to .constrained prefix*/).ToString()); } StringBuilder stringBuilder2 = stringBuilder.Append(" rootLossyScale="); Vector3 lossyScale = _go.transform.lossyScale; stringBuilder2.Append(((Vector3)(ref lossyScale)).ToString("0.00")); for (int i = 0; i < _go.transform.childCount; i++) { Transform child = _go.transform.GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (!((Object)(object)val == (Object)null)) { StringBuilder stringBuilder3 = stringBuilder.Append(" | ").Append(((Object)val).name).Append(" lossy="); lossyScale = ((Transform)val).lossyScale; StringBuilder stringBuilder4 = stringBuilder3.Append(((Vector3)(ref lossyScale)).ToString("0.00")).Append(" anchor="); Vector2 val2 = val.anchorMin; StringBuilder stringBuilder5 = stringBuilder4.Append(((Vector2)(ref val2)).ToString("0.00")).Append(" pos="); val2 = val.anchoredPosition; stringBuilder5.Append(((Vector2)(ref val2)).ToString("0")); } } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } catch { } } internal static void Close() { IsOpen = false; _capTarget = null; if ((Object)(object)_go != (Object)null) { _go.SetActive(false); } } internal static void Tick() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (!IsOpen) { return; } if (CouchCoop.CouchBodies.Count == 0) { Close(); return; } LogOpenState(); ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { Close(); return; } Gamepad val = all[1]; if (_capTarget != null) { TickCapture(val); return; } float num = ((val.leftStick != null) ? ((InputControl)(object)val.leftStick).ReadValue().y : 0f); bool flag = (val.dpad != null && val.dpad.up.isPressed) || num > 0.6f; bool flag2 = (val.dpad != null && val.dpad.down.isPressed) || num < -0.6f; bool flag3 = val.buttonSouth != null && val.buttonSouth.isPressed; if (flag && !_prevUp) { _sel = (_sel + _items.Length - 1) % _items.Length; Redraw(); } if (flag2 && !_prevDown) { _sel = (_sel + 1) % _items.Length; Redraw(); } if (flag3 && !_prevA) { Activate(); } _prevUp = flag; _prevDown = flag2; _prevA = flag3; } private static void Activate() { Item item = _items[_sel]; if (item.action != null) { item.action(); if (IsOpen) { Redraw(); } } else { _capTarget = item.cfg; _capLabel = item.label; _capWait = true; Redraw(); } } private static void TickCapture(Gamepad pad) { ButtonControl val = FirstPressed(pad); if (_capWait) { if (val == null) { _capWait = false; } } else if (val != null) { _capTarget.Value = ((InputControl)val).name; CouchCoop.InvalidateP2ButtonCache(); Plugin.Log.LogInfo((object)("[p2menu] bound '" + _capLabel + "' to '" + ((InputControl)val).name + "'.")); _capTarget = null; Redraw(); } } private static ButtonControl FirstPressed(Gamepad pad) { foreach (ButtonControl item in Candidates(pad)) { if (item != null && item.isPressed) { return item; } } return null; } private static IEnumerable Candidates(Gamepad pad) { yield return pad.buttonNorth; yield return pad.buttonEast; yield return pad.buttonWest; yield return pad.buttonSouth; yield return pad.leftShoulder; yield return pad.rightShoulder; yield return pad.leftTrigger; yield return pad.rightTrigger; yield return pad.leftStickButton; yield return pad.rightStickButton; yield return pad.selectButton; if (pad.dpad != null) { yield return pad.dpad.up; yield return pad.dpad.down; yield return pad.dpad.left; yield return pad.dpad.right; } } private static void Redraw() { string s; if (_capTarget != null) { s = "PLAYER 2\n\nPress a button on controller 2\nto use for " + _capLabel.ToUpperInvariant() + "\n\n(Start = cancel)"; } else { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("PLAYER 2\n\n"); for (int i = 0; i < _items.Length; i++) { stringBuilder.Append((i == _sel) ? "> " : " ").Append(_items[i].label); if (_items[i].cfg != null) { stringBuilder.Append(": ").Append(_items[i].cfg.Value); } stringBuilder.Append('\n'); } stringBuilder.Append("\n(A = select, Start = close)"); s = stringBuilder.ToString(); } SetText(_shadow, s); SetText(_text, s); } private static bool EnsureUi() { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) if (_ready) { return true; } if (_failed) { return false; } try { _tmpType = AccessTools.TypeByName("TMPro.TextMeshProUGUI"); if (_tmpType == null) { _failed = true; Plugin.Log.LogWarning((object)"[p2menu] TMP type not found."); return false; } _fontProp = _tmpType.GetProperty("font"); Object[] array = Resources.FindObjectsOfTypeAll(_tmpType); foreach (Object obj in array) { Component val = (Component)(object)((obj is Component) ? obj : null); if (!((Object)(object)val != (Object)null)) { continue; } Scene scene = val.gameObject.scene; if (((Scene)(ref scene)).IsValid()) { _font = ((_fontProp != null) ? _fontProp.GetValue(val) : null); if (_font != null) { break; } } } _go = new GameObject("CouchCrew_P2Menu"); Object.DontDestroyOnLoad((Object)(object)_go); Canvas val2 = _go.AddComponent(); Camera val3 = ResolveUiCamera(); if ((Object)(object)val3 != (Object)null) { val2.renderMode = (RenderMode)1; val2.worldCamera = val3; val2.planeDistance = Mathf.Max(val3.nearClipPlane + 0.5f, 1f); } else { val2.renderMode = (RenderMode)0; } val2.sortingOrder = 28000; Vector2 val4 = (Plugin.SplitStacked.Value ? new Vector2(0.5f, 0.25f) : new Vector2(0.75f, 0.5f)); _imgType = AccessTools.TypeByName("UnityEngine.UI.Image"); if (_imgType != null) { GameObject val5 = new GameObject("Bg"); val5.transform.SetParent(_go.transform, false); Component obj2 = val5.AddComponent(_imgType); PropertyInfo property = _imgType.GetProperty("color"); if (property != null) { property.SetValue(obj2, (object)new Color(0f, 0f, 0f, 0.78f), null); } RectTransform component = val5.GetComponent(); Vector2 val6 = (component.pivot = val4); Vector2 anchorMin = (component.anchorMax = val6); component.anchorMin = anchorMin; component.anchoredPosition = Vector2.zero; component.sizeDelta = new Vector2(430f, 520f); } _shadow = MakeText("Shadow", val4, new Vector2(3f, -3f), new Color(0f, 0f, 0f, 0.6f)); _text = MakeText("Text", val4, Vector2.zero, Color.white); SetLayerRecursive(_go.transform, 5); _go.SetActive(false); _ready = true; Plugin.Log.LogInfo((object)("[p2menu] created (font=" + (_font != null) + ", uiCam=" + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "none — overlay fallback") + ").")); return true; } catch (Exception ex) { _failed = true; Plugin.Log.LogWarning((object)("[p2menu] setup: " + ex.Message)); return false; } } private static Camera ResolveUiCamera() { try { if (!_uiCamTried) { _uiCamTried = true; Type type = AccessTools.TypeByName("GameUtil"); _miUiCam = ((type != null) ? AccessTools.Method(type, "get_uiCamera", (Type[])null, (Type[])null) : null); } return (Camera)((_miUiCam != null) ? /*isinst with value type is only supported in some contexts*/: null); } catch { return null; } } private static void SetLayerRecursive(Transform t, int layer) { ((Component)t).gameObject.layer = layer; for (int i = 0; i < t.childCount; i++) { SetLayerRecursive(t.GetChild(i), layer); } } private static object MakeText(string name, Vector2 anchor, Vector2 pos, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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) GameObject val = new GameObject(name); val.transform.SetParent(_go.transform, false); Component val2 = val.AddComponent(_tmpType); if (_font != null && _fontProp != null) { _fontProp.SetValue(val2, _font); } RectTransform component = val.GetComponent(); Vector2 val3 = (component.pivot = anchor); Vector2 anchorMin = (component.anchorMax = val3); component.anchorMin = anchorMin; component.anchoredPosition = pos; component.sizeDelta = new Vector2(400f, 500f); SetProp(val2, "fontSize", 22f); SetProp(val2, "color", color); SetProp(val2, "richText", true); SetEnumProp(val2, "alignment", "TopLeft"); return val2; } private static void SetText(object tmp, string s) { if (tmp == null) { return; } try { PropertyInfo property = tmp.GetType().GetProperty("text"); if (property != null && property.CanWrite) { property.SetValue(tmp, s, null); } } catch { } } private static void SetProp(object o, string prop, object val) { try { PropertyInfo property = o.GetType().GetProperty(prop); if (property != null && property.CanWrite) { property.SetValue(o, val, null); } } catch { } } private static void SetEnumProp(object o, string prop, string enumName) { try { PropertyInfo property = o.GetType().GetProperty(prop); if (property != null) { property.SetValue(o, Enum.Parse(property.PropertyType, enumName), null); } } catch { } } } [BepInPlugin("com.hunter.couchcrew", "Couch Crew", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.hunter.couchcrew"; public const string Name = "Couch Crew"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry ProbeKey; internal static ConfigEntry SpawnKey; internal static ConfigEntry Enabled; internal static ConfigEntry DemuxInput; internal static ConfigEntry RawDriveInput; internal static ConfigEntry CamFrameBoth; internal static ConfigEntry CamZoom; internal static ConfigEntry FixTransition; internal static ConfigEntry TransitionSpacing; internal static ConfigEntry TransitionDelayFrames; internal static ConfigEntry SplitScreen; internal static ConfigEntry SplitStacked; internal static ConfigEntry JoinOnStart; internal static ConfigEntry P2ToolButton; internal static ConfigEntry P2BeepButton; internal static ConfigEntry P2BrakeButton; internal static ConfigEntry P2DriftButton; internal static ConfigEntry P2BoostButton; internal static ConfigEntry P2GrabButton; internal static ConfigEntry P2LiftButton; internal static ConfigEntry P2PlaceButton; internal static ConfigEntry ShowTwitchCredit; internal static ConfigEntry CreditCornerCfg; internal static ConfigEntry CreditWidth; internal static ConfigEntry PerPlayerNameplates; internal static ConfigEntry PerPlayerShopItems; internal static ConfigEntry PerPlayerTransactions; internal static ConfigEntry PerPlayerHazardIcons; private void Awake() { //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Expected O, but got Unknown //IL_03d8: Expected O, but got Unknown //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03fb: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ProbeKey = ((BaseUnityPlugin)this).Config.Bind("Probe", "DumpKey", (KeyCode)290, "Press in-game to re-dump the couch-coop internals. The probe also auto-dumps once a player body is driving, so this is optional (and a no-op if legacy Input is unavailable)."); Enabled = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "Enabled", true, "PoC #1 master switch. When on, the SpawnKey spawns an extra forklift body owned by the host and forces its isLocalPlayer=true. Host-only. EXPERIMENTAL."); SpawnKey = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "SpawnKey", (KeyCode)288, "Host-only: press during an active shift to spawn ONE extra couch forklift body (PoC #1). (Avoid F10 — Windows binds it to search.)"); JoinOnStart = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "JoinOnStart", true, "Player 2 can press Start on the SECOND controller during an active shift to hop in, no keyboard needed (same as pressing the SpawnKey). Host-only. After joining, Start opens the P2 menu (resume / change color / rebind buttons / leave)."); P2ToolButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2ToolButton", "rightShoulder", "Controller-2 button that uses held tools (blower/extinguisher/vacuum/scrubber). Rebindable in-game from the P2 menu (Start after joining)."); P2BeepButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2BeepButton", "buttonNorth", "Controller-2 button for the horn/beep. Rebindable in-game from the P2 menu."); P2BrakeButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2BrakeButton", "buttonEast", "Controller-2 button for brake/reverse. Rebindable in-game from the P2 menu."); P2DriftButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2DriftButton", "leftTrigger", "Controller-2 button for drift. Rebindable in-game from the P2 menu."); P2BoostButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2BoostButton", "buttonSouth", "Controller-2 button for boost/nitro. Rebindable in-game from the P2 menu."); P2GrabButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2GrabButton", "auto", "Controller-2 button for grab/throw. 'auto' = use the game's own binding. Rebindable in-game from the P2 menu."); P2LiftButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2LiftButton", "auto", "Controller-2 button for lift/lower. 'auto' = use the game's own binding. Rebindable in-game from the P2 menu."); P2PlaceButton = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "P2PlaceButton", "dpadDown", "Controller-2 button for placing/picking up stations. Rebindable in-game from the P2 menu."); ShowTwitchCredit = ((BaseUnityPlugin)this).Config.Bind("Credit", "ShowTwitchCredit", true, "Show the small 'CouchCrew by izaya_here' logo in the corner (menu, lobby and break room only, hidden during shifts). Set to false to hide it."); CreditCornerCfg = ((BaseUnityPlugin)this).Config.Bind("Credit", "Corner", CreditCorner.TopLeft, "Which screen corner the credit logo sits in."); CreditWidth = ((BaseUnityPlugin)this).Config.Bind("Credit", "ImageWidth", 320f, "On-screen width (pixels) of the credit logo."); DemuxInput = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "DemuxInput", true, "Route gamepad #2 to the couch body (independent driving) instead of mirroring P1's input. Needs 2 gamepads connected. Restricts P1's input to exclude gamepad #2 while active."); RawDriveInput = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "RawDriveInput", true, "Driving demux mode. TRUE (default): raw gamepad-2 read written into P2's VehicleInput (the only reliable demux — Unity input getters read the ACTIVE device, so the getter path mirrors P1). FALSE: let the game's getters run (will sync to whoever moved last). Keep this TRUE."); CamFrameBoth = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "CamFrameBoth", true, "Shared-screen camera: keep ALL player forklifts in frame (recenters on their midpoint and zooms out as they spread apart). Only active while a couch body exists."); CamZoom = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "CamZoom", 2f, "How hard the shared camera zooms out as players spread apart (higher = further back). Tune to taste."); FixTransition = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "FixTransition", true, "Bring the couch body along on the break-room->shift transition. The game teleports ONE body per network connection, so the couch body (which shares the host connection) would otherwise be left behind in the break room when the shift loads. This re-teleports it next to the host."); TransitionSpacing = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "TransitionSpacing", 2f, "Sideways gap (metres, to the host's right) the couch body is placed at after a transition so the two bodies don't spawn stacked on each other."); SplitScreen = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "SplitScreen", true, "EXPERIMENTAL true splitscreen: P1 and P2 each get half the screen, rendered DIRECT to screen (bypasses the game's fullscreen render-texture blit, so the scaled/FXAA post path is skipped — slightly rawer image). Overrides CamFrameBoth when on. If the screen goes black or breaks, set this to false to fall back to the shared zoom-out camera."); SplitStacked = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "SplitStacked", false, "Split TOP/BOTTOM (true: P1 top, P2 bottom) instead of LEFT/RIGHT (false: P1 left, P2 right)."); PerPlayerNameplates = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "PerPlayerNameplates", true, "Duplicate the player name labels onto each player's half of the splitscreen. Without this the nameplates only project onto P1's half. Turn off if nameplates misbehave."); PerPlayerShopItems = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "PerPlayerShopItems", true, "Duplicate the shop item name/description popups onto each half so both players see them while shopping. Turn off if shop popups misbehave."); PerPlayerTransactions = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "PerPlayerTransactions", true, "Duplicate the money popups (the +$/-$ that appears when buying or selling) onto each half. Turn off if money popups misbehave."); PerPlayerHazardIcons = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "PerPlayerHazardIcons", true, "Duplicate the hazard effect icons so each player sees their OWN active hazards on their half. Turn off if hazard icons misbehave."); TransitionDelayFrames = ((BaseUnityPlugin)this).Config.Bind("CouchCoop", "TransitionDelayFrames", 240, "SAFETY CAP (frames) on the post-transition re-anchor. After a transition the couch body is dragged to the host until the HOST stops moving (it glides to the shift over ~1s, not an instant snap), then released to drive freely. This caps that follow in case the host never settles (~4s at 60fps)."); Harmony val = new Harmony("com.hunter.couchcrew"); Probe.PatchAll(val); CouchCoop.PatchAll(val); Log.LogInfo((object)("Couch Crew 1.0.0 loaded. P2 joins with Start on controller 2 during a shift " + $"(or {SpawnKey.Value}); {ProbeKey.Value}=probe dump.")); } } internal static class Probe { private static bool _ready; private static Type _camCtrlType; private static Type _vehicleType; private static Type _inputMgrType; private static Type _aggroInputType; private static FieldInfo _fCam; private static FieldInfo _fInputStatic; private static PropertyInfo _pAsset; private static object _camCtrl; private static readonly List _vehicles = new List(); private static int _firstTickFrame = -1; private static int _lastPollFrame = -1; private static bool _tickLogged; private static bool _inputBroken; private static bool _loggedPath; private static string DumpPath { get { try { return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CouchCrew-probe.txt"); } catch { return "CouchCrew-probe.txt"; } } } internal static void PatchAll(Harmony h) { Init(); Patch(h, _camCtrlType, "OnUpdatePresentation", "Post_CamTick"); Patch(h, _vehicleType, "OnUpdateSimulation", "Post_Vehicle"); } private static void Patch(Harmony h, Type t, string method, string postfixName) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (t == null) { Plugin.Log.LogWarning((object)("[probe] type not found for ." + method + " — skipped.")); return; } MethodInfo methodInfo = AccessTools.Method(t, method, (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogWarning((object)("[probe] " + t.Name + "." + method + " not found — skipped.")); } else { MethodInfo method2 = typeof(Probe).GetMethod(postfixName, BindingFlags.Static | BindingFlags.NonPublic); h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("[probe] patched " + t.Name + "." + method)); } } private static void Init() { if (!_ready) { _ready = true; _camCtrlType = AccessTools.TypeByName("CameraController"); _vehicleType = AccessTools.TypeByName("VehicleController"); _inputMgrType = AccessTools.TypeByName("AggroInputManager"); _aggroInputType = AccessTools.TypeByName("AggroInput"); if (_camCtrlType != null) { _fCam = AccessTools.Field(_camCtrlType, "_cam"); } if (_inputMgrType != null) { _fInputStatic = AccessTools.Field(_inputMgrType, "input"); } if (_aggroInputType != null) { _pAsset = AccessTools.Property(_aggroInputType, "asset"); } } } private static void Post_CamTick(object __instance) { //IL_0051: 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) _camCtrl = __instance; if (!_tickLogged) { _tickLogged = true; Plugin.Log.LogInfo((object)"[probe] tick active (CameraController.OnUpdatePresentation)."); } int frameCount = Time.frameCount; if (frameCount == _lastPollFrame) { return; } _lastPollFrame = frameCount; if (_firstTickFrame < 0) { _firstTickFrame = frameCount; } if (!_inputBroken) { try { if (Input.GetKeyDown(Plugin.ProbeKey.Value)) { Dump("hotkey"); } if (Plugin.Enabled.Value && Input.GetKeyDown(Plugin.SpawnKey.Value)) { CouchCoop.SpawnCouchBody(); } } catch (Exception ex) { _inputBroken = true; Plugin.Log.LogWarning((object)("[probe] legacy Input unavailable (" + ex.GetType().Name + ") — hotkeys off; using auto-dump only.")); } } CouchCoop.TickJoinButton(); CouchMenu.Tick(); CouchCredit.Tick(); } private static void Post_Vehicle(object __instance) { foreach (object vehicle in _vehicles) { if (vehicle == __instance) { return; } } if (_vehicles.Count < 12) { _vehicles.Add(__instance); } } internal static void Dump(string trigger) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine("================ CouchCrew probe (" + trigger + ") frame=" + Time.frameCount + " ================"); try { DumpDevices(stringBuilder); } catch (Exception ex) { stringBuilder.AppendLine("[devices] ERROR: " + ex); } try { DumpInputMaps(stringBuilder); } catch (Exception ex2) { stringBuilder.AppendLine("[inputmaps] ERROR: " + ex2); } try { DumpNetwork(stringBuilder); } catch (Exception ex3) { stringBuilder.AppendLine("[network] ERROR: " + ex3); } try { DumpCameras(stringBuilder); } catch (Exception ex4) { stringBuilder.AppendLine("[cameras] ERROR: " + ex4); } try { DumpLocalBody(stringBuilder); } catch (Exception ex5) { stringBuilder.AppendLine("[localbody] ERROR: " + ex5); } stringBuilder.AppendLine("================ end probe ================"); string text = stringBuilder.ToString(); Plugin.Log.LogInfo((object)text); try { File.AppendAllText(DumpPath, text); } catch (Exception ex6) { Plugin.Log.LogWarning((object)("[probe] file write failed: " + ex6.Message)); } if (!_loggedPath) { _loggedPath = true; Plugin.Log.LogInfo((object)("[probe] dump file: " + DumpPath)); } } private static void DumpDevices(StringBuilder sb) { //IL_0010: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- 1. INPUT DEVICES (InputSystem.devices) ---"); int num = 0; int num2 = 0; Enumerator enumerator = InputSystem.devices.GetEnumerator(); try { while (enumerator.MoveNext()) { InputDevice current = enumerator.Current; num2++; bool flag = current is Gamepad; if (flag) { num++; } sb.AppendLine(" [" + (flag ? "GAMEPAD" : ((object)current).GetType().Name) + "] name='" + ((InputControl)current).name + "' display='" + ((InputControl)current).displayName + "' layout='" + ((InputControl)current).layout + "' added=" + current.added); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } sb.AppendLine(" TOTALS: " + num2 + " devices, " + num + " gamepad(s). (couch coop needs >=2 input sources)"); } private static void DumpInputMaps(StringBuilder sb) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("--- 2. AGGROINPUT ACTION MAPS (.enabled) ---"); if (_fInputStatic == null) { sb.AppendLine("AggroInputManager.input field not found."); return; } object value = _fInputStatic.GetValue(null); if (value == null) { sb.AppendLine("AggroInputManager.input is null (input not initialized yet)."); return; } if (_pAsset == null) { sb.AppendLine("AggroInput.asset property not found."); return; } object? value2 = _pAsset.GetValue(value); InputActionAsset val = (InputActionAsset)((value2 is InputActionAsset) ? value2 : null); if ((Object)(object)val == (Object)null) { sb.AppendLine("AggroInput.asset is null / not an InputActionAsset."); return; } sb.AppendLine(" asset='" + ((Object)val).name + "' control schemes: " + DescribeSchemes(val)); Enumerator enumerator = val.actionMaps.GetEnumerator(); try { while (enumerator.MoveNext()) { InputActionMap current = enumerator.Current; int num = 0; try { if (current.devices.HasValue) { num = current.devices.Value.Count; } } catch { } sb.AppendLine(" map '" + current.name + "' enabled=" + current.enabled + " actions=" + current.actions.Count + " boundDevices=" + num); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } sb.AppendLine(" (Expect: Game enabled; Game1/Game2/Game3 present but disabled — those are the spare per-player maps we'd bind controller #2+ to.)"); } private static string DescribeSchemes(InputActionAsset asset) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); try { Enumerator enumerator = asset.controlSchemes.GetEnumerator(); try { while (enumerator.MoveNext()) { InputControlScheme current = enumerator.Current; if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(((InputControlScheme)(ref current)).name); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } catch { return ""; } if (stringBuilder.Length <= 0) { return ""; } return stringBuilder.ToString(); } private static void DumpNetwork(StringBuilder sb) { sb.AppendLine("--- 3. NETWORK / OWNERSHIP (Mirror) ---"); sb.AppendLine(" NetworkServer.active=" + NetworkServer.active + " NetworkClient.active=" + NetworkClient.active + " isHost=" + (NetworkServer.active && NetworkClient.active)); NetworkIdentity localPlayer = NetworkClient.localPlayer; sb.AppendLine(" NetworkClient.localPlayer = " + IdName(localPlayer) + " (the ONE isLocalPlayer body this process drives)"); if (!NetworkServer.active) { sb.AppendLine(" server not active (client-only / not in a hosted run) — connection table is host-side only."); return; } sb.AppendLine(" NetworkServer.connections.Count = " + NetworkServer.connections.Count); foreach (KeyValuePair connection in NetworkServer.connections) { NetworkConnectionToClient value = connection.Value; int num = 0; try { num = ((((NetworkConnection)value).owned != null) ? ((NetworkConnection)value).owned.Count : 0); } catch { } sb.AppendLine(" conn #" + connection.Key + " identity=" + IdName(((NetworkConnection)value).identity) + " owned=" + num); try { if (((NetworkConnection)value).owned == null) { continue; } foreach (NetworkIdentity item in ((NetworkConnection)value).owned) { sb.AppendLine(" owns: " + IdName(item) + ((item == localPlayer) ? " <-- localPlayer" : "")); } } catch (Exception ex) { sb.AppendLine(" "); } } sb.AppendLine(" (Confirms: one controllable body per connection. A 2nd couch body would be an EXTRA owned identity on the host connection whose isLocalPlayer we force true.)"); } private static string IdName(NetworkIdentity id) { if ((Object)(object)id == (Object)null) { return ""; } try { return "'" + ((Object)id).name + "' netId=" + id.netId; } catch { return "netId?"; } } private static void DumpCameras(StringBuilder sb) { sb.AppendLine("--- 4. CAMERA RIG ---"); if (_camCtrl != null && _fCam != null) { object? value = _fCam.GetValue(_camCtrl); Camera val = (Camera)((value is Camera) ? value : null); sb.AppendLine(" CameraController._cam = " + (((Object)(object)val != (Object)null) ? DescribeCamera(val) : "")); if ((Object)(object)val != (Object)null) { List list = new List(); Component[] components = ((Component)val).gameObject.GetComponents(); foreach (Component val2 in components) { list.Add(((object)val2).GetType().Name); } sb.AppendLine(" camera GO components (what drives the scaled RenderTexture?): " + string.Join(", ", list.ToArray())); } } else { sb.AppendLine(" CameraController not captured / _cam field missing."); } sb.AppendLine(" All cameras (" + Camera.allCamerasCount + "):"); Camera[] allCameras = Camera.allCameras; foreach (Camera cam in allCameras) { sb.AppendLine(" " + DescribeCamera(cam)); } sb.AppendLine(" (Splitscreen = clone this rig per player and set Camera.rect viewports; watch for a targetTexture/URP render-texture path that may not compose with rect.)"); } private static string DescribeCamera(Camera cam) { //IL_0010: 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) if ((Object)(object)cam == (Object)null) { return ""; } Rect rect = cam.rect; return "go='" + ((Object)((Component)cam).gameObject).name + "' enabled=" + ((Behaviour)cam).enabled + " depth=" + cam.depth + " rect=(" + ((Rect)(ref rect)).x.ToString("0.##") + "," + ((Rect)(ref rect)).y.ToString("0.##") + "," + ((Rect)(ref rect)).width.ToString("0.##") + "," + ((Rect)(ref rect)).height.ToString("0.##") + ") targetTexture=" + (((Object)(object)cam.targetTexture != (Object)null) ? ((Object)cam.targetTexture).name : "") + " cullingMask=0x" + cam.cullingMask.ToString("X"); } private static void DumpLocalBody(StringBuilder sb) { sb.AppendLine("--- 5. LOCAL PLAYER BODY (captured VehicleControllers) ---"); if (_vehicles.Count == 0) { sb.AppendLine(" none captured yet (no forklift has run OnUpdateSimulation)."); return; } int num = 0; foreach (object vehicle in _vehicles) { num++; Component val = (Component)((vehicle is Component) ? vehicle : null); if ((Object)(object)val == (Object)null) { sb.AppendLine(" [" + num + "] "); continue; } GameObject gameObject = val.gameObject; NetworkIdentity component = val.GetComponent(); sb.AppendLine(" [" + num + "] go='" + ((Object)gameObject).name + "' " + IdName(component) + (((Object)(object)component != (Object)null) ? (" isLocalPlayer=" + component.isLocalPlayer + " connToClient=" + ((component.connectionToClient != null) ? component.connectionToClient.connectionId.ToString() : "")) : "")); List list = new List(); Component[] components = gameObject.GetComponents(); for (int i = 0; i < components.Length; i++) { string name = ((object)components[i]).GetType().Name; if (name.StartsWith("Player") || name == "VehicleController" || name == "NitroController") { list.Add(name); } } sb.AppendLine(" player components: " + string.Join(", ", list.ToArray())); } sb.AppendLine(" (This is the body+component set a 2nd couch player must replicate & have driven locally.)"); } } internal static class CouchCoop { internal static readonly HashSet CouchBodies = new HashSet(); private const int PocBodyCap = 1; private static MethodInfo _serverGetSpawnedPlayer; private static Harmony _harmony; private static Type _vehicleType; private static FieldInfo _vehInputField; private static PropertyInfo _aggroAssetProp; private static object _p2Input; private static bool _demuxReady; private static bool _demuxFailed; private const int ReapplyFrames = 15; private static int _reapplyLeft; private static Type _entityType; private static MethodInfo _miGetNetTransform; private static FieldInfo _fNitroInput; private static bool _actionPatchesApplied; private static ButtonControl _toolBtnCache; private static ButtonControl _beepBtnCache; private static ButtonControl _brakeBtnCache; private static ButtonControl _driftBtnCache; private static ButtonControl _boostBtnCache; private static ButtonControl _grabBtnCache; private static ButtonControl _liftBtnCache; private static ButtonControl _placeBtnCache; private static bool _btnCacheValid; private static Type _stripNitroType; private static MethodInfo _miStripActivate; private static FieldInfo _fStripTransform; private static FieldInfo _fStripBounds; private static FieldInfo _fStripNitroActive; private static object _hintsClone; private static MethodInfo _miHintLate; private static Camera _hintCam; private static bool _hintReentry; private static bool _hintSwapped; private static NetworkIdentity _savedLP; private static MethodInfo _miSetLocalPlayer; private static FieldInfo _fLocalPlayerField; private static bool _lpResolved; private static MethodInfo _miUpdateFloaters; private static Camera _floaterCam; private static bool _floaterReentry; private static Type _floaterUIType; private static Type _entityBehaviourBaseType; private static FieldInfo _fFloatersList; private static FieldInfo _fFloTargetPos; private static FieldInfo _fFloOffset; private static FieldInfo _fFloVisible; private static FieldInfo _fFloAlwaysVis; private static FieldInfo _fFloOnScreen; private static FieldInfo _fFloScale; private static bool _floaterFieldsReady; private static bool _floaterFailed; private static GameObject _floaterHolder; private static readonly Dictionary _floaterClones = new Dictionary(); private static Type _nameplateType; private static MethodInfo _miNameplateLate; private static Camera _nameplateCam; private static bool _npReentry; private static FieldInfo _fNpPlayer; private static FieldInfo _fNpPlayerEntity; private static FieldInfo _fNpColorMgr; private static FieldInfo _fNpContainer; private static FieldInfo _fNpNameText; private static bool _npFieldsReady; private static readonly Dictionary _nameplateClones = new Dictionary(); private static Type _shopItemType; private static MethodInfo _miShopItemUpdate; private static Camera _shopItemCam; private static bool _siReentry; private static bool _siSwapped; private static NetworkIdentity _siSavedLP; private static FieldInfo _fSiContainer; private static bool _siFieldsReady; private static readonly Dictionary _shopItemClones = new Dictionary(); private static Type _transactionType; private static MethodInfo _miTransactionLate; private static Camera _transactionCam; private static bool _trReentry; private static bool _trFieldsReady; private static FieldInfo _fTrFollow; private static FieldInfo _fTrAmount; private static FieldInfo _fTrStart; private static FieldInfo _fTrDestroySelf; private static FieldInfo _fTrText; private static readonly Dictionary _transactionClones = new Dictionary(); private static Type _hazardMgrType; private static MethodInfo _miHazardLate; private static Camera _hazardCam; private static bool _hzReentry; private static bool _hzSwapped; private static NetworkIdentity _hzSavedLP; private static readonly Dictionary _hazardClones = new Dictionary(); private static Type _shopHolderType; private static Type _shopPanelType; private static MethodInfo _miShopHolderEarly; private static FieldInfo _shopInstField; private static object _shopPanelOrig; private static object _shopPanelClone; private static FieldInfo _fShopContainer; private static FieldInfo _fShopShouldDisplay; private static FieldInfo _fShopCurrentData; private static FieldInfo _fShopNextData; private static FieldInfo _fShopIsVisible; private static FieldInfo _fShopIsTransitioning; private static FieldInfo _fShopHideOffset; private static FieldInfo _fShopAnimTime; private static FieldInfo _fShopEase; private static MethodInfo _miShopPanelUpdate; private static float _shopCloneProgress; private static object _easeObj; private static MethodInfo _miEaseEval; private static bool _easeStatic; private static bool _easeResolved; private static bool _shopHolderReentry; private static bool _shopPanelReady; private static bool _shopPanelFailed; private static FieldInfo _fInRotate; private static FieldInfo _fInPlace; private static FieldInfo _fInStartPickUp; private static FieldInfo _fInPickingUp; private static bool _stationFieldsReady; private static FieldInfo _fGrabData; private static FieldInfo _fGrabReq; private static FieldInfo _fRaised; private static ButtonControl _p2GrabBtn; private static ButtonControl _p2LiftBtn; private static ButtonControl _p2DriftBtn; private static bool _p2BtnsResolved; private static FieldInfo _fCamOffset; private static FieldInfo _fCamTransform; private static FieldInfo _fCamCamera; internal static bool SplitActive; private static Camera _p2Cam; private static Camera _mainCam; private static GameObject _p2CamGo; private static RenderTexture _mainOrigRT; private static bool _mainRTCaptured; private static Type _nitroCtrlType; private static Type _nitroBarType; private static FieldInfo _fNitroBars; private static FieldInfo _fNitroCharges; private static FieldInfo _fNitroActive; private static FieldInfo _fNitroBurn; private static FieldInfo _fNitroBuild; private static MethodInfo _miChargeCount; private static MethodInfo _miSetFull; private static MethodInfo _miSetEmpty; private static MethodInfo _miSetFill; private static object _nitroUI; private static Array _p1Bars; private static Array _p2Bars; private static bool _nitroReady; private static bool _nitroFailed; private static readonly Dictionary _stressBarOwner = new Dictionary(); private static NetworkIdentity _sbSaved; private static bool _sbSwapped; private static bool _p1Restricted; private static Type _colorNetType; private static MethodInfo _miSetColorIdx; private static FieldInfo _fColorIdx; private static FieldInfo _fColorMgrRef; private static FieldInfo _fPlayerColors; private static bool _colorResolved; private static int _couchColorIdx = -1; private static readonly Dictionary _colorNetOwner = new Dictionary(); private static Type _shiftMgrTypeJ; private static FieldInfo _fShiftPhaseJ; private static bool _joinReflTried; private static bool _joinPrevPressed; internal static void PatchAll(Harmony h) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Expected O, but got Unknown //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Expected O, but got Unknown //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a8: Expected O, but got Unknown //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Expected O, but got Unknown //IL_0595: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Expected O, but got Unknown //IL_0621: Unknown result type (might be due to invalid IL or missing references) //IL_062f: Expected O, but got Unknown //IL_069d: Unknown result type (might be due to invalid IL or missing references) //IL_06aa: Expected O, but got Unknown //IL_00f3: 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) //IL_011b: Expected O, but got Unknown //IL_011b: Expected O, but got Unknown //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(NetworkIdentity), "isLocalPlayer"); if (methodInfo != null) { h.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_IsLocalPlayer", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[couch] patched NetworkIdentity.get_isLocalPlayer (forces our couch bodies local)."); } else { Plugin.Log.LogWarning((object)"[couch] NetworkIdentity.isLocalPlayer getter not found — PoC disabled."); } MethodInfo methodInfo2 = AccessTools.Method(AccessTools.TypeByName("GameMenuUI"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo2 != null) { h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("MenuOpen_Transpiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[couch] patched GameMenuUI.OnUpdatePresentation (pad-2 Start joins instead of opening the menu)."); } MethodInfo methodInfo3 = AccessTools.Method(AccessTools.TypeByName("PlayerStressBarUI"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo3 != null) { h.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_StressBar", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_StressBar", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[couch] patched PlayerStressBarUI.OnUpdatePresentation (each crashout bar reads its OWN player)."); } MethodInfo methodInfo4 = AccessTools.Method(AccessTools.TypeByName("PlayerColorManagerNetwork"), "OnUpdatePresentationEarly", (Type[])null, (Type[])null); if (methodInfo4 != null) { h.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_ColorNetEarly", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[couch] patched PlayerColorManagerNetwork.OnUpdatePresentationEarly (couch body keeps its own color)."); } try { InputSystem.onDeviceChange += OnDeviceChange; Plugin.Log.LogInfo((object)"[couch] watching device changes (late-connected gamepads get reset + quarantined from P1)."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] onDeviceChange hook failed: " + ex.Message)); } try { MethodInfo methodInfo5 = AccessTools.Method(AccessTools.TypeByName("NetworkUtil"), "ServerGetPing", (Type[])null, (Type[])null); if (methodInfo5 != null) { h.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_ServerGetPing", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[couch] patched NetworkUtil.ServerGetPing (null-conn guard)."); } else { Plugin.Log.LogWarning((object)"[couch] NetworkUtil.ServerGetPing not found — null-conn guard skipped."); } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[couch] ServerGetPing guard failed to apply: " + ex2.Message)); } try { _vehicleType = AccessTools.TypeByName("VehicleController"); HarmonyMethod val = new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_VehSim", BindingFlags.Static | BindingFlags.NonPublic)); HarmonyMethod val2 = new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_VehSim", BindingFlags.Static | BindingFlags.NonPublic)); string[] array = new string[4] { "OnUpdatePresentation", "OnUpdateSimulationEarly", "OnUpdateSimulation", "OnUpdateSimulationLate" }; foreach (string text in array) { MethodInfo methodInfo6 = AccessTools.Method(_vehicleType, text, (Type[])null, (Type[])null); if (methodInfo6 != null) { h.Patch((MethodBase)methodInfo6, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } Plugin.Log.LogInfo((object)"[demux] patched VehicleController (per-body raw input)."); HarmonyMethod val3 = new HarmonyMethod(typeof(CouchCoop).GetMethod("Driving_Transpiler", BindingFlags.Static | BindingFlags.NonPublic)); array = new string[5] { "GetSteeringInput", "GetAccelerationInput", "GetBrakeInput", "GetDriftInput", "CheckForDrifting" }; foreach (string text2 in array) { MethodInfo methodInfo7 = AccessTools.Method(_vehicleType, text2, (Type[])null, (Type[])null); if (methodInfo7 != null) { h.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null, (HarmonyMethod)null); } } Plugin.Log.LogInfo((object)"[demux] transpiled steering/accel/brake/drift getters + CheckForDrifting (P2 = game math)."); } catch (Exception ex3) { Plugin.Log.LogWarning((object)("[demux] swap patch failed to apply: " + ex3.Message)); } try { MethodInfo methodInfo8 = AccessTools.Method(AccessTools.TypeByName("PlayerGrabber"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo8 != null) { h.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_GrabberInput", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[grab] patched PlayerGrabber.OnUpdatePresentation (P2 grab/lift)."); } } catch (Exception ex4) { Plugin.Log.LogWarning((object)("[grab] patch failed: " + ex4.Message)); } try { MethodInfo methodInfo9 = AccessTools.Method(AccessTools.TypeByName("CameraController"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo9 != null) { h.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_CamFrame", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[cam] patched CameraController.OnUpdatePresentation (frame-both)."); } } catch (Exception ex5) { Plugin.Log.LogWarning((object)("[cam] frame-both patch failed: " + ex5.Message)); } try { MethodInfo methodInfo10 = AccessTools.Method(AccessTools.TypeByName("NitroController"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo10 != null) { h.Patch((MethodBase)methodInfo10, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_NitroPresentation", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[boost] patched NitroController.OnUpdatePresentation (per-player Gas->boost)."); } } catch (Exception ex6) { Plugin.Log.LogWarning((object)("[boost] patch failed: " + ex6.Message)); } _harmony = h; try { MethodInfo methodInfo11 = AccessTools.Method(AccessTools.TypeByName("CameraRenderTextureRenderPass"), "Execute", (Type[])null, (Type[])null); if (methodInfo11 != null) { h.Patch((MethodBase)methodInfo11, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_BlitPass", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[split] patched CameraRenderTextureRenderPass.Execute (skip fullscreen blit while split)."); } else { Plugin.Log.LogWarning((object)"[split] CameraRenderTextureRenderPass.Execute not found — splitscreen disabled."); } } catch (Exception ex7) { Plugin.Log.LogWarning((object)("[split] blit-skip patch failed: " + ex7.Message)); } try { MethodInfo methodInfo12 = AccessTools.Method(AccessTools.TypeByName("NitroUI"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo12 != null) { h.Patch((MethodBase)methodInfo12, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_NitroUI", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[hud] patched NitroUI.OnUpdatePresentation (per-player gauges while split)."); } } catch (Exception ex8) { Plugin.Log.LogWarning((object)("[hud] NitroUI patch failed: " + ex8.Message)); } try { MethodInfo methodInfo13 = AccessTools.Method(AccessTools.TypeByName("GameUtil"), "ServerTeleportPlayers", (Type[])null, (Type[])null); if (methodInfo13 != null) { h.Patch((MethodBase)methodInfo13, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_TeleportPlayers", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[transition] patched GameUtil.ServerTeleportPlayers (bring couch body along)."); } else { Plugin.Log.LogWarning((object)"[transition] GameUtil.ServerTeleportPlayers not found — couch body may be left behind on transition."); } } catch (Exception ex9) { Plugin.Log.LogWarning((object)("[transition] patch failed: " + ex9.Message)); } } private static void Post_TeleportPlayers() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) try { if (Plugin.FixTransition.Value) { CouchBodies.RemoveWhere((NetworkIdentity b) => (Object)(object)b == (Object)null); if (CouchBodies.Count != 0) { NetworkIdentity realHost = GetRealHost(); Plugin.Log.LogInfo((object)("[transition] detected; anchoring couch body to real P1 netId=" + (((Object)(object)realHost != (Object)null) ? realHost.netId.ToString() : "") + " @ " + (((Object)(object)realHost != (Object)null) ? ((object)HostPos(realHost)/*cast due to .constrained prefix*/).ToString() : "") + ".")); _reapplyLeft = 15; SnapCouchToHost(realHost, "transition"); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[transition] flag failed: " + ex.Message)); } } private static NetworkIdentity GetRealHost() { foreach (KeyValuePair connection in NetworkServer.connections) { NetworkIdentity val = ((connection.Value != null) ? ((NetworkConnection)connection.Value).identity : null); if ((Object)(object)val != (Object)null && !CouchBodies.Contains(val)) { return val; } } return null; } private static Vector3 HostPos(NetworkIdentity id) { //IL_0009: 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_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)id == (Object)null) { return Vector3.zero; } Rigidbody componentInChildren = ((Component)id).GetComponentInChildren(); if (!((Object)(object)componentInChildren != (Object)null)) { return ((Component)id).transform.position; } return componentInChildren.position; } private static void TickTransitionHold() { if (_reapplyLeft <= 0) { return; } _reapplyLeft--; try { SnapCouchToHost(GetRealHost(), (_reapplyLeft == 0) ? "reapply-final" : null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[transition] reapply failed: " + ex.Message)); _reapplyLeft = 0; } } private unsafe static void SnapCouchToHost(NetworkIdentity host, string logWhy) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)host == (Object)null) { if (logWhy != null) { Plugin.Log.LogWarning((object)"[transition] no real P1 to anchor to."); } return; } Vector3 val = HostPos(host); Quaternion rotation = ((Component)host).transform.rotation; if (_entityType == null) { _entityType = AccessTools.TypeByName("Aggro.Core.Entity") ?? AccessTools.TypeByName("Entity"); if (_entityType != null) { _miGetNetTransform = AccessTools.Method(_entityType, "get_netTransform", (Type[])null, (Type[])null); } } int num = 0; foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody == (Object)null) { continue; } num++; Vector3 val2 = val + rotation * new Vector3(Plugin.TransitionSpacing.Value * (float)num, 0f, 0f); NetworkTransformBase val3 = null; if (_entityType != null && _miGetNetTransform != null) { Component component = ((Component)couchBody).GetComponent(_entityType); if ((Object)(object)component != (Object)null) { object? obj = _miGetNetTransform.Invoke(component, null); val3 = (NetworkTransformBase)((obj is NetworkTransformBase) ? obj : null); } } if ((Object)(object)val3 == (Object)null) { val3 = ((Component)couchBody).GetComponentInChildren(true); } if ((Object)(object)val3 != (Object)null) { val3.ServerTeleport(val2, rotation); } Rigidbody componentInChildren = ((Component)couchBody).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.position = val2; componentInChildren.rotation = rotation; componentInChildren.velocity = Vector3.zero; componentInChildren.angularVelocity = Vector3.zero; } if (logWhy != null) { ManualLogSource log = Plugin.Log; string[] obj2 = new string[7] { "[transition] snapped couch body netId=", couchBody.netId.ToString(), " to P1 @ ", null, null, null, null }; Vector3 val4 = val2; obj2[3] = ((object)(*(Vector3*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj2[4] = " ("; obj2[5] = logWhy; obj2[6] = ")."; log.LogInfo((object)string.Concat(obj2)); } } } private static void Post_NitroPresentation(object __instance) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return; } Component val = (Component)((__instance is Component) ? __instance : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)val2 == (Object)null) { return; } bool flag = CouchBodies.Contains(val2); bool flag2 = val2 == GetRealHost(); if (!flag && !flag2) { return; } if (_fNitroInput == null) { _fNitroInput = AccessTools.Field(__instance.GetType(), "_nitroInput"); } if (_fNitroInput == null) { return; } ReadOnlyArray all = Gamepad.all; bool flag3; if (flag) { flag3 = false; if (!CouchMenu.IsOpen && all.Count >= 2) { EnsureP2ActionButtons(all[1]); flag3 = _boostBtnCache != null && _boostBtnCache.isPressed; } } else { flag3 = (Keyboard.current != null && ((ButtonControl)Keyboard.current.spaceKey).isPressed) || (all.Count >= 1 && all[0].buttonSouth != null && all[0].buttonSouth.isPressed); } _fNitroInput.SetValue(__instance, flag3); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[boost] " + ex.Message)); } } private static void Post_IsLocalPlayer(NetworkIdentity __instance, ref bool __result) { if (!((CouchBodies.Count == 0) | __result) && CouchBodies.Contains(__instance)) { __result = true; } } private static bool Pre_ServerGetPing(NetworkConnectionToClient conn, ref double __result) { if (conn != null) { return true; } __result = 0.0; return false; } private static void EnsureDemux() { //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Expected O, but got Unknown //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_011e: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) if (_demuxReady || _demuxFailed || !Plugin.DemuxInput.Value) { return; } try { if (_vehicleType == null) { _vehicleType = AccessTools.TypeByName("VehicleController"); } Type type = AccessTools.TypeByName("AggroInput"); _vehInputField = AccessTools.Field(AccessTools.TypeByName("AggroInputManager"), "input"); _aggroAssetProp = AccessTools.Property(type, "asset"); if (_vehInputField == null || _aggroAssetProp == null || !_vehInputField.IsStatic) { _demuxFailed = true; Plugin.Log.LogWarning((object)"[demux] AggroInputManager.input (static) or AggroInput.asset not found."); return; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { Plugin.Log.LogWarning((object)("[demux] need >=2 gamepads, have " + all.Count + " — couch body will mirror P1 until a 2nd pad is connected.")); return; } Gamepad val = all[1]; _p2Input = Activator.CreateInstance(type); InputActionAsset val2 = (InputActionAsset)_aggroAssetProp.GetValue(_p2Input); val2.devices = new ReadOnlyArray((InputDevice[])(object)new InputDevice[1] { (InputDevice)val }); val2.FindActionMap("Game", true).Enable(); try { InputUser val3 = InputUser.PerformPairingWithDevice((InputDevice)(object)val, default(InputUser), (InputUserPairingOptions)0); ((InputUser)(ref val3)).AssociateActionsWithUser((IInputActionCollection)(object)val2); Plugin.Log.LogInfo((object)("[demux] InputUser paired gamepad#2 -> P2 input (valid=" + ((InputUser)(ref val3)).valid + ").")); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[demux] InputUser pairing failed: " + ex.Message)); } object value = _vehInputField.GetValue(null); if (value != null) { InputActionAsset val4 = (InputActionAsset)_aggroAssetProp.GetValue(value); List list = new List(); if (Keyboard.current != null) { list.Add((InputDevice)(object)Keyboard.current); } if (Mouse.current != null) { list.Add((InputDevice)(object)Mouse.current); } Enumerator enumerator = all.GetEnumerator(); try { while (enumerator.MoveNext()) { Gamepad current = enumerator.Current; if (current != val) { list.Add((InputDevice)(object)current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } val4.devices = new ReadOnlyArray(list.ToArray()); } DumpGameBindings(val2); _demuxReady = true; Plugin.Log.LogInfo((object)("[demux] ready: gamepad#2 '" + ((InputControl)val).displayName + "' -> couch body; P1 input excludes it.")); Plugin.Log.LogInfo((object)("[demux] P2 input devices = " + DevList(val2) + " (should be ONLY gamepad#2)")); object value2 = _vehInputField.GetValue(null); if (value2 != null) { Plugin.Log.LogInfo((object)("[demux] P1 input devices = " + DevList((InputActionAsset)_aggroAssetProp.GetValue(value2)) + " (should EXCLUDE gamepad#2)")); } } catch (Exception ex2) { _demuxFailed = true; Plugin.Log.LogError((object)("[demux] setup failed (driving will mirror P1): " + ex2)); } } private static void DumpGameBindings(InputActionAsset asset) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) try { InputActionMap val = asset.FindActionMap("Game", false); if (val == null) { Plugin.Log.LogWarning((object)"[bind] Game map not found."); return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[bind] Game action map bindings:"); Enumerator enumerator = val.actions.GetEnumerator(); try { while (enumerator.MoveNext()) { InputAction current = enumerator.Current; List list = new List(); Enumerator enumerator2 = current.bindings.GetEnumerator(); try { while (enumerator2.MoveNext()) { InputBinding current2 = enumerator2.Current; if (!string.IsNullOrEmpty(((InputBinding)(ref current2)).effectivePath)) { list.Add(((InputBinding)(ref current2)).effectivePath); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } stringBuilder.AppendLine(" '" + current.name + "' (" + ((object)current.type/*cast due to .constrained prefix*/).ToString() + ") -> " + string.Join(" | ", list.ToArray())); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[bind] dump failed: " + ex.Message)); } } private static string DevList(InputActionAsset a) { //IL_001e: 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_0026: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) ReadOnlyArray? devices = a.devices; if (!devices.HasValue) { return ""; } StringBuilder stringBuilder = new StringBuilder(); Enumerator enumerator = devices.Value.GetEnumerator(); try { while (enumerator.MoveNext()) { InputDevice current = enumerator.Current; stringBuilder.Append("'" + ((InputControl)current).displayName + "' "); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } if (devices.Value.Count != 0) { return stringBuilder.ToString(); } return ""; } private static void Pre_VehSim(object __instance, out object __state) { __state = null; if (_demuxReady && _p2Input != null && CouchBodies.Count != 0 && !(_vehInputField == null)) { Component val = (Component)((__instance is Component) ? __instance : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { __state = _vehInputField.GetValue(null); _vehInputField.SetValue(null, _p2Input); } } } private static void Post_VehSim(object __state) { if (__state != null) { _vehInputField.SetValue(null, __state); } } private static IEnumerable Driving_Transpiler(IEnumerable instructions) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown List list = new List(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(CouchCoop), "SteeringFor", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(CouchCoop), "BrakeFor", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(CouchCoop), "DriftFor", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { MethodInfo methodInfo4 = list[i].operand as MethodInfo; if (methodInfo4 == null) { continue; } MethodInfo methodInfo5 = ((methodInfo4.Name == "get_Steering") ? methodInfo : ((methodInfo4.Name == "get_Brake") ? methodInfo2 : ((methodInfo4.Name == "get_Drift") ? methodInfo3 : null))); if (methodInfo5 == null) { continue; } for (int j = i + 1; j < list.Count && j <= i + 4; j++) { MethodInfo methodInfo6 = list[j].operand as MethodInfo; if (methodInfo6 != null && methodInfo6.Name == "ReadValue") { list.Insert(j + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(j + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo5)); i = j + 2; break; } } } return list; } private static Vector2 SteeringFor(Vector2 orig, object veh) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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_007b: 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) try { if (CouchBodies.Count == 0) { return orig; } Component val = (Component)((veh is Component) ? veh : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { if (CouchMenu.IsOpen) { return Vector2.zero; } ReadOnlyArray all = Gamepad.all; if (all.Count >= 2 && all[1].leftStick != null) { return ((InputControl)(object)all[1].leftStick).ReadValue(); } } return orig; } catch { return orig; } } private static float BrakeFor(float orig, object veh) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return orig; } Component val = (Component)((veh is Component) ? veh : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { if (CouchMenu.IsOpen) { return 0f; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return 0f; } EnsureP2ActionButtons(all[1]); return (_brakeBtnCache != null) ? ((InputControl)(object)_brakeBtnCache).ReadValue() : 0f; } return orig; } catch { return orig; } } private static float DriftFor(float orig, object veh) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return orig; } Component val = (Component)((veh is Component) ? veh : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { if (CouchMenu.IsOpen) { return 0f; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return 0f; } EnsureP2ActionButtons(all[1]); return (_driftBtnCache != null) ? ((InputControl)(object)_driftBtnCache).ReadValue() : 0f; } return orig; } catch { return orig; } } private static void EnsureActionPatches() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Expected O, but got Unknown //IL_0247: Expected O, but got Unknown //IL_0247: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown //IL_02b6: Expected O, but got Unknown //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Expected O, but got Unknown //IL_0353: Expected O, but got Unknown //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Expected O, but got Unknown //IL_0502: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Expected O, but got Unknown //IL_0544: Expected O, but got Unknown //IL_0544: Expected O, but got Unknown //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Expected O, but got Unknown //IL_0456: Expected O, but got Unknown //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Expected O, but got Unknown //IL_06bb: Unknown result type (might be due to invalid IL or missing references) //IL_06d6: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Unknown result type (might be due to invalid IL or missing references) //IL_06fd: Expected O, but got Unknown //IL_06fd: Expected O, but got Unknown //IL_06fd: Expected O, but got Unknown //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_0602: Unknown result type (might be due to invalid IL or missing references) //IL_060f: Expected O, but got Unknown //IL_060f: Expected O, but got Unknown //IL_062f: Unknown result type (might be due to invalid IL or missing references) //IL_063b: Expected O, but got Unknown if (_actionPatchesApplied || _harmony == null) { return; } _actionPatchesApplied = true; try { Type type = AccessTools.TypeByName("CCTags"); if (type != null) { RuntimeHelpers.RunClassConstructor(type.TypeHandle); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[actions] CCTags pre-init failed: " + ex.Message)); } try { HarmonyMethod val = new HarmonyMethod(typeof(CouchCoop).GetMethod("Tool_UseBox_Transpiler", BindingFlags.Static | BindingFlags.NonPublic)); string[] array = new string[4] { "PlayerBlower", "PlayerExtinguisher", "PlayerVacuum", "PlayerScrubber" }; for (int i = 0; i < array.Length; i++) { MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName(array[i]), "OnUpdateSimulation", (Type[])null, (Type[])null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); } } MethodInfo methodInfo2 = AccessTools.Method(AccessTools.TypeByName("PlayerStationPlacer"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_StationInput", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo3 = AccessTools.Method(AccessTools.TypeByName("PingController"), "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo3 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Beep_Transpiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo4 = AccessTools.Method(AccessTools.TypeByName("Booststrip"), "OnUpdateSimulation", (Type[])null, (Type[])null); if (methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_Booststrip", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo5 = AccessTools.Method(AccessTools.TypeByName("HotkeyHintsUI"), "OnUpdatePresentationLate", (Type[])null, (Type[])null); if (methodInfo5 != null) { _harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_Hints", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_Hints", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Hints_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo6 = AccessTools.Method(AccessTools.TypeByName("FloaterManagerUI"), "UpdateFloaters", (Type[])null, (Type[])null); if (methodInfo6 != null) { _miUpdateFloaters = methodInfo6; _harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_Floaters", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Floater_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); } _shopHolderType = AccessTools.TypeByName("ShopHolder"); _miShopHolderEarly = AccessTools.Method(_shopHolderType, "OnUpdatePresentationEarly", (Type[])null, (Type[])null); _shopPanelType = AccessTools.TypeByName("ShopPanelUI"); if (_miShopHolderEarly != null && _shopPanelType != null) { _harmony.Patch((MethodBase)_miShopHolderEarly, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_ShopHolder", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_ShopHolder", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo7 = AccessTools.Method(_shopPanelType, "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo7 != null) { _harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_ShopPanelTick", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } Plugin.Log.LogInfo((object)"[shoppanel] patched ShopHolder.OnUpdatePresentationEarly + ShopPanelUI tick (per-player shop detail panel)."); } if (Plugin.PerPlayerNameplates.Value) { _nameplateType = AccessTools.TypeByName("NamePlateUI"); MethodInfo methodInfo8 = AccessTools.Method(_nameplateType, "OnUpdatePresentationLate", (Type[])null, (Type[])null); MethodInfo methodInfo9 = AccessTools.Method(_nameplateType, "SetTargetPosition", (Type[])null, (Type[])null); if (methodInfo8 != null && methodInfo9 != null) { _miNameplateLate = methodInfo8; _harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_Nameplate", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_Nameplate", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo9, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Nameplate_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[nameplate] patched NamePlateUI (per-player name labels)."); } else { Plugin.Log.LogWarning((object)"[nameplate] NamePlateUI methods not found — per-player nameplates off."); } } if (Plugin.PerPlayerShopItems.Value) { _shopItemType = AccessTools.TypeByName("ShopItemUI"); MethodInfo methodInfo10 = AccessTools.Method(_shopItemType, "OnUpdatePresentation", (Type[])null, (Type[])null); if (methodInfo10 != null) { _miShopItemUpdate = methodInfo10; _harmony.Patch((MethodBase)methodInfo10, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_ShopItem", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_ShopItem", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("ShopItem_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[shopitem] patched ShopItemUI (per-player shop item popups)."); } else { Plugin.Log.LogWarning((object)"[shopitem] ShopItemUI.OnUpdatePresentation not found — per-player shop items off."); } } if (Plugin.PerPlayerTransactions.Value) { _transactionType = AccessTools.TypeByName("TransactionUI"); MethodInfo methodInfo11 = AccessTools.Method(_transactionType, "OnUpdatePresentationLate", (Type[])null, (Type[])null); MethodInfo methodInfo12 = AccessTools.Method(_transactionType, "SetTargetPosition", (Type[])null, (Type[])null); if (methodInfo11 != null && methodInfo12 != null) { _miTransactionLate = methodInfo11; _harmony.Patch((MethodBase)methodInfo11, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_Transaction", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_Transaction", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _harmony.Patch((MethodBase)methodInfo12, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(CouchCoop).GetMethod("Transaction_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[transaction] patched TransactionUI (per-player money popups)."); } else { Plugin.Log.LogWarning((object)"[transaction] TransactionUI methods not found — per-player money popups off."); } } if (Plugin.PerPlayerHazardIcons.Value) { _hazardMgrType = AccessTools.TypeByName("HazardIconManagerUI"); MethodInfo methodInfo13 = AccessTools.Method(_hazardMgrType, "OnUpdatePresentationLate", (Type[])null, (Type[])null); if (methodInfo13 != null) { _miHazardLate = methodInfo13; _harmony.Patch((MethodBase)methodInfo13, new HarmonyMethod(typeof(CouchCoop).GetMethod("Pre_HazardIcons", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Post_HazardIcons", BindingFlags.Static | BindingFlags.NonPublic)), new HarmonyMethod(typeof(CouchCoop).GetMethod("Hazard_CamTranspiler", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)"[hazard] patched HazardIconManagerUI (per-player hazard icons)."); } else { Plugin.Log.LogWarning((object)"[hazard] HazardIconManagerUI.OnUpdatePresentationLate not found — per-player hazard icons off."); } } Plugin.Log.LogInfo((object)"[actions] tools + stations + beep + boost-strip + floaters + shop-panel + nameplates + shop-items + transactions + hazard-icons patched lazily (CCTags pre-initialized)."); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[actions] lazy patch failed: " + ex2.Message)); } } private static IEnumerable Tool_UseBox_Transpiler(IEnumerable instructions) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown List list = new List(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(CouchCoop), "ToolUseBoxFor", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { MethodInfo methodInfo2 = list[i].operand as MethodInfo; if (methodInfo2 == null || methodInfo2.Name != "get_UseBox") { continue; } for (int j = i + 1; j < list.Count && j <= i + 4; j++) { MethodInfo methodInfo3 = list[j].operand as MethodInfo; if (methodInfo3 != null && methodInfo3.Name == "IsPressed") { list.Insert(j + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(j + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo)); i = j + 2; break; } } } return list; } private static bool ToolUseBoxFor(bool orig, object tool) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return orig; } Component val = (Component)((tool is Component) ? tool : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { if (CouchMenu.IsOpen) { return false; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return false; } EnsureP2ActionButtons(all[1]); return _toolBtnCache != null && _toolBtnCache.isPressed; } return orig; } catch { return orig; } } internal static void InvalidateP2ButtonCache() { _btnCacheValid = false; } private static void EnsureP2ActionButtons(Gamepad pad) { if (!_btnCacheValid) { _btnCacheValid = true; ResolveP2Buttons(pad); _toolBtnCache = NamedButton(pad, Plugin.P2ToolButton.Value); if (_toolBtnCache == null) { _toolBtnCache = pad.rightShoulder; } _beepBtnCache = NamedButton(pad, Plugin.P2BeepButton.Value); if (_beepBtnCache == null) { _beepBtnCache = pad.buttonNorth; } _brakeBtnCache = NamedButton(pad, Plugin.P2BrakeButton.Value); if (_brakeBtnCache == null) { _brakeBtnCache = pad.buttonEast; } _driftBtnCache = NamedButton(pad, Plugin.P2DriftButton.Value); if (_driftBtnCache == null) { _driftBtnCache = pad.leftTrigger; } _boostBtnCache = NamedButton(pad, Plugin.P2BoostButton.Value); if (_boostBtnCache == null) { _boostBtnCache = pad.buttonSouth; } _grabBtnCache = NamedButton(pad, Plugin.P2GrabButton.Value); if (_grabBtnCache == null) { _grabBtnCache = _p2GrabBtn; } _liftBtnCache = NamedButton(pad, Plugin.P2LiftButton.Value); if (_liftBtnCache == null) { _liftBtnCache = _p2LiftBtn; } _placeBtnCache = NamedButton(pad, Plugin.P2PlaceButton.Value); if (_placeBtnCache == null) { _placeBtnCache = ((pad.dpad != null) ? pad.dpad.down : null); } if (_grabBtnCache == null || _liftBtnCache == null) { _btnCacheValid = false; } } } private static ButtonControl NamedButton(Gamepad pad, string name) { if (pad == null || string.IsNullOrEmpty(name) || name == "auto") { return null; } switch (name) { case "buttonNorth": return pad.buttonNorth; case "buttonSouth": return pad.buttonSouth; case "buttonEast": return pad.buttonEast; case "buttonWest": return pad.buttonWest; case "leftShoulder": return pad.leftShoulder; case "rightShoulder": return pad.rightShoulder; case "leftTrigger": return pad.leftTrigger; case "rightTrigger": return pad.rightTrigger; case "leftStickPress": return pad.leftStickButton; case "rightStickPress": return pad.rightStickButton; case "select": return pad.selectButton; case "dpadDown": if (pad.dpad == null) { return null; } return pad.dpad.down; case "dpadUp": if (pad.dpad == null) { return null; } return pad.dpad.up; case "dpadLeft": if (pad.dpad == null) { return null; } return pad.dpad.left; case "dpadRight": if (pad.dpad == null) { return null; } return pad.dpad.right; case "down": if (pad.dpad == null) { return null; } return pad.dpad.down; case "up": if (pad.dpad == null) { return null; } return pad.dpad.up; case "left": if (pad.dpad == null) { return null; } return pad.dpad.left; case "right": if (pad.dpad == null) { return null; } return pad.dpad.right; default: try { return ((InputControl)pad).TryGetChildControl(name); } catch { return null; } } } private static IEnumerable Beep_Transpiler(IEnumerable instructions) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown List list = new List(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(CouchCoop), "BeepFor", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { MethodInfo methodInfo2 = list[i].operand as MethodInfo; if (methodInfo2 == null || methodInfo2.Name != "get_Beep") { continue; } for (int j = i + 1; j < list.Count && j <= i + 4; j++) { MethodInfo methodInfo3 = list[j].operand as MethodInfo; if (methodInfo3 != null && methodInfo3.Name == "IsPressed") { list.Insert(j + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(j + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo)); i = j + 2; break; } } } return list; } private static bool BeepFor(bool orig, object ping) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return orig; } Component val = (Component)((ping is Component) ? ping : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)val2 != (Object)null && CouchBodies.Contains(val2)) { if (CouchMenu.IsOpen) { return false; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return false; } EnsureP2ActionButtons(all[1]); return _beepBtnCache != null && _beepBtnCache.isPressed; } return orig; } catch { return orig; } } private static void Post_Booststrip(object __instance) { //IL_008c: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return; } if (_fStripTransform == null) { Type type = __instance.GetType(); _fStripTransform = AccessTools.Field(type, "_transform"); _fStripBounds = AccessTools.Field(type, "_bounds"); } if (_fStripTransform == null || _fStripBounds == null) { return; } object? value = _fStripTransform.GetValue(__instance); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { return; } Bounds bounds = (Bounds)_fStripBounds.GetValue(__instance); if (_stripNitroType == null) { _stripNitroType = AccessTools.TypeByName("NitroController"); } BoostBodyIfOnStrip(GetRealHost(), val, bounds); foreach (NetworkIdentity couchBody in CouchBodies) { BoostBodyIfOnStrip(couchBody, val, bounds); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[boost-strip] " + ex.Message)); } } private static void SetClientLocalPlayer(NetworkIdentity ni) { if (!_lpResolved) { _lpResolved = true; _miSetLocalPlayer = AccessTools.PropertySetter(typeof(NetworkClient), "localPlayer"); if (_miSetLocalPlayer == null) { _fLocalPlayerField = AccessTools.Field(typeof(NetworkClient), "localPlayer") ?? AccessTools.Field(typeof(NetworkClient), "k__BackingField"); } } if (_miSetLocalPlayer != null) { _miSetLocalPlayer.Invoke(null, new object[1] { ni }); } else if (_fLocalPlayerField != null) { _fLocalPlayerField.SetValue(null, ni); } } private static Camera GetHintCam() { if (!((Object)(object)_hintCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _hintCam; } private static IEnumerable Hints_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetHintCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static void Pre_Hints(object __instance) { try { _hintSwapped = false; if (_hintReentry) { return; } if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { _hintCam = null; return; } NetworkIdentity realHost = GetRealHost(); if ((Object)(object)realHost == (Object)null) { _hintCam = null; return; } if (_hintsClone == null) { GameObject gameObject = ((Component)((__instance is Component) ? __instance : null)).gameObject; GameObject obj = Object.Instantiate(gameObject, gameObject.transform.parent); ((Object)obj).name = "CouchCrew_P2Hints"; _hintsClone = obj.GetComponent(__instance.GetType()); if (_miHintLate == null) { _miHintLate = AccessTools.Method(__instance.GetType(), "OnUpdatePresentationLate", (Type[])null, (Type[])null); } Plugin.Log.LogInfo((object)"[hints] cloned HotkeyHintsUI for P2."); } _savedLP = NetworkClient.localPlayer; SetClientLocalPlayer(realHost); _hintCam = _mainCam; _hintSwapped = true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[hints] pre: " + ex.Message)); } } private static void Post_Hints(object __instance) { if (_hintReentry || !_hintSwapped) { return; } try { SetClientLocalPlayer(_savedLP); if (_hintsClone != null && _miHintLate != null) { _hintCam = _p2Cam; _hintReentry = true; try { _miHintLate.Invoke(_hintsClone, null); } catch { } _hintReentry = false; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[hints] post: " + ex.Message)); } finally { _hintCam = null; _hintSwapped = false; } } private static Camera GetFloaterCam() { if (!((Object)(object)_floaterCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _floaterCam; } private static IEnumerable Floater_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetFloaterCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static void Post_Floaters(object __instance) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_03cb: Unknown result type (might be due to invalid IL or missing references) if (_floaterReentry || _floaterFailed) { return; } try { if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { if (_floaterClones.Count > 0) { ClearFloaterClones(); } return; } if (!_floaterFieldsReady) { _fFloatersList = AccessTools.Field(__instance.GetType(), "floaters"); _floaterUIType = AccessTools.TypeByName("FloaterUI"); if (_floaterUIType != null) { _fFloTargetPos = AccessTools.Field(_floaterUIType, "targetWorldPosition"); _fFloOffset = AccessTools.Field(_floaterUIType, "offset"); _fFloVisible = AccessTools.Field(_floaterUIType, "visible"); _fFloAlwaysVis = AccessTools.Field(_floaterUIType, "alwaysVisible"); _fFloOnScreen = AccessTools.Field(_floaterUIType, "onScreen"); _fFloScale = AccessTools.Field(_floaterUIType, "_floaterScale"); } _entityBehaviourBaseType = AccessTools.TypeByName("Aggro.Core.EntityBehaviourBase"); _floaterFieldsReady = true; if (_fFloatersList == null || _floaterUIType == null) { _floaterFailed = true; Plugin.Log.LogWarning((object)"[floaters] reflection incomplete — per-player floaters off."); return; } Plugin.Log.LogInfo((object)"[floaters] per-player floaters ready."); } if (!(_fFloatersList.GetValue(__instance) is IList list)) { return; } HashSet hashSet = new HashSet(); IList list2 = (IList)Activator.CreateInstance(list.GetType()); foreach (object item in list) { if (item == null) { continue; } Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val == (Object)null) { continue; } hashSet.Add(item); if (!_floaterClones.TryGetValue(item, out var value) || (Object)((value is Component) ? value : null) == (Object)null) { if ((Object)(object)_floaterHolder == (Object)null) { _floaterHolder = new GameObject("CouchCrew_FloaterCloneHolder"); _floaterHolder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_floaterHolder); } GameObject val2 = Object.Instantiate(val.gameObject, _floaterHolder.transform); ((Object)val2).name = ((Object)val.gameObject).name + "_P2"; if (_entityBehaviourBaseType != null) { Component[] componentsInChildren = val2.GetComponentsInChildren(_entityBehaviourBaseType, true); foreach (Component val3 in componentsInChildren) { if (!_floaterUIType.IsInstanceOfType(val3)) { Object.DestroyImmediate((Object)(object)val3); } } } val2.transform.SetParent(val.gameObject.transform.parent, false); value = val2.GetComponent(_floaterUIType); _floaterClones[item] = value; } Component val4 = (Component)((value is Component) ? value : null); if (!((Object)(object)val4 == (Object)null)) { if (_fFloTargetPos != null) { _fFloTargetPos.SetValue(value, _fFloTargetPos.GetValue(item)); } if (_fFloOffset != null) { _fFloOffset.SetValue(value, _fFloOffset.GetValue(item)); } if (_fFloVisible != null) { _fFloVisible.SetValue(value, _fFloVisible.GetValue(item)); } if (_fFloAlwaysVis != null) { _fFloAlwaysVis.SetValue(value, _fFloAlwaysVis.GetValue(item)); } if (_fFloOnScreen != null) { _fFloOnScreen.SetValue(value, _fFloOnScreen.GetValue(item)); } if (_fFloScale != null) { _fFloScale.SetValue(value, _fFloScale.GetValue(item)); } val4.transform.localScale = val.transform.localScale; if (val4.gameObject.activeSelf != val.gameObject.activeSelf) { val4.gameObject.SetActive(val.gameObject.activeSelf); } list2.Add(value); } } if (_floaterClones.Count > hashSet.Count) { List list3 = new List(); foreach (KeyValuePair floaterClone in _floaterClones) { if (!hashSet.Contains(floaterClone.Key)) { list3.Add(floaterClone.Key); } } foreach (object item2 in list3) { object obj = _floaterClones[item2]; Component val5 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val5 != (Object)null) { val5.gameObject.SetActive(false); Object.Destroy((Object)(object)val5.gameObject); } _floaterClones.Remove(item2); } } _floaterReentry = true; _floaterCam = _p2Cam; _fFloatersList.SetValue(__instance, list2); try { _miUpdateFloaters.Invoke(__instance, null); } finally { _fFloatersList.SetValue(__instance, list); _floaterCam = null; _floaterReentry = false; } HideOffScreenFloaters(list, _mainCam); HideOffScreenFloaters(list2, _p2Cam); EnforceHalfSeparation(list, isP2: false); EnforceHalfSeparation(list2, isP2: true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[floaters] " + ex.Message)); } } private static void HideOffScreenFloaters(IList list, Camera cam) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (_fFloOnScreen == null || list == null) { return; } foreach (object item in list) { Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val == (Object)null) { continue; } bool flag; try { flag = (bool)_fFloOnScreen.GetValue(item); } catch { continue; } if (flag && _fFloTargetPos != null) { try { flag = InCamView(cam, (Vector3)_fFloTargetPos.GetValue(item)); } catch { } } if (val.gameObject.activeSelf != flag) { val.gameObject.SetActive(flag); } } } private static bool InCamView(Camera cam, Vector3 worldPos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cam == (Object)null) { return true; } Vector3 val = cam.WorldToViewportPoint(worldPos); if (val.z > 0f && val.x > -0.1f && val.x < 1.1f && val.y > -0.1f) { return val.y < 1.1f; } return false; } private static bool WrongHalf(Transform t, bool isP2) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null); if ((Object)(object)val == (Object)null) { return false; } Transform parent = ((Transform)val).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 == (Object)null) { return false; } Rect rect = val2.rect; Vector2 center = ((Rect)(ref rect)).center; Vector3 localPosition = ((Transform)val).localPosition; if (Plugin.SplitStacked.Value) { if (!isP2) { return localPosition.y < center.y; } return localPosition.y > center.y; } if (!isP2) { return localPosition.x > center.x; } return localPosition.x < center.x; } private static void EnforceHalfSeparation(IList list, bool isP2) { if (list == null) { return; } foreach (object item in list) { Component val = (Component)((item is Component) ? item : null); if (!((Object)(object)val == (Object)null) && val.gameObject.activeSelf && WrongHalf(val.transform, isP2)) { val.gameObject.SetActive(false); } } } private static void ClearFloaterClones() { foreach (KeyValuePair floaterClone in _floaterClones) { object value = floaterClone.Value; Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null) { val.gameObject.SetActive(false); Object.Destroy((Object)(object)val.gameObject); } } _floaterClones.Clear(); } private static Camera GetNameplateCam() { if (!((Object)(object)_nameplateCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _nameplateCam; } private static IEnumerable Nameplate_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetNameplateCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static bool Pre_Nameplate(object __instance) { if (_npReentry) { return true; } return !_nameplateClones.ContainsValue(__instance); } private static void Post_Nameplate(object __instance) { if (_npReentry) { return; } try { if (_nameplateClones.ContainsValue(__instance)) { return; } if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { if (_nameplateClones.Count > 0) { ClearUiClones(_nameplateClones); } return; } if (!_npFieldsReady) { _npFieldsReady = true; _fNpPlayer = AccessTools.Field(_nameplateType, "player"); _fNpPlayerEntity = AccessTools.Field(_nameplateType, "playerEntity"); _fNpColorMgr = AccessTools.Field(_nameplateType, "playerColorManager"); _fNpContainer = AccessTools.Field(_nameplateType, "container"); _fNpNameText = AccessTools.Field(_nameplateType, "nameTextUI"); if (_entityBehaviourBaseType == null) { _entityBehaviourBaseType = AccessTools.TypeByName("Aggro.Core.EntityBehaviourBase"); } } bool created; object orMakeUiClone = GetOrMakeUiClone(_nameplateClones, __instance, _nameplateType, out created); Component val = (Component)((orMakeUiClone is Component) ? orMakeUiClone : null); if (!((Object)(object)val == (Object)null)) { if (_fNpPlayer != null) { _fNpPlayer.SetValue(orMakeUiClone, _fNpPlayer.GetValue(__instance)); } if (_fNpPlayerEntity != null) { _fNpPlayerEntity.SetValue(orMakeUiClone, _fNpPlayerEntity.GetValue(__instance)); } if (_fNpColorMgr != null) { _fNpColorMgr.SetValue(orMakeUiClone, _fNpColorMgr.GetValue(__instance)); } Component val2 = (Component)((__instance is Component) ? __instance : null); if (val.gameObject.activeSelf != val2.gameObject.activeSelf) { val.gameObject.SetActive(val2.gameObject.activeSelf); } SweepDeadClones(_nameplateClones); _nameplateCam = _p2Cam; _npReentry = true; try { _miNameplateLate.Invoke(orMakeUiClone, null); } finally { _npReentry = false; _nameplateCam = null; } GateNameplate(__instance, _mainCam, isP2: false); GateNameplate(orMakeUiClone, _p2Cam, isP2: true); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[nameplate] " + ex.Message)); } } private static void GateNameplate(object plate, Camera cam, bool isP2) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) try { if (_fNpPlayer == null || _fNpContainer == null) { return; } object value = _fNpPlayer.GetValue(plate); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { Component val2 = (Component)((value is Component) ? value : null); if ((Object)(object)val2 != (Object)null) { val = val2.transform; } } if ((Object)(object)val == (Object)null) { return; } object? value2 = _fNpContainer.GetValue(plate); Component val3 = (Component)((value2 is Component) ? value2 : null); if ((Object)(object)val3 == (Object)null) { return; } bool flag = !InCamView(cam, val.position); if (!flag && _fNpNameText != null) { object? value3 = _fNpNameText.GetValue(plate); Component val4 = (Component)((value3 is Component) ? value3 : null); if ((Object)(object)val4 != (Object)null) { flag = WrongHalf(val4.transform, isP2); } } if (flag && val3.gameObject.activeSelf) { val3.gameObject.SetActive(false); } } catch { } } private static object GetOrMakeUiClone(Dictionary map, object original, Type keepType, out bool created) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown created = false; if (map.TryGetValue(original, out var value) && (Object)((value is Component) ? value : null) != (Object)null) { return value; } Component val = (Component)((original is Component) ? original : null); if ((Object)(object)val == (Object)null) { return null; } if (_entityBehaviourBaseType == null) { _entityBehaviourBaseType = AccessTools.TypeByName("Aggro.Core.EntityBehaviourBase"); } if ((Object)(object)_floaterHolder == (Object)null) { _floaterHolder = new GameObject("CouchCrew_FloaterCloneHolder"); _floaterHolder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_floaterHolder); } GameObject val2 = Object.Instantiate(val.gameObject, _floaterHolder.transform); ((Object)val2).name = ((Object)val.gameObject).name + "_P2"; if (_entityBehaviourBaseType != null) { Component[] componentsInChildren = val2.GetComponentsInChildren(_entityBehaviourBaseType, true); foreach (Component val3 in componentsInChildren) { if (!keepType.IsInstanceOfType(val3)) { Object.DestroyImmediate((Object)(object)val3); } } } val2.transform.SetParent(val.gameObject.transform.parent, false); value = (map[original] = val2.GetComponent(keepType)); created = true; return value; } private static void SweepDeadClones(Dictionary map) { List list = null; foreach (KeyValuePair item in map) { object key = item.Key; if ((Object)((key is Component) ? key : null) == (Object)null) { (list ?? (list = new List())).Add(item.Key); } } if (list == null) { return; } foreach (object item2 in list) { object obj = map[item2]; Component val = (Component)((obj is Component) ? obj : null); if ((Object)(object)val != (Object)null) { val.gameObject.SetActive(false); Object.Destroy((Object)(object)val.gameObject); } map.Remove(item2); } } private static void ClearUiClones(Dictionary map) { foreach (KeyValuePair item in map) { object value = item.Value; Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null) { val.gameObject.SetActive(false); Object.Destroy((Object)(object)val.gameObject); } } map.Clear(); } private static Camera GetShopItemCam() { if (!((Object)(object)_shopItemCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _shopItemCam; } private static IEnumerable ShopItem_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetShopItemCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static bool Pre_ShopItem(object __instance) { if (_siReentry) { return true; } if (_shopItemClones.ContainsValue(__instance)) { return false; } _siSwapped = false; if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { _shopItemCam = null; if (_shopItemClones.Count > 0) { RestoreShopItemContainers(); ClearUiClones(_shopItemClones); } return true; } NetworkIdentity realHost = GetRealHost(); if ((Object)(object)realHost == (Object)null) { _shopItemCam = null; return true; } _siSavedLP = NetworkClient.localPlayer; SetClientLocalPlayer(realHost); _shopItemCam = _mainCam; _siSwapped = true; return true; } private static void Post_ShopItem(object __instance) { if (_siReentry || !_siSwapped) { return; } try { SetClientLocalPlayer(_siSavedLP); bool created; object orMakeUiClone = GetOrMakeUiClone(_shopItemClones, __instance, _shopItemType, out created); Component val = (Component)((orMakeUiClone is Component) ? orMakeUiClone : null); if ((Object)(object)val != (Object)null) { Component val2 = (Component)((__instance is Component) ? __instance : null); if (val.gameObject.activeSelf != val2.gameObject.activeSelf) { val.gameObject.SetActive(val2.gameObject.activeSelf); } _shopItemCam = _p2Cam; _siReentry = true; try { _miShopItemUpdate.Invoke(orMakeUiClone, null); } catch { } _siReentry = false; } GateShopItem(__instance, isP2: false); GateShopItem(orMakeUiClone, isP2: true); SweepDeadClones(_shopItemClones); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[shopitem] " + ex.Message)); } finally { _shopItemCam = null; _siSwapped = false; } } private static void GateShopItem(object item, bool isP2) { try { Component val = (Component)((item is Component) ? item : null); if ((Object)(object)val == (Object)null) { return; } if (!_siFieldsReady) { _siFieldsReady = true; _fSiContainer = AccessTools.Field(_shopItemType, "container"); } if (_fSiContainer == null) { return; } object? value = _fSiContainer.GetValue(item); Component val2 = (Component)((value is Component) ? value : null); if (!((Object)(object)val2 == (Object)null)) { bool flag = !WrongHalf(val.transform, isP2); if (val2.gameObject.activeSelf != flag) { val2.gameObject.SetActive(flag); } } } catch { } } private static void RestoreShopItemContainers() { if (_fSiContainer == null) { return; } foreach (KeyValuePair shopItemClone in _shopItemClones) { try { object? value = _fSiContainer.GetValue(shopItemClone.Key); Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null && !val.gameObject.activeSelf) { val.gameObject.SetActive(true); } } catch { } } } private static Camera GetTransactionCam() { if (!((Object)(object)_transactionCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _transactionCam; } private static IEnumerable Transaction_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetTransactionCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static bool Pre_Transaction(object __instance) { if (_trReentry) { return true; } return !_transactionClones.ContainsValue(__instance); } private static void Post_Transaction(object __instance) { if (_trReentry) { return; } try { if (_transactionClones.ContainsValue(__instance)) { return; } if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { if (_transactionClones.Count > 0) { ClearUiClones(_transactionClones); } return; } if (!_trFieldsReady) { _trFieldsReady = true; _fTrFollow = AccessTools.Field(_transactionType, "followTransform"); _fTrAmount = AccessTools.Field(_transactionType, "amount"); _fTrStart = AccessTools.Field(_transactionType, "_startTime"); _fTrDestroySelf = AccessTools.Field(_transactionType, "destroySelf"); _fTrText = AccessTools.Field(_transactionType, "text"); } bool created; object orMakeUiClone = GetOrMakeUiClone(_transactionClones, __instance, _transactionType, out created); Component val = (Component)((orMakeUiClone is Component) ? orMakeUiClone : null); if (!((Object)(object)val == (Object)null)) { if (created && _fTrDestroySelf != null) { _fTrDestroySelf.SetValue(orMakeUiClone, false); } if (_fTrFollow != null) { _fTrFollow.SetValue(orMakeUiClone, _fTrFollow.GetValue(__instance)); } if (_fTrAmount != null) { _fTrAmount.SetValue(orMakeUiClone, _fTrAmount.GetValue(__instance)); } if (_fTrStart != null) { _fTrStart.SetValue(orMakeUiClone, _fTrStart.GetValue(__instance)); } Component val2 = (Component)((__instance is Component) ? __instance : null); if (val.gameObject.activeSelf != val2.gameObject.activeSelf) { val.gameObject.SetActive(val2.gameObject.activeSelf); } _transactionCam = _p2Cam; _trReentry = true; try { _miTransactionLate.Invoke(orMakeUiClone, null); } finally { _trReentry = false; _transactionCam = null; } GateTransaction(__instance, _mainCam, isP2: false); GateTransaction(orMakeUiClone, _p2Cam, isP2: true); SweepDeadClones(_transactionClones); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[transaction] " + ex.Message)); } } private static void GateTransaction(object tr, Camera cam, bool isP2) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) try { if (_fTrFollow == null || _fTrText == null) { return; } object? value = _fTrFollow.GetValue(tr); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { return; } object? value2 = _fTrText.GetValue(tr); Component val2 = (Component)((value2 is Component) ? value2 : null); if (!((Object)(object)val2 == (Object)null)) { Component val3 = (Component)((tr is Component) ? tr : null); bool flag = InCamView(cam, val.position) && ((Object)(object)val3 == (Object)null || !WrongHalf(val3.transform, isP2)); if (val2.gameObject.activeSelf != flag) { val2.gameObject.SetActive(flag); } } } catch { } } private static Camera GetHazardCam() { if (!((Object)(object)_hazardCam != (Object)null)) { if (!((Object)(object)_mainCam != (Object)null)) { return Camera.main; } return _mainCam; } return _hazardCam; } private static IEnumerable Hazard_CamTranspiler(IEnumerable instructions) { MethodInfo get = AccessTools.Method(typeof(CouchCoop), "GetHazardCam", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo methodInfo = instruction.operand as MethodInfo; if (methodInfo != null && methodInfo.Name == "get_mainCamera") { instruction.opcode = OpCodes.Call; instruction.operand = get; } yield return instruction; } } private static bool Pre_HazardIcons(object __instance) { if (_hzReentry) { return true; } if (_hazardClones.ContainsValue(__instance)) { return false; } _hzSwapped = false; if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { _hazardCam = null; if (_hazardClones.Count > 0) { ClearUiClones(_hazardClones); } return true; } NetworkIdentity realHost = GetRealHost(); if ((Object)(object)realHost == (Object)null) { _hazardCam = null; return true; } _hzSavedLP = NetworkClient.localPlayer; SetClientLocalPlayer(realHost); _hazardCam = _mainCam; _hzSwapped = true; return true; } private static void Post_HazardIcons(object __instance) { if (_hzReentry || !_hzSwapped) { return; } try { SetClientLocalPlayer(_hzSavedLP); bool created; object orMakeUiClone = GetOrMakeUiClone(_hazardClones, __instance, _hazardMgrType, out created); if (orMakeUiClone != null) { _hazardCam = _p2Cam; _hzReentry = true; try { _miHazardLate.Invoke(orMakeUiClone, null); } catch { } _hzReentry = false; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[hazard] " + ex.Message)); } finally { _hazardCam = null; _hzSwapped = false; } } private static void EnsureShopPanel() { //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown if (_shopPanelReady || _shopPanelFailed) { return; } try { Type baseType = _shopPanelType.BaseType; while (baseType != null && _shopInstField == null) { FieldInfo[] fields = baseType.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (_shopPanelType.IsAssignableFrom(fieldInfo.FieldType)) { _shopInstField = fieldInfo; break; } } baseType = baseType.BaseType; } if (_shopInstField == null) { _shopPanelFailed = true; Plugin.Log.LogWarning((object)"[shoppanel] singleton field not found — per-player panel off."); return; } _shopPanelOrig = _shopInstField.GetValue(null); if (_shopPanelOrig == null) { return; } _fShopContainer = AccessTools.Field(_shopPanelType, "container"); _fShopShouldDisplay = AccessTools.Field(_shopPanelType, "shouldDisplay"); _fShopCurrentData = AccessTools.Field(_shopPanelType, "currentData"); _fShopNextData = AccessTools.Field(_shopPanelType, "nextData"); _fShopIsVisible = AccessTools.Field(_shopPanelType, "isVisible"); _fShopIsTransitioning = AccessTools.Field(_shopPanelType, "isTransitioning"); _fShopHideOffset = AccessTools.Field(_shopPanelType, "hideOffset"); _fShopAnimTime = AccessTools.Field(_shopPanelType, "animationTime"); _fShopEase = AccessTools.Field(_shopPanelType, "ease"); _miShopPanelUpdate = AccessTools.Method(_shopPanelType, "OnUpdatePresentation", (Type[])null, (Type[])null); object shopPanelOrig = _shopPanelOrig; Component val = (Component)((shopPanelOrig is Component) ? shopPanelOrig : null); if ((Object)(object)_floaterHolder == (Object)null) { _floaterHolder = new GameObject("CouchCrew_FloaterCloneHolder"); _floaterHolder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_floaterHolder); } if (_entityBehaviourBaseType == null) { _entityBehaviourBaseType = AccessTools.TypeByName("Aggro.Core.EntityBehaviourBase"); } GameObject val2 = Object.Instantiate(val.gameObject, _floaterHolder.transform); ((Object)val2).name = ((Object)val.gameObject).name + "_P2"; if (_entityBehaviourBaseType != null) { Component[] componentsInChildren = val2.GetComponentsInChildren(_entityBehaviourBaseType, true); foreach (Component val3 in componentsInChildren) { if (!_shopPanelType.IsInstanceOfType(val3)) { Object.DestroyImmediate((Object)(object)val3); } } } _shopInstField.SetValue(null, null); val2.transform.SetParent(val.gameObject.transform.parent, false); _shopPanelClone = val2.GetComponent(_shopPanelType); _shopInstField.SetValue(null, _shopPanelOrig); if (_fShopContainer != null) { object? value = _fShopContainer.GetValue(_shopPanelOrig); SetHalfAnchor((RectTransform)((value is RectTransform) ? value : null), 0.25f); object? value2 = _fShopContainer.GetValue(_shopPanelClone); SetHalfAnchor((RectTransform)((value2 is RectTransform) ? value2 : null), 0.75f); } _shopPanelReady = true; Plugin.Log.LogInfo((object)("[shoppanel] cloned ShopPanelUI for P2 (singleton field='" + _shopInstField.Name + "'); panels anchored P1=left, P2=right.")); } catch (Exception ex) { _shopPanelFailed = true; Plugin.Log.LogWarning((object)("[shoppanel] setup failed: " + ex.Message)); } } private static void Pre_ShopHolder(object __instance, out object __state) { __state = null; if (_shopHolderReentry) { return; } try { if (!SplitActive || CouchBodies.Count == 0 || (Object)(object)_p2Cam == (Object)null) { return; } EnsureShopPanel(); if (_shopPanelReady) { NetworkIdentity realHost = GetRealHost(); if (!((Object)(object)realHost == (Object)null)) { NetworkIdentity localPlayer = NetworkClient.localPlayer; object value = _shopInstField.GetValue(null); SetClientLocalPlayer(realHost); _shopInstField.SetValue(null, _shopPanelOrig); __state = new object[2] { localPlayer, value }; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[shoppanel] pre: " + ex.Message)); } } private static void Post_ShopHolder(object __instance, object __state) { if (_shopHolderReentry || !(__state is object[] array)) { return; } try { object obj = array[0]; SetClientLocalPlayer((NetworkIdentity)((obj is NetworkIdentity) ? obj : null)); _shopInstField.SetValue(null, _shopPanelClone); _shopHolderReentry = true; try { _miShopHolderEarly.Invoke(__instance, null); } catch { } _shopHolderReentry = false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[shoppanel] post: " + ex.Message)); } finally { try { if (array.Length > 1) { _shopInstField.SetValue(null, array[1]); } } catch { } } } private static void Post_ShopPanelTick(object __instance) { if (_shopPanelReady && __instance == _shopPanelOrig) { DriveClonePanel(); } } private static void DriveClonePanel() { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) try { object shopPanelClone = _shopPanelClone; if ((Object)((shopPanelClone is Component) ? shopPanelClone : null) == (Object)null || _fShopShouldDisplay == null) { return; } bool flag = (bool)_fShopShouldDisplay.GetValue(_shopPanelClone); RectTransform val = (RectTransform)((_fShopContainer != null) ? /*isinst with value type is only supported in some contexts*/: null); float num = ((_fShopHideOffset != null) ? Convert.ToSingle(_fShopHideOffset.GetValue(_shopPanelClone)) : 0f); if (flag && _fShopCurrentData != null && _fShopNextData != null) { _fShopCurrentData.SetValue(_shopPanelClone, _fShopNextData.GetValue(_shopPanelClone)); } float num2 = ((_fShopAnimTime != null) ? Convert.ToSingle(_fShopAnimTime.GetValue(_shopPanelClone)) : 0.25f); float num3 = ((num2 > 0.0001f) ? (Time.deltaTime / num2) : 1f); _shopCloneProgress = Mathf.MoveTowards(_shopCloneProgress, flag ? 1f : 0f, num3); float num4 = EvalEase(1f - _shopCloneProgress); if ((Object)(object)val != (Object)null) { Vector3 localPosition = ((Transform)val).localPosition; ((Transform)val).localPosition = new Vector3(localPosition.x, num4 * num, localPosition.z); } if (_fShopIsVisible != null) { _fShopIsVisible.SetValue(_shopPanelClone, _shopCloneProgress > 0.001f); } if (_fShopIsTransitioning != null) { _fShopIsTransitioning.SetValue(_shopPanelClone, false); } if (_miShopPanelUpdate != null) { NetworkIdentity localPlayer = NetworkClient.localPlayer; NetworkIdentity val2 = null; foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody != (Object)null) { val2 = couchBody; break; } } if ((Object)(object)val2 != (Object)null) { SetClientLocalPlayer(val2); } try { _miShopPanelUpdate.Invoke(_shopPanelClone, null); } catch { } SetClientLocalPlayer(localPlayer); } if (_fShopShouldDisplay != null) { _fShopShouldDisplay.SetValue(_shopPanelClone, false); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[shoppanel] drive: " + ex.Message)); } } private static float EvalEase(float t) { if (!_easeResolved) { _easeResolved = true; try { _easeObj = ((_fShopEase != null) ? _fShopEase.GetValue(_shopPanelClone) : null); if (_easeObj != null) { Type type = _easeObj.GetType(); _miEaseEval = type.GetMethod("Evaluate", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(float) }, null); if (_miEaseEval == null) { Type type2 = AccessTools.TypeByName("EasingFunction") ?? AccessTools.TypeByName("Aggro.Core.EasingFunction"); Type[] array = new Type[2] { type2, type }; foreach (Type type3 in array) { if (!(type3 == null)) { _miEaseEval = type3.GetMethod("Evaluate", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { type, typeof(float) }, null); if (_miEaseEval != null) { _easeStatic = true; break; } } } } Plugin.Log.LogInfo((object)("[shoppanel] ease='" + type.Name + "' eval=" + ((!(_miEaseEval != null)) ? "" : (_easeStatic ? "EasingFunction.Evaluate" : "instance")))); } } catch { } } try { if (_miEaseEval != null) { return Convert.ToSingle(_easeStatic ? _miEaseEval.Invoke(null, new object[2] { _easeObj, t }) : _miEaseEval.Invoke(_easeObj, new object[1] { t })); } } catch { } return t * t * (3f - 2f * t); } private static void BoostBodyIfOnStrip(NetworkIdentity body, Transform stripT, Bounds bounds) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)body == (Object)null || _stripNitroType == null || !((Bounds)(ref bounds)).Contains(stripT.InverseTransformPoint(((Component)body).transform.position))) { return; } Component componentInChildren = ((Component)body).GetComponentInChildren(_stripNitroType); if ((Object)(object)componentInChildren == (Object)null) { return; } if (_fStripNitroActive == null) { _fStripNitroActive = AccessTools.Field(_stripNitroType, "nitroActiveSync"); } if (!(_fStripNitroActive != null) || !(bool)_fStripNitroActive.GetValue(componentInChildren)) { if (_miStripActivate == null) { _miStripActivate = AccessTools.Method(_stripNitroType, "LocalPlayerActivateNitro", (Type[])null, (Type[])null); } _miStripActivate?.Invoke(componentInChildren, null); Rigidbody componentInChildren2 = ((Component)body).GetComponentInChildren(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.rotation = Quaternion.LookRotation(stripT.forward, Vector3.up); Vector3 forward = stripT.forward; Vector3 velocity = componentInChildren2.velocity; componentInChildren2.velocity = forward * ((Vector3)(ref velocity)).magnitude; } Plugin.Log.LogInfo((object)("[boost-strip] boosted netId=" + body.netId + " over strip.")); } } private static void Post_StationInput(object __instance) { //IL_00ab: 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) try { if (CouchBodies.Count == 0) { return; } Component val = (Component)((__instance is Component) ? __instance : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)val2 == (Object)null) { return; } bool flag = CouchBodies.Contains(val2); bool flag2 = val2 == GetRealHost(); if (!flag && !flag2) { return; } if (!_stationFieldsReady) { Type type = __instance.GetType(); _fInRotate = AccessTools.Field(type, "_inputRotate"); _fInPlace = AccessTools.Field(type, "_inputPlace"); _fInStartPickUp = AccessTools.Field(type, "_inputStartPickUp"); _fInPickingUp = AccessTools.Field(type, "_inputPickingUp"); _stationFieldsReady = true; } ReadOnlyArray all = Gamepad.all; bool flag3; bool flag4; bool flag5; bool flag6; if (flag) { Gamepad val3 = ((all.Count >= 2) ? all[1] : null); if (val3 == null) { return; } if (CouchMenu.IsOpen) { flag3 = (flag4 = (flag5 = (flag6 = false))); } else { EnsureP2ActionButtons(val3); flag3 = val3.dpad.right.wasPressedThisFrame; flag4 = val3.dpad.left.wasPressedThisFrame; flag5 = _placeBtnCache != null && _placeBtnCache.wasPressedThisFrame; flag6 = _placeBtnCache != null && _placeBtnCache.isPressed; } } else { Keyboard current = Keyboard.current; Gamepad val4 = ((all.Count >= 1) ? all[0] : null); flag3 = (current != null && ((ButtonControl)current.eKey).wasPressedThisFrame) || (val4 != null && val4.dpad.right.wasPressedThisFrame); flag4 = (current != null && ((ButtonControl)current.qKey).wasPressedThisFrame) || (val4 != null && val4.dpad.left.wasPressedThisFrame); flag5 = (current != null && ((ButtonControl)current.fKey).wasPressedThisFrame) || (val4 != null && val4.dpad.down.wasPressedThisFrame); flag6 = (current != null && ((ButtonControl)current.fKey).isPressed) || (val4 != null && val4.dpad.down.isPressed); } if (_fInRotate != null) { _fInRotate.SetValue(__instance, (flag3 ? 1 : 0) + (flag4 ? (-1) : 0)); } if (_fInPlace != null) { _fInPlace.SetValue(__instance, flag5); } if (_fInStartPickUp != null) { _fInStartPickUp.SetValue(__instance, flag5); } if (_fInPickingUp != null) { _fInPickingUp.SetValue(__instance, flag6); } } catch { } } private static void Post_GrabberInput(object __instance) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) try { if (CouchBodies.Count == 0) { return; } Component val = (Component)((__instance is Component) ? __instance : null); NetworkIdentity val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); if ((Object)(object)val2 == (Object)null || !CouchBodies.Contains(val2)) { return; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return; } EnsureP2ActionButtons(all[1]); if (_fGrabData == null) { _fGrabData = AccessTools.Field(__instance.GetType(), "_data"); } if (_fGrabData == null) { return; } object value = _fGrabData.GetValue(__instance); if (value != null) { if (_fGrabReq == null) { Type type = value.GetType(); _fGrabReq = type.GetField("grabReleaseRequested"); _fRaised = type.GetField("raisedHeld"); } bool isOpen = CouchMenu.IsOpen; if (_fGrabReq != null) { _fGrabReq.SetValue(value, !isOpen && _grabBtnCache != null && _grabBtnCache.wasPressedThisFrame); } if (_fRaised != null) { _fRaised.SetValue(value, !isOpen && _liftBtnCache != null && _liftBtnCache.isPressed); } _fGrabData.SetValue(__instance, value); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[grab] " + ex.Message)); } } private static void ResolveP2Buttons(Gamepad pad) { if (!_p2BtnsResolved && _p2Input != null) { _p2BtnsResolved = true; _p2GrabBtn = FindPadButton(_p2Input, "get_GrabRelease", pad); _p2LiftBtn = FindPadButton(_p2Input, "get_RaiseLower", pad); _p2DriftBtn = FindPadButton(_p2Input, "get_Drift", pad); Plugin.Log.LogInfo((object)("[p2btn] grab=" + N(_p2GrabBtn) + " lift=" + N(_p2LiftBtn) + " drift=" + N(_p2DriftBtn))); } } private static string N(ButtonControl b) { if (b == null) { return ""; } return ((InputControl)b).name; } private static ButtonControl FindPadButton(object aggro, string actionGetter, Gamepad pad) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) try { object obj = aggro.GetType().GetMethod("get_Game").Invoke(aggro, null); object? obj2 = obj.GetType().GetMethod(actionGetter).Invoke(obj, null); InputAction val = (InputAction)((obj2 is InputAction) ? obj2 : null); if (val == null) { return null; } Enumerator enumerator = val.bindings.GetEnumerator(); try { while (enumerator.MoveNext()) { InputBinding current = enumerator.Current; string effectivePath = ((InputBinding)(ref current)).effectivePath; if (!string.IsNullOrEmpty(effectivePath) && (effectivePath.IndexOf("Gamepad", StringComparison.OrdinalIgnoreCase) >= 0 || effectivePath.IndexOf("XInput", StringComparison.OrdinalIgnoreCase) >= 0)) { InputControl obj3 = InputControlPath.TryFindControl((InputControl)(object)pad, effectivePath, 0); ButtonControl val2 = (ButtonControl)(object)((obj3 is ButtonControl) ? obj3 : null); if (val2 != null) { return val2; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } catch { } return null; } private static void Post_CamFrame(object __instance) { //IL_00d4: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: 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_018a: 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_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: 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_0218: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) TickTransitionHold(); try { if (CouchBodies.Count == 0) { DeactivateSplit(); return; } if (_fCamOffset == null) { Type type = __instance.GetType(); _fCamOffset = AccessTools.Field(type, "offset"); _fCamTransform = AccessTools.Field(type, "_transform"); _fCamCamera = AccessTools.Field(type, "_cam"); } if (_fCamTransform == null) { return; } object? value = _fCamTransform.GetValue(__instance); Transform val = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null) { return; } if (Plugin.SplitScreen.Value) { DoSplit(__instance, val); return; } DeactivateSplit(); if (!Plugin.CamFrameBoth.Value || _fCamOffset == null) { return; } Vector3 val2 = (Vector3)_fCamOffset.GetValue(__instance); List list = new List(); NetworkIdentity realHost = GetRealHost(); if ((Object)(object)realHost != (Object)null) { list.Add(((Component)realHost).transform.position); } foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody != (Object)null && !list.Contains(((Component)couchBody).transform.position)) { list.Add(((Component)couchBody).transform.position); } } if (list.Count < 2) { return; } Vector3 val3 = Vector3.zero; foreach (Vector3 item in list) { val3 += item; } val3 /= (float)list.Count; float num = 0f; foreach (Vector3 item2 in list) { num = Mathf.Max(num, Vector3.Distance(item2, val3)); } Vector3 val4 = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val2)).normalized : Vector3.up); val.position = val3 + val2 + val4 * (num * Plugin.CamZoom.Value); } catch { } } private static void DoSplit(object camCtrl, Transform mainCamT) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_01af: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) if (_fCamCamera == null) { return; } object? value = _fCamCamera.GetValue(camCtrl); Camera val = (Camera)((value is Camera) ? value : null); if ((Object)(object)val == (Object)null) { return; } _mainCam = val; NetworkIdentity realHost = GetRealHost(); NetworkIdentity val2 = null; foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody != (Object)null) { val2 = couchBody; break; } } if (!((Object)(object)realHost == (Object)null) && !((Object)(object)val2 == (Object)null)) { Quaternion rotation = mainCamT.rotation; Vector3 val3 = (Vector3)((_fCamOffset != null) ? ((Vector3)_fCamOffset.GetValue(camCtrl)) : (mainCamT.position - ((Component)val2).transform.position)); if ((Object)(object)_p2Cam == (Object)null) { _p2CamGo = new GameObject("CouchCrew_P2Cam"); Object.DontDestroyOnLoad((Object)(object)_p2CamGo); _p2Cam = _p2CamGo.AddComponent(); _p2Cam.CopyFrom(val); Plugin.Log.LogInfo((object)("[split] created P2 camera (clone of main). mainCam='" + ((Object)val).name + "' cullingMask=0x" + val.cullingMask.ToString("X"))); DumpCanvases(); } if (!_mainRTCaptured) { _mainOrigRT = val.targetTexture; _mainRTCaptured = true; } RenderTexture targetTexture = (((Object)(object)_mainOrigRT != (Object)null) ? _mainOrigRT : val.targetTexture); bool value2 = Plugin.SplitStacked.Value; Rect rect = (value2 ? new Rect(0f, 0.5f, 1f, 0.5f) : new Rect(0f, 0f, 0.5f, 1f)); Rect rect2 = (value2 ? new Rect(0f, 0f, 1f, 0.5f) : new Rect(0.5f, 0f, 0.5f, 1f)); val.targetTexture = targetTexture; val.rect = rect; mainCamT.position = ((Component)realHost).transform.position + val3; mainCamT.rotation = rotation; _p2Cam.CopyFrom(val); _p2Cam.targetTexture = targetTexture; _p2Cam.rect = rect2; _p2CamGo.transform.position = ((Component)val2).transform.position + val3; _p2CamGo.transform.rotation = rotation; ((Behaviour)_p2Cam).enabled = true; SplitActive = true; } } private static void DeactivateSplit() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!SplitActive) { return; } SplitActive = false; try { if ((Object)(object)_p2Cam != (Object)null) { ((Behaviour)_p2Cam).enabled = false; } if ((Object)(object)_mainCam != (Object)null) { _mainCam.rect = new Rect(0f, 0f, 1f, 1f); if (_mainRTCaptured) { _mainCam.targetTexture = _mainOrigRT; } } Plugin.Log.LogInfo((object)"[split] deactivated — restored fullscreen camera."); } catch { } } private static bool Pre_BlitPass() { return true; } private static bool Pre_NitroUI(object __instance) { if (!SplitActive || CouchBodies.Count == 0) { return true; } try { EnsureNitroSplit(__instance); if (!_nitroReady) { return true; } if (__instance != _nitroUI) { return false; } NetworkIdentity realHost = GetRealHost(); NetworkIdentity body = null; foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody != (Object)null) { body = couchBody; break; } } UpdateBars(_p1Bars, NitroCtrlOf(realHost)); UpdateBars(_p2Bars, NitroCtrlOf(body)); return false; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[hud] nitro update failed: " + ex.Message)); return true; } } private static Component NitroCtrlOf(NetworkIdentity body) { if ((Object)(object)body == (Object)null || _nitroCtrlType == null) { return null; } return ((Component)body).GetComponentInChildren(_nitroCtrlType); } private static void EnsureNitroSplit(object nitroUI) { //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) if (_nitroReady || _nitroFailed) { return; } try { _nitroUI = nitroUI; Type type = nitroUI.GetType(); _nitroCtrlType = AccessTools.TypeByName("NitroController"); _nitroBarType = AccessTools.TypeByName("NitroBarUI"); _fNitroBars = AccessTools.Field(type, "nitroBars"); _fNitroCharges = AccessTools.Field(_nitroCtrlType, "nitroCharges"); _fNitroActive = AccessTools.Field(_nitroCtrlType, "nitroActiveSync"); _fNitroBurn = AccessTools.Field(_nitroCtrlType, "nitroBurnProgress"); _fNitroBuild = AccessTools.Field(_nitroCtrlType, "nitroBuildUpLevel"); _miChargeCount = AccessTools.Method(_nitroCtrlType, "LocalPlayerGetChargeCount", (Type[])null, (Type[])null); _miSetFull = AccessTools.Method(_nitroBarType, "SetFull", (Type[])null, (Type[])null); _miSetEmpty = AccessTools.Method(_nitroBarType, "SetEmpty", (Type[])null, (Type[])null); _miSetFill = AccessTools.Method(_nitroBarType, "SetFill", (Type[])null, (Type[])null); if (_fNitroBars == null || _miSetFull == null) { _nitroFailed = true; Plugin.Log.LogWarning((object)"[hud] nitro reflection incomplete — per-player gauges off."); return; } _p1Bars = _fNitroBars.GetValue(nitroUI) as Array; GameObject gameObject = ((Component)((nitroUI is Component) ? nitroUI : null)).gameObject; GameObject obj = Object.Instantiate(gameObject, gameObject.transform.parent); ((Object)obj).name = "CouchCrew_P2NitroUI"; Component component = obj.GetComponent(type); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } _p2Bars = obj.GetComponentsInChildren(_nitroBarType, true); Transform transform = gameObject.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = obj.transform; RectTransform val2 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if ((Object)(object)val != (Object)null) { Plugin.Log.LogInfo((object)("[hud] orig gauge: aMin=" + ((object)val.anchorMin/*cast due to .constrained prefix*/).ToString() + " aMax=" + ((object)val.anchorMax/*cast due to .constrained prefix*/).ToString() + " pivot=" + ((object)val.pivot/*cast due to .constrained prefix*/).ToString() + " anchoredPos=" + ((object)val.anchoredPosition/*cast due to .constrained prefix*/).ToString())); } SetHalfAnchor(val, 0.25f); SetHalfAnchor(val2, 0.75f); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { Plugin.Log.LogInfo((object)("[hud] gauges anchored — P1@" + ((object)val.anchoredPosition/*cast due to .constrained prefix*/).ToString() + " (x25%), P2@" + ((object)val2.anchoredPosition/*cast due to .constrained prefix*/).ToString() + " (x75%).")); } _nitroReady = true; Plugin.Log.LogInfo((object)("[hud] per-player gauges ready (P1 bars=" + ((_p1Bars != null) ? _p1Bars.Length : 0) + ", P2 bars=" + ((_p2Bars != null) ? _p2Bars.Length : 0) + ").")); } catch (Exception ex) { _nitroFailed = true; Plugin.Log.LogWarning((object)("[hud] nitro split setup failed: " + ex.Message)); } } private static void SetHalfAnchor(RectTransform rt, float xFrac) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rt == (Object)null)) { rt.anchorMin = new Vector2(xFrac, rt.anchorMin.y); rt.anchorMax = new Vector2(xFrac, rt.anchorMax.y); rt.anchoredPosition = new Vector2(0f, rt.anchoredPosition.y); } } private static void UpdateBars(Array bars, Component nc) { if (bars == null || (Object)(object)nc == (Object)null) { return; } int num = (int)_miChargeCount.Invoke(nc, null); int num2 = (int)_fNitroCharges.GetValue(nc); bool flag = (bool)_fNitroActive.GetValue(nc); float num3 = Convert.ToSingle(_fNitroBurn.GetValue(nc)); float num4 = Convert.ToSingle(_fNitroBuild.GetValue(nc)); for (int i = 0; i < bars.Length; i++) { object value = bars.GetValue(i); Component val = (Component)((value is Component) ? value : null); bool flag2 = i < num; if ((Object)(object)val != (Object)null) { val.gameObject.SetActive(flag2); } if (flag2) { if (i < num2) { _miSetFull.Invoke(value, null); } else if (i > num2) { _miSetEmpty.Invoke(value, null); } else if (flag) { _miSetFill.Invoke(value, new object[2] { 1f - num3, true }); } else { _miSetFill.Invoke(value, new object[2] { num4, false }); } } } } private static void DumpCanvases() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("[split] CANVAS DUMP (Camera.main='" + (((Object)(object)Camera.main != (Object)null) ? ((Object)Camera.main).name : "") + "'):"); Canvas[] array = Object.FindObjectsOfType(true); foreach (Canvas val in array) { if (val.isRootCanvas) { stringBuilder.AppendLine(" '" + ((Object)val).name + "' mode=" + ((object)val.renderMode/*cast due to .constrained prefix*/).ToString() + " cam=" + (((Object)(object)val.worldCamera != (Object)null) ? ((Object)val.worldCamera).name : "") + " active=" + ((Behaviour)val).isActiveAndEnabled + " sort=" + val.sortingOrder + " layer=" + LayerMask.LayerToName(((Component)val).gameObject.layer) + "(" + ((Component)val).gameObject.layer + ")"); } } Type type = AccessTools.TypeByName("NitroUI"); if (type != null) { Object[] array2 = Object.FindObjectsOfType(type); foreach (Object obj in array2) { Component val2 = (Component)(object)((obj is Component) ? obj : null); Canvas val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInParent() : null); stringBuilder.AppendLine(" NitroUI on '" + (((Object)(object)val2 != (Object)null) ? ((Object)val2.gameObject).name : "?") + "' rootCanvas='" + (((Object)(object)val3 != (Object)null) ? ((Object)val3).name : "") + "'"); } } stringBuilder.AppendLine(" --- cameras (render order = ascending depth) ---"); Camera[] allCameras = Camera.allCameras; foreach (Camera val4 in allCameras) { Rect rect = val4.rect; stringBuilder.AppendLine(" cam '" + ((Object)val4).name + "' depth=" + val4.depth + " clear=" + ((object)val4.clearFlags/*cast due to .constrained prefix*/).ToString() + " target=" + (((Object)(object)val4.targetTexture != (Object)null) ? ((Object)val4.targetTexture).name : "screen") + " rect=(" + ((Rect)(ref rect)).x.ToString("0.##") + "," + ((Rect)(ref rect)).y.ToString("0.##") + "," + ((Rect)(ref rect)).width.ToString("0.##") + "," + ((Rect)(ref rect)).height.ToString("0.##") + ") mask=0x" + val4.cullingMask.ToString("X") + " enabled=" + ((Behaviour)val4).enabled); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[split] canvas dump failed: " + ex.Message)); } } private static IEnumerable MenuOpen_Transpiler(IEnumerable instructions) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown List list = new List(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(CouchCoop), "MenuOpenFor", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { MethodInfo methodInfo2 = list[i].operand as MethodInfo; if (methodInfo2 == null || methodInfo2.Name != "get_OpenGameMenu") { continue; } for (int j = i + 1; j < list.Count && j <= i + 4; j++) { MethodInfo methodInfo3 = list[j].operand as MethodInfo; if (methodInfo3 != null && methodInfo3.Name == "WasPressedThisFrame") { list.Insert(j + 1, new CodeInstruction(OpCodes.Call, (object)methodInfo)); i = j + 1; break; } } } return list; } private static bool MenuOpenFor(bool orig) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) try { if (!orig) { return false; } if (!Plugin.Enabled.Value || !Plugin.JoinOnStart.Value) { return orig; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return orig; } if (all[1].startButton == null || !all[1].startButton.isPressed) { return orig; } bool num = all[0].startButton != null && all[0].startButton.isPressed; bool flag = Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).isPressed; return num || flag; } catch { return orig; } } private static void Pre_StressBar(object __instance) { _sbSwapped = false; try { if (CouchBodies.Count != 0) { if (!_stressBarOwner.TryGetValue(__instance, out var value) || (Object)(object)value == (Object)null) { Component val = (Component)((__instance is Component) ? __instance : null); value = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); _stressBarOwner[__instance] = value; } if (!((Object)(object)value == (Object)null)) { _sbSaved = NetworkClient.localPlayer; SetClientLocalPlayer(value); _sbSwapped = true; } } } catch { } } private static void Post_StressBar() { if (!_sbSwapped) { return; } _sbSwapped = false; try { SetClientLocalPlayer(_sbSaved); } catch { } } private unsafe static void OnDeviceChange(InputDevice device, InputDeviceChange change) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 try { if (device is Gamepad && ((int)change == 0 || (int)change == 3) && Plugin.Enabled.Value) { try { InputSystem.ResetDevice(device, false); } catch { } _p1Restricted = false; EnsureP1DeviceRestriction(); Plugin.Log.LogInfo((object)("[couch] gamepad '" + ((InputControl)device).displayName + "' " + ((object)(*(InputDeviceChange*)(&change))/*cast due to .constrained prefix*/).ToString() + " — state reset; P1 device list refreshed.")); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] device change: " + ex.Message)); } } private static void EnsureP1DeviceRestriction() { //IL_0030: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) try { if (_p1Restricted || _demuxReady || !Plugin.Enabled.Value || !Plugin.DemuxInput.Value) { return; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { return; } if (_vehInputField == null || _aggroAssetProp == null) { Type type = AccessTools.TypeByName("AggroInputManager"); Type type2 = AccessTools.TypeByName("AggroInput"); if (type != null) { _vehInputField = AccessTools.Field(type, "input"); } if (type2 != null) { _aggroAssetProp = AccessTools.Property(type2, "asset"); } } if (_vehInputField == null || _aggroAssetProp == null) { return; } object value = _vehInputField.GetValue(null); if (value == null) { return; } InputActionAsset val = (InputActionAsset)_aggroAssetProp.GetValue(value); List list = new List(); if (Keyboard.current != null) { list.Add((InputDevice)(object)Keyboard.current); } if (Mouse.current != null) { list.Add((InputDevice)(object)Mouse.current); } Enumerator enumerator = all.GetEnumerator(); try { while (enumerator.MoveNext()) { Gamepad current = enumerator.Current; if (current != all[1]) { list.Add((InputDevice)(object)current); } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } val.devices = new ReadOnlyArray(list.ToArray()); _p1Restricted = true; Plugin.Log.LogInfo((object)"[couch] P1 input now excludes gamepad #2 (pre-join quarantine)."); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] early P1 restriction: " + ex.Message)); } } internal static void CycleCouchColor() { try { if (!_colorResolved) { _colorResolved = true; _colorNetType = AccessTools.TypeByName("PlayerColorManagerNetwork"); if (_colorNetType != null) { _fColorIdx = AccessTools.Field(_colorNetType, "activePlayerColorIndex"); _miSetColorIdx = AccessTools.Method(_colorNetType, "set_NetworkactivePlayerColorIndex", (Type[])null, (Type[])null); _fColorMgrRef = AccessTools.Field(_colorNetType, "playerColorManager"); } } if (_fColorIdx == null || _miSetColorIdx == null) { Plugin.Log.LogWarning((object)"[couch] color: PlayerColorManagerNetwork members not found."); return; } foreach (NetworkIdentity couchBody in CouchBodies) { if ((Object)(object)couchBody == (Object)null) { continue; } Component componentInChildren = ((Component)couchBody).GetComponentInChildren(_colorNetType, true); if ((Object)(object)componentInChildren == (Object)null) { Plugin.Log.LogWarning((object)"[couch] color: no PlayerColorManagerNetwork on the couch body."); continue; } int num = 0; try { object obj = ((_fColorMgrRef != null) ? _fColorMgrRef.GetValue(componentInChildren) : null); if (obj != null) { if (_fPlayerColors == null) { _fPlayerColors = AccessTools.Field(obj.GetType(), "playerColors"); } ICollection collection = ((_fPlayerColors != null) ? (_fPlayerColors.GetValue(obj) as ICollection) : null); if (collection != null) { num = collection.Count; } } } catch { } if (num <= 0) { num = 8; } _couchColorIdx = (((_couchColorIdx >= 0) ? _couchColorIdx : Convert.ToInt32(_fColorIdx.GetValue(componentInChildren))) + 1) % num; Plugin.Log.LogInfo((object)("[couch] P2 color -> " + _couchColorIdx + " of " + num + " (held by the per-frame override).")); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] color cycle: " + ex.Message)); } } private static bool Pre_ColorNetEarly(object __instance) { try { if (CouchBodies.Count == 0 || _couchColorIdx < 0) { return true; } if (!_colorNetOwner.TryGetValue(__instance, out var value) || (Object)(object)value == (Object)null) { Component val = (Component)((__instance is Component) ? __instance : null); value = (((Object)(object)val != (Object)null) ? val.GetComponentInParent() : null); _colorNetOwner[__instance] = value; } if ((Object)(object)value == (Object)null || !CouchBodies.Contains(value)) { return true; } if (_miSetColorIdx != null) { ParameterInfo[] parameters = _miSetColorIdx.GetParameters(); _miSetColorIdx.Invoke(__instance, new object[1] { Convert.ChangeType(_couchColorIdx, parameters[0].ParameterType) }); } return false; } catch { return true; } } internal static void LeaveCouch() { try { NetworkIdentity realHost = GetRealHost(); if ((Object)(object)realHost != (Object)null) { SetClientLocalPlayer(realHost); } foreach (NetworkIdentity item in new List(CouchBodies)) { if (!((Object)(object)item == (Object)null)) { try { NetworkServer.Destroy(((Component)item).gameObject); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] leave destroy: " + ex.Message)); } } } CouchBodies.Clear(); Plugin.Log.LogInfo((object)"[couch] P2 left the session (press Start to rejoin)."); } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[couch] leave: " + ex2.Message)); } } internal static void TickJoinButton() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) try { if (!Plugin.Enabled.Value) { return; } EnsureP1DeviceRestriction(); if (!Plugin.JoinOnStart.Value || !NetworkServer.active) { return; } ReadOnlyArray all = Gamepad.all; if (all.Count < 2) { _joinPrevPressed = false; return; } Gamepad val = all[1]; if (val == null || val.startButton == null) { return; } bool isPressed = val.startButton.isPressed; bool num = isPressed && !_joinPrevPressed; _joinPrevPressed = isPressed; if (!num) { return; } CouchBodies.RemoveWhere((NetworkIdentity b) => (Object)(object)b == (Object)null); if (CouchBodies.Count > 0) { CouchMenu.HandleStartPress(); } else { if (CouchBodies.Count >= 1) { return; } int num2 = -1; try { if (!_joinReflTried) { _joinReflTried = true; _shiftMgrTypeJ = AccessTools.TypeByName("ShiftManager"); _fShiftPhaseJ = ((_shiftMgrTypeJ != null) ? AccessTools.Field(_shiftMgrTypeJ, "_shiftPhase") : null); } if (_fShiftPhaseJ != null) { Object val2 = Object.FindObjectOfType(_shiftMgrTypeJ); if (val2 != (Object)null) { num2 = Convert.ToInt32(_fShiftPhaseJ.GetValue(val2)); } } } catch { } if (num2 < 1 || num2 > 3) { Plugin.Log.LogInfo((object)("[couch] controller 2 pressed Start outside a run (phase " + num2 + ") — join works in the break room or during a shift.")); return; } Plugin.Log.LogInfo((object)"[couch] controller 2 pressed Start — spawning the couch player."); SpawnCouchBody(); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] join button: " + ex.Message)); } } internal static void SpawnCouchBody() { try { if (!NetworkServer.active) { Plugin.Log.LogWarning((object)"[couch] not the host (NetworkServer inactive) — couch coop is host-only."); return; } CouchBodies.RemoveWhere((NetworkIdentity b) => (Object)(object)b == (Object)null); if (CouchBodies.Count >= 1) { Plugin.Log.LogInfo((object)("[couch] PoC body cap reached (" + 1 + " live) — not spawning another.")); return; } NetworkManager singleton = NetworkManager.singleton; if ((Object)(object)singleton == (Object)null) { Plugin.Log.LogWarning((object)"[couch] NetworkManager.singleton is null."); return; } if (_serverGetSpawnedPlayer == null) { _serverGetSpawnedPlayer = AccessTools.Method(((object)singleton).GetType(), "ServerGetSpawnedPlayer", (Type[])null, (Type[])null); } if (_serverGetSpawnedPlayer == null) { Plugin.Log.LogWarning((object)("[couch] ServerGetSpawnedPlayer not found on " + ((object)singleton).GetType().Name + ".")); return; } object[] parameters = ((_serverGetSpawnedPlayer.GetParameters().Length == 0) ? null : new object[1] { NetworkServer.localConnection }); object obj = _serverGetSpawnedPlayer.Invoke(_serverGetSpawnedPlayer.IsStatic ? null : singleton, parameters); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { Component val2 = (Component)((obj is Component) ? obj : null); if (val2 != null) { val = val2.gameObject; } } if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"[couch] ServerGetSpawnedPlayer returned null/non-GameObject."); return; } NetworkIdentity component = val.GetComponent(); if ((Object)(object)component != (Object)null) { CouchBodies.Add(component); } LocalConnectionToClient localConnection = NetworkServer.localConnection; NetworkServer.Spawn(val, (NetworkConnectionToClient)(object)localConnection); string authNote = ""; if ((Object)(object)component != (Object)null && component.connectionToClient == null && localConnection != null) { try { component.AssignClientAuthority((NetworkConnectionToClient)(object)localConnection); authNote = " (AssignClientAuthority called post-Spawn)"; } catch (Exception ex) { authNote = " (AssignClientAuthority threw: " + ex.Message + ")"; } } int num = 0; Rigidbody[] componentsInChildren = val.GetComponentsInChildren(true); foreach (Rigidbody val3 in componentsInChildren) { if (val3.isKinematic) { val3.isKinematic = false; num++; } } EnsureDemux(); EnsureActionPatches(); WriteDiag(val, component, (NetworkConnectionToClient)(object)localConnection, num, authNote); } catch (Exception ex2) { Plugin.Log.LogError((object)("[couch] SpawnCouchBody failed: " + ex2)); } } private static void WriteDiag(GameObject go, NetworkIdentity ni, NetworkConnectionToClient owner, int flipped, string authNote) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); stringBuilder.AppendLine("================ CouchCrew SPAWN DIAG frame=" + Time.frameCount + " ================"); stringBuilder.AppendLine("owner(localConnection) = " + ((owner == null) ? "" : ("connId=" + owner.connectionId)) + authNote); if ((Object)(object)ni != (Object)null) { NetworkConnectionToClient connectionToClient = ni.connectionToClient; stringBuilder.AppendLine("body '" + ((Object)go).name + "' netId=" + ni.netId); stringBuilder.AppendLine(" connectionToClient = " + ((connectionToClient == null) ? " <-- no authority => Mirror keeps it kinematic + ping NRE" : ("connId=" + connectionToClient.connectionId))); stringBuilder.AppendLine(" isServer=" + ni.isServer + " isClient=" + ni.isClient + " isOwned=" + ni.isOwned + " isLocalPlayer=" + ni.isLocalPlayer); } stringBuilder.AppendLine(" rigidbodies un-kinematic'd this call = " + flipped); stringBuilder.AppendLine("================ end diag ================"); string text = stringBuilder.ToString(); Plugin.Log.LogInfo((object)text); try { string text2 = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CouchCrew-couch.txt"); File.AppendAllText(text2, text); Plugin.Log.LogInfo((object)("[couch] diag written to " + text2)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("[couch] diag file write failed: " + ex.Message)); } } } }