Decompiled source of PortalGun v1.0.0

PortalRenderSpike.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib.Modules;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PortalRenderSpike")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PortalRenderSpike")]
[assembly: AssemblyTitle("PortalRenderSpike")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PortalRenderSpike
{
	[BepInPlugin("jonathan.portalrenderspike", "Portal Render Spike", "0.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private sealed class Traveller
		{
			public PortalLink Portal;

			public float PrevSideZ;

			public bool Armed;

			public Collider[] HoleCols = Array.Empty<Collider>();

			public readonly List<Collider> IgnoredEnv = new List<Collider>();

			public float LastSwapTime;

			public int Parity;

			public GameObject? RenderClone;

			public bool RenderCloneFailed;

			public float HeldThroughGraceUntil;

			public bool VanishLogged;

			public bool WallOpened;

			public float PrevMaxDepen = -1f;

			public Rigidbody? Body;

			public bool HoleOpen;
		}

		private sealed class PortalLink
		{
			public Transform Quad;

			public Camera PortalCam;

			public RenderTexture Texture;

			public MeshRenderer ScreenRenderer;

			public Collider? Hit;

			public int RenderCount;

			public bool DebugInZone;

			public GameObject? Rim;

			public GameObject? RimCollider;

			public readonly List<Collider> TrimColliders = new List<Collider>();

			public GameObject? SwirlOverlay;

			public Material? SwirlMat;

			public readonly List<Renderer> ClearedRenderers = new List<Renderer>();
		}

		private enum PortalId
		{
			A,
			B
		}

		private static ManualLogSource Log = null;

		private const float WallSearchDistance = 10f;

		private const float InsetFromWall = 0.05f;

		private const float PortalWidth = 1.3f;

		private const float PortalHeight = 2.2f;

		private const float PortalSeparationDistance = 10f;

		private const float ActivationRadius = 3.5f;

		private const float ActivationHalfDepth = 1f;

		private const float TeleportCooldownSeconds = 1f;

		private const float ProximityTeleportDepth = 0.4f;

		private const float ItemProximityTeleportDepth = 1.4f;

		private const float ItemPortalYSlack = 1.2f;

		private const float ExitInsetDistance = 0.8f;

		private const float MinExitSpeed = 1f;

		private const float PortalCamFarPlane = 150f;

		private const float PlayerCenterHeightOffset = 1f;

		private const float PortalYSlack = 0.4f;

		private int _renderDownscale = 2;

		private bool _qualityAuto;

		private float _smoothFrameMs = 12f;

		private int _autoRenderSkip;

		private int _autoFrameCounter;

		private const float PortalViewFogDistance = 23f;

		private const float PortalFarMargin = 8f;

		private bool portalInterleave;

		private bool renderAToggle;

		private double lastPortalRenderMs;

		private bool portalMode;

		private bool holdingPortalGun;

		private bool _portalItemFixupDone;

		private int _fixupAttempts;

		private bool _gunDiagDone;

		private bool _devMode;

		private bool _cameraFallbackWarned;

		private PhysGrabObject? _activeGun;

		private bool _activeGunWasSet;

		private bool seamlessPlayer;

		private readonly Dictionary<Collider, Collider[]> _openWallHoles = new Dictionary<Collider, Collider[]>();

		private bool seamlessItems;

		private readonly Dictionary<PhysGrabObject, Collider[]> _openItemHoles = new Dictionary<PhysGrabObject, Collider[]>();

		private PortalLink? _heldItemStraddlePortal;

		private bool _heldItemPastPlane;

		private readonly Dictionary<PhysGrabObject, Traveller> _travellers = new Dictionary<PhysGrabObject, Traveller>();

		private bool _travellerRework = true;

		private const float TravellerRegisterSlab = 1.6f;

		private const float TravellerDeregisterSlab = 2.2f;

		private const float TravellerCrossEps = 0.04f;

		private PortalLink? portalA;

		private PortalLink? portalB;

		private bool wasInFrontOfA;

		private bool wasInFrontOfB;

		private float teleportCooldownUntil;

		private readonly Dictionary<PhysGrabObject, float> itemTeleportCooldownUntil = new Dictionary<PhysGrabObject, float>();

		private readonly Dictionary<int, float> travellerIgnoreUntil = new Dictionary<int, float>();

		private GameObject? showcaseMarker;

		private Coroutine? selfWalkRoutine;

		private Light? flashlightProxyLight;

		private int flashlightProxySide;

		private float _lastAutoLogMs;

		private float _nextAutoQHeartbeatT;

		private float nextZoneDiagTime;

		internal static readonly Color PortalBlue = new Color(0.25f, 0.65f, 1f);

		internal static readonly Color PortalOrange = new Color(1f, 0.55f, 0.12f);

		private const float FlashlightThroughRange = 12f;

		private static FieldInfo? _grabbedPhysGrabObjectField;

		private static FieldInfo? _fPrevVel;

		private static FieldInfo? _fPrevVelRaw;

		private static FieldInfo? _fPrevPrevVelRaw;

		private static FieldInfo? _fPrevAngVel;

		private float _singletonCheckTimer;

		private PhysGrabObject? _knownGun;

		private int _gunFreefallSamples;

		private Vector3 _gunLastHeldPos;

		private bool _gunLastHeldPosValid;

		private const float ShowcasePortalADistance = 4f;

		private const float ShowcasePortalBExtraDistance = 8f;

		private const float PortalFireRange = 120f;

		private const float MaxPortalSurfaceNormalY = 0.35f;

		private bool multiplayerWarned;

		private NetworkedEvent? _fireEvent;

		private NetworkedEvent? _clearEvent;

		private const string MpMagic = "PGUN.v1";

		private Coroutine? linkSelfTestRoutine;

		private static bool cameraDumpDone;

		private const float SelfWalkSpeed = 3f;

		private const float SelfWalkMaxSeconds = 3f;

		private static Texture2D? _swirlTex;

		private bool _loggedAvatarRenderers;

		private static Shader? _cachedShader;

		private static AssetBundle? _cachedBundle;

		private static bool _bundleLoadAttempted;

		private const string BundleFileName = "portalrenderspikebundle";

		private const string PortalShaderAssetPath = "Assets/PortalRenderSpike/Shaders/Portal.shader";

		private AssetBundle? _visualsBundle;

		private bool _visualsBundleTried;

		private GameObject? _viewmodel;

		private Camera? _viewmodelCam;

		private Animator? _viewmodelAnimator;

		private bool _forceViewmodel;

		private float _vmRecoil;

		private float _vmDrawT = 1f;

		private static readonly Vector3 VmBasePos = new Vector3(0.42f, -0.15f, 0.42f);

		private int _viewmodelLayer = -1;

		private Renderer[]? _hiddenWorldGunRenderers;

		private const string ViewmodelPrefabName = "PortalGunViewmodel";

		private const string ViewmodelDrawClip = "v_portalgun_ARM|@draw";

		private const string ViewmodelFireClip = "v_portalgun_ARM|@fire1";

		private const string WorldModelPrefabName = "PortalGunWorldModel";

		private readonly HashSet<int> _reskinnedGuns = new HashSet<int>();

		private const float PortalSoundRelayRange = 12f;

		private float _sightRelayTimer;

		private const float SightRelayInterval = 0.25f;

		private const float PortalSightRange = 10f;

		private const float NearClipOffset = 0.05f;

		private const float NearClipLimit = 0.2f;

		private PhysGrabObject? _gtHover;

		private PortalLink? _gtExitPortal;

		private Vector3 _gtHoverHitOnEntry;

		private float _gtHoverTA;

		private float _gtHoverFarDist;

		private PhysGrabObject? _gtHeld;

		private float _gtDist;

		private float _gtDistRefreshUntil;

		private float _gtAimLostTimer;

		private FieldInfo? _physGrabberMaskField;

		private bool _gtTestMode;

		private bool _brightAmbient;

		private AmbientMode _savedAmbMode;

		private Color _savedAmbLight;

		private float _savedAmbIntensity;

		private Shader? _sliceShader;

		private bool _sliceShaderTried;

		private bool _travellerBeamHidden;

		private readonly List<Renderer> _travellerHiddenRends = new List<Renderer>();

		private float _gripLogThrottle;

		private float _swapDiagThrottle;

		private int _gripGuardMisses;

		public static Plugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Expected O, but got Unknown
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_devMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DevKeys", false, "Developer test keys (F3 spawn pair, J self-walk, Y spawn gun, ';' perf, '\\' seamless-player, ']' item-straddle, Mouse3/G + Mouse4/H direct-fire). OFF for normal play.").Value;
			string value = ((BaseUnityPlugin)this).Config.Bind<string>("Visual", "PortalQuality", "Auto", "Portal render quality: Auto (degrades invisibly under load - default), High (full-res), Balanced, or Performance (lowest cost).").Value;
			string text = value.Trim().ToLowerInvariant();
			_qualityAuto = text == "auto";
			_renderDownscale = text switch
			{
				"high" => 1, 
				"performance" => 3, 
				"auto" => 2, 
				_ => 2, 
			};
			Log.LogInfo((object)string.Format("[PortalRenderSpike] Portal quality = {0} (render downscale {1}x, auto-degrade {2}).", value, _renderDownscale, _qualityAuto ? "ON" : "off"));
			PortalSounds.LoadAll(Log);
			try
			{
				new Harmony("jonathan.portalrenderspike").PatchAll(Assembly.GetExecutingAssembly());
				Log.LogInfo((object)"[PortalRenderSpike] Harmony patches applied.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[PortalRenderSpike] Harmony patch failed: " + ex.Message + " - level-change portal cleanup + perception-through-portals will be inactive this session."));
			}
			try
			{
				_fireEvent = new NetworkedEvent("PortalGunFire", (Action<EventData>)OnPortalFireEvent);
				_clearEvent = new NetworkedEvent("PortalGunClear", (Action<EventData>)OnPortalClearEvent);
				Log.LogInfo((object)"[PortalRenderSpike] MP sync events registered (PortalGunFire / PortalGunClear).");
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("[PortalRenderSpike] MP sync event registration failed (" + ex2.Message + ") - portals will be single-player-local this session."));
			}
			Log.LogInfo((object)"Portal Render Spike loaded. PORTAL GUN: Mouse4/G fires Portal A, Mouse5/H fires Portal B at the aimed wall (re-fire to move; pair links when both are placed).");
			Log.LogInfo((object)"Debug harness: F3 = auto wall-mounted pair near the player; Shift+F3 = floating showcase pair centered in view (+ liveness marker cube); J = self-walk the player into Portal A (verification without WASD input).");
			Log.LogInfo((object)"Note: F4-F12 are taken by other REPO_Mods test plugins tonight (PortalGun/src/Plugin.cs uses F5-F9) - this plugin uses F3/J plus the unbound Mouse4/Mouse5/G/H only (J confirmed vanilla-free in the decompile's KeyCode census).");
		}

		private void Update()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_049a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
			PruneDeadPortals();
			EnsurePortalItemFixup();
			UpdatePerceptionSight();
			EnforceSingleton();
			UpdateViewmodel();
			UpdateGrabThroughPortal();
			float num = Time.time * 0.12f;
			if ((Object)(object)portalA?.SwirlMat != (Object)null && (Object)(object)portalA.SwirlOverlay != (Object)null && portalA.SwirlOverlay.activeSelf)
			{
				portalA.SwirlMat.SetTextureOffset("_MainTex", new Vector2(num, 0f));
			}
			if ((Object)(object)portalB?.SwirlMat != (Object)null && (Object)(object)portalB.SwirlOverlay != (Object)null && portalB.SwirlOverlay.activeSelf)
			{
				portalB.SwirlMat.SetTextureOffset("_MainTex", new Vector2(num, 0f));
			}
			if (_devMode && Input.GetKeyDown((KeyCode)285))
			{
				_forceViewmodel = !_forceViewmodel;
				Log.LogInfo((object)$"[PortalRenderSpike] DEV F4: force-viewmodel = {_forceViewmodel} (diagnostic - show the first-person gun without grabbing).");
			}
			if (_devMode && Input.GetKeyDown((KeyCode)286))
			{
				StartPlacementSelfTest();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)288))
			{
				StartGrabThroughSelfTest();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)289))
			{
				StartUnrippableSelfTest();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)110))
			{
				StartMpAndApertureSelfTest();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)98))
			{
				ToggleBrightAmbient();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)287))
			{
				PortalGunItem portalGunItem = Object.FindObjectOfType<PortalGunItem>();
				if ((Object)(object)portalGunItem == (Object)null)
				{
					SpawnPortalGunItemForTesting();
					Log.LogInfo((object)"[PortalRenderSpike] DEV F6: no gun present - spawned one; press F6 again to equip it.");
				}
				else
				{
					PhysGrabObject componentInParent = ((Component)portalGunItem).GetComponentInParent<PhysGrabObject>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						PhysGrabber instance = PhysGrabber.instance;
						if (instance != null)
						{
							instance.OverrideGrab(componentInParent, 1f, false);
						}
						_activeGun = componentInParent;
						portalMode = true;
						Log.LogInfo((object)"[PortalRenderSpike] DEV F6: force-equipped the gun in PORTAL MODE (scaffold - real viewmodel/orb/fire path).");
					}
				}
			}
			if (_devMode && Input.GetKeyDown((KeyCode)284))
			{
				if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
				{
					SpawnShowcasePair();
				}
				else
				{
					SpawnOrRespawnPair();
				}
			}
			if (_devMode && (Input.GetKeyDown((KeyCode)326) || Input.GetKeyDown((KeyCode)103)))
			{
				FirePortal(PortalId.A);
			}
			if (_devMode && (Input.GetKeyDown((KeyCode)327) || Input.GetKeyDown((KeyCode)104)))
			{
				FirePortal(PortalId.B);
			}
			PhysGrabObject val = LocalHeldPortalGun();
			if ((Object)(object)val != (Object)null)
			{
				_activeGun = val;
			}
			if ((Object)(object)val != (Object)null && !_gunDiagDone)
			{
				_gunDiagDone = true;
				PhysGrabObjectImpactDetector componentInChildren = ((Component)val).GetComponentInChildren<PhysGrabObjectImpactDetector>();
				PhysGrabObject val2 = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).GetComponent<PhysGrabObject>() : null);
				Log.LogInfo((object)$"[PortalRenderSpike] GUN-DIAG: impactDetector={(Object)(object)componentInChildren != (Object)null} pgoOnSameGO={(Object)(object)componentInChildren != (Object)null && (Object)(object)val2 != (Object)null} rootPGO={(Object)(object)val != (Object)null} LevelGenerator.Instance={(Object)(object)LevelGenerator.Instance != (Object)null}. Component layout:");
				Component[] componentsInChildren = ((Component)val).GetComponentsInChildren<Component>(true);
				foreach (Component val3 in componentsInChildren)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						Log.LogInfo((object)("[PortalRenderSpike] GUN-DIAG    " + ((Object)val3.gameObject).name + " :: " + ((object)val3).GetType().Name));
					}
				}
			}
			if ((Object)(object)_activeGun == (Object)null || !Object.op_Implicit((Object)(object)_activeGun))
			{
				if ((Object)(object)_activeGun != (Object)null || _activeGunWasSet)
				{
					Log.LogWarning((object)$"[PortalRenderSpike] GUN-LOSS: _activeGun object was DESTROYED (portalMode={portalMode}) - this is how the gun 'vanishes' in portal mode. Nothing in this mod destroys it, so it's REPO/another mod (impact, level teardown, or a network despawn).");
				}
				_activeGun = null;
			}
			else if ((Object)(object)val == (Object)null)
			{
				PlayerController instance2 = PlayerController.instance;
				string text = null;
				if ((Object)(object)instance2 == (Object)null)
				{
					text = "no PlayerController";
				}
				else if ((Object)(object)_activeGun.rb == (Object)null)
				{
					text = "gun.rb null";
				}
				else if (!((Component)_activeGun).gameObject.activeInHierarchy)
				{
					text = "holstered (inventory deactivated it)";
				}
				else if (Vector3.Distance(_activeGun.rb.position, ((Component)instance2).transform.position) > 3.5f)
				{
					text = $"dropped+walked-away ({Vector3.Distance(_activeGun.rb.position, ((Component)instance2).transform.position):F1}m, gun at {_activeGun.rb.position})";
				}
				if (text != null)
				{
					if (portalMode)
					{
						Log.LogWarning((object)("[PortalRenderSpike] GUN-DROP (in PORTAL MODE!): force-hold lost the gun - reason: " + text + ". portalMode kept for re-draw; grab it again to restore."));
					}
					_activeGun = null;
				}
			}
			_activeGunWasSet = (Object)(object)_activeGun != (Object)null;
			PhysGrabObject activeGun = _activeGun;
			holdingPortalGun = (Object)(object)activeGun != (Object)null;
			if ((Object)(object)activeGun != (Object)null)
			{
				if (Input.GetKeyDown((KeyCode)101))
				{
					portalMode = !portalMode;
					Log.LogInfo((object)("[PortalRenderSpike] Portal Gun -> " + (portalMode ? "PORTAL MODE (LMB=blue A, RMB=orange B)" : "normal beam-held item") + "."));
				}
				if (portalMode)
				{
					PhysGrabber instance3 = PhysGrabber.instance;
					if (instance3 != null)
					{
						instance3.OverrideGrab(activeGun, 0.3f, false);
					}
					PhysGrabber instance4 = PhysGrabber.instance;
					if (instance4 != null)
					{
						instance4.OverrideAlwaysGrabbable(0.5f);
					}
					activeGun.OverrideKnockOutOfGrabDisable(0.5f);
					GameObject val4 = PhysGrabber.instance?.physGrabBeam;
					if ((Object)(object)val4 != (Object)null)
					{
						Renderer[] componentsInChildren2 = val4.GetComponentsInChildren<Renderer>();
						foreach (Renderer val5 in componentsInChildren2)
						{
							if (val5.enabled)
							{
								val5.enabled = false;
							}
						}
					}
					Transform val6 = PhysGrabber.instance?.physGrabPoint;
					if ((Object)(object)val6 != (Object)null)
					{
						Renderer[] componentsInChildren2 = ((Component)val6).GetComponentsInChildren<Renderer>();
						foreach (Renderer val7 in componentsInChildren2)
						{
							if (val7.enabled)
							{
								val7.enabled = false;
							}
						}
					}
					if (Input.GetMouseButtonDown(0))
					{
						FirePortal(PortalId.A);
						_vmRecoil = 1f;
					}
					if (Input.GetMouseButtonDown(1))
					{
						FirePortal(PortalId.B);
						_vmRecoil = 1f;
					}
					if (Input.GetMouseButtonDown(2))
					{
						DestroyStraddlers();
						DestroyExistingPair();
						BroadcastPortalClear();
						Log.LogInfo((object)"[PortalRenderSpike] Portal Gun: cleared all placed portals (middle mouse).");
					}
				}
			}
			if (_devMode && Input.GetKeyDown((KeyCode)106))
			{
				StartSelfWalk();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)121))
			{
				SpawnPortalGunItemForTesting();
			}
			if (_devMode && Input.GetKeyDown((KeyCode)59))
			{
				portalInterleave = !portalInterleave;
				Log.LogInfo((object)string.Format("[PortalRenderSpike] PERF: portal render interleave = {0}. Last single-render {1:F2}ms.", portalInterleave ? "ON (1 cam/frame)" : "OFF (both cams/frame)", lastPortalRenderMs));
			}
			if (_devMode && Input.GetKeyDown((KeyCode)92))
			{
				seamlessPlayer = !seamlessPlayer;
				if (!seamlessPlayer)
				{
					CloseAllPlayerHoles(PlayerController.instance);
				}
				Log.LogInfo((object)("[PortalRenderSpike] SEAMLESS player traversal = " + (seamlessPlayer ? "ON (walk-through hole + plane teleport)" : "OFF (discrete teleport)") + "."));
			}
			if (_devMode && Input.GetKeyDown((KeyCode)93))
			{
				_travellerRework = !_travellerRework;
				if (!_travellerRework)
				{
					ClearAllTravellers();
				}
				Log.LogInfo((object)("[PortalRenderSpike] TRAVELLER REWORK (Stage A+B: per-object registry + crossing swap) = " + (_travellerRework ? "ON - free items cross cleanly with no juggle; HELD poke/pull still needs Stage C parity" : "OFF (legacy path)") + "."));
			}
			if ((Object)(object)showcaseMarker != (Object)null)
			{
				showcaseMarker.transform.Rotate(20f * Time.deltaTime, 45f * Time.deltaTime, 0f);
			}
			if (portalA == null || portalB == null)
			{
				return;
			}
			UpdateAutoQuality();
			Camera val8 = FindPlayerCamera();
			_autoFrameCounter++;
			bool flag = _autoRenderSkip <= 0 || _autoFrameCounter % (_autoRenderSkip + 1) == 0;
			if (!((Object)(object)val8 != (Object)null && flag))
			{
				return;
			}
			if (portalInterleave)
			{
				if (renderAToggle)
				{
					RenderPortalView(portalB, portalA, val8);
				}
				else
				{
					RenderPortalView(portalA, portalB, val8);
				}
				renderAToggle = !renderAToggle;
			}
			else
			{
				RenderPortalView(portalB, portalA, val8);
				RenderPortalView(portalA, portalB, val8);
			}
		}

		private void UpdateAutoQuality()
		{
			if (!_qualityAuto)
			{
				return;
			}
			_smoothFrameMs = Mathf.Lerp(_smoothFrameMs, Time.unscaledDeltaTime * 1000f, 0.05f);
			int autoRenderSkip = _autoRenderSkip;
			bool flag = portalInterleave;
			if (_smoothFrameMs > 22f)
			{
				portalInterleave = true;
				if (_smoothFrameMs > 30f)
				{
					_autoRenderSkip = Mathf.Min(2, _autoRenderSkip + 1);
				}
			}
			else if (_smoothFrameMs < 14f)
			{
				if (_autoRenderSkip > 0)
				{
					_autoRenderSkip--;
				}
				else
				{
					portalInterleave = false;
				}
			}
			if ((_autoRenderSkip != autoRenderSkip || portalInterleave != flag) && Mathf.Abs(_smoothFrameMs - _lastAutoLogMs) > 1f)
			{
				_lastAutoLogMs = _smoothFrameMs;
				Log.LogInfo((object)$"[PortalRenderSpike] AUTO-QUALITY: frame={_smoothFrameMs:F1}ms -> interleave={portalInterleave} renderSkip={_autoRenderSkip} (degrade under load / restore when it recovers).");
			}
			if (_devMode && (portalA != null || portalB != null) && Time.unscaledTime > _nextAutoQHeartbeatT)
			{
				_nextAutoQHeartbeatT = Time.unscaledTime + 5f;
				Log.LogInfo((object)$"[AUTOQ-LIVE] real frame={_smoothFrameMs:F1}ms (raw {Time.unscaledDeltaTime * 1000f:F1}ms) -> tier: interleave={portalInterleave} renderSkip={_autoRenderSkip} (live sensor tick during real play).");
			}
		}

		private void FixedUpdate()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (portalA == null || portalB == null)
			{
				return;
			}
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (_devMode && Time.time >= nextZoneDiagTime)
			{
				nextZoneDiagTime = Time.time + 1f;
				Vector3 playerCenter = ((Component)instance).transform.position + Vector3.up * 1f;
				LogZoneDiagnostic(portalA, playerCenter);
				LogZoneDiagnostic(portalB, playerCenter);
				Camera val = FindPlayerCamera();
				if ((Object)(object)val != (Object)null)
				{
					GetCameraRenderPose(val, out var pos, out var rot);
					Log.LogInfo((object)$"[PortalRenderSpike] RENDER-HEART: A.renderCount={portalA.RenderCount} B.renderCount={portalB.RenderCount} playerViewPos={pos} playerViewFwd={rot * Vector3.forward} (from cameraToWorldMatrix)");
				}
			}
			UpdatePlayerHole(instance);
			UpdateHeldItemStraddle();
			if (Time.time >= teleportCooldownUntil && !CheckCrossingAndTeleport(portalA, portalB, ref wasInFrontOfA, instance))
			{
				CheckCrossingAndTeleport(portalB, portalA, ref wasInFrontOfB, instance);
			}
			if (_travellerRework)
			{
				UpdateTravellers();
			}
			else
			{
				CheckPhysGrabObjectPortals();
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, float> item in travellerIgnoreUntil)
			{
				if (Time.time >= item.Value)
				{
					list.Add(item.Key);
				}
			}
			foreach (int item2 in list)
			{
				travellerIgnoreUntil.Remove(item2);
			}
		}

		private void LateUpdate()
		{
			UpdateFlashlightProxy();
			RemapHeldItemPuller();
		}

		private void OnGUI()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if (portalMode && holdingPortalGun)
			{
				float num = (float)Screen.width * 0.5f;
				float num2 = (float)Screen.height * 0.5f;
				Color color = GUI.color;
				Texture2D whiteTexture = Texture2D.whiteTexture;
				GUI.color = Color.white;
				GUI.DrawTexture(new Rect(num - 1.5f, num2 - 1.5f, 3f, 3f), (Texture)(object)whiteTexture);
				GUI.color = PortalBlue;
				GUI.DrawTexture(new Rect(num - 14f, num2 - 1f, 9f, 2f), (Texture)(object)whiteTexture);
				GUI.DrawTexture(new Rect(num - 1f, num2 - 14f, 2f, 9f), (Texture)(object)whiteTexture);
				GUI.color = PortalOrange;
				GUI.DrawTexture(new Rect(num + 5f, num2 - 1f, 9f, 2f), (Texture)(object)whiteTexture);
				GUI.DrawTexture(new Rect(num - 1f, num2 + 5f, 2f, 9f), (Texture)(object)whiteTexture);
				GUI.color = color;
			}
		}

		private void UpdateFlashlightProxy()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: 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 (portalA == null || portalB == null)
			{
				DestroyFlashlightProxy();
				return;
			}
			FlashlightController instance = FlashlightController.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.spotlight == (Object)null || !instance.LightActive || !((Behaviour)instance.spotlight).enabled)
			{
				DestroyFlashlightProxy();
				return;
			}
			Light spotlight = instance.spotlight;
			Vector3 position = ((Component)spotlight).transform.position;
			Vector3 forward = ((Component)spotlight).transform.forward;
			float num = 0.2f;
			float slack = ((flashlightProxySide == 1) ? (num + 0.35f) : num);
			float slack2 = ((flashlightProxySide == 2) ? (num + 0.35f) : num);
			int num2 = 0;
			PortalLink portalLink = null;
			PortalLink portalLink2 = null;
			if (FlashlightThroughPortal(portalA, position, forward, slack))
			{
				num2 = 1;
				portalLink = portalA;
				portalLink2 = portalB;
			}
			else if (FlashlightThroughPortal(portalB, position, forward, slack2))
			{
				num2 = 2;
				portalLink = portalB;
				portalLink2 = portalA;
			}
			if (num2 == 0)
			{
				DestroyFlashlightProxy();
				return;
			}
			Vector3 val = portalLink2.Quad.position + portalLink2.Quad.forward * 0.1f;
			Vector3 val2 = portalLink2.Quad.rotation * Quaternion.AngleAxis(180f, Vector3.up) * Quaternion.Inverse(portalLink.Quad.rotation) * forward;
			if ((Object)(object)flashlightProxyLight == (Object)null || flashlightProxySide != num2)
			{
				DestroyFlashlightProxy();
				GameObject val3 = new GameObject("PortalRenderSpike_FlashlightProxy");
				val3.transform.SetPositionAndRotation(val, Quaternion.LookRotation(val2, Vector3.up));
				flashlightProxyLight = val3.AddComponent<Light>();
				flashlightProxyLight.type = (LightType)0;
				flashlightProxySide = num2;
			}
			((Component)flashlightProxyLight).transform.position = val;
			((Component)flashlightProxyLight).transform.rotation = Quaternion.LookRotation(val2, Vector3.up);
			flashlightProxyLight.spotAngle = spotlight.spotAngle;
			flashlightProxyLight.range = spotlight.range;
			flashlightProxyLight.intensity = spotlight.intensity;
			flashlightProxyLight.color = spotlight.color;
			flashlightProxyLight.shadows = (LightShadows)0;
			flashlightProxyLight.shadowStrength = spotlight.shadowStrength;
			flashlightProxyLight.innerSpotAngle = spotlight.innerSpotAngle;
			flashlightProxyLight.cullingMask = spotlight.cullingMask;
			if ((Object)(object)spotlight.cookie != (Object)null)
			{
				flashlightProxyLight.cookie = spotlight.cookie;
			}
		}

		private bool FlashlightThroughPortal(PortalLink p, Vector3 srcPos, Vector3 srcFwd, float slack)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 forward = p.Quad.forward;
			if (Vector3.Dot(srcPos - p.Quad.position, forward) <= 0f)
			{
				return false;
			}
			float num = Vector3.Dot(srcFwd, forward);
			if (num >= -0.0001f)
			{
				return false;
			}
			float num2 = Vector3.Dot(p.Quad.position - srcPos, forward) / num;
			if (num2 <= 0f || num2 > 12f)
			{
				return false;
			}
			Vector3 val = srcPos + srcFwd * num2 - p.Quad.position;
			float num3 = Vector3.Dot(val, p.Quad.right);
			float num4 = Vector3.Dot(val, p.Quad.up);
			if (Mathf.Abs(num3) < 0.65f + slack)
			{
				return Mathf.Abs(num4) < 1.1f + slack;
			}
			return false;
		}

		private void DestroyFlashlightProxy()
		{
			if ((Object)(object)flashlightProxyLight != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)flashlightProxyLight).gameObject);
				flashlightProxyLight = null;
			}
			flashlightProxySide = 0;
		}

		private void LogZoneDiagnostic(PortalLink link, Vector3 playerCenter)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = playerCenter - link.Quad.position;
			if (!(((Vector3)(ref val)).magnitude > 3.5f))
			{
				float num = Vector3.Dot(val, link.Quad.forward);
				float num2 = Vector3.Dot(val, link.Quad.right);
				float num3 = Vector3.Dot(val, link.Quad.up);
				bool flag = Mathf.Abs(num2) < 0.65f && Mathf.Abs(num3) < 1.5f;
				Log.LogInfo((object)$"[PortalRenderSpike] ZONE-DIAG {((Object)link.Quad).name}: zDist={num:F2} xDist={num2:F2} yDist={num3:F2} withinRect={flag} (need |x|<{0.65f:F2} |y|<{1.5f:F2} 0<z<{0.4f:F2}) renderCount={link.RenderCount} camPos={((Component)link.PortalCam).transform.position} cooldownActive={Time.time < teleportCooldownUntil}");
			}
		}

		private PhysGrabObject? LocalHeldObject()
		{
			PhysGrabber instance = PhysGrabber.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (_grabbedPhysGrabObjectField == null)
			{
				_grabbedPhysGrabObjectField = typeof(PhysGrabber).GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.NonPublic);
			}
			object? obj = _grabbedPhysGrabObjectField?.GetValue(instance);
			return (PhysGrabObject?)((obj is PhysGrabObject) ? obj : null);
		}

		private PhysGrabObject? LocalHeldPortalGun()
		{
			PhysGrabObject val = LocalHeldObject();
			if (!((Object)(object)val != (Object)null) || !((Object)(object)((Component)val).GetComponentInChildren<PortalGunItem>() != (Object)null))
			{
				return null;
			}
			return val;
		}

		private void MakeImpactContinuous(PhysGrabObject obj, Vector3 newVel, Vector3 newAngVel)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)obj == (Object)null)
			{
				return;
			}
			PhysGrabObjectImpactDetector component = ((Component)obj).GetComponent<PhysGrabObjectImpactDetector>();
			if (!((Object)(object)component == (Object)null))
			{
				Type typeFromHandle = typeof(PhysGrabObjectImpactDetector);
				if ((object)_fPrevVel == null)
				{
					_fPrevVel = typeFromHandle.GetField("previousVelocity", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if ((object)_fPrevVelRaw == null)
				{
					_fPrevVelRaw = typeFromHandle.GetField("previousVelocityRaw", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if ((object)_fPrevPrevVelRaw == null)
				{
					_fPrevPrevVelRaw = typeFromHandle.GetField("previousPreviousVelocityRaw", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				if ((object)_fPrevAngVel == null)
				{
					_fPrevAngVel = typeFromHandle.GetField("previousAngularVelocity", BindingFlags.Instance | BindingFlags.NonPublic);
				}
				float num = Mathf.Max(Time.fixedDeltaTime, 0.0001f);
				_fPrevVel?.SetValue(component, newVel / num);
				_fPrevAngVel?.SetValue(component, newAngVel / num);
				_fPrevVelRaw?.SetValue(component, newVel);
				_fPrevPrevVelRaw?.SetValue(component, newVel);
			}
		}

		private void EnsurePortalItemFixup()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			if (_portalItemFixupDone)
			{
				return;
			}
			_fixupAttempts++;
			if (_fixupAttempts % 30 != 0)
			{
				return;
			}
			IReadOnlyList<Item> registeredItems = Items.RegisteredItems;
			if (registeredItems == null)
			{
				return;
			}
			foreach (Item item in registeredItems)
			{
				if ((Object)(object)item != (Object)null && item.itemName == "Portal Gun")
				{
					if ((Object)(object)item.itemNameLocalized != (Object)null)
					{
						item.itemNameLocalized = null;
						Log.LogInfo((object)"[PortalRenderSpike] FIXUP: nulled Portal Gun item.itemNameLocalized - it was throwing 'Empty Table Reference' every frame the gun was visible. Name falls back to 'Portal Gun'.");
					}
					if ((Object)(object)item.value == (Object)null || item.value.valueMin != 15000f || item.value.valueMax != 20000f)
					{
						Value val = ScriptableObject.CreateInstance<Value>();
						val.valueMin = 15000f;
						val.valueMax = 20000f;
						item.value = val;
					}
					item.itemType = (itemType)13;
					item.itemSecretShopType = (itemSecretShopType)0;
					item.itemVolume = (itemVolume)1;
					item.maxAmountInShop = 1;
					item.maxAmount = 1;
					item.disabled = false;
					bool flag = (Object)(object)StatsManager.instance != (Object)null && StatsManager.instance.itemDictionary != null && StatsManager.instance.itemDictionary.ContainsValue(item);
					Log.LogInfo((object)$"[PortalRenderSpike] SHOP-FIXUP: Portal Gun priced {item.value.valueMin:F0}-{item.value.valueMax:F0}, itemType={item.itemType}, itemVolume={item.itemVolume}, maxAmountInShop={item.maxAmountInShop}, inStatsItemDictionary={flag} (needs true to appear in the shop).");
					_portalItemFixupDone = true;
					break;
				}
			}
		}

		private void EnforceSingleton()
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			_singletonCheckTimer -= Time.deltaTime;
			if (_singletonCheckTimer > 0f)
			{
				return;
			}
			_singletonCheckTimer = 0.4f;
			PortalGunItem[] array = Object.FindObjectsOfType<PortalGunItem>();
			List<PhysGrabObject> list = new List<PhysGrabObject>();
			PortalGunItem[] array2 = array;
			foreach (PortalGunItem portalGunItem in array2)
			{
				if (!((Object)(object)portalGunItem == (Object)null))
				{
					PhysGrabObject componentInParent = ((Component)portalGunItem).GetComponentInParent<PhysGrabObject>();
					if ((Object)(object)componentInParent != (Object)null && !list.Contains(componentInParent))
					{
						list.Add(componentInParent);
					}
				}
			}
			foreach (PhysGrabObject item in list)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				PhysGrabObjectImpactDetector[] componentsInChildren = ((Component)item).GetComponentsInChildren<PhysGrabObjectImpactDetector>(true);
				foreach (PhysGrabObjectImpactDetector val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled)
					{
						((Behaviour)val).enabled = false;
						Log.LogInfo((object)("[PortalRenderSpike] Disabled impact detector on '" + ((Object)((Component)val).gameObject).name + "' (NullRef-spam)."));
					}
				}
				ReskinWorldGun(item);
				if (item.playerGrabbing != null && item.playerGrabbing.Count > 0)
				{
					item.OverrideKnockOutOfGrabDisable(0.6f);
				}
			}
			if (list.Count >= 1)
			{
				RecoverLostGun(list[0]);
			}
			if (list.Count <= 1)
			{
				if (list.Count == 1)
				{
					_knownGun = list[0];
				}
				return;
			}
			PhysGrabObject val2 = (_knownGun = (PhysGrabObject?)(((Object)(object)_knownGun != (Object)null && list.Contains(_knownGun)) ? ((object)_knownGun) : ((object)list[0])));
			foreach (PhysGrabObject item2 in list)
			{
				if (!((Object)(object)item2 == (Object)(object)val2) && !((Object)(object)item2 == (Object)null))
				{
					Log.LogWarning((object)("[PortalRenderSpike] SINGLETON GUARD: a second Portal Gun exists - despawning the extra '" + ((Object)item2).name + "' (one per run)."));
					PhysGrabObjectImpactDetector component = ((Component)item2).GetComponent<PhysGrabObjectImpactDetector>();
					if ((Object)(object)component != (Object)null)
					{
						component.DestroyObject(false);
					}
					else
					{
						Object.Destroy((Object)(object)((Component)item2).gameObject);
					}
				}
			}
		}

		private void RecoverLostGun(PhysGrabObject gun)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)gun == (Object)null || (Object)(object)gun.rb == (Object)null)
			{
				return;
			}
			if (gun.playerGrabbing != null && gun.playerGrabbing.Count > 0)
			{
				_gunLastHeldPos = ((Component)gun.playerGrabbing[0]).transform.position + Vector3.up * 0.5f;
				_gunLastHeldPosValid = true;
				_gunFreefallSamples = 0;
			}
			else if (gun.rb.velocity.y < -15f)
			{
				_gunFreefallSamples++;
				if (_gunFreefallSamples >= 4)
				{
					_gunFreefallSamples = 0;
					Vector3 val = (_gunLastHeldPosValid ? _gunLastHeldPos : (((Object)(object)PlayerController.instance != (Object)null) ? (((Component)PlayerController.instance).transform.position + Vector3.up * 0.5f) : gun.rb.position));
					gun.Teleport(val, Quaternion.identity);
					gun.rb.velocity = Vector3.zero;
					gun.rb.angularVelocity = Vector3.zero;
					Log.LogWarning((object)"[PortalRenderSpike] Gun-loss safety: the Portal Gun was free-falling through the world - recovered it to its last in-bounds position (a glitch-loss, not an intentional drop).");
				}
			}
			else
			{
				_gunFreefallSamples = 0;
			}
		}

		private void SpawnPortalGunItemForTesting()
		{
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Log.LogWarning((object)"[PortalRenderSpike] Spawn Portal Gun item: PlayerController.instance is null (not in a run yet?).");
				return;
			}
			Item val = null;
			foreach (Item registeredItem in Items.RegisteredItems)
			{
				if ((Object)(object)registeredItem != (Object)null && registeredItem.itemName == "Portal Gun")
				{
					val = registeredItem;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)$"[PortalRenderSpike] Spawn Portal Gun item: 'Portal Gun' not found in REPOLib.RegisteredItems (count={Items.RegisteredItems.Count}) - is jonathan-PortalGun/PortalGun.repobundle installed and loaded by REPOLib?");
				return;
			}
			Camera val2 = FindPlayerCamera();
			Vector3 val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).transform.forward : ((Component)instance).transform.forward);
			Vector3 val4 = ((Component)instance).transform.position + val3 * 1.5f + Vector3.up * 0.6f;
			GameObject val5 = Items.SpawnItem(val, val4, Quaternion.identity);
			try
			{
				StatsManager instance2 = StatsManager.instance;
				if (instance2 != null)
				{
					instance2.ItemPurchase(((Object)val).name);
				}
				Log.LogInfo((object)("[PortalRenderSpike] Registered '" + ((Object)val).name + "' as purchased so it persists across levels (dev-spawn persistence)."));
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[PortalRenderSpike] ItemPurchase register failed: " + ex.Message));
			}
			Log.LogInfo((object)$"[PortalRenderSpike] Spawned Portal Gun item at {val4} (result null={(Object)(object)val5 == (Object)null}). Grab it and press E to place Portal A, E again for Portal B.");
		}

		private void SpawnOrRespawnPair()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: 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_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			DestroyExistingPair();
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Log.LogWarning((object)"F3 pressed but PlayerController.instance is null (not in a run yet?).");
				return;
			}
			if ((Object)(object)FindPlayerCamera() == (Object)null)
			{
				Log.LogWarning((object)"F3: could not find any Camera to use as the player camera (Camera.main and controller.cameraGameObject both failed) - aborting portal spawn.");
				return;
			}
			Vector3 val = ((Component)instance).transform.position + Vector3.up * 0.5f;
			if (!FindNearestWall(val, ((Component)instance).transform, out var hit))
			{
				Log.LogWarning((object)$"F3: no wall found within {10f}m in forward/right/left/back directions (F7's search pattern) - move closer to a wall and retry.");
				return;
			}
			Vector3 val2 = Vector3.Cross(Vector3.up, ((RaycastHit)(ref hit)).normal);
			Vector3 val3 = ((Vector3)(ref val2)).normalized;
			if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
			{
				val3 = ((Component)instance).transform.right;
			}
			Vector3 val4 = ((RaycastHit)(ref hit)).point + val3 * 10f + ((RaycastHit)(ref hit)).normal * 1f;
			RaycastHit hit2 = default(RaycastHit);
			bool flag = Physics.Raycast(val4, -((RaycastHit)(ref hit)).normal, ref hit2, 10f);
			string text = "same-wall tangent offset (10m)";
			if (!flag)
			{
				flag = FindNearestWall(val4, ((Component)instance).transform, out hit2);
				text = "general 4-direction search from tangent-offset point";
			}
			if (!flag)
			{
				flag = Physics.Raycast(val, -((Component)instance).transform.forward, ref hit2, 10f);
				text = "opposite-wall fallback from player position";
			}
			if (!flag)
			{
				Log.LogWarning((object)"F3: found a wall for Portal A but could not find a second wall for Portal B by any strategy (same-wall offset, general search, or opposite wall) - aborting spawn. Try a bigger room.");
				return;
			}
			if (Vector3.Distance(((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit2)).point) < 1.3f)
			{
				Log.LogWarning((object)$"F3: Portal A and B candidate points are only {Vector3.Distance(((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit2)).point):F2}m apart (< portal width {1.3f}m) - room too small for this spike's fixed geometry, aborting.");
				return;
			}
			portalA = CreatePortal("PortalRenderSpike_A", hit);
			portalB = CreatePortal("PortalRenderSpike_B", hit2);
			wasInFrontOfA = Vector3.Dot(((Component)instance).transform.position - portalA.Quad.position, portalA.Quad.forward) > 0f;
			wasInFrontOfB = Vector3.Dot(((Component)instance).transform.position - portalB.Quad.position, portalB.Quad.forward) > 0f;
			teleportCooldownUntil = 0f;
			UpdatePortalActivationVisuals();
			ArmLinkSelfTest();
			Log.LogInfo((object)$"[PortalRenderSpike] Spawned pair. A pos={((RaycastHit)(ref hit)).point} normal={((RaycastHit)(ref hit)).normal} wall='{((Object)((Component)((RaycastHit)(ref hit)).collider).gameObject).name}'; B pos={((RaycastHit)(ref hit2)).point} normal={((RaycastHit)(ref hit2)).normal} wall='{((Object)((Component)((RaycastHit)(ref hit2)).collider).gameObject).name}' via strategy='{text}'; separation={Vector3.Distance(((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit2)).point):F2}m.");
			Log.LogInfo((object)"[PortalRenderSpike] Walk into either portal quad to teleport out the other. Press F3 again to despawn and respawn a fresh pair at your current location.");
		}

		private void SpawnShowcasePair()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: 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_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			DestroyExistingPair();
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Log.LogWarning((object)"Shift+F3 pressed but PlayerController.instance is null (not in a run yet?).");
				return;
			}
			Camera val = FindPlayerCamera();
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"Shift+F3: could not find any Camera to use as the player camera - aborting showcase spawn.");
				return;
			}
			Vector3 position = ((Component)val).transform.position;
			Vector3 forward = ((Component)val).transform.forward;
			forward.y = 0f;
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
			{
				forward = ((Component)instance).transform.forward;
				forward.y = 0f;
			}
			((Vector3)(ref forward)).Normalize();
			Quaternion val2 = Quaternion.LookRotation(-forward, Vector3.up);
			Vector3 val3 = position + forward * 4f;
			RaycastHit val4 = default(RaycastHit);
			float num = (Physics.Raycast(val3, forward, ref val4, 8f) ? (((RaycastHit)(ref val4)).distance - 1f) : 8f);
			Vector3 val5;
			Quaternion val6;
			if (num >= 4f)
			{
				val5 = val3 + forward * num;
				val6 = val2;
				if (num < 8f)
				{
					Log.LogInfo((object)$"[PortalRenderSpike] SHOWCASE: B clamped to {num:F1}m past A (wall '{((Object)((Component)((RaycastHit)(ref val4)).collider).gameObject).name}' at {((RaycastHit)(ref val4)).distance:F1}m on the A->B axis) instead of the default {8f:F0}m.");
				}
			}
			else
			{
				RaycastHit val7 = default(RaycastHit);
				float num2 = (Physics.Raycast(position, -forward, ref val7, 8f) ? (((RaycastHit)(ref val7)).distance - 1f) : 8f);
				if (!(num2 >= 4f))
				{
					Log.LogError((object)$"[PortalRenderSpike] SHOWCASE ABORTED: no room for Portal B in either direction (forward {num:F1}m / backward {num2:F1}m clear, need {4f:F0}m). Move to a larger space and retry Shift+F3.");
					DestroyExistingPair();
					return;
				}
				val5 = position - forward * num2;
				val6 = Quaternion.LookRotation(forward, Vector3.up);
				Log.LogWarning((object)$"[PortalRenderSpike] SHOWCASE: forward axis too cramped ({num:F1}m clear past A, need {4f:F0}m) - Portal B placed {num2:F1}m BEHIND the player instead, facing them.");
			}
			portalA = CreatePortalAt("PortalRenderSpike_A", val3, val2, null);
			portalB = CreatePortalAt("PortalRenderSpike_B", val5, val6, null);
			Vector3 val8 = -(val6 * Vector3.forward);
			RaycastHit val9 = default(RaycastHit);
			float num3 = (Physics.Raycast(val5, val8, ref val9, 2f) ? Mathf.Max(0.3f, ((RaycastHit)(ref val9)).distance - 0.4f) : 2f);
			Vector3 val10 = val5 + val8 * num3;
			showcaseMarker = CreateShowcaseMarker(val10);
			Log.LogInfo((object)$"SHOWCASE MARKER: magenta cube at {val10} - visible ONLY through portal A");
			wasInFrontOfA = Vector3.Dot(((Component)instance).transform.position - portalA.Quad.position, portalA.Quad.forward) > 0f;
			wasInFrontOfB = Vector3.Dot(((Component)instance).transform.position - portalB.Quad.position, portalB.Quad.forward) > 0f;
			teleportCooldownUntil = 0f;
			UpdatePortalActivationVisuals();
			ArmLinkSelfTest();
			if ((Object)(object)instance.cameraGameObject != (Object)null && (Object)(object)CameraAim.Instance != (Object)null)
			{
				Quaternion localRotation = instance.cameraGameObject.transform.localRotation;
				float y = ((Quaternion)(ref localRotation)).eulerAngles.y;
				Quaternion val11 = Quaternion.Euler(0f, y, 0f);
				CameraAim.Instance.SetPlayerAim(val11, true);
				Log.LogInfo((object)$"SHOWCASE: portal A centered in view at {4f:F1}m");
			}
			else
			{
				Log.LogWarning((object)$"SHOWCASE: spawned pair but could NOT force-aim the camera (cameraGameObject null={(Object)(object)instance.cameraGameObject == (Object)null}, CameraAim.Instance null={(Object)(object)CameraAim.Instance == (Object)null}) - portal A is 4m ahead at eye height along the camera's pre-spawn horizontal forward, but centering is not guaranteed.");
			}
			Log.LogInfo((object)$"[PortalRenderSpike] SHOWCASE spawn: A pos={val3} B pos={val5} axis={forward} (floating, both facing the player; walk forward through A to exit B; plain F3 for the normal wall-mounted spawn).");
		}

		public void FirePortalFromItem(bool portalA)
		{
			FirePortal((!portalA) ? PortalId.B : PortalId.A);
		}

		private bool PortalFitsSurface(Vector3 point, Vector3 normal)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.up - Vector3.Dot(Vector3.up, normal) * normal;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.forward - Vector3.Dot(Vector3.forward, normal) * normal;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = Vector3.Cross(val, normal);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			float num = 0.598f;
			float num2 = 1.0120001f;
			RaycastHit val3 = default(RaycastHit);
			for (int i = -2; i <= 2; i++)
			{
				for (int j = -2; j <= 2; j++)
				{
					float num3 = (float)i * 0.5f;
					float num4 = (float)j * 0.5f;
					if (!(num3 * num3 + num4 * num4 > 1.02f))
					{
						if (!Physics.Raycast(point + normalized * (num3 * num) + val * (num4 * num2) + normal * 0.15f, -normal, ref val3, 0.5f, -1, (QueryTriggerInteraction)1))
						{
							return false;
						}
						if (Vector3.Dot(((RaycastHit)(ref val3)).normal, normal) < 0.96f)
						{
							return false;
						}
						if (Mathf.Abs(Vector3.Dot(((RaycastHit)(ref val3)).point - point, normal)) > 0.04f)
						{
							return false;
						}
					}
				}
			}
			return true;
		}

		private bool AutoFitPoint(ref Vector3 point, Vector3 normal)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if (PortalFitsSurface(point, normal))
			{
				return true;
			}
			Vector3 val = Vector3.up - Vector3.Dot(Vector3.up, normal) * normal;
			if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
			{
				val = Vector3.forward - Vector3.Dot(Vector3.forward, normal) * normal;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = Vector3.Cross(val, normal);
			Vector3 normalized = ((Vector3)(ref val2)).normalized;
			int num = LayerMask.NameToLayer("Default");
			float num2 = Mathf.Max(1.3f, 2.2f) * 0.6f;
			RaycastHit val3 = default(RaycastHit);
			for (float num3 = 0.2f; num3 <= num2; num3 += 0.2f)
			{
				for (int i = 0; i < 8; i++)
				{
					float num4 = (float)i * ((float)Math.PI / 4f);
					if (Physics.Raycast(point + normalized * (Mathf.Cos(num4) * num3) + val * (Mathf.Sin(num4) * num3) + normal * 0.25f, -normal, ref val3, 0.6f, -1, (QueryTriggerInteraction)1) && (Object)(object)((RaycastHit)(ref val3)).collider != (Object)null && ((Component)((RaycastHit)(ref val3)).collider).gameObject.layer == num && Vector3.Dot(((RaycastHit)(ref val3)).normal, normal) > 0.9f && PortalFitsSurface(((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal))
					{
						point = ((RaycastHit)(ref val3)).point;
						return true;
					}
				}
			}
			return false;
		}

		private void FirePortal(PortalId id)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: 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_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)PlayerController.instance == (Object)null)
			{
				Log.LogWarning((object)$"[PortalRenderSpike] Fire Portal {id} pressed but PlayerController.instance is null (not in a run yet?).");
				return;
			}
			Camera val = FindPlayerCamera();
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)$"[PortalRenderSpike] Fire Portal {id}: no player camera found - cannot aim.");
				return;
			}
			PortalSounds.Play((id == PortalId.A) ? "fire_blue" : "fire_orange", ((Component)val).transform.position, 0.5f);
			Vector3 position = ((Component)val).transform.position;
			Vector3 forward = ((Component)val).transform.forward;
			PhysGrabObject val2 = LocalHeldPortalGun();
			RaycastHit[] array = Physics.RaycastAll(position, forward, 120f, -1, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit val3 = default(RaycastHit);
			bool flag = false;
			int num = LayerMask.NameToLayer("RoomVolume");
			int num2 = LayerMask.NameToLayer("Default");
			string text = null;
			RaycastHit[] array2 = array;
			for (int num3 = 0; num3 < array2.Length; num3++)
			{
				RaycastHit val4 = array2[num3];
				if ((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null || ((Object)(object)val2 != (Object)null && ((Component)((RaycastHit)(ref val4)).collider).transform.IsChildOf(((Component)val2).transform)) || ((Component)((RaycastHit)(ref val4)).collider).gameObject.layer == num)
				{
					continue;
				}
				if (((Component)((RaycastHit)(ref val4)).collider).gameObject.layer != num2)
				{
					text = ((Object)((Component)((RaycastHit)(ref val4)).collider).gameObject).name;
					continue;
				}
				if ((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<BreakableWall>() != (Object)null)
				{
					text = ((Object)((Component)((RaycastHit)(ref val4)).collider).gameObject).name;
					continue;
				}
				val3 = val4;
				flag = true;
				break;
			}
			if (!flag)
			{
				if (text != null)
				{
					Log.LogWarning((object)$"[PortalRenderSpike] Portal {id} FIZZLE: only non-placeable geometry ('{text}' - a movable/door/cart/breakable) in the aim path within {120f:F0}m; no static wall behind it.");
				}
				else
				{
					Log.LogInfo((object)$"[PortalRenderSpike] Portal {id} FIZZLE: no surface within {120f:F0}m of the aim ray.");
				}
				PortalSounds.Play("fizzle", position + forward * 3f, 0.5f);
				return;
			}
			Vector3 point = ((RaycastHit)(ref val3)).point;
			if (!AutoFitPoint(ref point, ((RaycastHit)(ref val3)).normal))
			{
				Log.LogWarning((object)$"[PortalRenderSpike] Portal {id} FIZZLE: no spot near {((RaycastHit)(ref val3)).point} fits the whole portal (surface too curved/small/edged). Aim at a bigger flat wall section.");
				PortalSounds.Play("fizzle", ((RaycastHit)(ref val3)).point, 0.5f);
				return;
			}
			((RaycastHit)(ref val3)).point = point;
			PortalLink portalLink = ((id == PortalId.A) ? portalB : portalA);
			if (portalLink != null && Vector3.Distance(((RaycastHit)(ref val3)).point, portalLink.Quad.position) < 1.3f)
			{
				Log.LogWarning((object)$"[PortalRenderSpike] Portal {id} FIZZLE: aim point is only {Vector3.Distance(((RaycastHit)(ref val3)).point, portalLink.Quad.position):F2}m from the other portal (< portal width {1.3f}m) - pick a spot farther away.");
				return;
			}
			Vector3 pos = ((RaycastHit)(ref val3)).point + ((RaycastHit)(ref val3)).normal * 0.05f;
			Quaternion rot = PortalRotationForNormal(((RaycastHit)(ref val3)).normal);
			ApplyPortalPlacement(id, pos, rot);
			BroadcastPortalFire(id, pos, rot);
			bool flag2 = portalA != null && portalB != null;
			Log.LogInfo((object)string.Format("[PortalRenderSpike] Portal {0} PLACED on '{1}' at {2} (normal={3}, {4:F1}m from camera). {5}", id, ((Object)((Component)((RaycastHit)(ref val3)).collider).gameObject).name, ((RaycastHit)(ref val3)).point, ((RaycastHit)(ref val3)).normal, ((RaycastHit)(ref val3)).distance, flag2 ? "Pair LINKED - live view + walk-through active." : "Waiting for the other portal - this one shows its inactive colour until the pair is complete."));
		}

		private static bool InSharedRoom()
		{
			if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null)
			{
				return PhotonNetwork.CurrentRoom.PlayerCount > 1;
			}
			return false;
		}

		private void ApplyPortalPlacement(PortalId id, Vector3 pos, Quaternion rot)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			DestroyStraddlers();
			Vector3 val = rot * Vector3.forward;
			Collider val2 = null;
			RaycastHit val3 = default(RaycastHit);
			if (Physics.Raycast(pos + val * 0.25f, -val, ref val3, 0.6f, -1, (QueryTriggerInteraction)1))
			{
				val2 = ((RaycastHit)(ref val3)).collider;
			}
			if (id == PortalId.A)
			{
				DestroyPortalLink(ref portalA);
				portalA = CreatePortalAt("PortalRenderSpike_A", pos, rot, val2);
				if (portalA != null)
				{
					ClearProtrudingTrim(portalA);
					if ((Object)(object)val2 != (Object)null)
					{
						portalA.RimCollider = BuildPortalAperture(portalA);
					}
				}
			}
			else
			{
				DestroyPortalLink(ref portalB);
				portalB = CreatePortalAt("PortalRenderSpike_B", pos, rot, val2);
				if (portalB != null)
				{
					ClearProtrudingTrim(portalB);
					if ((Object)(object)val2 != (Object)null)
					{
						portalB.RimCollider = BuildPortalAperture(portalB);
					}
				}
			}
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (portalA != null)
				{
					wasInFrontOfA = Vector3.Dot(((Component)instance).transform.position - portalA.Quad.position, portalA.Quad.forward) > 0f;
				}
				if (portalB != null)
				{
					wasInFrontOfB = Vector3.Dot(((Component)instance).transform.position - portalB.Quad.position, portalB.Quad.forward) > 0f;
				}
			}
			UpdatePortalActivationVisuals();
			PortalSounds.Play((id == PortalId.A) ? "open_blue" : "open_orange", pos, 0.8f);
			if (portalA != null && portalB != null)
			{
				ArmLinkSelfTest();
			}
		}

		private object[] BuildFirePayload(PortalId id, Vector3 pos, Quaternion rot)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			return new object[4]
			{
				"PGUN.v1",
				(byte)id,
				pos,
				rot
			};
		}

		private bool TryApplyRemoteFire(object[] a)
		{
			//IL_0030: 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)
			if (a == null || a.Length < 4 || !(a[0] is string text) || text != "PGUN.v1")
			{
				return false;
			}
			ApplyPortalPlacement((PortalId)(byte)a[1], (Vector3)a[2], (Quaternion)a[3]);
			return true;
		}

		private void BroadcastPortalFire(PortalId id, Vector3 pos, Quaternion rot)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (_fireEvent == null || !InSharedRoom())
			{
				return;
			}
			try
			{
				_fireEvent.RaiseEvent((object)BuildFirePayload(id, pos, rot), NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[PortalRenderSpike] portal FIRE broadcast failed: " + ex.Message));
			}
		}

		private void OnPortalFireEvent(EventData data)
		{
			try
			{
				if (data.CustomData is object[] a && TryApplyRemoteFire(a))
				{
					Log.LogInfo((object)$"[PortalRenderSpike] MP: applied remote portal placement from sender {data.Sender}.");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[PortalRenderSpike] portal FIRE receive failed: " + ex.Message));
			}
		}

		private void BroadcastPortalClear()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (_clearEvent == null || !InSharedRoom())
			{
				return;
			}
			try
			{
				_clearEvent.RaiseEvent((object)new object[1] { "PGUN.v1" }, NetworkingEvents.RaiseOthers, SendOptions.SendReliable);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[PortalRenderSpike] portal CLEAR broadcast failed: " + ex.Message));
			}
		}

		private void OnPortalClearEvent(EventData data)
		{
			try
			{
				if (data.CustomData is object[] array && array.Length >= 1 && array[0] is string text && !(text != "PGUN.v1"))
				{
					DestroyStraddlers();
					DestroyExistingPair();
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[PortalRenderSpike] portal CLEAR receive failed: " + ex.Message));
			}
		}

		private void UpdatePortalActivationVisuals()
		{
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			bool flag = portalA != null && portalB != null;
			if ((Object)(object)portalA?.SwirlOverlay != (Object)null)
			{
				portalA.SwirlOverlay.SetActive(!flag);
			}
			if ((Object)(object)portalB?.SwirlOverlay != (Object)null)
			{
				portalB.SwirlOverlay.SetActive(!flag);
			}
			if (flag)
			{
				((Renderer)portalA.ScreenRenderer).material.mainTexture = (Texture)(object)portalB.Texture;
				((Renderer)portalB.ScreenRenderer).material.mainTexture = (Texture)(object)portalA.Texture;
				Log.LogInfo((object)("[PortalRenderSpike] CROSS-WIRE: " + ((Object)portalA.Quad).name + ".screen <- " + ((Object)portalB.Quad).name + "_Camera.RT ('" + ((Object)portalB.Texture).name + "'); " + ((Object)portalB.Quad).name + ".screen <- " + ((Object)portalA.Quad).name + "_Camera.RT ('" + ((Object)portalA.Texture).name + "')."));
			}
			if (portalA != null)
			{
				((Renderer)portalA.ScreenRenderer).material.SetInt("displayMask", flag ? 1 : 0);
				((Renderer)portalA.ScreenRenderer).material.SetColor("_InactiveColour", new Color(0.15f, 0.45f, 1f, 1f));
			}
			if (portalB != null)
			{
				((Renderer)portalB.ScreenRenderer).material.SetInt("displayMask", flag ? 1 : 0);
				((Renderer)portalB.ScreenRenderer).material.SetColor("_InactiveColour", new Color(1f, 0.55f, 0.1f, 1f));
			}
		}

		private void ArmLinkSelfTest()
		{
			if (portalA != null && portalB != null)
			{
				if (linkSelfTestRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(linkSelfTestRoutine);
				}
				linkSelfTestRoutine = ((MonoBehaviour)this).StartCoroutine(LinkSelfTestCoroutine());
			}
		}

		private IEnumerator LinkSelfTestCoroutine()
		{
			yield return (object)new WaitForSeconds(2f);
			Camera val = FindPlayerCamera();
			if (!cameraDumpDone && (Object)(object)val != (Object)null)
			{
				cameraDumpDone = true;
				Component[] components = ((Component)val).gameObject.GetComponents<Component>();
				StringBuilder stringBuilder = new StringBuilder();
				Component[] array = components;
				foreach (Component val2 in array)
				{
					stringBuilder.Append(((Object)(object)val2 != (Object)null) ? ((object)val2).GetType().Name : "null").Append(", ");
				}
				Log.LogInfo((object)string.Format("[PortalRenderSpike] CAMERA-DUMP: name='{0}' tag='{1}' clearFlags={2} cullingMask=0x{3:X} targetTexture={4} fov={5:F1} near={6:F3} far={7:F0} allowHDR={8} components=[{9}]", ((Object)((Component)val).gameObject).name, ((Component)val).gameObject.tag, val.clearFlags, val.cullingMask, ((Object)(object)val.targetTexture != (Object)null) ? $"'{((Object)val.targetTexture).name}' {((Texture)val.targetTexture).width}x{((Texture)val.targetTexture).height}" : "none (renders to screen)", val.fieldOfView, val.nearClipPlane, val.farClipPlane, val.allowHDR, stringBuilder));
			}
			SelfTestPortal(portalA, "A", val);
			SelfTestPortal(portalB, "B", val);
			linkSelfTestRoutine = null;
		}

		private void SelfTestPortal(PortalLink? link, string label, Camera? playerCam)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (link == null)
			{
				return;
			}
			try
			{
				if ((Object)(object)playerCam != (Object)null && portalA != null && portalB != null)
				{
					PortalLink portalLink = ((label == "A") ? portalB : portalA);
					GetCameraRenderPose(playerCam, out var pos, out var rot);
					ComputeMirroredPose(pos, rot, portalLink.Quad.position, portalLink.Quad.rotation, link.Quad.position, link.Quad.rotation, out var camPos, out var camRot);
					((Component)link.PortalCam).transform.SetPositionAndRotation(camPos, camRot);
					link.PortalCam.ResetProjectionMatrix();
					link.PortalCam.fieldOfView = playerCam.fieldOfView;
					link.PortalCam.aspect = playerCam.aspect;
					link.PortalCam.nearClipPlane = playerCam.nearClipPlane;
				}
				link.PortalCam.Render();
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = link.Texture;
				int num = Mathf.Max(0, ((Texture)link.Texture).width / 2 - 8);
				int num2 = Mathf.Max(0, ((Texture)link.Texture).height / 2 - 8);
				Texture2D val = new Texture2D(16, 16, (TextureFormat)3, false);
				val.ReadPixels(new Rect((float)num, (float)num2, 16f, 16f), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				Color32[] pixels = val.GetPixels32();
				byte b = byte.MaxValue;
				byte b2 = 0;
				long num3 = 0L;
				Color32[] array = pixels;
				foreach (Color32 val2 in array)
				{
					byte b3 = (byte)((val2.r + val2.g + val2.b) / 3);
					if (b3 < b)
					{
						b = b3;
					}
					if (b3 > b2)
					{
						b2 = b3;
					}
					num3 += b3;
				}
				Object.Destroy((Object)(object)val);
				float num4 = (float)num3 / (float)pixels.Length;
				string text = ((b2 - b > 8) ? "NON-UNIFORM (RENDERED - real pixels; if it still looks black in-game the issue is brightness/post, not a dead RT)" : ((b2 <= 12) ? "UNIFORM BLACK (dead or seeing nothing - check cullingMask/transform/renderCount)" : "UNIFORM NON-BLACK (clear colour only - camera renders but sees no geometry)"));
				Log.LogInfo((object)$"[PortalRenderSpike] SELF-TEST portal {label}: normal-path renderCount={link.RenderCount}, forced-render readback 16x16 center: min={b} max={b2} avg={num4:F1} -> {text}. NOTE cross-wiring: this RT is rendered by portal {label}'s camera and DISPLAYS ON THE PARTNER portal's screen (Lague convention). renderCount stays 0 while the partner's quad is never on-screen - that is the visibility cull working, not a dead driver. Driver=manual Camera.Render() from Update (Built-in RP - no SRP assemblies in REPO_Data/Managed).");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[PortalRenderSpike] SELF-TEST portal " + label + " FAILED: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void StartSelfWalk()
		{
			if (portalA == null || portalB == null)
			{
				Log.LogWarning((object)"[PortalRenderSpike] J pressed but no active portal pair - spawn one first (Shift+F3 showcase recommended for verification).");
				return;
			}
			PlayerController instance = PlayerController.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.rb == (Object)null)
			{
				Log.LogWarning((object)"[PortalRenderSpike] J pressed but PlayerController.instance/rb is null - cannot self-walk.");
				return;
			}
			if (selfWalkRoutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(selfWalkRoutine);
			}
			Log.LogInfo((object)"SELF-WALK: driving player into portal A");
			selfWalkRoutine = ((MonoBehaviour)this).StartCoroutine(SelfWalkCoroutine(instance));
		}

		private IEnumerator SelfWalkCoroutine(PlayerController controller)
		{
			float startTime = Time.time;
			Rigidbody rb = controller.rb;
			while (Time.time - startTime < 3f)
			{
				if (Time.time < teleportCooldownUntil)
				{
					Log.LogInfo((object)$"SELF-WALK: teleport fired after {Time.time - startTime:F2}s - player is now at {((Component)controller).transform.position} (past portal B; see the Teleport log line above for the full delta).");
					selfWalkRoutine = null;
					yield break;
				}
				if (portalA == null)
				{
					Log.LogWarning((object)"SELF-WALK: portal A vanished mid-walk (re-fired/despawned?) - stopping.");
					selfWalkRoutine = null;
					yield break;
				}
				Vector3 val = portalA.Quad.po