Decompiled source of OpenBodyCams v2.6.0
OpenBodyCams.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using AdvancedCompany.Game; using AdvancedCompany.Objects; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using GeneralImprovements.API; using HarmonyLib; using LethalLib.Modules; using LethalVRM; using Microsoft.CodeAnalysis; using ModelReplacement; using ModelReplacement.Monobehaviors; using MoreCompany.Cosmetics; using OpenBodyCams.API; using OpenBodyCams.Compatibility; using OpenBodyCams.Overlay; using OpenBodyCams.Patches; using OpenBodyCams.Utilities; using OpenBodyCams.Utilities.IL; using ReservedItemSlotCore.Data; using ReservedItemSlotCore.Patches; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.Rendering.RendererUtils; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OpenBodyCams")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OpenBodyCams")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("3d49e5ff-443d-44f6-90aa-a870ecfeb2d5")] [assembly: AssemblyFileVersion("2.6.0")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.6.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OpenBodyCams { public class BodyCamComponent : MonoBehaviour { public delegate void RenderersToHideTransformer(BodyCamComponent bodyCam, ref Renderer[] renderers); [Obsolete] public delegate Renderer[] GetRenderersToHide(Renderer[] renderers); private delegate void GetCameraPosition(in Vector3 position, ref bool isInInterior, ref bool isInShip); [Flags] private enum TargetDirtyStatus { None = 0, Immediate = 1, UntilRender = 2 } private const float RADAR_BOOSTER_INITIAL_PAN = 270f; private static readonly Vector3 BODY_CAM_OFFSET = new Vector3(0.07f, 0f, 0.16f); private static readonly Vector3 CAMERA_CONTAINER_OFFSET = new Vector3(0.07f, 0f, 0.125f); private static readonly int CullModeProperty = Shader.PropertyToID("_CullMode"); private static int bodyCamCullingMask; private static FrameSettings mainCameraCustomFrameSettings; private static FrameSettingsOverrideMask mainCameraCustomFrameSettingsMask; private static Material fogShaderMaterial; private static GameObject nightVisionPrefab; private static Light vanillaMapNightVisionLight; private static BodyCamComponent[] AllBodyCams = Array.Empty<BodyCamComponent>(); private static BodyCamComponent lastBodyCamCulled; private static BodyCamComponent lastBodyCamRendered; private static bool disableCameraWhileTargetIsOnShip = false; private static float radarBoosterPanSpeed; private static bool bruteForcePreventNullModels; internal GameObject CameraObject; internal Camera Camera; internal Renderer MonitorRenderer; internal int MonitorMaterialIndex = -1; internal Material MonitorOnMaterial; internal Material MonitorNoTargetMaterial; internal Material MonitorOffMaterial; internal Material MonitorDisabledMaterial; internal bool MonitorIsOn = true; internal bool EnableCamera = true; private bool keepCameraOn; private static readonly Vector2Int DefaultResolution = new Vector2Int(160, 120); private Vector2Int resolution = DefaultResolution; private bool isRemoteCamera = true; private bool vanillaMapNightVisionLightWasEnabled; private PlayerModelState localPlayerModelState; private PlayerControllerB currentPlayer; private PlayerModelState currentPlayerModelState; private Transform currentActualTarget; private Renderer[] currentRenderersToHide = Array.Empty<Renderer>(); private Material currentObstructingMaterial; private float currentObstructingMaterialCullMode; private GetCameraPosition cameraPositionGetter; private bool originalDirectSunlightEnabled; private bool originalIndirectSunlightEnabled; private bool targetSunlightEnabled; private float originalBlackSkyVolumeWeight; private float targetBlackSkyVolumeWeight; private float originalIndirectSunlightDimmer; private float targetIndirectSunlightDimmer; private Light nightVisionLight; private MeshRenderer greenFlashRenderer; private Animator greenFlashAnimator; private MeshRenderer fogShaderPlaneRenderer; private TargetDirtyStatus targetDirtyStatus; private float elapsedSinceLastFrame; private float timePerFrame; private bool panCamera; private float panAngle = 270f; private CameraRenderingStatus cameraStatus; public bool IsRemoteCamera { get { return isRemoteCamera; } set { if (isRemoteCamera != value) { isRemoteCamera = value; TargetHasChanged(); } } } public bool ForceEnableCamera { get { return keepCameraOn; } set { keepCameraOn = value; } } public Vector2Int Resolution { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return resolution; } set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) resolution = value; UpdateSettings(); } } public bool IsBlanked => !CameraShouldRender(cameraStatus); public CameraRenderingStatus CameraStatus => cameraStatus; public float Framerate { get { return 1f / timePerFrame; } set { if (value != 0f) { timePerFrame = 1f / value; } else { timePerFrame = 0f; } } } public PlayerControllerB? CurrentPlayerTarget => currentPlayer; public Transform? CurrentTarget => currentActualTarget; public static event RenderersToHideTransformer? RenderersToHideTransformers; public event Action<Camera>? OnCameraCreated; public event Action<RenderTexture>? OnRenderTextureCreated; public event Action<bool>? OnBlankedSet; public event Action<CameraRenderingStatus>? OnCameraStatusChanged; public event Action<bool>? OnScreenPowerChanged; [Obsolete("Use RenderersToHideTransformers")] public event GetRenderersToHide? OnRenderersToHideChanged; public event BodyCam.BodyCamStatusUpdate? OnTargetChanged; public static BodyCamComponent[] GetAllBodyCams() { return new ReadOnlySpan<BodyCamComponent>(AllBodyCams).ToArray(); } public Camera? GetCamera() { return Camera; } internal static void InitializeStatic() { PatchHDRenderPipeline.BeforeCameraCulling = (Action<ScriptableRenderContext, Camera>)Delegate.Combine(PatchHDRenderPipeline.BeforeCameraCulling, new Action<ScriptableRenderContext, Camera>(BeforeCullingAnyCamera)); PatchHDRenderPipeline.BeforeCameraRendering = (Action<ScriptableRenderContext, Camera>)Delegate.Combine(PatchHDRenderPipeline.BeforeCameraRendering, new Action<ScriptableRenderContext, Camera>(BeforeRenderingAnyCamera)); RenderPipelineManager.endCameraRendering += AfterRenderingAnyCamera; } internal static void InitializeAtStartOfGame() { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[0]; bodyCamCullingMask = val.gameplayCamera.cullingMask & ~LayerMask.GetMask(new string[3] { "Ignore Raycast", "UI", "HelmetVisor" }); HDAdditionalCameraData component = ((Component)val.gameplayCamera).GetComponent<HDAdditionalCameraData>(); if (component.customRenderingSettings) { Plugin.Instance.Logger.LogInfo((object)("Using custom camera settings from " + ((Object)component).name + ".")); mainCameraCustomFrameSettings = component.renderingPathCustomFrameSettings; mainCameraCustomFrameSettingsMask = component.renderingPathCustomFrameSettingsOverrideMask; } fogShaderMaterial = ((Renderer)((Component)((Component)val.localVisor).transform.Find("ScavengerHelmet/Plane")).GetComponent<MeshRenderer>()).sharedMaterial; nightVisionPrefab = Object.Instantiate<GameObject>(((Component)val.nightVision).gameObject); ((Object)nightVisionPrefab).hideFlags = (HideFlags)61; ((Object)nightVisionPrefab).name = "NightVision"; nightVisionPrefab.transform.localPosition = Vector3.zero; nightVisionPrefab.SetActive(false); ((Behaviour)nightVisionPrefab.GetComponent<Light>()).enabled = false; vanillaMapNightVisionLight = StartOfRound.Instance.mapScreen.mapCameraLight; UpdateAllCameraSettings(); } internal static bool HasFinishedGameStartSetup() { return (Object)(object)vanillaMapNightVisionLight != (Object)null; } public static void UpdateAllCameraSettings() { UpdateStaticSettings(); BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { allBodyCams[i].UpdateSettings(); } } internal static void UpdateStaticSettings() { disableCameraWhileTargetIsOnShip = Plugin.DisableCameraWhileTargetIsOnShip.Value; radarBoosterPanSpeed = Plugin.RadarBoosterPanRPM.Value * 360f / 60f; bruteForcePreventNullModels = Plugin.BruteForcePreventFreezes.Value; } public static void MarkTargetDirtyUntilRenderForAllBodyCams(Transform target) { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { allBodyCams[i].MarkTargetDirtyUntilRender(target); } } public static void MarkAnyParentDirtyUntilRenderForAllBodyCams(Transform target) { while ((Object)(object)target != (Object)null) { MarkTargetDirtyUntilRenderForAllBodyCams(target); target = target.parent; } } public static void MarkTargetDirtyUntilRenderForAllBodyCams() { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { allBodyCams[i].MarkTargetDirtyUntilRender(); } } public static void MarkTargetStatusChangedForAllBodyCams(Transform target) { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { allBodyCams[i].MarkTargetStatusChanged(target); } } public static void MarkTargetStatusChangedForAllBodyCams() { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { allBodyCams[i].MarkTargetStatusChanged(); } } private static void RevertLastOverrides() { if ((Object)(object)lastBodyCamCulled != (Object)null) { lastBodyCamCulled.RevertCullingOverrides(); lastBodyCamCulled = null; } if ((Object)(object)lastBodyCamRendered != (Object)null) { lastBodyCamRendered.RevertRenderingOverrides(); lastBodyCamRendered = null; } } private static void BeforeCullingAnyCamera(ScriptableRenderContext context, Camera camera) { RevertLastOverrides(); int num = AllBodyCams.Length; for (int i = 0; i < num; i++) { BodyCamComponent bodyCamComponent = AllBodyCams[i]; if (bodyCamComponent.Camera == camera) { lastBodyCamCulled = bodyCamComponent; bodyCamComponent.ApplyCullingOverrides(); break; } } } internal static void BeforeRenderingAnyCamera(ScriptableRenderContext context, Camera camera) { RevertLastOverrides(); int num = AllBodyCams.Length; for (int i = 0; i < num; i++) { BodyCamComponent bodyCamComponent = AllBodyCams[i]; if (bodyCamComponent.Camera == camera) { lastBodyCamRendered = bodyCamComponent; bodyCamComponent.ApplyRenderingOverrides(); break; } } } internal static void AfterRenderingAnyCamera(ScriptableRenderContext context, Camera camera) { RevertLastOverrides(); } private void Awake() { if (!HasFinishedGameStartSetup()) { Plugin.Instance.Logger.LogError((object)"Attempted to create a body cam before static initialization has been completed."); Plugin.Instance.Logger.LogError((object)"This may occur if the save is corrupted, or if a mod caused an error during the start of the game."); Object.Destroy((Object)(object)this); return; } BodyCamComponent[] allBodyCams = AllBodyCams; int num = 0; BodyCamComponent[] array = new BodyCamComponent[1 + allBodyCams.Length]; ReadOnlySpan<BodyCamComponent> readOnlySpan = new ReadOnlySpan<BodyCamComponent>(allBodyCams); readOnlySpan.CopyTo(new Span<BodyCamComponent>(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array[num] = this; num++; AllBodyCams = array; BodyCam.BodyCamInstantiated(this); } private void Start() { if (EnsureCameraExistsOrReturnFalse()) { SyncBodyCamToRadarMap.UpdateBodyCamTarget(this); } } private void SetMonitorMaterial(Material material) { if (!((Object)(object)MonitorRenderer == (Object)null)) { MonitorRenderer.SetMaterial(MonitorMaterialIndex, material); } } private void EnsureMaterialsExist() { //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) //IL_002e: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MonitorOnMaterial == (Object)null) { MonitorOnMaterial = new Material(Shader.Find("HDRP/Unlit")) { name = "BodyCamMaterial" }; MonitorOnMaterial.SetFloat("_AlbedoAffectEmissive", 1f); MonitorOnMaterial.SetColor("_EmissiveColor", Color.white); } if ((Object)(object)MonitorOffMaterial == (Object)null) { MonitorOffMaterial = ShipObjects.BlackScreenMaterial; } } private bool EnsureCameraExistsOrReturnFalse() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_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_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_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0264: 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) if (!HasFinishedGameStartSetup()) { return false; } if ((Object)(object)CameraObject != (Object)null) { return true; } Plugin.Instance.Logger.LogInfo((object)"Camera has been destroyed, recreating it."); UpdateScreenMaterial(); CameraObject = new GameObject("BodyCam"); Camera = CameraObject.AddComponent<Camera>(); Camera.nearClipPlane = 0.01f; Camera.cullingMask = bodyCamCullingMask; HDAdditionalCameraData val = CameraObject.AddComponent<HDAdditionalCameraData>(); val.volumeLayerMask = LayerMask.op_Implicit(1); _ = mainCameraCustomFrameSettings; val.customRenderingSettings = true; ref FrameSettings renderingPathCustomFrameSettings = ref val.renderingPathCustomFrameSettings; ref FrameSettingsOverrideMask renderingPathCustomFrameSettingsOverrideMask = ref val.renderingPathCustomFrameSettingsOverrideMask; renderingPathCustomFrameSettings = mainCameraCustomFrameSettings; renderingPathCustomFrameSettingsOverrideMask = mainCameraCustomFrameSettingsMask; ((FrameSettings)(ref renderingPathCustomFrameSettings)).SetEnabled((FrameSettingsField)93, false); ((BitArray128)(ref renderingPathCustomFrameSettingsOverrideMask.mask))[93u] = true; ((FrameSettings)(ref renderingPathCustomFrameSettings)).SetEnabled((FrameSettingsField)88, false); ((BitArray128)(ref renderingPathCustomFrameSettingsOverrideMask.mask))[88u] = true; val.hasPersistentHistory = true; GameObject val2 = Object.Instantiate<GameObject>(nightVisionPrefab); val2.transform.SetParent(CameraObject.transform, false); val2.SetActive(true); nightVisionLight = val2.GetComponent<Light>(); UpdateSettings(); GameObject val3 = new GameObject("CameraGreenTransitionScaler"); val3.transform.SetParent(CameraObject.transform, false); val3.transform.localScale = new Vector3(1f, 0.004f, 1f); GameObject val4 = Object.Instantiate<GameObject>(((Component)StartOfRound.Instance.mapScreen.mapCameraAnimator).gameObject); val4.transform.SetParent(val3.transform, false); val4.transform.localPosition = new Vector3(0f, 0f, 0.1f); val4.layer = 0; greenFlashRenderer = val4.GetComponent<MeshRenderer>(); ((Renderer)greenFlashRenderer).forceRenderingOff = true; greenFlashAnimator = val4.GetComponent<Animator>() ?? throw new Exception("Green flash object copied from the map screen has no Animator."); greenFlashAnimator.Play("MapTransitionGreen", 0, 1f); greenFlashAnimator.WriteDefaultValues(); GameObject val5 = GameObject.CreatePrimitive((PrimitiveType)5); Object.Destroy((Object)(object)val5.GetComponent<MeshCollider>()); val5.transform.SetParent(CameraObject.transform, false); val5.transform.localPosition = new Vector3(0f, 0f, Camera.nearClipPlane * 2f); val5.transform.localRotation = Quaternion.Euler(0f, 0f, 0f); fogShaderPlaneRenderer = val5.GetComponent<MeshRenderer>(); ((Renderer)fogShaderPlaneRenderer).sharedMaterial = fogShaderMaterial; ((Renderer)fogShaderPlaneRenderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)fogShaderPlaneRenderer).receiveShadows = false; ((Renderer)fogShaderPlaneRenderer).forceRenderingOff = true; this.OnCameraCreated?.Invoke(Camera); return true; } [Obsolete] private void EnsureCameraExists() { EnsureCameraExistsOrReturnFalse(); } public void UpdateSettings() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown if (!((Object)(object)Camera == (Object)null)) { int x = ((Vector2Int)(ref resolution)).x; int y = ((Vector2Int)(ref resolution)).y; Camera.targetTexture = new RenderTexture(x, y, 32) { name = ((Object)this).name + ".RenderTexture", filterMode = Plugin.MonitorTextureFiltering.Value }; Camera.fieldOfView = Plugin.FieldOfView.Value; if ((Object)(object)MonitorOnMaterial != (Object)null) { MonitorOnMaterial.mainTexture = (Texture)(object)Camera.targetTexture; } Camera.farClipPlane = Plugin.RenderDistance.Value; nightVisionLight.intensity = 367f * Plugin.NightVisionBrightness.Value; nightVisionLight.range = 12f * Plugin.NightVisionBrightness.Value; this.OnRenderTextureCreated?.Invoke(Camera.targetTexture); } } public void StartTargetTransition() { if (Plugin.UseTargetTransitionAnimation.Value) { Animator obj = greenFlashAnimator; if (obj != null) { obj.SetTrigger("Transition"); } } } public void UpdateScreenMaterial() { //IL_0049: 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) if (!HasFinishedGameStartSetup()) { return; } EnsureMaterialsExist(); if (!MonitorIsOn) { if ((Object)(object)MonitorOffMaterial != (Object)null) { SetMonitorMaterial(MonitorOffMaterial); } return; } bool enabled = ((Behaviour)this).enabled; if (IsBlanked || !enabled) { MonitorOnMaterial.color = Color.black; if (!enabled && (Object)(object)MonitorDisabledMaterial != (Object)null) { SetMonitorMaterial(MonitorDisabledMaterial); return; } if ((Object)(object)MonitorNoTargetMaterial != (Object)null) { SetMonitorMaterial(MonitorNoTargetMaterial); return; } } else { MonitorOnMaterial.color = Color.white; } SetMonitorMaterial(MonitorOnMaterial); } public void SetScreenPowered(bool powered) { if (!((Object)(object)MonitorRenderer == (Object)null) && powered != MonitorIsOn) { if (powered) { StartTargetTransition(); } MonitorIsOn = powered; UpdateScreenMaterial(); this.OnScreenPowerChanged?.Invoke(MonitorIsOn); } } public bool IsScreenPowered() { return MonitorIsOn; } private bool CameraShouldRender(CameraRenderingStatus status) { return status == CameraRenderingStatus.Rendering; } private void SetStatus(CameraRenderingStatus newStatus) { if (newStatus != cameraStatus) { bool num = CameraShouldRender(cameraStatus) == CameraShouldRender(newStatus); cameraStatus = newStatus; UpdateScreenMaterial(); if (num) { this.OnBlankedSet?.Invoke(IsBlanked); } this.OnCameraStatusChanged?.Invoke(cameraStatus); } } private CameraRenderingStatus GetUpdatedCameraStatus() { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (!EnableCamera) { return CameraRenderingStatus.Disabled; } if ((Object)(object)currentActualTarget == (Object)null) { return CameraRenderingStatus.TargetInvalid; } if (currentPlayer != null) { if (currentPlayer.isPlayerControlled) { if (currentPlayer.isInHangarShipRoom) { return CameraRenderingStatus.TargetDisabledOnShip; } return CameraRenderingStatus.Rendering; } if (!currentPlayer.isPlayerDead) { return CameraRenderingStatus.Rendering; } if ((Object)(object)currentPlayer.redirectToEnemy != (Object)null) { if (currentPlayer.redirectToEnemy.isInsidePlayerShip) { return CameraRenderingStatus.TargetDisabledOnShip; } return CameraRenderingStatus.Rendering; } if ((Object)(object)currentPlayer.deadBody != (Object)null) { if (currentPlayer.deadBody.isInShip) { return CameraRenderingStatus.TargetDisabledOnShip; } return CameraRenderingStatus.Rendering; } } RadarBoosterItem component = ((Component)currentActualTarget).GetComponent<RadarBoosterItem>(); if (component != null) { Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(3000f, -400f, 3000f); if (((Vector3)(ref ((GrabbableObject)component).targetFloorPosition)).Equals(val)) { return CameraRenderingStatus.TargetInvalid; } if (((GrabbableObject)component).isInShipRoom) { return CameraRenderingStatus.TargetDisabledOnShip; } return CameraRenderingStatus.Rendering; } return CameraRenderingStatus.Rendering; } private static void CollectDescendentModelsToHide(Transform parent, List<Renderer> list) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown BodyCamComponent[] allBodyCams = AllBodyCams; foreach (BodyCamComponent bodyCamComponent in allBodyCams) { if ((Object)(object)parent == (Object)(object)bodyCamComponent.CameraObject.transform) { return; } } Renderer component = ((Component)parent).GetComponent<Renderer>(); if ((Object)(object)component != (Object)null && ((1 << ((Component)component).gameObject.layer) & bodyCamCullingMask) != 0) { list.Add(component); } foreach (Transform item in parent) { CollectDescendentModelsToHide(item, list); } } private static Renderer[] CollectModelsToHide(Transform parent) { List<Renderer> list = new List<Renderer>(20); CollectDescendentModelsToHide(parent, list); return list.ToArray(); } private bool TargetWouldRequireUpdate(Transform target) { if (target == null) { return true; } if (currentActualTarget == target) { return true; } if (((Component)StartOfRound.Instance.localPlayerController).transform == target) { return true; } return false; } public void MarkTargetStatusChanged(Transform transform) { if (!targetDirtyStatus.HasFlag(TargetDirtyStatus.Immediate) && TargetWouldRequireUpdate(transform)) { targetDirtyStatus |= TargetDirtyStatus.Immediate; } } public void MarkTargetStatusChanged() { MarkTargetStatusChanged(null); } public void MarkTargetDirtyUntilRender(Transform transform) { if (!targetDirtyStatus.HasFlag(TargetDirtyStatus.UntilRender) && TargetWouldRequireUpdate(transform)) { targetDirtyStatus |= TargetDirtyStatus.UntilRender; } } public void MarkTargetDirtyUntilRender() { MarkTargetDirtyUntilRender(null); } private void ClearTargetDirtyImmediate() { targetDirtyStatus &= ~TargetDirtyStatus.Immediate; } private void SetRenderersToHide(Renderer[] renderers) { if ((Object)(object)currentActualTarget != (Object)null && this.OnRenderersToHideChanged != null) { renderers = this.OnRenderersToHideChanged(renderers); } BodyCamComponent.RenderersToHideTransformers?.Invoke(this, ref renderers); currentRenderersToHide = renderers; } private void TargetHasChanged() { this.OnTargetChanged?.Invoke(this); } public void SetTargetToNone() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) ClearTargetDirtyImmediate(); currentPlayer = null; currentActualTarget = null; SetRenderersToHide(Array.Empty<Renderer>()); UpdateModelReferences(); cameraPositionGetter = null; if ((Object)(object)CameraObject != (Object)null) { CameraObject.transform.SetParent((Transform)null, false); CameraObject.transform.localPosition = Vector3.zero; CameraObject.transform.localRotation = Quaternion.identity; } TargetHasChanged(); } public void SetTargetToPlayer(PlayerControllerB player) { //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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //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_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { SetTargetToNone(); } else { if (!EnsureCameraExistsOrReturnFalse()) { return; } ClearTargetDirtyImmediate(); currentPlayer = player; UpdateModelReferences(); panCamera = false; Vector3 localPosition = Vector3.zero; currentActualTarget = null; Transform val = null; currentRenderersToHide = Array.Empty<Renderer>(); currentObstructingMaterial = null; if (!currentPlayer.isPlayerDead) { if (Plugin.CameraMode.Value == CameraModeOptions.Head) { val = ((Component)currentPlayer.gameplayCamera).transform; localPosition = CAMERA_CONTAINER_OFFSET; } else { val = ((Component)currentPlayer.playerGlobalHead).transform.parent; localPosition = BODY_CAM_OFFSET; } currentActualTarget = ((Component)currentPlayer).transform; SetRenderersToHide(Array.Empty<Renderer>()); cameraPositionGetter = delegate(in Vector3 _, ref bool isInInterior, ref bool isInShip) { isInInterior = currentPlayer.isInsideFactory; isInShip = currentPlayer.isInHangarShipRoom; }; } else if ((Object)(object)currentPlayer.redirectToEnemy != (Object)null) { EnemyAI redirectToEnemy = currentPlayer.redirectToEnemy; MaskedPlayerEnemy val2 = (MaskedPlayerEnemy)(object)((redirectToEnemy is MaskedPlayerEnemy) ? redirectToEnemy : null); if (val2 != null) { if (Plugin.CameraMode.Value == CameraModeOptions.Head) { val = val2.headTiltTarget; localPosition = CAMERA_CONTAINER_OFFSET; } else { val = val2.animationContainer.Find("metarig/spine/spine.001/spine.002/spine.003"); localPosition = BODY_CAM_OFFSET; } } else { val = currentPlayer.redirectToEnemy.eye; } currentActualTarget = ((Component)currentPlayer.redirectToEnemy).transform; SetRenderersToHide(CollectModelsToHide(currentActualTarget)); cameraPositionGetter = delegate(in Vector3 _, ref bool isInInterior, ref bool isInShip) { if (!((Object)(object)currentPlayer.redirectToEnemy == (Object)null)) { isInInterior = !currentPlayer.redirectToEnemy.isOutside; isInShip = currentPlayer.redirectToEnemy.isInsidePlayerShip; } }; } else if ((Object)(object)currentPlayer.deadBody != (Object)null) { Transform parent; if (Plugin.CameraMode.Value == CameraModeOptions.Head) { val = ((Component)currentPlayer.deadBody).transform.Find("spine.001/spine.002/spine.003/spine.004/spine.004_end"); parent = val.parent; localPosition = CAMERA_CONTAINER_OFFSET; } else { val = ((Component)currentPlayer.deadBody).transform.Find("spine.001/spine.002/spine.003"); parent = val; localPosition = BODY_CAM_OFFSET; } currentActualTarget = ((Component)currentPlayer.deadBody).transform; SetRenderersToHide(CollectModelsToHide(parent)); Renderer component = ((Component)currentActualTarget).GetComponent<Renderer>(); currentObstructingMaterial = ((component != null) ? component.sharedMaterial : null); cameraPositionGetter = delegate(in Vector3 _, ref bool isInInterior, ref bool isInShip) { if (!((Object)(object)currentPlayer.deadBody == (Object)null)) { if ((Object)(object)currentPlayer.deadBody.grabBodyObject != (Object)null) { isInInterior = currentPlayer.deadBody.grabBodyObject.isInFactory; } isInShip = currentPlayer.deadBody.isInShip; } }; } CameraObject.transform.SetParent(val, false); CameraObject.transform.localPosition = localPosition; CameraObject.transform.localRotation = Quaternion.identity; TargetHasChanged(); } } public void SetTargetToTransform(Transform transform) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) if ((Object)(object)transform == (Object)null || (Object)(object)((Component)transform).gameObject == (Object)null) { SetTargetToNone(); } else { if (!EnsureCameraExistsOrReturnFalse()) { return; } ClearTargetDirtyImmediate(); currentPlayer = null; currentActualTarget = transform; UpdateModelReferences(); panCamera = false; Vector3 zero = Vector3.zero; RadarBoosterItem radarBooster = ((Component)currentActualTarget).GetComponent<RadarBoosterItem>(); if (radarBooster != null) { SetRenderersToHide((Renderer[])(object)new Renderer[1] { ((Component)((Component)currentActualTarget).transform.Find("AnimContainer/Rod")).GetComponent<Renderer>() }); ((Vector3)(ref zero))..ctor(0f, 1.5f, 0f); panCamera = true; cameraPositionGetter = delegate(in Vector3 _, ref bool isInInterior, ref bool isInShip) { if (!((Object)(object)currentActualTarget != (Object)(object)((Component)radarBooster).transform)) { isInInterior = ((GrabbableObject)radarBooster).isInFactory; isInShip = ((GrabbableObject)radarBooster).isInShipRoom; } }; } else { cameraPositionGetter = delegate(in Vector3 position, ref bool isInInterior, ref bool isInShip) { isInInterior = position.y < -80f; }; } CameraObject.transform.SetParent(((Component)currentActualTarget).transform, false); CameraObject.transform.localPosition = zero; CameraObject.transform.localRotation = Quaternion.identity; TargetHasChanged(); } } private void UpdateTargetStatus() { if ((Object)(object)currentPlayer != (Object)null) { SetTargetToPlayer(currentPlayer); } else { SetTargetToTransform(currentActualTarget); } } private void UpdateModelReferences() { ViewPerspective.PrepareModelState(currentPlayer, ref currentPlayerModelState); if ((Object)(object)currentPlayer != (Object)(object)StartOfRound.Instance.localPlayerController) { ViewPerspective.PrepareModelState(StartOfRound.Instance.localPlayerController, ref localPlayerModelState); } } private void UpdateTargetStatusBeforeRender() { if (targetDirtyStatus.HasFlag(TargetDirtyStatus.UntilRender)) { UpdateTargetStatus(); targetDirtyStatus ^= TargetDirtyStatus.UntilRender; } } private void ApplyCullingOverrides() { UpdateTargetStatusBeforeRender(); vanillaMapNightVisionLightWasEnabled = ((Behaviour)vanillaMapNightVisionLight).enabled; ((Behaviour)vanillaMapNightVisionLight).enabled = false; ((Behaviour)nightVisionLight).enabled = true; ((Renderer)greenFlashRenderer).forceRenderingOff = false; ((Renderer)fogShaderPlaneRenderer).forceRenderingOff = false; PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; ViewPerspective.Apply(ref currentPlayerModelState, Perspective.FirstPerson); if (currentPlayer != localPlayerController) { ViewPerspective.Apply(ref localPlayerModelState, Perspective.ThirdPerson); } bool flag = false; Renderer[] array = currentRenderersToHide; foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { if (!flag) { Plugin.Instance.Logger.LogError((object)("Mesh obstructing the body cam on " + ((Object)this).name + " which should be hidden was unexpectedly null.")); } flag = true; } else { val.forceRenderingOff = true; } } if ((Object)(object)currentObstructingMaterial != (Object)null) { currentObstructingMaterialCullMode = currentObstructingMaterial.GetFloat(CullModeProperty); currentObstructingMaterial.SetFloat(CullModeProperty, 2f); } Light sunDirect = TimeOfDay.Instance.sunDirect; if ((Object)(object)sunDirect != (Object)null) { Light sunIndirect = TimeOfDay.Instance.sunIndirect; originalDirectSunlightEnabled = ((Behaviour)sunDirect).enabled; originalIndirectSunlightEnabled = ((Behaviour)sunIndirect).enabled; ((Behaviour)sunDirect).enabled = targetSunlightEnabled; ((Behaviour)sunIndirect).enabled = targetSunlightEnabled; } Volume blackSkyVolume = StartOfRound.Instance.blackSkyVolume; originalBlackSkyVolumeWeight = blackSkyVolume.weight; blackSkyVolume.weight = targetBlackSkyVolumeWeight; } private void RevertCullingOverrides() { ((Behaviour)vanillaMapNightVisionLight).enabled = vanillaMapNightVisionLightWasEnabled; ((Behaviour)nightVisionLight).enabled = false; ((Renderer)greenFlashRenderer).forceRenderingOff = true; ((Renderer)fogShaderPlaneRenderer).forceRenderingOff = true; PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; ViewPerspective.Restore(ref currentPlayerModelState); if (currentPlayer != localPlayerController) { ViewPerspective.Restore(ref localPlayerModelState); } Renderer[] array = currentRenderersToHide; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null)) { val.forceRenderingOff = false; } } Material obj = currentObstructingMaterial; if (obj != null) { obj.SetFloat(CullModeProperty, currentObstructingMaterialCullMode); } Light sunDirect = TimeOfDay.Instance.sunDirect; if ((Object)(object)sunDirect != (Object)null) { Light sunIndirect = TimeOfDay.Instance.sunIndirect; ((Behaviour)sunDirect).enabled = originalDirectSunlightEnabled; ((Behaviour)sunIndirect).enabled = originalIndirectSunlightEnabled; } StartOfRound.Instance.blackSkyVolume.weight = originalBlackSkyVolumeWeight; } private void ApplyRenderingOverrides() { HDAdditionalLightData indirectLightData = TimeOfDay.Instance.indirectLightData; if ((Object)(object)indirectLightData != (Object)null) { originalIndirectSunlightDimmer = indirectLightData.lightDimmer; indirectLightData.lightDimmer = targetIndirectSunlightDimmer; targetIndirectSunlightDimmer = indirectLightData.lightDimmer; } } private void RevertRenderingOverrides() { HDAdditionalLightData indirectLightData = TimeOfDay.Instance.indirectLightData; if ((Object)(object)indirectLightData != (Object)null) { indirectLightData.lightDimmer = originalIndirectSunlightDimmer; } } private void UpdateTargetStatusDuringUpdate() { if (targetDirtyStatus.HasFlag(TargetDirtyStatus.Immediate)) { UpdateTargetStatus(); } } private void UpdateOverrides() { //IL_001b: 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) bool isInInterior = false; bool isInShip = false; GetCameraPosition getCameraPosition = cameraPositionGetter; if (getCameraPosition != null) { Vector3 position = ((Component)Camera).transform.position; getCameraPosition(in position, ref isInInterior, ref isInShip); } targetSunlightEnabled = !isInInterior; targetBlackSkyVolumeWeight = (isInInterior ? 1 : 0); targetIndirectSunlightDimmer = Mathf.Lerp(targetIndirectSunlightDimmer, (float)((!isInShip) ? 1 : 0), 5f * Time.deltaTime); } private void Update() { UpdateOverrides(); } private void LateUpdate() { //IL_01cf: Unknown result type (might be due to invalid IL or missing references) if (!EnsureCameraExistsOrReturnFalse()) { return; } UpdateTargetStatusDuringUpdate(); PlayerControllerB val = StartOfRound.Instance.localPlayerController; if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)val.spectatedPlayerScript != (Object)null) { val = val.spectatedPlayerScript; } bool flag = keepCameraOn || ((Object)(object)MonitorRenderer != (Object)null && MonitorRenderer.isVisible && val.isInHangarShipRoom && IsScreenPowered()); if (flag) { CameraRenderingStatus cameraRenderingStatus = GetUpdatedCameraStatus(); if (cameraRenderingStatus == CameraRenderingStatus.TargetDisabledOnShip && (!disableCameraWhileTargetIsOnShip || keepCameraOn)) { cameraRenderingStatus = CameraRenderingStatus.Rendering; } SetStatus(cameraRenderingStatus); flag = !IsBlanked; } if (flag && bruteForcePreventNullModels) { bool flag2 = false; if ((Object)(object)currentPlayer != (Object)null && !currentPlayerModelState.VerifyCosmeticsExist(currentPlayer.playerUsername)) { flag2 = true; } PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController; if (currentPlayer != localPlayerController && !localPlayerModelState.VerifyCosmeticsExist(localPlayerController.playerUsername)) { flag2 = true; } Renderer[] array = currentRenderersToHide; for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] == (Object)null) { Plugin.Instance.Logger.LogError((object)("A mesh attached to non-player target " + ((Object)currentActualTarget).name + " is null, marking dirty.")); flag2 = true; break; } } if (flag2) { UpdateTargetStatus(); } } if (!flag) { ((Behaviour)Camera).enabled = false; return; } if (radarBoosterPanSpeed != 0f) { panAngle = (panAngle + Time.deltaTime * radarBoosterPanSpeed) % 360f; } else { panAngle = 270f; } if (panCamera) { CameraObject.transform.localRotation = Quaternion.Euler(0f, panAngle, 0f); } if (timePerFrame > 0f) { elapsedSinceLastFrame += Time.deltaTime; ((Behaviour)Camera).enabled = elapsedSinceLastFrame >= timePerFrame; elapsedSinceLastFrame %= timePerFrame; } else { ((Behaviour)Camera).enabled = true; } } private void OnDisable() { SetStatus(CameraRenderingStatus.Disabled); UpdateScreenMaterial(); if ((Object)(object)Camera != (Object)null) { ((Behaviour)Camera).enabled = false; } } private void OnEnable() { UpdateScreenMaterial(); } private void OnDestroy() { Object.Destroy((Object)(object)CameraObject); AllBodyCams = AllBodyCams.Where((BodyCamComponent bodyCam) => bodyCam != this).ToArray(); SyncBodyCamToRadarMap.OnBodyCamDestroyed(this); BodyCam.BodyCamDestroyed(this); } private static bool PlayerContainsRenderer(PlayerControllerB player, Renderer renderer) { if ((Object)(object)player == (Object)null) { return false; } if ((Object)(object)player.thisPlayerModelArms == (Object)(object)renderer) { return true; } if ((Object)(object)player.thisPlayerModel == (Object)(object)renderer) { return true; } return false; } public bool HasReference(Renderer renderer) { if (targetDirtyStatus.HasFlag(TargetDirtyStatus.UntilRender)) { return false; } if (targetDirtyStatus.HasFlag(TargetDirtyStatus.Immediate)) { UpdateTargetStatus(); } if (PlayerContainsRenderer(currentPlayer, renderer)) { return true; } if (PlayerContainsRenderer(StartOfRound.Instance?.localPlayerController, renderer)) { return true; } if (Array.IndexOf(currentRenderersToHide, renderer) != -1) { return true; } return false; } public bool HasReference(GameObject gameObject) { if (targetDirtyStatus.HasFlag(TargetDirtyStatus.UntilRender)) { return false; } if (targetDirtyStatus.HasFlag(TargetDirtyStatus.Immediate)) { UpdateTargetStatus(); } if (currentPlayerModelState.ReferencesObject(gameObject)) { return true; } if (localPlayerModelState.ReferencesObject(gameObject)) { return true; } return false; } public static bool AnyBodyCamHasReference(Renderer renderer) { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { if (allBodyCams[i].HasReference(renderer)) { return true; } } return false; } public static bool AnyBodyCamHasReference(GameObject gameObject) { BodyCamComponent[] allBodyCams = AllBodyCams; for (int i = 0; i < allBodyCams.Length; i++) { if (allBodyCams[i].HasReference(gameObject)) { return true; } } return false; } } public enum CameraRenderingStatus { Rendering, Disabled, TargetInvalid, TargetDisabledOnShip } public enum CameraModeOptions { Body, Head } [BepInPlugin("Zaggy1024.OpenBodyCams", "OpenBodyCams", "2.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string MOD_NAME = "OpenBodyCams"; public const string MOD_UNIQUE_NAME = "Zaggy1024.OpenBodyCams"; public const string MOD_VERSION = "2.6.0"; private readonly Harmony harmony = new Harmony("Zaggy1024.OpenBodyCams"); public static ConfigEntry<CameraModeOptions> CameraMode; public static ConfigEntry<int> HorizontalResolution; public static ConfigEntry<float> FieldOfView; public static ConfigEntry<float> RenderDistance; public static ConfigEntry<float> Framerate; public const float NightVisionIntensityBase = 367f; public const float NightVisionRangeBase = 12f; public static ConfigEntry<float> NightVisionBrightness; public static ConfigEntry<string> MonitorEmissiveColor; public static ConfigEntry<FilterMode> MonitorTextureFiltering; public static ConfigEntry<float> RadarBoosterPanRPM; public static ConfigEntry<bool> UseTargetTransitionAnimation; public static ConfigEntry<bool> DisableCameraWhileTargetIsOnShip; public static ConfigEntry<bool> EnableCamera; public static ConfigEntry<bool> DisplayOriginalScreenWhenDisabled; public static ConfigEntry<bool> OverlayEnabled; public static ConfigEntry<float> OverlayTextScale; public static ConfigEntry<string> DefaultText; public static ConfigEntry<string> BuyAntennaText; public static ConfigEntry<string> AntennaStoredText; public static ConfigEntry<string> TargetInvalidText; public static ConfigEntry<string> TargetOnShipText; public static ConfigEntry<bool> TerminalPiPBodyCamEnabled; public static ConfigEntry<PiPPosition> TerminalPiPPosition; public static ConfigEntry<int> TerminalPiPWidth; public static ConfigEntry<bool> ShipUpgradeEnabled; public static ConfigEntry<int> ShipUpgradePrice; public static ConfigEntry<int> GeneralImprovementsBetterMonitorIndex; public static ConfigEntry<bool> EnableMoreCompanyCosmeticsCompatibility; public static ConfigEntry<bool> EnableAdvancedCompanyCosmeticsCompatibility; public static ConfigEntry<bool> EnableModelReplacementAPICompatibility; public static ConfigEntry<bool> EnableLethalVRMCompatibility; public static ConfigEntry<bool> EnableReservedItemSlotsCompatibility; public static ConfigEntry<bool> SwapInternalAndExternalShipCameras; public static ConfigEntry<bool> DisableCameraOnSmallMonitor; public static ConfigEntry<string> ExternalCameraEmissiveColor; public static ConfigEntry<bool> FixDroppedItemRotation; public static ConfigEntry<bool> FixMaskedConversionForClients; public static ConfigEntry<bool> PrintCosmeticsDebugInfo; public static ConfigEntry<bool> BruteForcePreventFreezes; public static ConfigEntry<bool> ReferencedObjectDestructionDetectionEnabled; public static ConfigEntry<string> LastConfigVersion; internal static bool DisplayBodyCamUpgradeTip = false; private static readonly Harmony DestructionDetectionPatch = new Harmony("Zaggy1024.OpenBodyCams.DestructionDetectionPatch"); internal static AssetBundle Assets; private const string OptionDisabledWithBetterMonitors = "This has no effect when GeneralImprovements's UseBetterMonitors option is enabled."; public static Plugin Instance { get; private set; } public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0739: Unknown result type (might be due to invalid IL or missing references) //IL_0743: Expected O, but got Unknown Instance = this; Assets = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "openbodycams")); if ((Object)(object)Assets != (Object)null) { Instance.Logger.LogInfo((object)"Successfully loaded OpenBodyCams assets."); } else { Instance.Logger.LogError((object)"Failed to load the asset bundle, some features may be missing."); } CameraMode = ((BaseUnityPlugin)this).Config.Bind<CameraModeOptions>("Camera", "Mode", CameraModeOptions.Head, "Choose where to attach the camera. 'Head' will attach the camera to the right side of the head, 'Body' will attach it to the chest."); HorizontalResolution = ((BaseUnityPlugin)this).Config.Bind<int>("Camera", "HorizontalResolution", 160, "The horizontal resolution of the rendering. The vertical resolution is calculated based on the aspect ratio of the monitor."); FieldOfView = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "FieldOfView", 65f, "The vertical FOV of the camera in degrees."); RenderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "RenderDistance", 25f, "The far clip plane for the body cam. Lowering may improve framerates."); Framerate = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "Framerate", 0f, "The number of frames to render per second. A value of 0 will render at the game's framerate. Setting this significantly below the average framerate on the ship will improve performance."); NightVisionBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "NightVisionBrightness", 1f, "A multiplier for the intensity of the area light used to brighten dark areas. A value of 1 is identical to the player's actual vision."); MonitorEmissiveColor = ((BaseUnityPlugin)this).Config.Bind<string>("Camera", "MonitorEmissiveColor", "0.05, 0.13, 0.05", "Adjust the color that is emitted from the body cam monitor, using comma-separated decimal numbers for red, green and blue."); MonitorTextureFiltering = ((BaseUnityPlugin)this).Config.Bind<FilterMode>("Camera", "MonitorTextureFiltering", (FilterMode)1, "The texture filtering to use for the body cam on the monitor. Bilinear and Trilinear will result in a smooth image, while Point will result in sharp square edges. If Point is used, a fairly high resolution is recommended."); RadarBoosterPanRPM = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "RadarBoosterPanRPM", 9f, "The rotations per minute to turn the camera when a radar booster is selected. If the value is set to 0, the radar booster camera will face in the direction player faces when it is placed."); UseTargetTransitionAnimation = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "UseTargetTransitionAnimation", true, "Enables a green flash animation on the body cam screen mirroring the one that the radar map shows when switching targets."); DisableCameraWhileTargetIsOnShip = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "DisableCameraWhileTargetIsOnShip", false, "With this option enabled, the camera will stop rendering when the target is onboard the ship to reduce the performance hit of rendering a large number of items on the ship twice."); EnableCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableCamera", true, "Enables/disables rendering of the body cam, and can be enabled/disabled during a game with LethalConfig."); DisplayOriginalScreenWhenDisabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "DisplayOriginalScreenWhenDisabled", true, "When enabled, the screen that the body cam replaces will be displayed when it is disabled due to invalid targets."); CameraMode.SettingChanged += delegate { BodyCamComponent.MarkTargetStatusChangedForAllBodyCams(); }; FieldOfView.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; RenderDistance.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; NightVisionBrightness.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; MonitorTextureFiltering.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; RadarBoosterPanRPM.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; DisableCameraWhileTargetIsOnShip.SettingChanged += delegate { BodyCamComponent.UpdateAllCameraSettings(); }; DisplayOriginalScreenWhenDisabled.SettingChanged += delegate { ShipObjects.UpdateMainBodyCamNoTargetMaterial(); }; HorizontalResolution.SettingChanged += delegate { ShipObjects.UpdateMainBodyCamSettings(); }; Framerate.SettingChanged += delegate { ShipObjects.UpdateMainBodyCamSettings(); }; MonitorEmissiveColor.SettingChanged += delegate { ShipObjects.UpdateMainBodyCamSettings(); }; EnableCamera.SettingChanged += delegate { ShipObjects.UpdateMainBodyCamSettings(); }; OverlayEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Overlay", "Enabled", true, "Displays an overlay on the monitor that the body cam replaces to communicate the status of the body cam. This will only work if the screen is displaying a render texture connected to a camera. Restart the lobby to apply."); OverlayTextScale = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "TextScale", 1f, "The factor by which to scale the text on the overlay screen."); DefaultText = ((BaseUnityPlugin)this).Config.Bind<string>("Overlay", "DefaultText", "", "The text displayed on the body cam monitor when it is operating normally."); BuyAntennaText = ((BaseUnityPlugin)this).Config.Bind<string>("Overlay", "BuyAntennaText", "<color=\"yellow\">Body cam ${price}", "The text displayed on the body cam monitor to prompt players to buy the antenna in the store to enable body cams."); AntennaStoredText = ((BaseUnityPlugin)this).Config.Bind<string>("Overlay", "AntennaStoredText", "<color=\"yellow\">Antenna stored", "The text displayed when the antenna is stored, preventing the body cams displaying on the monitor."); TargetInvalidText = ((BaseUnityPlugin)this).Config.Bind<string>("Overlay", "TargetInvalidText", "<color=\"red\">Signal lost", "The text displayed when the selected target is invalid (for example, the target is a player that has been eaten)."); TargetOnShipText = ((BaseUnityPlugin)this).Config.Bind<string>("Overlay", "TargetOnShipText", "<color=\"green\">Target on ship", "The text displayed when the selected target is safe on the ship with DisableCameraWhileTargetIsOnShip enabled."); OverlayTextScale.SettingChanged += UpdateOverlayPrefs; DefaultText.SettingChanged += UpdateOverlayText; BuyAntennaText.SettingChanged += UpdateOverlayText; AntennaStoredText.SettingChanged += UpdateOverlayText; TargetInvalidText.SettingChanged += UpdateOverlayText; TargetOnShipText.SettingChanged += UpdateOverlayText; TerminalPiPBodyCamEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Terminal", "EnablePiPBodyCam", false, "Adds a 'view bodycam' command to the terminal that places a picture-in-picture view of the bodycam in front of the radar map."); TerminalPiPPosition = ((BaseUnityPlugin)this).Config.Bind<PiPPosition>("Terminal", "PiPPosition", PiPPosition.BottomRight, "The corner inside the terminal's radar map to align the body cam to."); TerminalPiPWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Terminal", "PiPWidth", 150, "The width of the picture-in-picture in pixels."); TerminalPiPBodyCamEnabled.SettingChanged += delegate { TerminalCommands.Initialize(); }; TerminalPiPPosition.SettingChanged += delegate { TerminalCommands.Initialize(); }; TerminalPiPWidth.SettingChanged += delegate { TerminalCommands.Initialize(); }; harmony.PatchAll(typeof(TerminalCommands)); ShipUpgradeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("ShipUpgrade", "Enabled", true, "Adds a ship upgrade that enables the body cam on the main monitors only after it is bought.\n\nNOTE: The upgrade will only be available if LethalLib is installed. Without it, the main body cam will always be enabled."); ShipUpgradePrice = ((BaseUnityPlugin)this).Config.Bind<int>("ShipUpgrade", "Price", 200, "The price at which the ship upgrade is sold in the store."); GeneralImprovementsBetterMonitorIndex = ((BaseUnityPlugin)this).Config.Bind<int>("Compatibility", "GeneralImprovementsBetterMonitorIndex", 0, new ConfigDescription("With GeneralImprovements's UseBetterMonitors enabled, choose which monitor to display the body cam on.\nA value of 0 will place it on the large monitor on the right.\nValues greater than 0 go left to right, top to bottom, skipping the large center monitor. Without AddMoreBetterMonitors, the maximum value is 9, rather than 14.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 14), Array.Empty<object>())); EnableMoreCompanyCosmeticsCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableMoreCompanyCosmeticsCompatibility", true, "If this is enabled, a patch will be applied to MoreCompany to spawn cosmetics for the local player, and all cosmetics will be shown and hidden based on the camera's perspective."); EnableAdvancedCompanyCosmeticsCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableAdvancedCompanyCosmeticsCompatibility", true, "When this is enabled and AdvancedCompany is installed, all cosmetics will be shown and hidden based on the camera's perspective."); EnableModelReplacementAPICompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableModelReplacementAPICompatibility", true, "When enabled, this will get the third person model replacement and hide/show it based on the camera's perspective."); EnableLethalVRMCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableLethalVRMCompatibility", true, "When enabled, any VRM model will be hidden/shown based on the camera's perspective."); EnableReservedItemSlotsCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableReservedItemSlotsCompatibility", true, "When enabled, items holstered in reserved item slots will be hidden/shown based on the perspective."); SwapInternalAndExternalShipCameras = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship", "SwapInternalAndExternalShipCameras", false, "Causes the internal ship camera to be placed onto big monitor, and the external one to be placed onto the small monitor. This has no effect when GeneralImprovements's UseBetterMonitors option is enabled."); DisableCameraOnSmallMonitor = ((BaseUnityPlugin)this).Config.Bind<bool>("Ship", "DisableCameraOnSmallMonitor", false, "Disables whichever camera is placed onto the small camera monitor. This has no effect when GeneralImprovements's UseBetterMonitors option is enabled."); ExternalCameraEmissiveColor = ((BaseUnityPlugin)this).Config.Bind<string>("Ship", "ExternalCameraEmissiveColor", "", "Sets the color emitted by the external camera screen, using comma-separated decimal numbers for red, green and blue."); ExternalCameraEmissiveColor.SettingChanged += delegate { ShipObjects.SetExternalCameraEmissiveColor(); }; FixDroppedItemRotation = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "FixDroppedItemRotation", true, "If enabled, the mod will patch a bug that causes the rotation of dropped items to be desynced between clients."); FixMaskedConversionForClients = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "FixMaskedConversionForClients", true, "If enabled, the mod will patch a bug that causes maps and body cams to be unable to target a player that was converted into a masked enemy."); PrintCosmeticsDebugInfo = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "PrintCosmeticsDebugInfo", false, "Prints extra information about the cosmetics being collected for each player, as well as the code that is causing the collection."); BruteForcePreventFreezes = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "BruteForcePreventFreezes", false, "Enable a brute force approach to preventing errors in the camera setup callback that can cause the screen to freeze."); ReferencedObjectDestructionDetectionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ModelDestructionDebuggingPatchEnabled", false, "Enable this option when reproducing a camera freeze. This will cause a debug message to be printed when a model that a body cam is tracking is destroyed."); LastConfigVersion = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "LastConfigVersion", "", "The last version of the mod that loaded/saved this config file. Used for setting migration."); PrintCosmeticsDebugInfo.SettingChanged += delegate { Cosmetics.PrintDebugInfo = PrintCosmeticsDebugInfo.Value; }; Cosmetics.PrintDebugInfo = PrintCosmeticsDebugInfo.Value; BruteForcePreventFreezes.SettingChanged += delegate { BodyCamComponent.UpdateStaticSettings(); }; ReferencedObjectDestructionDetectionEnabled.SettingChanged += delegate { UpdateReferencedObjectDestructionDetectionEnabled(); }; UpdateReferencedObjectDestructionDetectionEnabled(); MigrateSettings(); harmony.PatchAll(typeof(PatchTerminal)); harmony.PatchAll(typeof(PatchStartOfRound)); harmony.PatchAll(typeof(PatchManualCameraRenderer)); harmony.PatchAll(typeof(PatchPlayerControllerB)); harmony.PatchAll(typeof(PatchHauntedMaskItem)); harmony.PatchAll(typeof(PatchMaskedPlayerEnemy)); harmony.PatchAll(typeof(PatchUnlockableSuit)); harmony.PatchAll(typeof(PatchCentipedeAI)); harmony.PatchAll(typeof(PatchFlowerSnakeEnemy)); harmony.PatchAll(typeof(PatchHDRenderPipeline)); harmony.PatchAll(typeof(PatchFixItemDropping)); BodyCamComponent.InitializeStatic(); ShipUpgrades.Initialize(); Cosmetics.Initialize(harmony); static void UpdateOverlayPrefs(object target, EventArgs args) { if ((Object)(object)ShipObjects.Overlay != (Object)null) { ShipObjects.Overlay.UpdatePreferences(); } } static void UpdateOverlayText(object target, EventArgs args) { if ((Object)(object)ShipObjects.Overlay != (Object)null) { ShipObjects.Overlay.UpdateText(); } } } private void UpdateReferencedObjectDestructionDetectionEnabled() { if (ReferencedObjectDestructionDetectionEnabled.Value) { DestructionDetectionPatch.PatchAll(typeof(PatchModelDestructionDebugging)); } else { DestructionDetectionPatch.UnpatchSelf(); } } private void MigrateSettings() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown Dictionary<ConfigDefinition, string> orphanedEntries; try { orphanedEntries = ((BaseUnityPlugin)this).Config.OrphanedEntries; } catch (MissingFieldException) { Logger.LogError((object)"Failed to migrate config, orphaned entries property was not found."); return; } if (!Version.TryParse(LastConfigVersion.Value, out Version result)) { result = new Version(2, 0, 0); } Logger.LogInfo((object)$"Last config version is {result}."); ConfigDefinition val = new ConfigDefinition("Misc", "DisableInternalShipCamera"); if (orphanedEntries.TryGetValue(val, out var value)) { Logger.LogInfo((object)$"{val} option was found set to '{value}' in the config, migrating it over to {((ConfigEntryBase)DisableCameraOnSmallMonitor).Definition}."); orphanedEntries.Remove(val); DisableCameraOnSmallMonitor.Value = TomlTypeConverter.ConvertToValue<bool>(value); } if (result < new Version(2, 0, 2) && !ShipUpgradeEnabled.Value) { Logger.LogInfo((object)$"{((ConfigEntryBase)ShipUpgradeEnabled).Definition} was set to its 2.0.0 default value 'false', resetting it to 'true'."); ShipUpgradeEnabled.Value = true; } if (result < new Version(2, 0, 4)) { DisplayBodyCamUpgradeTip = true; } LastConfigVersion.Value = "2.6.0"; } private static Color ParseColor(string str) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) float[] array = (from x in str.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) select float.Parse(x.Trim(), CultureInfo.InvariantCulture)).ToArray(); if (array.Length < 3) { throw new FormatException("Not enough color components"); } if (array.Length > 4) { throw new FormatException("Too many color components"); } return new Color(array[0], array[1], array[2], (array.Length == 4) ? array[3] : 0f); } internal static Color GetBodyCamEmissiveColor() { //IL_000a: 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_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_0044: Unknown result type (might be due to invalid IL or missing references) try { return ParseColor(MonitorEmissiveColor.Value); } catch (Exception arg) { Instance.Logger.LogWarning((object)$"Failed to parse the body cam screen's emissive color: {arg}"); return ParseColor((string)((ConfigEntryBase)MonitorEmissiveColor).DefaultValue); } } internal static Color? GetExternalCameraEmissiveColor() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (ExternalCameraEmissiveColor.Value == "") { return null; } try { return ParseColor(ExternalCameraEmissiveColor.Value); } catch (Exception arg) { Instance.Logger.LogWarning((object)$"Failed to parse the external camera screen's emissive color: {arg}"); return null; } } } public static class ShipObjects { internal static Material BlackScreenMaterial; internal static Terminal TerminalScript; internal static bool TwoRadarCamsPresent; internal static BodyCamComponent MainBodyCam; internal static OverlayManager Overlay; internal static ManualCameraRenderer InternalCameraRenderer; internal static ManualCameraRenderer ExternalCameraRenderer; internal static Material ExternalCameraMaterial; internal static Color OriginalExternalCameraEmissiveColor; internal static MeshRenderer DoorScreenRenderer; internal static bool DoorScreenUsesExternalCamera; internal static ManualCameraRenderer ShipCameraOnSmallMonitor; internal static ManualCameraRenderer CameraReplacedByBodyCam; public static void EarlyInitialization() { //IL_00b8: 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) if (HasFinishedEarlyInitialization()) { return; } BlackScreenMaterial = StartOfRound.Instance.mapScreen.offScreenMat; GameObject obj = GameObject.Find("Environment/HangarShip/Cameras/ShipCamera"); InternalCameraRenderer = ((obj != null) ? obj.GetComponent<ManualCameraRenderer>() : null); GameObject obj2 = GameObject.Find("Environment/HangarShip/Cameras/FrontDoorSecurityCam/SecurityCamera"); ExternalCameraRenderer = ((obj2 != null) ? obj2.GetComponent<ManualCameraRenderer>() : null); GameObject obj3 = GameObject.Find("Environment/HangarShip/ShipModels2b/MonitorWall/SingleScreen"); DoorScreenRenderer = ((obj3 != null) ? obj3.GetComponent<MeshRenderer>() : null); ShipCameraOnSmallMonitor = InternalCameraRenderer; BodyCamComponent.InitializeAtStartOfGame(); if ((Object)(object)ExternalCameraRenderer != (Object)null) { int cameraMaterialIndex = GetCameraMaterialIndex(ExternalCameraRenderer); if (cameraMaterialIndex != -1) { ExternalCameraMaterial = ((Renderer)ExternalCameraRenderer.mesh).sharedMaterials[cameraMaterialIndex]; OriginalExternalCameraEmissiveColor = ExternalCameraMaterial.GetColor("_EmissiveColor"); SetExternalCameraEmissiveColor(); } } } private static bool HasFinishedEarlyInitialization() { return (Object)(object)ShipCameraOnSmallMonitor != (Object)null; } internal static void SetExternalCameraEmissiveColor() { //IL_0008: 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_0022: Unknown result type (might be due to invalid IL or missing references) Color valueOrDefault = Plugin.GetExternalCameraEmissiveColor().GetValueOrDefault(OriginalExternalCameraEmissiveColor); Material externalCameraMaterial = ExternalCameraMaterial; if (externalCameraMaterial != null) { externalCameraMaterial.SetColor("_EmissiveColor", valueOrDefault); } } public static void LateInitialization() { ManageShipCameras(); TwoRadarCamsPresent = (Object)(object)((Component)TerminalScript).GetComponent<ManualCameraRenderer>() != (Object)null; if ((Object)(object)DoorScreenRenderer != (Object)null && (Object)(object)ExternalCameraRenderer?.cam != (Object)null) { DoorScreenUsesExternalCamera = ((Renderer)DoorScreenRenderer).sharedMaterials.Any((Material mat) => (Object)(object)mat.mainTexture == (Object)(object)ExternalCameraRenderer.cam.targetTexture); } InitializeBodyCam(); TerminalCommands.Initialize(); if (!TwoRadarCamsPresent && ((NetworkBehaviour)StartOfRound.Instance).IsServer) { ManualCameraRenderer mapScreen = StartOfRound.Instance.mapScreen; mapScreen.SwitchRadarTargetAndSync(Math.Min(mapScreen.targetTransformIndex, mapScreen.radarTargets.Count - 1)); } } private static void ManageShipCameras() { if (!GeneralImprovementsCompatibility.BetterMonitorsEnabled) { if (Plugin.SwapInternalAndExternalShipCameras.Value) { SwapShipCameras(); } if (Plugin.DisableCameraOnSmallMonitor.Value) { DisableCameraOnSmallMonitor(); } } } private static int GetCameraMaterialIndex(ManualCameraRenderer shipCamera) { if ((Object)(object)shipCamera == (Object)null) { return -1; } if ((Object)(object)shipCamera.mesh == (Object)null) { return -1; } Camera val = shipCamera.cam; if ((Object)(object)val == (Object)null) { val = ((Component)shipCamera).GetComponent<Camera>(); } RenderTexture texture = val.targetTexture; return Array.FindIndex(((Renderer)shipCamera.mesh).sharedMaterials, (Material material) => (Object)(object)material.mainTexture == (Object)(object)texture); } private static void SwapShipCameras() { int cameraMaterialIndex = GetCameraMaterialIndex(InternalCameraRenderer); int cameraMaterialIndex2 = GetCameraMaterialIndex(ExternalCameraRenderer); if (cameraMaterialIndex == -1 || cameraMaterialIndex2 == -1) { Plugin.Instance.Logger.LogError((object)$"{((ConfigEntryBase)Plugin.SwapInternalAndExternalShipCameras).Definition} is enabled, but one of the ship's cameras' materials was not found."); return; } Material material = ((Renderer)InternalCameraRenderer.mesh).sharedMaterials[cameraMaterialIndex]; ((Renderer)(object)InternalCameraRenderer.mesh).SetMaterial(cameraMaterialIndex, ((Renderer)ExternalCameraRenderer.mesh).sharedMaterials[cameraMaterialIndex2]); ((Renderer)(object)ExternalCameraRenderer.mesh).SetMaterial(cameraMaterialIndex2, material); ManualCameraRenderer internalCameraRenderer = InternalCameraRenderer; ManualCameraRenderer externalCameraRenderer = ExternalCameraRenderer; MeshRenderer mesh = ExternalCameraRenderer.mesh; MeshRenderer mesh2 = InternalCameraRenderer.mesh; internalCameraRenderer.mesh = mesh; externalCameraRenderer.mesh = mesh2; ShipCameraOnSmallMonitor = ExternalCameraRenderer; } private static void DisableCameraOnSmallMonitor() { int cameraMaterialIndex = GetCameraMaterialIndex(ShipCameraOnSmallMonitor); if (cameraMaterialIndex == -1) { Plugin.Instance.Logger.LogError((object)$"{((ConfigEntryBase)Plugin.DisableCameraOnSmallMonitor).Definition} is enabled, but the small monitor's camera material was not found."); return; } ((Renderer)(object)ShipCameraOnSmallMonitor.mesh).SetMaterial(cameraMaterialIndex, BlackScreenMaterial); ((Behaviour)ShipCameraOnSmallMonitor.cam).enabled = false; ((Behaviour)ShipCameraOnSmallMonitor).enabled = false; } private static void InitializeBodyCam() { GameObject val = GameObject.Find("Environment/HangarShip/ShipModels2b/MonitorWall/Cube.001"); if ((Object)(object)val == (Object)null) { Plugin.Instance.Logger.LogError((object)"Could not find the bottom monitors' game object."); return; } if ((Object)(object)val.GetComponent<BodyCamComponent>() == (Object)null) { MainBodyCam = val.AddComponent<BodyCamComponent>(); val.AddComponent<SyncBodyCamToRadarMap>(); if (!GeneralImprovementsCompatibility.BetterMonitorsEnabled) { MainBodyCam.MonitorRenderer = (Renderer)(object)val.GetComponent<MeshRenderer>(); MainBodyCam.MonitorMaterialIndex = 2; MainBodyCam.MonitorDisabledMaterial = MainBodyCam.MonitorRenderer.sharedMaterials[MainBodyCam.MonitorMaterialIndex]; } else { GeneralImprovementsCompatibility.GeneralImprovementsMonitorSpecification? monitorForID = GeneralImprovementsCompatibility.GetMonitorForID(Plugin.GeneralImprovementsBetterMonitorIndex.Value - 1); if (monitorForID.HasValue) { MainBodyCam.MonitorRenderer = monitorForID.Value.Renderer; MainBodyCam.MonitorMaterialIndex = monitorForID.Value.MaterialIndex; MainBodyCam.MonitorDisabledMaterial = monitorForID.Value.OriginalMaterial; } } if ((Object)(object)MainBodyCam.MonitorRenderer == (Object)null) { Plugin.Instance.Logger.LogError((object)"Failed to find the monitor renderer."); Object.DestroyImmediate((Object)(object)MainBodyCam); return; } if ((Object)(object)MainBodyCam.MonitorDisabledMaterial == (Object)null) { MainBodyCam.MonitorDisabledMaterial = BlackScreenMaterial; } UpdateMainBodyCamNoTargetMaterial(); if (ShipUpgrades.BodyCamUnlockable != null) { ((Behaviour)MainBodyCam).enabled = ShipUpgrades.BodyCamUnlockableIsPlaced; } else { BodyCam.BodyCamReceiverBecameEnabled(); } CameraReplacedByBodyCam = null; Texture mainTexture = MainBodyCam.MonitorDisabledMaterial.mainTexture; RenderTexture val2 = (RenderTexture)(object)((mainTexture is RenderTexture) ? mainTexture : null); if (val2 != null) { ManualCameraRenderer internalCameraRenderer = InternalCameraRenderer; object obj; if (internalCameraRenderer == null) { obj = null; } else { Camera cam = internalCameraRenderer.cam; obj = ((cam != null) ? cam.targetTexture : null); } if ((Object)(object)val2 == (Object)obj) { CameraReplacedByBodyCam = InternalCameraRenderer; } else { ManualCameraRenderer externalCameraRenderer = ExternalCameraRenderer; object obj2; if (externalCameraRenderer == null) { obj2 = null; } else { Camera cam2 = externalCameraRenderer.cam; obj2 = ((cam2 != null) ? cam2.targetTexture : null); } if ((Object)(object)val2 == (Object)obj2) { CameraReplacedByBodyCam = ExternalCameraRenderer; } } } } UpdateMainBodyCamSettings(); InitializeMainBodyCamOverlay(); } private static void InitializeMainBodyCamOverlay() { if (!((Object)(object)Plugin.Assets == (Object)null) && Plugin.OverlayEnabled.Value) { GameObject obj = Object.Instantiate<GameObject>(Plugin.Assets.LoadAsset<GameObject>("Assets/OpenBodyCams/Prefabs/BodyCamOverlayCanvas.prefab")); obj.transform.SetParent(GameObject.Find("Systems/UI").transform, false); Overlay = obj.AddComponent<OverlayManager>(); Overlay.BodyCam = MainBodyCam; } } internal static void UpdateMainBodyCamNoTargetMaterial() { if (Plugin.DisplayOriginalScreenWhenDisabled.Value) { MainBodyCam.MonitorNoTargetMaterial = MainBodyCam.MonitorDisabledMaterial; } else { MainBodyCam.MonitorNoTargetMaterial = null; } MainBodyCam.UpdateScreenMaterial(); } internal static void UpdateMainBodyCamSettings() { //IL_002b: 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) if (!((Object)(object)MainBodyCam == (Object)null)) { MainBodyCam.Resolution = new Vector2Int(Plugin.HorizontalResolution.Value, Plugin.HorizontalResolution.Value * 3 / 4); MainBodyCam.Framerate = Plugin.Framerate.Value; MainBodyCam.EnableCamera = Plugin.EnableCamera.Value; MainBodyCam.UpdateScreenMaterial(); MainBodyCam.MonitorOnMaterial.SetColor("_EmissiveColor", Plugin.GetBodyCamEmissiveColor()); } } } internal static class ShipUpgrades { internal static UnlockableItem BodyCamUnlockable; internal static int BodyCamPrice; internal static bool BodyCamUnlockableIsPlaced; public static void Initialize() { if (!Chainloader.PluginInfos.ContainsKey("evaisa.lethallib")) { Plugin.Instance.Logger.LogInfo((object)"LethalLib is not present, body cam will be enabled by default."); } else { RegisterUnlockables(); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RegisterUnlockables() { RegisterBodyCamShipUpgrade(); } private static void RegisterBodyCamShipUpgrade() { //IL_0050: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00a8: Expected O, but got Unknown if (!((Object)(object)Plugin.Assets == (Object)null) && Plugin.ShipUpgradeEnabled.Value) { GameObject val = Plugin.Assets.LoadAsset<GameObject>("Assets/OpenBodyCams/Prefabs/BodyCamAntenna.prefab"); if ((Object)(object)val == (Object)null) { Plugin.Instance.Logger.LogInfo((object)"Body cam antenna prop was not found within the asset bundle."); return; } val.AddComponent<EnableMainBodyCam>(); UnlockableItem val2 = new UnlockableItem { unlockableName = "Bodycam", unlockableType = 1, prefabObject = val, IsPlaceable = true, alwaysInStock = true }; BodyCamPrice = Plugin.ShipUpgradePrice.Value; Unlockables.RegisterUnlockable(val2, BodyCamPrice, (StoreType)1); NetworkPrefabs.RegisterNetworkPrefab(val); Utilities.FixMixerGroups(val); BodyCamUnlockable = val2; Plugin.Instance.Logger.LogInfo((object)$"Registered body cam unlockable for {BodyCamPrice} credits."); } } } internal class EnableMainBodyCam : MonoBehaviour { private void OnEnable() { ShipUpgrades.BodyCamUnlockableIsPlaced = true; BodyCam.BodyCamReceiverBecameEnabled(); if (!((Object)(object)ShipObjects.MainBodyCam == (Object)null)) { ((Behaviour)ShipObjects.MainBodyCam).enabled = true; } } private void OnDisable() { ShipUpgrades.BodyCamUnlockableIsPlaced = false; BodyCam.BodyCamReceiverBecameDisabled(); if (!((Object)(object)ShipObjects.MainBodyCam == (Object)null)) { ((Behaviour)ShipObjects.MainBodyCam).enabled = false; } } } public class SyncBodyCamToRadarMap : MonoBehaviour { private static SyncBodyCamToRadarMap[] AllSynchronizedCams = new SyncBodyCamToRadarMap[0]; internal ManualCameraRenderer MapRenderer; internal BodyCamComponent BodyCam; public static SyncBodyCamToRadarMap[] GetAllSynchronizedCams() { return AllSynchronizedCams; } public ManualCameraRenderer GetMapRenderer() { return MapRenderer; } public BodyCamComponent GetBodyCam() { return BodyCam; } private static void DoForMap(ManualCameraRenderer mapRenderer, Action<SyncBodyCamToRadarMap> action) { SyncBodyCamToRadarMap[] allSynchronizedCams = AllSynchronizedCams; foreach (SyncBodyCamToRadarMap syncBodyCamToRadarMap in allSynchronizedCams) { if (syncBodyCamToRadarMap.MapRenderer == mapRenderer) { action(syncBodyCamToRadarMap); } } } public static void UpdateBodyCamTargetForMap(ManualCameraRenderer mapRenderer) { DoForMap(mapRenderer, delegate(SyncBodyCamToRadarMap syncedCam) { syncedCam.UpdateBodyCamTarget(); }); } public static void StartTargetTransitionForMap(ManualCameraRenderer mapRenderer) { DoForMap(mapRenderer, delegate(SyncBodyCamToRadarMap syncedCam) { syncedCam.StartTargetTransition(); }); } private static void DoForCam(BodyCamComponent bodyCam, Action<SyncBodyCamToRadarMap> action) { SyncBodyCamToRadarMap[] allSynchronizedCams = AllSynchronizedCams; foreach (SyncBodyCamToRadarMap syncBodyCamToRadarMap in allSynchronizedCams) { if (syncBodyCamToRadarMap.BodyCam == bodyCam) { action(syncBodyCamToRadarMap); } } } public static void UpdateBodyCamTarget(BodyCamComponent bodyCam) { DoForCam(bodyCam, delegate(SyncBodyCamToRadarMap syncedCam) { syncedCam.UpdateBodyCamTarget(); }); } private void Awake() { SyncBodyCamToRadarMap[] allSynchronizedCams = AllSynchronizedCams; int num = 0; SyncBodyCamToRadarMap[] array = new SyncBodyCamToRadarMap[1 + allSynchronizedCams.Length]; ReadOnlySpan<SyncBodyCamToRadarMap> readOnlySpan = new ReadOnlySpan<SyncBodyCamToRadarMap>(allSynchronizedCams); readOnlySpan.CopyTo(new Span<SyncBodyCamToRadarMap>(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array[num] = this; num++; AllSynchronizedCams = array; if ((Object)(object)MapRenderer == (Object)null) { MapRenderer = ((Component)this).GetComponentsInChildren<ManualCameraRenderer>()?.FirstOrDefault((Func<ManualCameraRenderer, bool>)((ManualCameraRenderer renderer) => (Object)(object)renderer.cam == (Object)(object)renderer.mapCamera)); } if ((Object)(object)BodyCam == (Object)null) { BodyCam = ((Component)this).GetComponent<BodyCamComponent>(); } } private void Start() { UpdateBodyCamTarget(); } private void OnEnable() { if ((Object)(object)BodyCam != (Object)null && (Object)(object)MapRenderer != (Object)null) { UpdateBodyCamTarget(); } } public void UpdateBodyCamTarget() { if (((Behaviour)this).isActiveAndEnabled) { if ((Object)(object)MapRenderer.targetedPlayer != (Object)null) { BodyCam.SetTargetToPlayer(MapRenderer.targetedPlayer); } else { BodyCam.SetTargetToTransform(MapRenderer.radarTargets[MapRenderer.targetTransformIndex].transform); } BodyCam.SetScreenPowered(MapRenderer.isScreenOn); } } public void StartTargetTransition() { if (((Behaviour)this).isActiveAndEnabled) { BodyCam.StartTargetTransition(); } } internal static void OnBodyCamDestroyed(BodyCamComponent bodyCam) { DoForCam(bodyCam, (Action<SyncBodyCamToRadarMap>)Object.Destroy); } private void OnDestroy() { List<SyncBodyCamToRadarMap> list = new List<SyncBodyCamToRadarMap>(); list.AddRange(AllSynchronizedCams.Where((SyncBodyCamToRadarMap syncedCam) => syncedCam != this)); AllSynchronizedCams = list.ToArray(); } } public static class TerminalCommands { private static TerminalNode ViewMonitorNode; private static TerminalNode ViewBodyCamNode; private static TerminalKeyword BodyCamKeyword; private static TerminalNode BodyCamFailedNode; private static TerminalNode BodyCamLockedNode; private static RawImage PiPImage; private static readonly List<TerminalKeyword> newTerminalKeywords = new List<TerminalKeyword>(); private static readonly Dictionary<TerminalKeyword, List<TerminalKeyword>> addedCompatibleNouns = new Dictionary<TerminalKeyword, List<TerminalKeyword>>(); public static void Initialize() { //IL_00bb: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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_01a5: 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_01f2: 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_01f8: 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_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ShipObjects.TerminalScript == (Object)null || (Object)(object)ShipObjects.MainBodyCam == (Object)null) { return; } if ((Object)(object)PiPImage != (Object)null) { Object.Destroy((Object)(object)((Component)PiPImage).gameObject); } PiPImage = null; ShipObjects.MainBodyCam.OnRenderTextureCreated -= SetRenderTexture; ShipObjects.MainBodyCam.OnBlankedSet -= SetBodyCamBlanked; BodyCam.OnBodyCamReceiverBecameDisabled -= DisablePiPImage; if (Plugin.TerminalPiPBodyCamEnabled.Value) { GameObject val = new GameObject("PictureInPictureImage"); val.transform.SetParent(((Component)ShipObjects.TerminalScript.terminalImageMask).transform, false); PiPImage = val.AddComponent<RawImage>(); val.AddComponent<TerminalBodyCamVisibilityTracker>().BodyCamToActivate = ShipObjects.MainBodyCam; RectTransform rectTransform = ((Graphic)ShipObjects.TerminalScript.terminalImage).rectTransform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 0f); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(1f, 1f); int value = (int)Plugin.TerminalPiPPosition.Value; ref float x = ref val2.x; ref float x2 = ref val3.x; (float, int) tuple = ((((uint)value & (true ? 1u : 0u)) != 0) ? (rectTransform.offsetMax.x, -1) : (rectTransform.offsetMin.x, 1)); (float, int) tuple2 = tuple; float num = tuple2.Item2; x = tuple2.Item1; x2 = num; ref float y = ref val2.y; x2 = ref val3.y; (float, int) tuple3 = ((((uint)value & 2u) != 0) ? (rectTransform.offsetMax.y, -1) : (rectTransform.offsetMin.y, 1)); (float, int) tuple4 = tuple3; num = tuple4.Item2; y = tuple4.Item1; x2 = num; Vector2 val4 = val2 + new Vector2(1f, 0.75f) * val3 * (float)Plugin.TerminalPiPWidth.Value; ((Graphic)PiPImage).rectTransform.offsetMin = Vector2.Min(val2, val4); ((Graphic)PiPImage).rectTransform.offsetMax = Vector2.Max(val2, val4); if ((Object)(object)ShipObjects.MainBodyCam.Camera != (Object)null) { PiPImage.texture = (Texture)(object)ShipObjects.MainBodyCam.Camera.targetTexture; } ShipObjects.MainBodyCam.OnRenderTextureCreated += SetRenderTexture; ShipObjects.MainBodyCam.OnBlankedSet += SetBodyCamBlanked; BodyCam.OnBodyCamReceiverBecameDisabled += DisablePiPImage; val.SetActive(false); } InitializeCommands(); } public static void SetRenderTexture(RenderTexture texture) { PiPImage.texture = (Texture)(object)texture; } public static void SetBodyCamBlanked(bool blanked) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) ((Graphic)PiPImage).color = (blanked ? Color.black : Color.white); } private static void DisablePiPImage() { ((Component)PiPImage).gameObject.SetActive(false); } private static void EnablePiPImage() { ((Component)PiPImage).gameObject.SetActive(true); } private static void InitializeCommands() { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_0135: Expected O, but got Unknown RemoveAddedKeywords(); ViewBodyCamNode = null; BodyCamKeyword = null; TerminalKeyword val = FindKeyword("view", verb: true); ViewMonitorNode = ((val == null) ? null : val.FindCompatibleNoun("monitor")?.result); if (Plugin.TerminalPiPBodyCamEnabled.Value) { if ((Object)(object)ViewMonitorNode == (Object)null) { Plugin.Instance.Logger.LogWarning((object)"'view monitor' command does not exist, terminal PiP body cam view will be disabled."); return; } ViewBodyCamNode = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)ViewBodyCamNode).name = "ViewBodyCam"; ViewBodyCamNode.displayText = "Toggling picture-in-picture body cam.\n\n"; ViewBodyCamNode.clearPreviousText = true; BodyCamKeyword = FindOrCreateKeyword("BodyCam", "bodycam", verb: false); AddCompatibleNoun(val, BodyCamKeyword, ViewBodyCamNode); CompatibleNoun[] array = val.compatibleNouns ?? Array.Empty<CompatibleNoun>(); int num = 0; CompatibleNoun[] array2 = (CompatibleNoun[])(object)new CompatibleNoun[1 + array.Length]; ReadOnlySpan<CompatibleNoun> readOnlySpan = new ReadOnlySpan<CompatibleNoun>(array); readOnlySpan.CopyTo(new Span<CompatibleNoun>(array2).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array2[num] = new CompatibleNoun { noun = BodyCamKeyword, result = ViewBodyCamNode }; num++; val.compatibleNouns = array2; BodyCamFailedNode = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)BodyCamFailedNode).name = "BodyCamFailed"; BodyCamFailedNode.displayText = "Map view is currently disabled.\n\n"; BodyCamFailedNode.clearPreviousText = true; BodyCamLockedNode = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)BodyCamLockedNode).name = "BodyCamFailed"; BodyCamLockedNode.displayText = "Please place a body cams receiver antenna on the ship.\n\n"; BodyCamLockedNode.clearPreviousText = true; } AddNewlyCreatedCommands(); } private static bool TerminalIsDisplayingMap() { if ((Object)(object)ViewMonitorNode == (Object)null) { return false; } return (Object)(object)ShipObjects.TerminalScript.displayingPersistentImage == (Object)(object)ViewMonitorNode.displayTexture; } internal static bool TerminalIsDisplayingBodyCam() { if ((Object)(object)PiPImage == (Object)null) { return false; } return ((Component)PiPImage).gameObject.activeSelf; } [HarmonyPrefix] [HarmonyPatch(typeof(Terminal), "LoadNewNode")] private static void LoadNewNodePrefix(ref TerminalNode node) { if ((Object)(object)node == (Object)null || !((Object)(object)node == (Object)(object)ViewBodyCamNode)) { return; } if (TerminalIsDisplayingBodyCam()) { DisablePiPImage(); return; } if (!BodyCam.BodyCamsAreAvailable) { node = BodyCamLockedNode; return; } if (!TerminalIsDisplayingMap()) { ShipObjects.TerminalScript.LoadTerminalImage(ViewMonitorNode); } if (!TerminalIsDisplayingMap()) { node = BodyCamFailedNode; } else { EnablePiPImage(); } } [HarmonyPostfix] [HarmonyPatch(typeof(Terminal), "LoadNewNode")] private static void LoadNewNodePostfix(TerminalNode node) { if (!((Object)(object)PiPImage == (Object)null) && !((Object)(object)node != (Object)(object)ViewMonitorNode) && !TerminalIsDisplayingMap()) { DisablePiPImage(); } } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "SwitchMapMonitorPurpose")] private static void SwitchMapMonitorPurposePostfix() { if (!((Object)(object)PiPImage == (Object)null) && !TerminalIsDisplayingMap()) { DisablePiPImage(); } } private static TerminalKeyword FindKeyword(string word, bool verb) { return ((IEnumerable<TerminalKeyword>)ShipObjects.TerminalScript.terminalNodes.allKeywords).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword keyword) => keyword.word == word && keyword.isVerb == verb)); } private static CompatibleNoun FindCompatibleNoun(this TerminalKeyword keyword, string noun) { return ((IEnumerable<CompatibleNoun>)keyword.compatibleNouns).FirstOrDefault((Func<CompatibleNoun, bool>)((CompatibleNoun compatible) => compatible.noun.word == noun)); } private static TerminalKeyword FindOrCreateKeyword(string name, string word, bool verb, CompatibleNoun[] compatibleNouns = null) { Plugin.Instance.Logger.LogInfo((object)("Creating terminal " + (verb ? "verb" : "noun") + " '" + word + "' (" + name + ").")); TerminalKeyword val = FindKeyword(word, verb); if ((Object)(object)val == (Object)null) { val = ScriptableObject.CreateInstance<TerminalKeyword>(); ((Object)val).name = name; val.isVerb = verb; val.word = word; val.compatibleNouns = compatibleNouns; newTerminalKeywords.Add(val); Plugin.Instance.Logger.LogInfo((object)" Keyword was not found, created a new one."); } else if (compatibleNouns != null) { foreach (CompatibleNoun compatibleNoun in compatibleNouns) { AddCompatibleNoun(val, compatibleNoun); } Plugin.Instance.Logger.LogInfo((object)" Keyword existed, appended nouns."); } return val; } private static void AddCompatibleNoun(TerminalKeyword keyword, CompatibleNoun compatibleNoun) { if (!addedCompatibleNouns.TryGetValue(keyword, out var value)) { value = new List<TerminalKeyword>(); addedCompatibleNouns[keyword] = value; } CompatibleNoun[] array = keyword.compatibleNouns ?? Array.Empty<CompatibleNoun>(); int num = 0; CompatibleNoun[] array2 = (CompatibleNoun[])(object)new CompatibleNoun[1 + array.Length]; ReadOnlySpan<CompatibleNoun> readOnlySpan = new ReadOnlySpan<CompatibleNoun>(array); readOnlySpan.CopyTo(new Span<CompatibleNoun>(array2).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array2[num] = compatibleNoun; num++; keyword.compatibleNouns = array2; value.Add(compatibleNoun.noun); } private static void AddCompatibleNoun(TerminalKeyword keyword, TerminalKeyword compatibleKeyword, TerminalNode result) { //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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown AddCompatibleNoun(keyword, new CompatibleNoun { noun = compatibleKeyword, result = result }); } private static void AddNewlyCreatedCommands() { TerminalNodesList terminalNodes; TerminalKeyword[] allKeywords = (terminalNodes = ShipObjects.TerminalScript.terminalNodes).allKeywords; List<TerminalKeyword> list = newTerminalKeywords; int num = 0; TerminalKeyword[] array = (TerminalKeyword[])(object)new TerminalKeyword[allKeywords.Length + list.Count]; ReadOnlySpan<TerminalKeyword> readOnlySpan = new ReadOnlySpan<TerminalKeyword>(allKeywords); readOnlySpan.CopyTo(new Span<TerminalKeyword>(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; foreach (TerminalKeyword item in list) { array[num] = item; num++; } terminalNodes.allKeywords = array; } private static void RemoveAddedKeywords() { foreach (KeyValuePair<TerminalKeyword, List<TerminalKeyword>> addedCompatibleNoun in addedCompatibleNouns) { var (val2, addedNouns) = (KeyValuePair<TerminalKeyword, List<TerminalKeyword>>)(ref addedCompatibleNoun); if (val2.compatibleNouns != null) { List<CompatibleNoun> list2 = new List<CompatibleNoun>(); list2.AddRange(val2.compatibleNouns.Where((CompatibleNoun compatible) => !addedNouns.Contains(compatible.noun))); val2.compatibleNouns = list2.ToArray(); } } addedCompatibleNouns.Clear(); TerminalNodesList terminalNodes = ShipObjects.TerminalScript.terminalNodes; List<TerminalKeyword> list3 = new List<TerminalKeyword>(); list3.AddRange(terminalNodes.allKeywords.Where((TerminalKeyword keyword) => !newTerminalKeywords.Contains(keyword))); terminalNodes.allKeywords = list3.ToArray(); foreach (TerminalKeyword newTerminalKeyword in newTerminalKeywords) { Object.Destroy((Object)(object)newTerminalKeyword); } newTerminalKeywords.Clear(); } } public enum PiPPosition : uint { BottomLeft, BottomRight, TopLeft, TopRight } public class TerminalBodyCamVisibilityTracker : MonoBehaviour { public BodyCamComponent BodyCamToActivate; private void OnEnable() { if ((Object)(object)BodyCamToActivate != (Object)null) { BodyCamToActivate.ForceEnableCamera = true; } } private void OnDisable() { if ((Object)(object)BodyCamToActivate != (Object)null) { BodyCamToActivate.ForceEnableCamera = false; } } } } namespace OpenBodyCams.Utilities { internal static class Cosmetics { [Flags] private enum CompatibilityMode { None = 0, MoreCompany = 1, AdvancedCompany = 4, ModelReplacementAPI = 8, LethalVRM = 0x10, ReservedItemSlots = 0x20 } internal static bool PrintDebugInfo; private static CompatibilityMode compatibilityMode; public static void Initialize(Harmony harmony) { bool flag = Chainloader.PluginInfos.ContainsKey("com.potatoepet.AdvancedCompany"); if (Plugin.EnableAdvancedCompanyCosmeticsCompatibility.Value && flag) { if (AdvancedCompanyCompatibility.Initialize(harmony)) { compatibilityMode |= CompatibilityMode.AdvancedCompany; Plugin.Instance.Logger.LogInfo((object)"AdvancedCompany compatibility mode is enabled."); } else { Plugin.Instan