using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Photon.Pun; using Strobotnik.Klattersynth; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Utilities; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace TheShySage.SeparateMonitorPlayer2; public enum PlayerTwoController { XboxController1, XboxController2 } [BepInPlugin("TheShySage.SeparateMonitorPlayer2", "Separate Monitor Player 2-TheShySage", "0.9.27")] public sealed class Plugin : BaseUnityPlugin { internal static ConfigEntry Enabled; internal static ConfigEntry Controller; internal static ConfigEntry DisplayNumber; internal static ConfigEntry CameraSensitivity; private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown new Harmony("TheShySage.SeparateMonitorPlayer2").PatchAll(); Enabled = ((BaseUnityPlugin)this).Config.Bind("Player 2", "Enabled", true, "Enables the controller-only local Player 2 proxy."); Controller = ((BaseUnityPlugin)this).Config.Bind("Player 2", "Controller", PlayerTwoController.XboxController2, "Selects Xbox Controller 1 or Xbox Controller 2 for Player 2."); DisplayNumber = ((BaseUnityPlugin)this).Config.Bind("Player 2", "Monitor Number", 2, new ConfigDescription("Monitor used by Player 2.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 8), Array.Empty())); CameraSensitivity = ((BaseUnityPlugin)this).Config.Bind("Player 2", "Camera Sensitivity", 1.5f, new ConfigDescription("Player 2 camera look-speed multiplier. 1.00 is the previous sensitivity.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 4f), Array.Empty())); ((Component)this).gameObject.AddComponent(); } } public sealed class PlayerTwoManager : MonoBehaviour { private sealed class BindingBackup { internal InputAction Action; internal int Index; internal string OverridePath; } internal static PlayerTwoManager ActiveManager; private const float MoveFriction = 5f; private const float GrabDistance = 4f; private const float PlayerTwoScale = 0.75f; private const float PlayerTwoCartForceMultiplier = 9f; private const float PlayerTwoStrengthMultiplier = 0.5f; private const float DeadHeadDummyStatMultiplierPerLevel = 1.5f; private const float PlayerTwoGravityMultiplier = 0.999f; private GameObject proxy; private Rigidbody proxyBody; private Camera playerCamera; private GameObject playerTwoHud; private TextMeshProUGUI playerTwoHealthText; private TextMeshProUGUI playerTwoSprintText; private TextMeshProUGUI playerTwoVoiceLineText; private TextMeshProUGUI playerTwoHeldValueText; private GameObject playerTwoTtsObject; private GameObject playerTwoMapDevice; private Transform playerTwoMapMarker; private Transform playerOneMapMarker; private float playerTwoMapScale = 0.1f; private readonly List playerTwoMapLayers = new List(); private readonly List playerTwoMapLayerNumbers = new List(); private readonly List playerTwoMapSourceTransforms = new List(); private readonly List playerTwoMapCloneTransforms = new List(); private bool playerTwoMapActive; private bool previousMapButton; private float mapDeviceCreateRetry; private TTSVoice playerTwoTtsVoice; private Speech playerTwoNaturalSpeech; private int playerTwoVoiceLineIndex; private bool previousVoiceSpeak; private float ttsCreateRetry; private static readonly string[] PlayerTwoVoiceLines = new string[10] { "Hi", "Run", "Come here", "Follow me", "Enemy nearby", "Loot over here", "Up ahead", "Behind", "To the left", "To the right" }; private GameObject ghostVisual; private GameObject playerOneVisualForPlayerTwo; private Transform[] playerOneVisualSourceTransforms; private Transform[] playerOneVisualCloneTransforms; private PhysGrabObject heldValuable; private Rigidbody heldBody; private PhysGrabCart heldCart; private StaticGrabObject heldStaticObject; private Transform heldStaticTransform; private Vector3 heldStaticLocalPoint; private bool heldPhysRegistered; private Vector3 heldLocalPoint; private float grabHoldDistance; private Vector3 playerTwoCurrentGrabForce; private float grabForceRamp; private GameObject grabVisualRoot; private LineRenderer grabBeamLine; private GameObject grabPointVisual; private float pitch; private bool previousGrab; private bool previousUse; private int dummyExpressionIndex; private List dummyExpressions; private GameObject dummyEyelidLeft; private GameObject dummyEyelidRight; private Transform dummyEyelidLeftScale; private Transform dummyEyelidRightScale; private Transform dummyLeftUpperLidX; private Transform dummyLeftUpperLidZ; private Transform dummyLeftLowerLidX; private Transform dummyLeftLowerLidZ; private Transform dummyRightUpperLidX; private Transform dummyRightUpperLidZ; private Transform dummyRightLowerLidX; private Transform dummyRightLowerLidZ; private Transform dummyPupilLeftScale; private Transform dummyPupilRightScale; private Transform dummyPupilLeftRotation; private Transform dummyPupilRightRotation; private bool playerOneWasAlive; private float spawnRetry; private float avatarCloneReadyTimer; private GameObject mainMenuInfoCanvas; private GameObject mainMenuInfoPanel; private Canvas mainMenuInfoCanvasComponent; private readonly List mainMenuInfoTexts = new List(); private bool mainMenuInfoStyled; private const string MainMenuInfoText = "hi welcome to my first ever mod, thank you for giving it a try.\n\ncurrently its still sort of buggy and has a few issues\nbut overtime i want to improve it.\n\n-why use this mod instead of just something else that creates a second window\n\nthis mod is mostly aimed to be simpler to do and easier to do co op,\nthis mod does not create a second instance of the game instead\nits doing what true co op games do.\nits running in the same instance and same render\ntherefore no lag behaviors\n, \nthe co op player is not entirely an actual player, its more like a drone or a object to the game,\nwhich meant i had to recreate the movement system and everything else.\nbut because its not a actual player it will still load up without the use of adding a player to the playerlist.\n\nCurrently this only works with two monitors, and i do want to create a better control scheme for the tts\n\ndrone players cannot hold weapons properly yet, im still unsure about how to go about doing that, or the direction i want to go with it, so it will be on pause.\n\nFeatures:\n-drone/dummy co op player\nare 50% weaker then a normal player,\nbut anything player 1 grabs like upgrades does scale alongside the drone player, dead head player upgrade also increases all stats of the drone player by 1.5x for all drone players.\n-drone players share the same health as player 1.\nif player 1 or player 2 is attacked Player 1 health will drop.\nif player 1 dies so does the drone but the drone takes 15% less damage\n\nthank you again for giving my mod a try. i do hope that this becomes an actual feature for the game.\n-TheShySage"; private int activeDisplay = -1; private float inputIsolationTimer; private bool crouched; private bool crawling; private bool grounded; private bool sprinting; private bool canSlide; private bool sliding; private float sprintLerp; private float sprintGrace; private float sprintDrainTimer; private float slideTimer; private float energy = 100f; private float jumpBuffer; private float groundedBuffer; private float groundedLatch; private float groundedDisableTimer; private float jumpCooldown; private float sprintRechargeTimer; private Vector3 relativeVelocity; private Vector3 relativeVelocityTarget; private bool velocityIdle = true; private Vector3 slideDirection; private Vector3 slideDirectionCurrent; private CapsuleCollider proxyCapsule; private float standingCapsuleHeight = 1.7f; private Vector3 standingCapsuleCenter = new Vector3(0f, 0.85f, 0f); private float crouchCollisionRatio = 0.56f; private float crawlCollisionRatio = 0.38f; private Vector3 groundProbeOffset = new Vector3(0f, 0.08f, 0f); private float groundProbeRadius = 0.3f; private int groundProbeMask = -1; private Vector3 cameraStandingOffset = new Vector3(0f, 0.85f, 0f); private float cameraPositionSmooth = 2f; private float tumbleCameraBlendTimer; private float cameraCrouchLerp; private float cameraCrouchPosition = -0.3f; private float cameraCrouchSpeed = 5f; private AnimationCurve cameraCrouchCurve; private Gamepad isolatedPad; private readonly List ghostLights = new List(); private Light playerTwoFlashlight; private float playerTwoFlashlightBaseIntensity = 1f; private float flashlightCreateRetry; private bool flashlightOn = true; private readonly List bindingBackups = new List(); private readonly List isolatedActionMaps = new List(); private GameObject tumbleRig; private Rigidbody tumbleBody; private PhysGrabObject tumblePhysGrabObject; private RigidbodyInterpolation tumbleInterpolation; private Collider[] tumbleColliders = (Collider[])(object)new Collider[0]; private Transform tumbleFollowPosition; private bool isTumbling; private float tumbleInputCooldown; private bool previousTumbleButton; private float tumbleNotMovingTimer; private Vector3 tumbleLastPosition; private float tumbleCustomGravity = 10f; private Animator dummyAnimator; private Transform dummyHeadTransform; private Transform dummyMouthTransform; private Quaternion dummyMouthNeutralRotation = Quaternion.identity; private float dummyMouthMaxAngle = 45f; private readonly float[] dummyMouthSamples = new float[64]; private Transform dummyHeadUpTransform; private Transform dummyHeadSideTransform; private Transform dummyHeadLookTransform; private Transform dummyEyeLeft; private Transform dummyEyeRight; private Vector3 cameraMotionPosition; private Vector3 cameraMotionRotation; private bool animatorJumping; private float animatorJumpTimer; private bool animatorSprinting; private bool animatorSliding; private float vanillaBobUpAmount; private float vanillaBobUpActive; private float vanillaBobUpStrength; private float vanillaBobSideAmount; private float vanillaBobSideActive; private float vanillaBobSideStrength; private bool vanillaBobSideReverse; private float vanillaBobMultiplier; private PlayerAvatar soundPlayer; private PlayerAvatar enemyTargetAvatar; private bool enemyTargetRegistered; private readonly HashSet enemyTargetRegistrations = new HashSet(); private float enemyVisionScanTimer; private PlayerVisionTarget enemyVisionTarget; private Transform enemyVisionTransform; private float footstepDistance; private Vector3 soundLastPosition; private bool soundWasGrounded; private bool soundWasSliding; private float tumbleImpactSoundCooldown; private Vector3 tumbleSoundVelocity; private float tumbleRollSoundTimer; private readonly Dictionary sharedHealthHitCooldowns = new Dictionary(); private float sharedHealthScanTimer; private void OnEnable() { ActiveManager = this; } internal Vector3 RouteAudioPosition(Vector3 sourcePosition) { //IL_002f: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled.Value || !Object.op_Implicit((Object)(object)proxy) || !Object.op_Implicit((Object)(object)playerCamera)) { return sourcePosition; } AudioListener[] array = Object.FindObjectsOfType(); Transform val = null; AudioListener[] array2 = array; foreach (AudioListener val2 in array2) { if (Object.op_Implicit((Object)(object)val2) && ((Behaviour)val2).enabled && ((Component)val2).gameObject.activeInHierarchy && !((Component)val2).transform.IsChildOf(proxy.transform)) { val = ((Component)val2).transform; break; } } if (!Object.op_Implicit((Object)(object)val)) { return sourcePosition; } Vector3 val3 = sourcePosition - val.position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; Vector3 val4 = sourcePosition - ((Component)playerCamera).transform.position; float sqrMagnitude2 = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude2 >= sqrMagnitude) { return sourcePosition; } return val.position + val.rotation * Quaternion.Inverse(((Component)playerCamera).transform.rotation) * (sourcePosition - ((Component)playerCamera).transform.position); } private void Update() { //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Enabled.Value) { RestorePlayerOneInputDevices(); DespawnProxy(); return; } UpdateMainMenuInfoPopup(); PlayerAvatar instance = PlayerAvatar.instance; inputIsolationTimer -= Time.unscaledDeltaTime; if (inputIsolationTimer <= 0f) { inputIsolationTimer = 1f; ApplyPlayerOneInputIsolation(); IgnoreActorCollisions(); } if (!IsPlayerOneAlive(instance)) { if (playerOneWasAlive) { DespawnProxy(); } playerOneWasAlive = false; return; } playerOneWasAlive = true; if (!Object.op_Implicit((Object)(object)proxy)) { if (!AvatarCloneSourceReady(instance)) { avatarCloneReadyTimer = 0f; return; } avatarCloneReadyTimer += Time.unscaledDeltaTime; if (!(avatarCloneReadyTimer < 1.25f)) { spawnRetry -= Time.unscaledDeltaTime; if (spawnRetry <= 0f) { spawnRetry = 2f; SpawnProxy(instance); } } return; } Gamepad val = SelectedGamepad(); if (val == null) { previousTumbleButton = false; previousVoiceSpeak = false; previousMapButton = false; SetPlayerTwoMapActive(active: false); return; } avatarCloneReadyTimer = 0f; ttsCreateRetry -= Time.unscaledDeltaTime; if (!Object.op_Implicit((Object)(object)playerTwoTtsVoice) && !Object.op_Implicit((Object)(object)playerTwoNaturalSpeech) && ttsCreateRetry <= 0f) { ttsCreateRetry = 0.5f; CreatePlayerTwoTts(instance); } bool isPressed = val.rightStickButton.isPressed; UpdateLook(val); UpdateAutomaticCrawl(val); tumbleInputCooldown = Mathf.Max(0f, tumbleInputCooldown - Time.deltaTime); if (isPressed && !previousTumbleButton && tumbleInputCooldown <= 0f) { SetTumbling(!isTumbling, instance, playerInput: true); } previousTumbleButton = isPressed; if (isTumbling) { UpdateTumbleRecovery(val, instance); } else { UpdateGrab(val); UpdateGrabDistance(val); UpdateUseInteraction(val); } UpdateExpressionInput(val); UpdateVoiceLineInput(val, instance); UpdatePlayerTwoMap(val); UpdateEnemyTargetState(); UpdateGrabVisuals(); if (val.buttonNorth.wasPressedThisFrame) { flashlightOn = !flashlightOn; PlayNestedSound((!Object.op_Implicit((Object)(object)soundPlayer)) ? null : soundPlayer.flashlightController, (!flashlightOn) ? "lightOffAudio" : "lightOnAudio", proxy.transform.position); foreach (Light ghostLight in ghostLights) { if (Object.op_Implicit((Object)(object)ghostLight)) { ((Behaviour)ghostLight).enabled = flashlightOn; } } } if (Object.op_Implicit((Object)(object)ghostVisual)) { if (isTumbling && Object.op_Implicit((Object)(object)tumbleFollowPosition)) { ghostVisual.transform.SetPositionAndRotation(tumbleFollowPosition.position, tumbleFollowPosition.rotation); } else { ghostVisual.transform.SetPositionAndRotation(proxy.transform.position, proxy.transform.rotation); } } flashlightCreateRetry -= Time.unscaledDeltaTime; if (!Object.op_Implicit((Object)(object)playerTwoFlashlight) && flashlightCreateRetry <= 0f) { flashlightCreateRetry = 0.5f; CreatePlayerTwoFlashlight(instance); } if (Object.op_Implicit((Object)(object)playerTwoFlashlight)) { ((Behaviour)playerTwoFlashlight).enabled = flashlightOn; if (flashlightOn && playerTwoFlashlight.intensity <= 0.001f) { playerTwoFlashlight.intensity = playerTwoFlashlightBaseIntensity; } if (val.buttonNorth.wasPressedThisFrame) { Debug.Log((object)("[Separate Monitor Player 2] Flashlight toggled " + ((!flashlightOn) ? "OFF" : "ON") + "; enabled=" + ((Behaviour)playerTwoFlashlight).enabled + "; intensity=" + playerTwoFlashlight.intensity)); } } UpdateDummyAnimation(); ApplyDummyExpression(); UpdatePlayerTwoMouth(); UpdateDummyLook(); UpdatePlayerTwoSounds(); SyncPlayerOneVisualClone(); UpdateSharedHealth(instance); UpdatePlayerTwoHudValues(instance); UpdatePlayerTwoHeldValue(); } private void UpdateMainMenuInfoPopup() { if (!SemiFunc.MenuLevel()) { if (Object.op_Implicit((Object)(object)mainMenuInfoCanvas)) { mainMenuInfoCanvas.SetActive(false); } return; } if (!Object.op_Implicit((Object)(object)mainMenuInfoCanvas)) { CreateMainMenuInfoPopup(); } if (Object.op_Implicit((Object)(object)mainMenuInfoCanvas) && !mainMenuInfoCanvas.activeSelf) { mainMenuInfoCanvas.SetActive(true); } if (Object.op_Implicit((Object)(object)CursorManager.instance)) { CursorManager.instance.Unlock(0.1f); } if (Object.op_Implicit((Object)(object)MenuCursor.instance)) { MenuCursor.instance.Show(); Canvas componentInParent = ((Component)MenuCursor.instance).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)mainMenuInfoCanvasComponent)) { mainMenuInfoCanvasComponent.sortingOrder = componentInParent.sortingOrder - 1; } } ApplyMainMenuInfoStyle(); } private void CreateMainMenuInfoPopup() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0190: 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_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03da: 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) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Expected O, but got Unknown //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Expected O, but got Unknown mainMenuInfoCanvas = new GameObject("Separate Monitor Player 2 - Main Menu Info"); mainMenuInfoCanvas.transform.SetParent(((Component)this).transform, false); Canvas val = (mainMenuInfoCanvasComponent = mainMenuInfoCanvas.AddComponent()); val.renderMode = (RenderMode)0; val.targetDisplay = 0; val.overrideSorting = true; val.sortingOrder = 100; CanvasScaler val2 = mainMenuInfoCanvas.AddComponent(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); val2.matchWidthOrHeight = 0.5f; mainMenuInfoCanvas.AddComponent(); GameObject val3 = CreatePopupRect("MOD INFO Button", mainMenuInfoCanvas.transform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-24f, 24f), new Vector2(220f, 64f)); Image val4 = val3.AddComponent(); ((Graphic)val4).color = new Color(0.04f, 0.12f, 0.2f, 0.96f); Button val5 = val3.AddComponent