If you appreciate the work done within the wiki, please consider supporting The Cutting Room Floor on Patreon. Thanks for all your support!

Notes:Superliminal

From The Cutting Room Floor
Jump to navigation Jump to search

This page contains notes for the game Superliminal.

Build Numbers

Hmmm...
To do:
  • Inspect Linux build manifest [674637684925818421] (aka 1.10.2021.11.12.858.39), it seems weird. Why does it keep only the first three scenes?
    • Recently did a simulation of what would happen with the latest build, it would only load the menu and the first cutscene then freeze because it can't find a loading scene to play, leaving Induction unplayable. If the player forces themselves into Induction (via UnityExplorer or debug commands) then once they hit the end trigger, the game freezes. Don't know if I should go on with documenting the build but it's still weird.

For version differences.

Pre-Release Prototypes

All of these prototypes (Excluding "Museum of Simulation Technology Version 1") are not downloadable at this time.

Build Number Release Date Notes Source
Museum of Simulation Technology
Version 1 10/27/2013 Playable Tech Demo that was the precursor to Superliminal. Source
??? 3/14/2014? Preview trailer for Game Developers Conference 2014. Source
??? 8/12/2014? Summer Promo Trailer Source
??? 9/15/2015? Work in Progress Update #001 & played by Polygon. Pillow Castle Trailer 9/15/2015
Polygon 10/26/2015
??? 6/18/2016? "Pre-Alpha Prototype" played by Gamespot at E3 2016. Source
Unnannounced Game Title
DEMO_4219134PAX 4/2/2019 Demo was played by Giant Bomb and it seems it may have been used for a Penny Arcade Expo, but none of the 2019 dates match up with the build date. Source
Superliminal
??? 6/19/2019? E3 2019 Trailer Source
??? 8/29/2019? Instructional Trailer Source
??? 9/6/2019? TheBrainJ's PAX West 2019 Dev Interview Source
??? 11/7/2019? Launch Trailer Source

Epic Games Store Exclusive Versions

Build Number Release Date Notes Twitter Source
1.0.2019.11.11.963 11/12/2019 Initial Epic Games Store Release. Bit hard to find online.
1.0.2019.11.12.1005 11/12/2019 Easier to find online.
1.0?.2019.11.1?.???? 11/15/2019 Currently lost Source
1.0?.2019.11.??.???? 11/20/2019 Currently lost Source
1.05.2019.12.9.797 12/9/2019 Currently lost Source

Steam Demos

App ID: 1271490
(I don't think it's possible to download this from steam, even if someone had a license for it. Only way I think it could be found is if someone downloaded it while the demo was available and decided to save it to a backup drive).

Build Number Steam Build ID Steam Manifest ID Release Date Notes Video Source
1.10.2020.3.17.067 4789330 512083530367008877 3/18/2020 Currently lost (According to SteamDB, it's unknown what files it started with) Source
1.10.2020.3.19.1077 4799269 1355647673322366196 3/20/2020 Currently lost Source
1.10.2020.6.1.1032 5107356 8754035545394644518 6/15/2020 Currently lost Source

Steam Versions

App ID: 1049410

Build Number Steam Build ID Steam Manifest ID Release Date Notes
N/A 5711630 189814675170018135 10/20/2020 Empty Steam Depot
1.10.2020.10.24.58 5731400 5361343928601884083 10/25/2020 *Not a press review or streamer build. Please wait for build to release.* Includes Somnasculpt Workshop prototype.
1.10.2020.10.28.32 5758952 950493532859608225 10/30/2020 Includes updated Somnasculpt Workshop prototype.
1.10.2020.10.29.1225 5759192 1314310522287257155 10/30/2020 *Not review build* *Please wait for streamer and review build* Includes updated Somnasculpt Workshop prototype.
N/A 5763344 189814675170018135 10/30/2020 Update rollbacks to build 5711630 (That's why if you view Manifest ID 189814675170018135 on SteamDB, you can see 5759192's data).
1.10.2020.11.3.1313 5781635 7959148786794348749 11/4/2020 Somnasculpt Workshop crashes game when loaded.
1.10.2020.11.4.465 5783691 2101740051927655154 11/4/2020 Somnasculpt Workshop loads fine now.
1.10.2020.11.4.884 5784879 947562870178145618 11/4/2020
1.10.2020.11.4.1036 5785443 2358911993831512816 11/5/2020 Initial Steam Release
N/A? 5785674 8931970647707267887 11/5/2020 Mac only update (I don't have a Mac on me to check this one)
N/A? 5785867 5370944651000226375 11/5/2020 superliminal-launch-version branch somehow points here but the manifest listed is a linux update.
1.10.2020.11.11.1354 5819802 6216358686798469830 11/12/2020 "First Post-launch Update: News, big fixes, etc"
1.10.2020.11.20.951 5862410 3384338906330942294 11/23/2020 "11/23 Bug fixes"
1.10.2020.12.3.1217 5920757 3366845502878191273 12/4/2020 "Announcing the Somnasculpt Dream Workshop Level Editor"
N/A 5924422 4953421770630229029 12/4/2020 Linux only update (no major changes)
N/A 5924654 193050540437693779 12/4/2020 Linux only update (no major changes)
N/A 5924843 1235173820590897149 12/4/2020 Linux only update (no major changes)
N/A 5934468 7455564673135445775 12/7/2020 Linux only update (no major changes)
1.10.2020.12.10.971 5952707 7110343821965905499 12/11/2020 "Level Editor: Major Update and End-of-year notes" [superliminal-previous-patch branch]
1.10.2021.4.18.111 6564234 119793487193499281 4/23/2021 "April 2021 Update & LudoNarraCon sale!"/"Quick Fix Patch"
1.10.2021.5.10.791 6678674 4743178048305939315 5/19/2021
1.10.2021.11.5.550.43 7665136 4269649591510852563 11/5/2021 "Out today: 'Group Therapy' - A Free Multiplayer Update to Superliminal + 50% off"
1.10.2021.11.12.858.39 7705875 3614934652523843138 11/13/2021 "Multiplayer Week One Update"
N/A? 7709483 3614934652523843138 11/14/2021 Unsure why this one is listed on SteamDB, it's just update 7705875 again but without the Linux build.
1.10.2021.11.12.858.39 7767071 7224305671286705868 11/24/2021 "Region merge"
1.10.2021.12.16.1298.39 7904836 3785643547020750819 12/17/2021 "Co-Op launch + Holiday Update for Multiplayer"
1.10.2021.12.20.828.57 7918004 5131471526541586811 12/21/2021
N/A? 8188286 5418825235250573680 2/11/2022 Mac only update (I don't have a Mac on me to check this one)
N/A? 8188287 5620902754772649130 2/11/2022 Linux only update (could possibly check this one)
1.10.2022.2.20.838.2 8242454 7149275414135219251 2/21/2022 "Steam Deck! Multiplayer on macOS and Linux + Content Update + Midweek Madness" (Was only available for seven hours and twenty-two minutes)
1.10.2022.2.20.838.2 8245107 7871867229536493116 2/21/2022 "Steam Deck! Multiplayer on macOS and Linux + Content Update + Midweek Madness"
1.10.2022.12.19.1005.12 10182655 4972230278923180684 12/21/2022 "Big sale! Plus, Holiday Decorations return to Multiplayer for the Winter season!"
1.10.2023.2.17.882.59 10585644 3646111955971398231 2/19/2022 "Multiplayer improvements patch, with a big ol' sale to celebrate!" (Latest Build)

GOG Versions

Hmmm...
To do:
  • Find out the rest of the version numbers.
Build Number GOG Version Release Date Notes
??? 1.05 11/05/2020
??? 1.06 11/12/2020
??? 1.11 12/11/2020
??? 1.15 04/19/2021
??? 1.16 05/11/2021
??? 1.2 11/17/2021
??? 1.2a 11/25/2021
??? 1.22 12/21/2021
1.10.2022.2.20.838.2 1.3 02/21/2022 Seems like Somnasculpt Workshop is slightly different, don't know if there's any changes with anything else.

Debug Commands Decompiling

DrawCursorScriptHand

Commands mentioned: pm

using UnityEngine;
using UnityEngine.UI;

public class DrawCursorScriptHand : MonoBehaviour
{
  public Texture pointTexture;
  private Texture resetPointTexture;
  public Texture handTexture;
  public Texture grabTexture;
  public Texture blockedTexture;
  public Texture returnTexture;
  public Texture pointLeftAndRightTexture;
  public Texture pointUpAndDownTexture;
  public Texture changePointTexture;
  public RawImage GrabProgress;
  public string PowerupHoverProgressSound;
  public float PowerupHoverProgressSoundTimerBase;
  public float PowerupHoverProgressSoundTimer;
  public RawImage BeingTargeted;
  public Texture optionalCanGrabUITexture;
  public Texture interactTexture;
  public Texture instantProjectTexture;
  private bool drawInteractTexture;
  private bool drawMPGroupTriggerStatus;
  private float? interactCountdownProgress;
  private bool drawButtonPrompt_Consoles;
  private int lastUpdatedFrame;
  private bool hasDrawnScreenYet;
  private bool drawGrabTexture;
  public bool drawPointLeftAndRightTexture;
  public bool drawPointUpAndDownTexture;
  public Texture interact_SWITCH_Texture;
  public Texture interact_PS4_Texture;
  public Texture interact_XBOX_Texture;
  public RawImage ButtonPrompt_Consoles;
  public ResizeScript resizescript;
  public Text MultiplayerGroupTriggerStatus;
  private int point_texture_size = 20;
  private int hand_texture_size = 80;
  private int grab_texture_size = 80;
  private int blocked_texture_size = 80;
  public float xOffset;
  public float yOffset;
  public float xMoveSpeed;
  public float yMoveSpeed;
  public bool driftingCrosshair;
  public bool growCursor;
  public float growSpeed;
  public float placeholder;
  public bool ForceHideCursor;
  private Canvas canvas;
  private RawImage cursor;
  public Vector2 crosshairScreenPos;
  private KeystrokeTracker typedPM;
  private Material grabProgressMaterial;
  private MultiplayerType matchType;
  private float debugHideCursorTimer;
  private const float DebugHideCursorTime = 1f;
  private bool debugHideCursor;
  private int lastPlayerCount = -1;
  private int lastTotalPlayerCount = -1;

  private void Start()
  {
    this.matchType = MultiplayerHelper.GetMatchType();
    this.resetPointTexture = this.pointTexture;
    if ((Object) this.canvas == (Object) null)
    {
      this.canvas = this.transform.GetComponentInChildren<Canvas>();
      this.cursor = this.canvas.GetComponentInChildren<RawImage>();
    }
    this.cursor.gameObject.SetActive(false);
    this.typedPM = new KeystrokeTracker()
    {
      KeyCodes = new KeyCode[2]{ KeyCode.P, KeyCode.M }
    };
  }

  private void OnDestroy()
  {
    Object.Destroy((Object) this.grabProgressMaterial);
    this.grabProgressMaterial = (Material) null;
  }

  private void Update()
  {
    if ((Object) this.canvas == (Object) null)
      return;
    if (!GameManager.GM.PM.canControl || this.ForceHideCursor || this.debugHideCursor)
    {
      this.cursor.gameObject.SetActive(false);
    }
    else
    {
      if (!this.cursor.gameObject.activeSelf)
        this.cursor.gameObject.SetActive(true);
      if (this.drawInteractTexture)
      {
        this.DrawCenteredGUI(this.interactTexture, this.hand_texture_size);
        this.hasDrawnScreenYet = false;
      }
      else if (!this.resizescript.isReadyToGrab && !this.resizescript.isGrabbing && (!this.resizescript.isObjectBlocked && !this.drawGrabTexture))
      {
        if (!this.drawPointUpAndDownTexture && !this.drawPointLeftAndRightTexture)
          this.DrawCenteredGUI(this.pointTexture, this.point_texture_size);
        else if (this.drawPointUpAndDownTexture)
          this.DrawCenteredGUI(this.pointUpAndDownTexture, this.grab_texture_size);
        else if (this.drawPointLeftAndRightTexture)
          this.DrawCenteredGUI(this.pointLeftAndRightTexture, this.grab_texture_size);
      }
      else if (this.resizescript.isGrabbing || this.drawGrabTexture || this.drawPointUpAndDownTexture)
      {
        if (this.resizescript.isObjectBlocked)
        {
          this.DrawCenteredGUI(this.blockedTexture, this.blocked_texture_size);
        }
        else
        {
          this.drawGrabTexture = true;
          if (this.drawGrabTexture)
            this.DrawCenteredGUI(this.grabTexture, this.grab_texture_size);
          else if (this.drawPointUpAndDownTexture)
            this.DrawCenteredGUI(this.pointUpAndDownTexture, this.grab_texture_size);
        }
      }
      else if (!this.resizescript.isGrabbing && !this.resizescript.isObjectBlocked && this.resizescript.isObjectReadyToReturn)
        this.DrawCenteredGUI(this.returnTexture, this.hand_texture_size);
      else if (!this.resizescript.isGrabbing && !this.resizescript.isObjectBlocked)
      {
        if (!this.resizescript.isPointingAtInstantProjectObj)
        {
          this.DrawCenteredGUI(this.handTexture, this.hand_texture_size);
          if ((bool) (Object) this.optionalCanGrabUITexture)
            this.DrawCenteredGUI(this.optionalCanGrabUITexture, this.hand_texture_size);
          this.drawButtonPrompt_Consoles = this.resizescript.GetGrabbedObject_ButtonPromptBool();
        }
        else
          this.DrawCenteredGUI(this.instantProjectTexture, this.hand_texture_size);
      }
      else if (!this.resizescript.isGrabbing && this.resizescript.isObjectBlocked)
        this.DrawCenteredGUI(this.blockedTexture, this.blocked_texture_size);
      if (GameManager.GM.CanUseKeyboardHotKeys() && this.typedPM.Check())
      {
        this.debugHideCursor = !this.debugHideCursor;
        Debug.developerConsoleVisible = !Debug.developerConsoleVisible;
        SaveAndCheckpointManager objectOfType = Object.FindObjectOfType<SaveAndCheckpointManager>();
        objectOfType.showSaveIconWhileSaving = !objectOfType.showSaveIconWhileSaving;
      }
      if (this.driftingCrosshair)
      {
        this.xOffset += Time.deltaTime * this.xMoveSpeed;
        this.yOffset += Time.deltaTime * this.yMoveSpeed;
      }
      if (this.growCursor)
      {
        this.placeholder += Time.deltaTime * this.growSpeed;
        this.point_texture_size = (int) this.placeholder;
      }
      float? percentWaitingToGrab = this.resizescript.GetPercentWaitingToGrab();
      float? forceLetGoProgress = this.resizescript.GetForceLetGoProgress();
      float? recoveryProgress = this.resizescript.GetShouldShowGrabRecoveryProgress();
      bool flag = this.interactCountdownProgress.HasValue && !this.resizescript.isGrabbing;
      this.GrabProgress.gameObject.SetActive(((percentWaitingToGrab.HasValue || forceLetGoProgress.HasValue ? 1 : (recoveryProgress.HasValue ? 1 : 0)) | (flag ? 1 : 0)) != 0);
      if (this.GrabProgress.gameObject.activeSelf && !(bool) (Object) this.grabProgressMaterial)
      {
        this.grabProgressMaterial = new Material(this.GrabProgress.material);
        this.GrabProgress.material = this.grabProgressMaterial;
      }
      if (recoveryProgress.HasValue)
      {
        this.grabProgressMaterial.SetFloat("_Progress", 0.0f);
        this.grabProgressMaterial.SetFloat("_Fill", recoveryProgress.Value);
        this.grabProgressMaterial.SetColor("_Tint", Color.white);
      }
      else if (percentWaitingToGrab.HasValue)
      {
        this.grabProgressMaterial.SetFloat("_Progress", percentWaitingToGrab.Value);
        this.grabProgressMaterial.SetFloat("_Fill", 1f);
        this.grabProgressMaterial.SetColor("_Tint", Color.white);
      }
      else if (forceLetGoProgress.HasValue)
      {
        this.grabProgressMaterial.SetFloat("_Progress", forceLetGoProgress.Value);
        this.grabProgressMaterial.SetFloat("_Fill", 0.0f);
        this.grabProgressMaterial.SetColor("_Tint", Color.white);
      }
      else if (flag)
      {
        this.grabProgressMaterial.SetFloat("_Progress", 1f - this.interactCountdownProgress.Value);
        this.grabProgressMaterial.SetFloat("_Fill", 1f);
        this.grabProgressMaterial.SetColor("_Tint", new Color(0.5f, 1f, 0.5f));
      }
      else
        this.PowerupHoverProgressSoundTimer = 0.0f;
      if ((bool) (Object) this.BeingTargeted && this.matchType == MultiplayerType.BattleRoyale)
      {
        MultiplayerPlayer component = GameManager.GM.player.GetComponent<MultiplayerPlayer>();
        if ((bool) (Object) component)
        {
          float? nullable = component.AmIBeingTargeted();
          this.BeingTargeted.gameObject.SetActive(nullable.HasValue);
          if (nullable.HasValue)
            this.BeingTargeted.color = new Color(1f, 0.0f, 0.0f, Mathf.Clamp01(nullable.Value));
        }
      }
      if ((bool) (Object) this.MultiplayerGroupTriggerStatus)
        this.MultiplayerGroupTriggerStatus.gameObject.SetActive(this.drawMPGroupTriggerStatus);
      this.drawInteractTexture = false;
      this.interactCountdownProgress = new float?();
      this.drawGrabTexture = false;
      this.drawButtonPrompt_Consoles = false;
      this.drawMPGroupTriggerStatus = false;
    }
  }

  private void DrawCenteredGUI(Texture texture, int textureSize)
  {
    this.cursor.texture = texture;
    RectTransform component = this.cursor.GetComponent<RectTransform>();
    component.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, (float) textureSize);
    component.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, (float) textureSize);
    this.crosshairScreenPos = new Vector2((float) ((double) Screen.width / 2.0 - (double) textureSize / 2.0) + this.xOffset, (float) ((double) Screen.height / 2.0 - (double) textureSize / 2.0) + this.yOffset);
  }

  private void UpdateMultiplayerGroupTriggerStatus(int playerCount, int totalPlayerCount)
  {
    if (playerCount == this.lastPlayerCount && totalPlayerCount == this.lastTotalPlayerCount)
      return;
    this.lastPlayerCount = playerCount;
    this.lastTotalPlayerCount = totalPlayerCount;
    this.MultiplayerGroupTriggerStatus.text = string.Format("{0} / {1}", (object) this.lastPlayerCount, (object) this.lastTotalPlayerCount);
  }

  public void DrawMultiplayerGroupTriggerStatus(int playerCount, int totalPlayerCount)
  {
    this.UpdateMultiplayerGroupTriggerStatus(playerCount, totalPlayerCount);
    this.drawMPGroupTriggerStatus = true;
  }

  public void DrawInteractGUI(bool includeButtonPrompt, float? countdownProgress = null)
  {
    this.drawInteractTexture = true;
    if (!this.interactCountdownProgress.HasValue)
      this.interactCountdownProgress = countdownProgress;
    if (!includeButtonPrompt)
      return;
    this.drawButtonPrompt_Consoles = true;
  }

  public void DrawGrabGUI() => this.drawGrabTexture = true;

  public void DrawPointLeftAndRightGUI() => this.drawPointLeftAndRightTexture = true;

  public void DrawPointUpAndDownGUI() => this.drawPointUpAndDownTexture = true;

  public void TurnOffPointLeftAndRightAndUpAndDownGUI()
  {
    this.drawPointLeftAndRightTexture = false;
    this.drawPointUpAndDownTexture = false;
  }

  public void ChangePointTexture() => this.pointTexture = this.changePointTexture;

  public void ResetPointTexture() => this.pointTexture = this.resetPointTexture;

  public void ReplacePointTexture(Texture replaceWith) => this.pointTexture = replaceWith;

  public void ReplaceInteractTexture(Texture replaceWith) => this.interactTexture = replaceWith;

  public void ChangePointTextureSize(int textureSize) => this.point_texture_size = textureSize;

  public void StartGrowCursor()
  {
    this.placeholder = (float) this.point_texture_size;
    this.growCursor = true;
  }

  public void SetGrowCursorSpeed(float theSpeed) => this.growSpeed = theSpeed;

  public void ToggleForceCursorOff() => this.ForceHideCursor = true;

  public void ToggleForceCursorOn() => this.ForceHideCursor = false;
}

GifMode

Commands mentioned: gif

using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

public class GifMode : MonoBehaviour
{
  public PostProcessVolume GifVolume;
  private PostProcessLayer ppLayer;
  private PostProcessLayer.Antialiasing antiAliasingOrig;
  private KeystrokeTracker typedGIF;

  private void Start()
  {
    this.typedGIF = new KeystrokeTracker()
    {
      KeyCodes = new KeyCode[3]
      {
        KeyCode.G,
        KeyCode.I,
        KeyCode.F
      }
    };
    this.ppLayer = this.GetComponent<PostProcessLayer>();
    this.antiAliasingOrig = this.ppLayer.antialiasingMode;
  }

  private void Update()
  {
    if (!GameManager.GM.CanUseKeyboardHotKeys() || !this.typedGIF.Check())
      return;
    PostProcessManager.instance.GlobalSettings.GifModeOn = !PostProcessManager.instance.GlobalSettings.GifModeOn;
    this._UpdateGIFMode();
  }

  private void _UpdateGIFMode()
  {
    this.GifVolume.gameObject.SetActive(PostProcessManager.instance.GlobalSettings.GifModeOn);
    this.ppLayer.antialiasingMode = PostProcessManager.instance.GlobalSettings.GifModeOn ? PostProcessLayer.Antialiasing.None : this.antiAliasingOrig;
  }
}

KeystrokeTracker

Only added here just for reference.

using UnityEngine;

public class KeystrokeTracker
{
  public KeyCode[] KeyCodes;
  private int currentIndex;
  private const float InARowTime = 1f;
  private float triggerTime;

  public bool Check()
  {
    if (GameManager.GM.CanUseKeyboardHotKeys() && this.KeyCodes.Length >= 2)
    {
      this.triggerTime -= Time.deltaTime;
      if (this.currentIndex > 0)
      {
        if ((double) this.triggerTime <= 0.0)
          this._Reset();
        else if (Input.GetKeyDown(this.KeyCodes[this.currentIndex]))
        {
          this._Next();
          if (this.currentIndex >= this.KeyCodes.Length)
          {
            this._Reset();
            return true;
          }
        }
      }
      else if (Input.GetKeyDown(this.KeyCodes[0]))
        this._Next();
    }
    return false;
  }

  private void _Next()
  {
    ++this.currentIndex;
    this.triggerTime = 1f;
  }

  private void _Reset()
  {
    this.currentIndex = 0;
    this.triggerTime = 0.0f;
  }
}

LevelJumpingScript

Commands mentioned: fps, tex, =, -, 77, [LeftShift]/[RightShift] + 0-9, gg

using FMODUnity;
using System;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelJumpingScript : MonoBehaviour
{
  private static GameObject firstInstance;
  public bool skipToSpecificLevel;
  public int specificLevelToSkipTo;
  private static DateTime currentLevelStartTime = DateTime.Now;
  private static DateTime lastTimeSinceMenu = DateTime.Now;
  public bool inDevFastForwardMode;
  public bool doubleTapForFastForward;
  public float doubleTapForFastForwardTimerBase;
  public float doubleTapForFastForwardTimer;
  public bool allowNoClip;
  public bool noClip;
  public GameObject cameraNoClip;
  public GameObject instanceCameraNoClip;
  public bool doubleTapForNoClip;
  public float doubleTapForNoClipTimerBase;
  public float doubleTapForNoClipTimer;
  public GameObject FPSCounter;
  public ShowTextureStreamingSummary TextureStreamingDebug;
  private readonly KeystrokeTracker fpsTracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[3]
    {
      KeyCode.F,
      KeyCode.P,
      KeyCode.S
    }
  };
  private readonly KeystrokeTracker streamingTracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[3]
    {
      KeyCode.T,
      KeyCode.E,
      KeyCode.X
    }
  };
  public bool cursorOn = true;
  public GameObject cursorObject;

  private void Start()
  {
    UnityEngine.Object.DontDestroyOnLoad((UnityEngine.Object) this);
    if ((UnityEngine.Object) LevelJumpingScript.firstInstance != (UnityEngine.Object) null)
      UnityEngine.Object.DestroyImmediate((UnityEngine.Object) this);
    else
      LevelJumpingScript.firstInstance = this.gameObject;
  }

  private void Update()
  {
    if (GameManager.GM.CanUseKeyboardHotKeys())
    {
      if (this.fpsTracker.Check())
        this.FPSCounter.SetActive(!this.FPSCounter.activeSelf);
      if (this.streamingTracker.Check())
        this.TextureStreamingDebug.enabled = !this.TextureStreamingDebug.enabled;
      if (Input.GetKeyDown(KeyCode.Equals))
      {
        int num = (int) RuntimeManager.GetBus("Bus:/").stopAllEvents(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
        SceneManager.LoadScene((Application.loadedLevel + 1) % Application.levelCount);
      }
      if (Input.GetKeyDown("-"))
      {
        int num = (int) RuntimeManager.GetBus("Bus:/").stopAllEvents(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
        SceneManager.LoadScene((Application.loadedLevel - 1) % Application.levelCount);
      }
    }
    if (!((UnityEngine.Object) this.GetComponent<GameManager>() != (UnityEngine.Object) null))
      return;
    int num1 = this.GetComponent<GameManager>().debugModeOn ? 1 : 0;
    if (!GameManager.GM.CanUseKeyboardHotKeys())
      return;
    if ((double) this.doubleTapForFastForwardTimer > 0.0)
    {
      this.doubleTapForFastForwardTimer -= Time.unscaledDeltaTime;
      if (Input.GetKeyDown(KeyCode.Alpha7))
        this.ToggleFastForward();
    }
    else
      this.doubleTapForFastForwardTimer = 0.0f;
    if (!this.doubleTapForFastForward)
    {
      if (Input.GetKeyDown(KeyCode.Alpha7))
        this.ToggleFastForward();
    }
    else if (Input.GetKeyDown(KeyCode.Alpha7))
      this.doubleTapForFastForwardTimer = this.doubleTapForFastForwardTimerBase;
    if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
    {
      for (int index = 0; index < 10; ++index)
      {
        if (Input.GetKeyDown((KeyCode) (48 + index)))
          GameManager.GM.GetComponent<SaveAndCheckpointManager>().TeleportToCheckpointIndexDebug(index);
      }
    }
    if (!this.allowNoClip)
      return;
    if (this.doubleTapForNoClip)
    {
      if ((double) this.doubleTapForNoClipTimer > 0.0)
      {
        this.doubleTapForNoClipTimer -= Time.deltaTime;
        if (Input.GetKeyDown(KeyCode.G))
        {
          if (!this.noClip || (UnityEngine.Object) this.instanceCameraNoClip == (UnityEngine.Object) null)
            this.CreateNoClipCamera();
          else
            this.EndNoClip();
        }
      }
      else
        this.doubleTapForNoClipTimer = 0.0f;
    }
    if (!Input.GetKeyDown(KeyCode.G))
      return;
    if (!this.doubleTapForNoClip)
    {
      if (!this.noClip || (UnityEngine.Object) this.instanceCameraNoClip == (UnityEngine.Object) null)
        this.CreateNoClipCamera();
      else
        this.EndNoClip();
    }
    else
      this.doubleTapForNoClipTimer = this.doubleTapForNoClipTimerBase;
  }

  private void CreateNoClipCamera()
  {
    MonoBehaviour.print((object) "noclip");
    this.instanceCameraNoClip = UnityEngine.Object.Instantiate<GameObject>(this.cameraNoClip, GameManager.GM.playerCamera.transform.position, Quaternion.identity);
    this.instanceCameraNoClip.transform.LookAt(this.instanceCameraNoClip.transform.position + Vector3.Scale(GameManager.GM.playerCamera.transform.forward, new Vector3(1f, 0.0f, 1f)), Vector3.up);
    GameManager.GM.player.gameObject.SetActive(false);
    this.noClip = true;
  }

  private void EndNoClip()
  {
    GameManager.GM.player.gameObject.transform.position = this.instanceCameraNoClip.transform.position;
    Vector3 worldPosition = this.instanceCameraNoClip.transform.position + Vector3.Scale(this.instanceCameraNoClip.transform.forward, new Vector3(1f, 0.0f, 1f));
    GameManager.GM.player.transform.LookAt(worldPosition);
    GameManager.GM.player.gameObject.SetActive(true);
    UnityEngine.Object.Destroy((UnityEngine.Object) this.instanceCameraNoClip);
    this.noClip = false;
  }

  private void ToggleFastForward()
  {
    if (!this.inDevFastForwardMode)
    {
      Time.timeScale = 10f;
      this.inDevFastForwardMode = true;
    }
    else
    {
      Time.timeScale = 1f;
      this.inDevFastForwardMode = false;
    }
  }

  private void OnApplicationFocus(bool hasFocus)
  {
  }

  public void GoToNextLevel()
  {
    GameManager.GM.MyLog("next level");
    SceneManager.LoadScene((Application.loadedLevel + 1) % Application.levelCount);
  }
}

MultiplayerLevelInfo

Commands mentioned: photon

using ExitGames.Client.Photon;
using Photon.Pun;
using Photon.Pun.UtilityScripts;
using Photon.Realtime;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

public class MultiplayerLevelInfo : MonoBehaviourPunCallbacks
{
  private const string recentlyUsedChunksNameKey = "recentlyUsedChunks";
  public bool IsPlayerCloneable;
  public CountdownTimer CountdownTimer;
  public PlayerProgressTracking PlayerPath;
  public UnityEvent OptionalInitializationEvents;
  public PowerupMetadata PowerupMetadata;
  public MultiplayerLevelChunk[] LevelChunks;
  public int NumberOfLevelChunksToUse = 6;
  public Camera[] ObservationModeCameras;
  public GameObject PhotonStats;
  public UnityEvent OnAllPlayersLoaded;
  [Tooltip("Look under this component for spawn points")]
  public GameObject OptionalSpawnPointSearch;
  public Transform[] TemporarySpawnPointsForAdditive;
  public GlobalPowerupState GlobalPowerupState;
  public MultiplayerLevelProfile LevelProfile;
  [NonSerialized]
  public MultiplayerSpawnPoints[] SpawnPoints;
  private HashSet<string> recentlyUsedChunkNames;
  private KeystrokeTracker trackerStats = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[6]
    {
      KeyCode.P,
      KeyCode.H,
      KeyCode.O,
      KeyCode.T,
      KeyCode.O,
      KeyCode.N
    }
  };
  public int AmountToSpaceOutChunks = 400;
  private bool sentLightProbesReady;
  [NonSerialized]
  public List<MultiplayerLevelChunk> FinalOrderedChunks;
  private bool countdownTimerFired;
  private Dictionary<string, FixedObjectAlongLevelPath> knownPositions = new Dictionary<string, FixedObjectAlongLevelPath>();
  private HashSet<Player> recentlyStunnedPlayers = new HashSet<Player>();

  private void Awake()
  {
    if (!(bool) (UnityEngine.Object) GameManager.GM)
      return;
    MultiplayerMode component1 = GameManager.GM.GetComponent<MultiplayerMode>();
    if ((bool) (UnityEngine.Object) component1)
      component1.LevelInfo = this;
    MultiplayerLevelInfoAdditive component2;
    if ((component2 = this.GetComponent<MultiplayerLevelInfoAdditive>()) == null)
      return;
    int randomSeed = GameManager.GM.GetComponent<MultiplayerMode>().GetRandomSeed();
    Debug.Log((object) ("Generating level using seed " + (object) randomSeed));
    System.Random random = new System.Random(randomSeed);
    component2.TriggerLoads(random, this.NumberOfLevelChunksToUse);
  }

  public void OnLightProbesReady()
  {
    if (this.FinalOrderedChunks == null)
      return;
    foreach (MultiplayerLevelChunk finalOrderedChunk in this.FinalOrderedChunks)
      finalOrderedChunk.OnLightProbesReady();
  }

  public static void SendOutRandoms(IEnumerable<MultiplayerLevelChunk> orderedChunks, System.Random random)
  {
    foreach (MultiplayerLevelChunk orderedChunk in orderedChunks)
      orderedChunk.SupplyThoseThatNeedRandoms(random);
  }

  private void Update()
  {
    if (!this.sentLightProbesReady)
    {
      this.sentLightProbesReady = true;
      if (!(bool) (UnityEngine.Object) this.GetComponent<MultiplayerLevelInfoAdditive>())
        this.OnLightProbesReady();
    }
    if (PhotonNetwork.IsConnected)
      this.CheckAllPlayerLoadedLevel();
    if (!this.trackerStats.Check())
      return;
    this.PhotonStats.SetActive(!this.PhotonStats.activeSelf);
  }

  public override void OnMasterClientSwitched(Player newMasterClient) => this.CountdownTimer.enabled = true;

  private void Start()
  {
    if (!PhotonNetwork.IsConnected)
      return;
    this.OptionalInitializationEvents?.Invoke();
    if ((bool) (UnityEngine.Object) this.GetComponent<MultiplayerLevelInfoAdditive>())
      return;
    this.MarkLevelAsLoaded();
  }

  public void MarkLevelAsLoaded()
  {
    Hashtable propertiesToSet1 = new Hashtable();
    propertiesToSet1.Add((object) "PlayerLoadedLevel", (object) true);
    PhotonNetwork.LocalPlayer.SetCustomProperties(propertiesToSet1);
    if (PhotonNetwork.IsMasterClient || !CountdownTimer.TryGetStartTime(out int _))
      return;
    this.CountdownTimer.Initialize();
    if (!(bool) (UnityEngine.Object) this.GetComponent<MultiplayerLevelInfoAdditive>())
      return;
    Player localPlayer = PhotonNetwork.LocalPlayer;
    Hashtable propertiesToSet2 = new Hashtable();
    propertiesToSet2.Add((object) "JoinedLate", (object) true);
    localPlayer.SetCustomProperties(propertiesToSet2);
    foreach (MultiplayerLevelChunk finalOrderedChunk in this.FinalOrderedChunks)
      finalOrderedChunk.OnLocalPlayerJoinedLate?.Invoke();
  }

  public override void OnEnable()
  {
    base.OnEnable();
    if (PhotonNetwork.IsConnected && SceneManager.GetActiveScene().name != "MPLobby")
      this.TurnOnOffLocalPlayerMovement(false);
    CountdownTimer.OnCountdownTimerHasExpired += new CountdownTimer.CountdownTimerHasExpired(this.OnCountdownTimerIsExpired);
    if (!PhotonNetwork.IsConnected || !PhotonNetwork.IsMasterClient)
      return;
    this.StartCountdownTimerIfAllPlayersLoaded();
  }

  public override void OnDisable()
  {
    base.OnDisable();
    CountdownTimer.OnCountdownTimerHasExpired -= new CountdownTimer.CountdownTimerHasExpired(this.OnCountdownTimerIsExpired);
  }

  public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
  {
    if (!propertiesThatChanged.ContainsKey((object) "StartTime"))
      return;
    this.CountdownTimer.Initialize();
  }

  public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
  {
    if (!PhotonNetwork.IsMasterClient || !changedProps.ContainsKey((object) "PlayerLoadedLevel"))
      return;
    this.StartCountdownTimerIfAllPlayersLoaded();
  }

  private void StartCountdownTimerIfAllPlayersLoaded()
  {
    bool startTime = CountdownTimer.TryGetStartTime(out int _);
    if (!this.CheckAllPlayerLoadedLevel() || startTime)
      return;
    CountdownTimer.SetStartTime();
    this.OnAllPlayersLoaded?.Invoke();
  }

  public int TotalPlayers { get; private set; }

  public int LoadedPlayers { get; private set; }

  public bool CheckAllPlayerLoadedLevel()
  {
    Player[] playersInCurrentRoom = GameManager.GM.GetComponent<MultiplayerMode>().GetPlayersInCurrentRoom();
    this.TotalPlayers = playersInCurrentRoom.Length;
    this.LoadedPlayers = 0;
    foreach (Player player in playersInCurrentRoom)
    {
      object obj;
      if (player.CustomProperties.TryGetValue((object) "PlayerLoadedLevel", out obj) && (bool) obj)
        ++this.LoadedPlayers;
    }
    return this.LoadedPlayers == this.TotalPlayers;
  }

  private void OnCountdownTimerIsExpired()
  {
    if (this.countdownTimerFired)
      return;
    if (this.FinalOrderedChunks != null)
    {
      foreach (MultiplayerLevelChunk finalOrderedChunk in this.FinalOrderedChunks)
        finalOrderedChunk.OnAllPlayersReady();
    }
    this.TurnOnOffLocalPlayerMovement(true);
    this.countdownTimerFired = true;
  }

  public void SetRoomPropertiesRecentlyUsedChunks()
  {
    if (!PhotonNetwork.IsMasterClient || this.recentlyUsedChunkNames == null)
      return;
    string[] array = this.recentlyUsedChunkNames.ToArray<string>();
    Hashtable propertiesToSet = new Hashtable();
    propertiesToSet.Add((object) "recentlyUsedChunks", (object) array);
    PhotonNetwork.CurrentRoom.SetCustomProperties(propertiesToSet);
  }

  private void TurnOnOffLocalPlayerMovement(bool onOrOff) => GameManager.GM.PM.canControlAlt = onOrOff;

  public Transform GetNextSpawnPoint(bool getRealSpawnPoint)
  {
    int playerSlot = MultiplayerHelper.GetPlayerSlot(PhotonNetwork.LocalPlayer);
    if (!getRealSpawnPoint && this.TemporarySpawnPointsForAdditive != null && this.TemporarySpawnPointsForAdditive.Length != 0)
      return this.TemporarySpawnPointsForAdditive[Mathf.Clamp(playerSlot, 0, this.TemporarySpawnPointsForAdditive.Length - 1)];
    if (this.SpawnPoints == null)
      this.SpawnPoints = !(bool) (UnityEngine.Object) this.OptionalSpawnPointSearch ? this.GetComponentsInChildren<MultiplayerSpawnPoints>() : this.OptionalSpawnPointSearch.GetComponentsInChildren<MultiplayerSpawnPoints>();
    return this.SpawnPoints[Mathf.Clamp(playerSlot, 0, this.SpawnPoints.Length - 1)].transform;
  }

  public void AddKnownPosition(string name, FixedObjectAlongLevelPath obj) => this.knownPositions[name] = obj;

  public FixedObjectAlongLevelPath GetKnownPosition(string name)
  {
    FixedObjectAlongLevelPath objectAlongLevelPath;
    this.knownPositions.TryGetValue(name, out objectAlongLevelPath);
    return objectAlongLevelPath;
  }

  public void SetRecentlyStunnedPlayer(Player player) => this.recentlyStunnedPlayers.Add(player);

  public bool GetWasRecentlyStunned(Player player)
  {
    int num = this.recentlyStunnedPlayers.Contains(player) ? 1 : 0;
    if (num == 0)
      return num != 0;
    this.recentlyStunnedPlayers.Remove(player);
    return num != 0;
  }
}

MultiplayerPlayer

Commands mentioned: mp

using Cinemachine;
using FMODUnity;
using Photon.Pun;
using Photon.Realtime;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class MultiplayerPlayer : MonoBehaviourPun, IPunInstantiateMagicCallback, IPunObservable
{
  public AimingVisualization AimingVisualization;
  public Transform LookDirection;
  public TextMeshPro TextMesh;
  public CapsuleCollider[] CollidersDisableWhenMe;
  public GameObject RenderersDisableWhenMe;
  public GameObject PlayerMeshParent;
  public Material StunMaterial;
  public CapsuleCollider CapsuleToTestGoingThroughPortal;
  public GameObject CinemachineCameras;
  public MP_Local_Cosmetic_Switcher cosmeticSwitcher;
  public MOSTEventVOPlayer FinishLineVO;
  public VoiceLineCollection FinishLineVoices;
  private GameObject MyPlayer;
  private Vector3 localScale;
  private Vector3 inverseLocalScale;
  private bool wasMineOriginally;
  private bool finishedLevel;
  private float finishTime = float.MaxValue;
  public Player realOwner;
  private Vector3 MyResetPosition;
  private Quaternion MyResetRotation;
  private Vector3 MyResetScale;
  private float teleportDistanceThreshold = 3f;
  public bool HUDon;
  private GameObject MPHud;
  private GameObject GUICam;
  public GameObject AntiGravParticle;
  public GameObject MakeSmallParticle;
  public Material InvisibilityMaterial;
  public GameObject GrabBlameArrow;
  public GameObject NeedsRemotePlayerRigidBody;
  private float invisibleTimeLeft;
  private float invisibleTotalTime;
  private KeystrokeTracker typedMP;
  private MultiplayerLevelInfo levelInfo;
  private PortalManager portalManager;
  private GameObject grabbedObject;
  private CharacterController ccHack;
  private FPSInputController fpsInput;
  private bool couldControlLastFrame;
  private bool wasHovered;
  private HashSet<int> playersTargettingUs = new HashSet<int>();
  private float? timeTargeted = new float?(0.0f);
  private List<CinemachineVirtualCameraBase> cinemachineCams = new List<CinemachineVirtualCameraBase>();
  private Vector3 lastPosition;
  private int? originalOwnerNr;
  private int ogOwnerDebug;
  public WentThroughPortalAndWho OnTeleportThroughPortal;
  private bool shouldShowStun;
  private Material originalMaterial;
  private Coroutine showStun;
  private List<RememberMyOriginalMaterial> playerVisualsWorker = new List<RememberMyOriginalMaterial>();
  private bool wasShowingInvisibility;
  private Player lastOwner;
  private Coroutine blameArrowRoutine;

  public GameObject BlameArrowParent { get; private set; }

  public float? InvisibleAmount
  {
    get
    {
      float? nullable = new float?();
      return (double) this.invisibleTimeLeft > 0.0 ? new float?(this.invisibleTimeLeft / this.invisibleTotalTime) : nullable;
    }
  }

  public void SetInvisibleTime(float time)
  {
    this.invisibleTimeLeft = time;
    this.invisibleTotalTime = time;
  }

  private void Awake()
  {
    if ((bool) (Object) this.GrabBlameArrow)
    {
      this.GrabBlameArrow.SetActive(false);
      this.BlameArrowParent = this.GrabBlameArrow.transform.parent.gameObject;
    }
    if (!this.originalOwnerNr.HasValue)
      this.originalOwnerNr = new int?(this.GetComponent<PhotonView>().OwnerActorNr);
    this.MyPlayer = this.gameObject;
    this.localScale = this.transform.localScale;
    this.inverseLocalScale = new Vector3(1f / this.localScale.x, 1f / this.localScale.y, 1f / this.localScale.z);
    if (this.photonView.IsMine && !(bool) (Object) GameManager.GM.player)
      GameManager.GM.AttachPlayer(this.gameObject);
    else
      this.gameObject.layer = MoSTLayer.CanGrab;
    PhotonTransformViewPositionModel positionModel = this.GetComponent<PhotonTransformViewClassic>().m_PositionModel;
    if (!positionModel.TeleportEnabled)
      return;
    this.teleportDistanceThreshold = positionModel.TeleportIfDistanceGreaterThan;
  }

  private void _AddRigidBodyToRemotePlayersSoTheyCanOpenDoors()
  {
    if (this.IsClone() || this.IsMainLocalPlayer || !(bool) (Object) this.NeedsRemotePlayerRigidBody)
      return;
    Rigidbody rigidbody = this.NeedsRemotePlayerRigidBody.AddComponent<Rigidbody>();
    rigidbody.mass = 1E-06f;
    rigidbody.drag = 0.0f;
    rigidbody.angularDrag = 0.5f;
    rigidbody.useGravity = false;
    rigidbody.isKinematic = true;
  }

  private void Start()
  {
    MultiplayerMode component = GameManager.GM.GetComponent<MultiplayerMode>();
    component.OnCreatePlayer(this.gameObject);
    this.portalManager = PortalInstanceTracker.instance.PortalManager;
    this.portalManager.OnTeleport += new global::WentThroughPortal(this.SendWentThroughPortal);
    this.levelInfo = component.LevelInfo;
    if ((bool) (Object) this.levelInfo && this.levelInfo.IsPlayerCloneable)
      this.GetComponent<DropTriggerScript>().grabValues.isCloneable = true;
    this._AddRigidBodyToRemotePlayersSoTheyCanOpenDoors();
    if (!this.IsClone())
      this.cosmeticSwitcher.TellOthersToUpdateMyCosmetics();
    if (this.IsMainLocalPlayer)
    {
      foreach (Collider collider in this.CollidersDisableWhenMe)
        collider.enabled = false;
      foreach (Renderer componentsInChild in this.RenderersDisableWhenMe.GetComponentsInChildren<MeshRenderer>())
        componentsInChild.enabled = false;
    }
    this.GetComponent<StunPlayerWhenHitByGrabObject>().enabled = this.IsMainLocalPlayer;
    this.realOwner = this.photonView.Owner.Get(this.originalOwnerNr.Value);
    this.TextMesh.text = this.realOwner.NickName;
    if (!this.IsMainLocalPlayer)
    {
      this.GetComponent<FaceGrabberWhenGrabbed>().GrabbedPostProcess.gameObject.SetActive(false);
      this.GetComponent<FaceGrabberWhenGrabbed>().enabled = false;
      MouseLook[] componentsInChildren = this.GetComponentsInChildren<MouseLook>();
      if (!this.IsLocalPlayerOrCloneOf())
      {
        foreach (Behaviour behaviour in componentsInChildren)
          behaviour.enabled = false;
      }
      foreach (Behaviour componentsInChild in this.GetComponentsInChildren<Camera>())
        componentsInChild.enabled = false;
      foreach (Behaviour componentsInChild in this.GetComponentsInChildren<CameraThatSeesPortals>())
        componentsInChild.enabled = false;
      this.GetComponentInChildren<StudioListener>().enabled = false;
      this.GetComponentInChildren<PlayerMovementSoundController>().enabled = false;
      this.GetComponentInChildren<AudioListener>().enabled = false;
      this.GetComponentInChildren<ResizeScript>().enabled = false;
      this.GetComponentInChildren<ResizeScriptPartTwo>().enabled = false;
      this.GetComponentInChildren<PlayerLerpMantle>().enabled = false;
    }
    else
      this.GetComponent<DropTriggerScript>().enabled = false;
    this.MyPlayer.GetComponent<PlayerResizer>().ForceNeverChangeGravity();
    this.ccHack = this.MyPlayer.GetComponent<CharacterController>();
    this.fpsInput = this.GetComponentInChildren<FPSInputController>();
    this.wasMineOriginally = this.MyPlayer.GetComponent<PhotonView>().IsMine;
    if (this.wasMineOriginally)
    {
      this.GetComponent<PhotonTransformViewClassic>().m_PositionModel.TeleportEnabled = false;
    }
    else
    {
      this.ccHack.enabled = false;
      this.fpsInput.enabled = false;
    }
    this.HUDon = true;
    this.MPHud = GameObject.Find("UI_PAUSE_MENU").transform.Find("Canvas").transform.Find("MultiplayerHUD").gameObject;
    this.GUICam = this.transform.Find("GUI Camera").gameObject;
    this.MaybeStealCosmetics();
    this.SetMyResetTransform();
    this.typedMP = new KeystrokeTracker()
    {
      KeyCodes = new KeyCode[2]{ KeyCode.M, KeyCode.P }
    };
  }

  private void MaybeStealCosmetics()
  {
    if (!this.IsClone())
      return;
    MP_Local_Cosmetic_Switcher componentInChildren = this.GetComponent<DropTriggerScript>().cloneRoot.GetComponentInChildren<MP_Local_Cosmetic_Switcher>();
    if (!(bool) (Object) componentInChildren)
      return;
    this.GetComponentInChildren<MP_Local_Cosmetic_Switcher>().GrabCosmeticsFromThisCosmeticSwitcher(componentInChildren);
  }

  public bool IsMainLocalPlayer => (Object) GameManager.GM.player == (Object) this.gameObject;

  public bool IsLocalPlayerOrCloneOf() => this.originalOwnerNr.HasValue ? this.originalOwnerNr.Value == PhotonNetwork.LocalPlayer.ActorNumber : this.photonView.IsMine;

  private static LayerMask GetPhysicsLayerMask(int currentLayer)
  {
    int num = 0;
    for (int layer2 = 0; layer2 < 32; ++layer2)
    {
      if (!Physics.GetIgnoreLayerCollision(currentLayer, layer2))
        num |= 1 << layer2;
    }
    return (LayerMask) num;
  }

  public void SetGrabbedObject(GameObject grabbedObject)
  {
    this.grabbedObject = grabbedObject;
    this.UpdateAimingVisualization();
  }

  public void UnSetGrabbedObjectIfItsMe(GameObject me)
  {
    if (!((Object) this.grabbedObject == (Object) me))
      return;
    this.SetGrabbedObject((GameObject) null);
  }

  private void Update()
  {
    this._UpdateInvisibility();
    if (this.originalOwnerNr.HasValue)
      this.ogOwnerDebug = this.originalOwnerNr.Value;
    bool flag = this.MyPlayer.GetComponent<PhotonView>().IsMine && this.originalOwnerNr.Value == PhotonNetwork.LocalPlayer.ActorNumber && this.MyPlayer.layer != MoSTLayer.Grabbed;
    if (!flag)
    {
      this.ccHack.enabled = false;
      this.fpsInput.enabled = false;
    }
    else
    {
      PlayerSizeBoundsVolumeManager.Instance.UpdatePlayerSize(this.GetComponent<PlayerResizer>(), this.transform);
      if (flag && !this.couldControlLastFrame)
      {
        if (!this.ccHack.enabled)
          this.GetComponent<PlayerResizer>().Poke();
        this.ccHack.enabled = true;
        this.fpsInput.enabled = true;
      }
      else if (!flag)
      {
        this.ccHack.enabled = false;
        this.fpsInput.enabled = false;
      }
    }
    this.couldControlLastFrame = flag;
    this.EvaluateRacePosition();
    if (this.finishedLevel)
      this.CinemachineCameras.SetActive(false);
    if (this.CinemachineCameras.activeSelf && (double) Vector3.Distance(this.lastPosition, this.transform.position) > (double) this.teleportDistanceThreshold)
    {
      this.cinemachineCams.Clear();
      this.CinemachineCameras.GetComponentsInChildren<CinemachineVirtualCameraBase>((List<M0>) this.cinemachineCams);
      foreach (CinemachineVirtualCameraBase cinemachineCam in this.cinemachineCams)
        cinemachineCam.PreviousStateIsValid = false;
    }
    this.lastPosition = this.transform.position;
    this._DetectWhenSomeoneIsTargettingUsAndTellOurOwner();
    this._CalculateHowLongWeveBeenTargeted();
    if (GameManager.GM.CanUseKeyboardHotKeys() && this.typedMP.Check())
    {
      if (this.HUDon)
      {
        this.MPHud.SetActive(false);
        this.HUDon = false;
      }
      else
      {
        this.MPHud.SetActive(true);
        this.HUDon = true;
      }
    }
    this._UpdatePlayerVisualsBasedOnState();
    this._UpdateBlameArrow();
  }

  private void _DetectWhenSomeoneIsTargettingUsAndTellOurOwner()
  {
    DropTriggerScript component = this.GetComponent<DropTriggerScript>();
    if (component.IsHovered == this.wasHovered)
      return;
    this.GetComponent<PhotonView>().RPC("YouAreTargeted", this.realOwner, (object) component.IsHovered, (object) PhotonNetwork.LocalPlayer.ActorNumber);
    this.wasHovered = component.IsHovered;
  }

  [PunRPC]
  public void YouAreTargeted(bool targetted, int byWhomActorNr)
  {
    if (targetted)
      this.playersTargettingUs.Add(byWhomActorNr);
    else
      this.playersTargettingUs.Remove(byWhomActorNr);
  }

  private void _CalculateHowLongWeveBeenTargeted()
  {
    if (this.playersTargettingUs.Count > 0)
    {
      if (!this.timeTargeted.HasValue)
        this.timeTargeted = new float?(0.0f);
      this.timeTargeted = new float?(this.timeTargeted.Value + Time.deltaTime);
    }
    else
      this.timeTargeted = new float?();
  }

  public float? AmIBeingTargeted() => this.timeTargeted;

  private void OnDestroy()
  {
    if ((bool) (Object) this.portalManager)
      this.portalManager.OnTeleport -= new global::WentThroughPortal(this.SendWentThroughPortal);
    if ((bool) (Object) GameManager.GM)
      GameManager.GM.GetComponent<MultiplayerMode>().OnDestroyPlayer(this.gameObject);
    if (!this.IsMainLocalPlayer || !PhotonNetwork.InRoom)
      return;
    PhotonNetwork.DestroyPlayerObjects(PhotonNetwork.LocalPlayer);
  }

  [PunRPC]
  private void SetDropPoint(
    Vector3 position,
    Quaternion rotation,
    Vector3 localScale,
    Vector3 exGrabberPosition,
    Vector3 exGrabberUp)
  {
    this.transform.position = position;
    this.transform.rotation = rotation;
    this.transform.localScale = localScale;
    float x;
    float y;
    FaceGrabberWhenGrabbed.GetDesiredMouseLookAngles(GameManager.GM.playerCamera.transform, exGrabberPosition, exGrabberUp, out x, out y);
    this.GetComponent<FaceGrabberWhenGrabbed>().SetMouseLookRotations(x, y);
  }

  public void OnDroppedLocal()
  {
    PhotonView component = this.MyPlayer.GetComponent<PhotonView>();
    if (!this.originalOwnerNr.HasValue)
      return;
    int ownerActorNr = component.OwnerActorNr;
    int? originalOwnerNr = this.originalOwnerNr;
    int valueOrDefault = originalOwnerNr.GetValueOrDefault();
    if (ownerActorNr == valueOrDefault & originalOwnerNr.HasValue)
      return;
    component.TransferOwnership(this.originalOwnerNr.Value);
    Transform transform = GameManager.GM.player.transform;
    component.RPC("SetDropPoint", PhotonNetwork.CurrentRoom.GetPlayer(this.originalOwnerNr.Value), (object) this.transform.position, (object) this.transform.rotation, (object) this.transform.localScale, (object) transform.position, (object) transform.up);
  }

  private void LateUpdate()
  {
    this.UpdateAimingVisualization();
    this.TextMesh.transform.rotation = GameManager.GM.playerCamera.transform.rotation;
  }

  private void UpdateAimingVisualization()
  {
    if ((bool) (Object) this.grabbedObject && !this.IsMainLocalPlayer)
    {
      this.AimingVisualization.gameObject.SetActive(true);
      this.AimingVisualization.Aim(this.LookDirection, this.grabbedObject.transform, this.grabbedObject);
    }
    else
      this.AimingVisualization.gameObject.SetActive(false);
  }

  public int GetSpecifiedOwnerId() => this.originalOwnerNr.Value;

  public bool CanClonePlayer_AndMaybeDestroy()
  {
    if (this.photonView.Owner.Get(this.originalOwnerNr.Value) != null)
      return true;
    if (this.photonView.AmOwner)
      PhotonNetwork.Destroy(this.gameObject);
    return false;
  }

  public void OnPhotonInstantiate(PhotonMessageInfo info)
  {
    int? playerNumberFromClone = MultiplayerHelper.MaybeExtractOriginalPlayerNumberFromClone(this.gameObject);
    if (!playerNumberFromClone.HasValue)
      return;
    this.originalOwnerNr = playerNumberFromClone;
    this.GetComponent<ReturnPlayerToNormalSize>().enabled = false;
  }

  private void OnTriggerEnter(Collider other)
  {
    if (other.gameObject.CompareTag("LavaMP"))
      this.gameObject.SetActive(false);
    if (other.gameObject.CompareTag("MPResetSpot"))
      this.SetMyResetTransform();
    MysteryPowerupBox componentInParent = other.gameObject.GetComponentInParent<MysteryPowerupBox>();
    if ((bool) (Object) componentInParent && this.IsLocalPlayerOrCloneOf())
      componentInParent.Open();
    if (!((Object) other.gameObject.GetComponent<ResetGrabbableObject>() != (Object) null) || !other.gameObject.GetComponent<ResetGrabbableObject>().ResetMPPlayer)
      return;
    this.ResetToMyResetTransform();
  }

  private bool IsClone() => (bool) (Object) this.GetComponent<DropTriggerScript>().cloneParent;

  public void EvaluateRacePosition()
  {
    if (this.IsClone() || !(bool) (Object) this.levelInfo)
      return;
    if (MultiplayerHelper.DidPlayerJoinLate(this.realOwner))
      this.levelInfo.PlayerPath.SetPlayerPositionAlongLevel(this.levelInfo.PlayerPath.StartNode.OriginalPosition, this.GetComponent<PhotonView>().CreatorActorNr, this.finishedLevel ? new float?(this.finishTime) : new float?());
    else
      this.levelInfo.PlayerPath.SetPlayerPositionAlongLevel(this.transform.position, this.GetComponent<PhotonView>().CreatorActorNr, this.finishedLevel ? new float?(this.finishTime) : new float?());
  }

  public bool HasFinishedLevel() => this.finishedLevel;

  [PunRPC]
  public void PhotonSetFinishedLevel(float time)
  {
    this.finishedLevel = true;
    this.finishTime = time;
  }

  public void SetFinishedLevel()
  {
    this.GetComponent<PhotonView>().RPC("PhotonSetFinishedLevel", RpcTarget.AllBuffered, (object) this.GetTimeSinceLevelLoad());
    if (!this.levelInfo.LevelProfile.IsCampaign)
    {
      int rankingForPlayer = this.levelInfo.PlayerPath.GetRankingForPlayer(this.realOwner);
      if (rankingForPlayer < this.FinishLineVoices.VoiceLines.Length)
      {
        this.FinishLineVO.GetComponent<StudioEventEmitter>().Event = this.FinishLineVoices.VoiceLines[rankingForPlayer].Event;
        this.FinishLineVO.gameObject.SetActive(true);
      }
    }
    List<MultiplayerPlayer> results = new List<MultiplayerPlayer>();
    MultiplayerHelper.GetPlayerComponentsNonAlloc<MultiplayerPlayer>(results, false);
    foreach (Component component in results)
      component.gameObject.layer = MoSTLayer.Default;
  }

  public void SendWentThroughPortal(Portal source)
  {
    PhotonView component = source.GetComponent<PhotonView>();
    if (!(bool) (Object) component)
      return;
    WentThroughPortalAndWho teleportThroughPortal = this.OnTeleportThroughPortal;
    if (teleportThroughPortal != null)
      teleportThroughPortal(source, this);
    this.GetComponent<PhotonView>().RPC("WentThroughPortal", RpcTarget.Others, (object) component.ViewID);
  }

  [PunRPC]
  private void WentThroughPortal(int sourcePortalViewId)
  {
    PhotonView photonView = PhotonView.Find(sourcePortalViewId);
    if (!(bool) (Object) photonView)
      return;
    Portal component = photonView.GetComponent<Portal>();
    if (!(bool) (Object) component || !(bool) (Object) component.Destination)
      return;
    WentThroughPortalAndWho teleportThroughPortal = this.OnTeleportThroughPortal;
    if (teleportThroughPortal != null)
      teleportThroughPortal(component, this);
    this.GetComponent<PhotonTransformViewClassic>().SetFromToTeleportTransform(component.ThisSide, component.OtherSide.transform);
  }

  [PunRPC]
  public void IGotStunned(int playerResponsibleActorNr)
  {
    if (this.showStun != null)
      this.StopCoroutine(this.showStun);
    this.showStun = this.StartCoroutine(this.ShowStun());
    if (playerResponsibleActorNr != PhotonNetwork.LocalPlayer.ActorNumber || !(bool) (Object) this.levelInfo)
      return;
    this.levelInfo.SetRecentlyStunnedPlayer(this.realOwner);
  }

  [PunRPC]
  public void StunRemotePlayer(float stunIntensity, float stunTime, int playerResponsibleActorNr)
  {
    if (!this.IsMainLocalPlayer)
      return;
    this.GetComponent<PlayerBuff>().SetWalkSpeedMultiplier(stunIntensity, 1f, stunTime, PhotonNetwork.CurrentRoom.GetPlayer(playerResponsibleActorNr));
  }

  private IEnumerator ShowStun()
  {
    this.shouldShowStun = true;
    yield return (object) new WaitForSeconds(2f);
    this.shouldShowStun = false;
  }

  private void _UpdateInvisibility() => this.invisibleTimeLeft = Mathf.Max(0.0f, this.invisibleTimeLeft - Time.deltaTime);

  private void _UpdatePlayerVisualsBasedOnState()
  {
    bool isInvisible = false;
    this.PlayerMeshParent.GetComponentsInChildren<RememberMyOriginalMaterial>(true, (List<M0>) this.playerVisualsWorker);
    if (this.shouldShowStun)
    {
      foreach (RememberMyOriginalMaterial originalMaterial in this.playerVisualsWorker)
        originalMaterial.MeshRenderer.sharedMaterial = this.StunMaterial;
    }
    else if (this.InvisibleAmount.HasValue)
    {
      foreach (RememberMyOriginalMaterial originalMaterial in this.playerVisualsWorker)
        originalMaterial.MeshRenderer.sharedMaterial = this.InvisibilityMaterial;
      isInvisible = true;
    }
    else
    {
      foreach (RememberMyOriginalMaterial originalMaterial in this.playerVisualsWorker)
        originalMaterial.MeshRenderer.sharedMaterial = originalMaterial.OriginalMaterial;
    }
    this._SetInvisibilityVisuals(isInvisible);
  }

  private void _SetInvisibilityVisuals(bool isInvisible)
  {
    this.wasShowingInvisibility = isInvisible;
    this.TextMesh.gameObject.SetActive(!isInvisible);
    this.RenderersDisableWhenMe.GetComponent<MP_Local_Cosmetic_Switcher>().CenterOfHead.gameObject.SetActive(!isInvisible);
    this.RenderersDisableWhenMe.GetComponent<MP_Local_Cosmetic_Switcher>().HatParent.gameObject.SetActive(!isInvisible);
    if (!(bool) (Object) this.BlameArrowParent)
      return;
    this.BlameArrowParent.SetActive(!isInvisible);
  }

  public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
  {
    if (stream.IsWriting)
      return;
    this.GetComponent<FaceGrabberWhenGrabbed>().RestoreLookAfterGettingSyncFromGrabber();
  }

  private float GetTimeSinceLevelLoad() => (bool) (Object) this.levelInfo && PhotonNetwork.IsConnected ? this.levelInfo.CountdownTimer.GetSynchronizedLevelTime() : Time.timeSinceLevelLoad;

  public float GetFinishTime() => this.finishTime;

  public void SetMyResetTransform()
  {
    this.MyResetPosition = this.transform.position;
    this.MyResetRotation = this.transform.rotation;
    this.MyResetScale = this.transform.localScale;
  }

  public void ResetToMyResetTransform()
  {
    this.transform.position = this.MyResetPosition;
    this.transform.rotation = this.MyResetRotation;
    this.transform.localScale = this.MyResetScale;
    this.GetComponent<PlayerResizer>().Poke();
  }

  private void _UpdateBlameArrow()
  {
    if (!this.IsMainLocalPlayer)
      return;
    Player owner = this.photonView.Owner;
    if (owner == this.lastOwner)
      return;
    if (owner == PhotonNetwork.LocalPlayer && this.lastOwner != null)
    {
      GameObject playerObjectForPlayer = GameManager.GM.GetComponent<MultiplayerMode>().GetPlayerObjectForPlayer(this.lastOwner);
      if ((bool) (Object) playerObjectForPlayer)
        playerObjectForPlayer.GetComponent<MultiplayerPlayer>().ShowGrabBlameArrow();
    }
    this.lastOwner = owner;
  }

  private void ShowGrabBlameArrow()
  {
    if (!(bool) (Object) this.GrabBlameArrow)
      return;
    if (this.blameArrowRoutine != null)
      this.StopCoroutine(this.blameArrowRoutine);
    this.blameArrowRoutine = this.StartCoroutine(this.ShowGrabBlameArrowFor(5f));
  }

  private IEnumerator ShowGrabBlameArrowFor(float time)
  {
    this.GrabBlameArrow.SetActive(true);
    yield return (object) new WaitForSeconds(time);
    this.GrabBlameArrow.SetActive(false);
  }
}

PopulateLoadingScreenList

Commands mentioned: db

using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class PopulateLoadingScreenList : MonoBehaviour
{
  public static int? SaveChosenLoadingScreen;
  public GameObject UnlockedLevelButtonTemplate;
  private readonly KeystrokeTracker tracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[2]{ KeyCode.D, KeyCode.B }
  };
  private bool madeButtons;

  private void Update()
  {
    if (!GameManager.GM.enableDebugFunctions || this.madeButtons || !this.tracker.Check())
      return;
    this.madeButtons = true;
    this._MakeButton("Normal loading screen", -1);
    SceneReference[] randomLoadingScreens = GameManager.GM.LevelInfo.RandomLoadingScreens;
    for (int loadingIndex = 0; loadingIndex < randomLoadingScreens.Length; ++loadingIndex)
      this._MakeButton(randomLoadingScreens[loadingIndex].ScenePath, loadingIndex);
    LayoutRebuilder.MarkLayoutForRebuild(this.transform as RectTransform);
  }

  private void _MakeButton(string loadingScenePath, int loadingIndex)
  {
    GameObject gameObject = Object.Instantiate<GameObject>(this.UnlockedLevelButtonTemplate, this.transform);
    gameObject.GetComponent<StartSpecificLevelScript>().SetLoadingScreenIndexOverride(loadingIndex);
    string withoutExtension = Path.GetFileNameWithoutExtension(loadingScenePath);
    gameObject.GetComponent<Text>().text = withoutExtension;
    gameObject.SetActive(true);
  }
}

PopulateUnlockedLevelList

Commands mentioned: db

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PopulateUnlockedLevelList : MonoBehaviour
{
  public GameObject UnlockedLevelButtonTemplate;
  private readonly KeystrokeTracker tracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[2]{ KeyCode.D, KeyCode.B }
  };
  private bool madeButtons;

  private void Update()
  {
    if (!GameManager.GM.enableDebugFunctions || this.madeButtons || !this.tracker.Check())
      return;
    this.madeButtons = true;
    this._MakeButtons(GameManager.GM.GetComponent<SaveAndCheckpointManager>().GetUnlockedLevelList());
    this._MakeButtons(GameManager.GM.GetComponent<SaveAndCheckpointManager>().GetLockedLevelList(), new Color?(Color.red));
    LayoutRebuilder.MarkLayoutForRebuild(this.transform as RectTransform);
  }

  private void _MakeButtons(List<string> levelNames, Color? optionalColor = null)
  {
    foreach (string levelName in levelNames)
    {
      GameObject gameObject = Object.Instantiate<GameObject>(this.UnlockedLevelButtonTemplate, this.transform);
      gameObject.GetComponent<StartSpecificLevelScript>().LevelSaveName = levelName;
      if (GameManager.GM.GetComponent<MiniChallengeMode>().MiniChallengeModeEnabled && gameObject.GetComponent<StartSpecificLevelScript>().LevelSaveName == "EndingMontage")
        gameObject.SetActive(false);
      gameObject.GetComponent<Text>().text = levelName;
      if (optionalColor.HasValue)
        gameObject.GetComponent<Text>().color = optionalColor.Value;
      gameObject.SetActive(true);
    }
  }
}

ReleaseTheBalls

Commands mentioned: ball

using System.Collections.Generic;
using UnityEngine;

public class ReleaseTheBalls : MonoBehaviour
{
  public TestCollisionBall CollisionBallPrefab;
  public Transform WorldCollidePlanePrefab;
  public Transform ActiveBallsParent;
  public Transform FrozenBallsParent;
  public int BallsToRelease = 20;
  public float BallVelocity = 2f;
  private KeystrokeTracker keyTracker;
  private Vector3 worldCenter;
  private float worldRadius;
  private Transform worldCollider;
  private readonly List<TestCollisionBall> collisionBalls = new List<TestCollisionBall>();

  private void Start() => this.keyTracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[4]
    {
      KeyCode.B,
      KeyCode.A,
      KeyCode.L,
      KeyCode.L
    }
  };

  private void Update()
  {
  }

  private void ReleaseBalls()
  {
    if (!(bool) (Object) this.worldCollider)
      this.ComputeWorldBounds();
    for (int index = 0; index < this.BallsToRelease; ++index)
    {
      TestCollisionBall testCollisionBall = Object.Instantiate<TestCollisionBall>(this.CollisionBallPrefab, this.ActiveBallsParent);
      CapsuleCollider component1 = testCollisionBall.GetComponent<CapsuleCollider>();
      if ((bool) (Object) component1)
      {
        CharacterController component2 = GameManager.GM.player.GetComponent<CharacterController>();
        component1.radius = component2.radius;
        component1.height = component2.height;
        component1.center = component2.center;
        testCollisionBall.transform.position = component2.transform.position;
      }
      testCollisionBall.GetComponent<Rigidbody>().AddForce(Random.insideUnitSphere * this.BallVelocity, ForceMode.VelocityChange);
    }
  }

  private void ComputeWorldBounds()
  {
    Vector3 rhs1 = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
    Vector3 rhs2 = new Vector3(float.MinValue, float.MinValue, float.MinValue);
    foreach (Renderer renderer in Object.FindObjectsOfType<Renderer>())
    {
      Bounds bounds = renderer.bounds;
      rhs1 = Vector3.Min(bounds.min, rhs1);
      bounds = renderer.bounds;
      rhs2 = Vector3.Max(bounds.max, rhs2);
    }
    this.worldCenter = (rhs2 + rhs1) * 0.5f;
    this.worldRadius = (rhs2 - rhs1).magnitude * 0.5f;
    Transform transform = Object.Instantiate<Transform>(this.WorldCollidePlanePrefab, this.transform);
    transform.position = this.worldCenter;
    transform.localScale = Vector3.one * this.worldRadius * 0.5f;
    this.worldCollider = transform;
    this.transform.SetParent((Transform) null, true);
  }
}

ResizeScript

Commands mentioned: rty

using Photon.Pun;
using Rewired;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

public class ResizeScript : MonoBehaviour, IPunOwnershipCallbacks
{
  [NonSerialized]
  public bool AllowScrollPlacement;
  public bool isEnableDebug;
  [Tooltip("Try to figure out the spherical-coordinates bounds of grabbed objects so we don't ignore their off-screen parts.")]
  public bool UseSphericalBounds = true;
  [Tooltip("Avoid the dropped object overlapping with the player capsule by artificially shrinking it.")]
  public bool UseOverlapForAvoidingPlayerCollision = true;
  [Tooltip("We'll make no attempt to avoid player overlap when dropping objects below this large in size.")]
  public float SmallObjectIgnoreOverlapThreshold = 1f;
  private const float SAMPLE_DENSITY_SCREEN = 20f;
  private const int MAX_SAMPLE_PER_EDGE = 40;
  private const int MIN_SAMPLE_PER_EDGE = 20;
  public const int MaxCountAllowedToUseMeshVerts = 200;
  private const int MaxRayCount = 1881;
  public ResizeInfo Info;
  public GrantAchievement CloneAlotAchievement;
  [NonSerialized]
  public CreateCreated OnCloneCreated;
  public MultiplayerGrabSettings MultiplayerGrabSettings;
  private bool isScrolling;
  private bool _hasSelection;
  private bool _isGrabbing;
  private GameObject grabbedObject;
  public bool isPointingAtInstantProjectObj;
  private Quaternion grabbedObjectRotationInCameraSpaceOriginal;
  private Quaternion grabbedObjectRotationInWorldSpaceOriginal;
  private Vector3 positionInCameraSpaceOriginal;
  private Vector3 positionInCameraSpaceOriginalFinal;
  private Vector3 accumulatedPlayerRotationCameraSpaceSelfRightingLock;
  public bool isReadyToGrab;
  public bool isObjectBlocked;
  public bool isObjectReadyToReturn;
  private bool notAllowedToGrab;
  private bool notAllowedToGrabNextFrame;
  private bool turnOffGrabDeniedSoundNextFrame;
  public SoundEffectScript soundEffectScript;
  private Material DrawOutlineMat;
  public PostProcessCamera drawOutlinePostProcessing;
  private Color canSpinColor = new Color(1f, 1f, 1f, 1f);
  private Color canFollowColor = new Color(1f, 0.3f, 0.3f, 1f);
  private Color cannotDoAnythingColor = new Color(0.0f, 0.0f, 0.0f, 1f);
  private MouseLook mouseLook1;
  private MouseLook mouseLook2;
  private bool isRejectProject;
  private bool toResizeWithoutDropping;
  private const float MinGrabDistance = 0.25f;
  private bool justDroppedThisFrame;
  private Color? outlineOverrideColor;
  private float _maxGrabDistance = 400f;
  private bool isObjectInSky;
  private int _layerMaskIgnoreGrabbed;
  private int _layerMaskGrabbed;
  private int _layerMaskIgnorePlayer;
  private int _layerMaskOnlyPlayer;
  public Texture SpinInstruction;
  public Texture DropInstruction;
  public PostProcessCamera BlockedPostProcessing;
  public Material blockedMat;
  public OutlinerCamera outlinerCamera;
  private bool isLerpingToPosition;
  private Vector3 prevPosition = Vector3.zero;
  public bool dontLerpObjectsToCenter;
  public bool immediatelyDropObjects;
  public MOSTTriggerOnXDrops triggerOnDrops;
  private GameObject oldObj;
  public int repeatInstantProjectCount;
  public int repeatInstantProjectMax;
  private const float HoldRotateTutorialTimerBase = 3f;
  private float holdRotateTutorialTimer;
  public bool doRotateTutInThisLevel;
  public Image rotateTut;
  [Tooltip("Min/max range for adding a random rotation when an object is dropped.")]
  public Vector2 RandomTorqueOnDrop = Vector2.zero;
  [Tooltip("Should random torque be limited to a plane, so that the object has less chance of rotating into a wall and bouncing out.")]
  public bool LimitRandomTorqueToCameraPlane = true;
  [Tooltip("World sized radius for grab object hit testing.")]
  public float CastRadius = 0.1f;
  [Tooltip("World sized radius for grab object hit testing for controllers.")]
  public float CastRadiusForController = 0.2f;
  public float AssistCastRadius = 0.2f;
  public float AssistCastDistance = 10f;
  private KeystrokeTracker keyTracker;
  public ChallengeMode _ChallengeMode;
  public MiniChallengeMode _MiniChallengeMode;
  public bool IsMultiplayerPlayer;
  public UnityEvent OnDropped;
  public UnityEvent OnGrabbed;
  public ResizeDroppedEvent OnDroppedParam;
  public ResizeDroppedEvent OnGrabbedParam;
  [NonSerialized]
  public DenyGrab DenyGrab;
  public Material SnapMaterial;
  private bool hasGrabRestrictions;
  private bool isCampaign;
  private float hoverTimeModifierDuration;
  private float hoverTimeModifier = 1f;
  private GameObject lastHoverObject;
  private float grabRecoveryCountdown;
  private float grabRecoveryTime;
  private float forceLetGoCountdown;
  private float forceLetGoTime;
  private GameObject lastGrabbedObject;
  private float curLerpingTime;
  private const float MaxLerpingTime = 0.8f;
  private Portal lastCrossedPortal;
  private MaterialPool fadeMaterialPool;
  private const float AlphaFade = 0.5f;
  private const float TooSmallEpsilon = 0.0001f;
  private bool continueInLateLateUpdate;
  private List<SmartSnapResult> snapWorker = new List<SmartSnapResult>();
  public Vector3 spinGUIStartinPoint;
  public Vector3 dropGUIStartinPoint;
  private static RaycastHit[] hitWorker = new RaycastHit[20];
  private const float Smidgen = 0.1f;
  private static readonly Collider[] lotsOfColliders = new Collider[100];
  private const int MaxIterations = 10;
  private List<Ray> rayListWorker = new List<Ray>();
  private List<Vector3> objWorldSpacePoints = new List<Vector3>();
  private List<Vector3> objPoints = new List<Vector3>();
  private const float PlatformRayReduction = 1f;
  public float TestingRayReduction = 1f;
  private const float RaysPerDegree = 0.5f;
  public GrabObjectRayCastType RayCastType;
  private List<Vector3> rayDirectionsWorkerPrelim = new List<Vector3>();
  private List<Vector3> rayDirectionsWorkerFinal = new List<Vector3>();
  private NativeArray<RaycastHit> rayCastResults;
  private NativeList<RaycastCommand> rayCastCommands;
  private NativeArray<RaycastHit> rayCastResultsPortal;
  private NativeList<RaycastCommand> rayCastCommandsPortal;
  private List<ResizeScript.PortalAndIndex> portalCommandToOriginalIndex = new List<ResizeScript.PortalAndIndex>();
  private List<Portal> portalsWeHit = new List<Portal>();
  private Matrix4x4[] portalMatrices = new Matrix4x4[100];
  private List<float> forwardHitDistances = new List<float>();
  private const float extraDistanceForComplexPieces = 0.0f;
  private NativeList<int> filteredRayIndices;
  private int portalRayCount;
  private int returnRayCount;
  private JobHandle handleToWaitFor;
  private static readonly string StopProjectionTag = "Stop projection";
  private static readonly string ChildThatIgnoresGrabTag = "ChildThatIgnoresGrab";
  private readonly Stopwatch swTotal = new Stopwatch();
  private readonly Stopwatch swInclusive = new Stopwatch();
  private readonly Stopwatch swEnsureNoPlayerCollide = new Stopwatch();
  private readonly Stopwatch swCalcBounds = new Stopwatch();
  private readonly Stopwatch swHitGrab = new Stopwatch();
  private Vector3 scaleAtMinDistance;
  private float massAtMinDistance;
  private float grabbedMinGrabDistance;
  public const float DefaultDistanceScaleModifier = 0.99f;
  private Vector3 scrollWorldAxis;
  private bool wasKinematic;
  private Vector3 mouseOffset;
  private Plane facingPlane;
  private Vector3 originalGrabbObjectPosition;
  private const float CounterZFightingAmount = 0.001f;

  public bool hasSelection
  {
    get => this._hasSelection;
    set
    {
      this._hasSelection = value;
      this.drawOutlinePostProcessing.enabled = this._hasSelection || this._isGrabbing;
      this.outlinerCamera.gameObject.SetActive(this.drawOutlinePostProcessing.enabled);
    }
  }

  public bool isGrabbing
  {
    get => this._isGrabbing;
    set
    {
      this._isGrabbing = value;
      this.mouseLook1.IsGrabbingObject = value;
      this.mouseLook2.IsGrabbingObject = value;
      this.drawOutlinePostProcessing.enabled = this._hasSelection || this._isGrabbing;
      this.outlinerCamera.gameObject.SetActive(this.drawOutlinePostProcessing.enabled);
    }
  }

  public GameObject GetGrabbedObject() => this.grabbedObject;

  private Quaternion _GetCurrentObjectRotationWorldSpace()
  {
    Quaternion quaternion = this.transform.localToWorldMatrix.rotation * this._GetCurrentObjectRotationCameraSpace();
    DreamObjectDropTriggerScript component = this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>();
    if (!(bool) (UnityEngine.Object) component)
      return quaternion;
    component.ShouldSnap(out float _);
    return quaternion;
  }

  private Quaternion _GetCurrentObjectRotationCameraSpace()
  {
    Quaternion quaternion = this.grabbedObjectRotationInCameraSpaceOriginal;
    DropTriggerScript component1 = this.grabbedObject.GetComponent<DropTriggerScript>();
    DreamObjectDropTriggerScript component2 = this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>();
    if ((bool) (UnityEngine.Object) component2 && component2.FreezeRotation)
      quaternion = this.transform.worldToLocalMatrix.rotation * this.grabbedObjectRotationInWorldSpaceOriginal;
    if (!component1.grabValues.selfRightingLock)
      return quaternion;
    Vector3 vector3_1 = Vector3.up;
    if (component1.optionalSelfRightingLocalUpVector != Vector3.zero)
      vector3_1 = component1.optionalSelfRightingLocalUpVector;
    Vector3 vector3_2 = this.transform.worldToLocalMatrix.rotation * Vector3.up;
    Vector3 fromDirection = quaternion * vector3_1;
    Quaternion b = Quaternion.FromToRotation(Vector3.up, vector3_2) * Quaternion.FromToRotation(fromDirection, Vector3.up);
    if (this.isLerpingToPosition)
      b = Quaternion.Slerp(Quaternion.identity, b, this._GetLerpProgress());
    return Quaternion.AngleAxis(this.accumulatedPlayerRotationCameraSpaceSelfRightingLock.y, vector3_2) * b * quaternion;
  }

  private float _GetMinGrabDistance() => GameManager.GM.player.transform.localScale.x * 0.25f;

  public void OverrideOutlineColor(Color? overrideColor)
  {
    this.outlineOverrideColor = overrideColor;
    if (!this.outlineOverrideColor.HasValue)
      return;
    this.DrawOutlineMat.color = this.outlineOverrideColor.Value;
  }

  private void Start()
  {
    MultiplayerMode component = GameManager.GM.GetComponent<MultiplayerMode>();
    this.hasGrabRestrictions = PhotonNetwork.IsConnected && component.MultiplayerType == MultiplayerType.BattleRoyale;
    this.isCampaign = PhotonNetwork.IsConnected && (bool) (UnityEngine.Object) component.LevelInfo && component.LevelInfo.LevelProfile.IsCampaign;
    this.keyTracker = new KeystrokeTracker()
    {
      KeyCodes = new KeyCode[3]
      {
        KeyCode.R,
        KeyCode.T,
        KeyCode.Y
      }
    };
    this.fadeMaterialPool = new MaterialPool(new CustomizeMaterial(this.MakeMaterialFade));
    if ((bool) (UnityEngine.Object) this.drawOutlinePostProcessing)
    {
      this.DrawOutlineMat = this.drawOutlinePostProcessing.mat;
      this.DrawOutlineMat.color = this.canSpinColor;
    }
    this._layerMaskIgnoreGrabbed = ~(1 << MoSTLayer.IgnoreRaycast | 1 << MoSTLayer.Grabbed | 1 << MoSTLayer.Player | 1 << MoSTLayer.IgnoreRaycastAndObjects | 1 << MoSTLayer.NoInteraction);
    this._layerMaskGrabbed = 1 << MoSTLayer.Grabbed;
    this._layerMaskIgnorePlayer = ~(1 << MoSTLayer.Player | 1 << MoSTLayer.IgnoreRaycast | 1 << MoSTLayer.IgnoreRaycastAndObjects);
    this._layerMaskOnlyPlayer = 1 << MoSTLayer.Player;
    MouseLook[] componentsInChildren = this.transform.root.GetComponentsInChildren<MouseLook>();
    if (componentsInChildren.Length >= 1)
      this.mouseLook1 = componentsInChildren[0];
    if (componentsInChildren.Length >= 2)
      this.mouseLook2 = componentsInChildren[1];
    this.repeatInstantProjectCount = this.repeatInstantProjectMax;
    this._ChallengeMode = GameManager.GM.GetComponent<ChallengeMode>();
    this._MiniChallengeMode = GameManager.GM.GetComponent<MiniChallengeMode>();
    if (!PhotonNetwork.IsConnected || !MultiplayerHelper.IsMine(this.gameObject))
      return;
    PhotonNetwork.AddCallbackTarget((object) this);
  }

  private bool _MultiplayerImGrabbed()
  {
    PhotonView component = this.transform.parent.GetComponent<PhotonView>();
    return (bool) (UnityEngine.Object) component && PhotonNetwork.IsConnected && !component.IsMine;
  }

  private bool _StillWaitingToGrab(DropTriggerScript dts) => (bool) (UnityEngine.Object) this.MultiplayerGrabSettings && dts.TimeSinceSomeoneElseGrabbed.HasValue;

  private bool _IsGrabRestricted(GameObject hoverObject)
  {
    DropTriggerScript component = hoverObject.GetComponent<DropTriggerScript>();
    return (bool) (UnityEngine.Object) this.MultiplayerGrabSettings && this.hasGrabRestrictions && ((bool) (UnityEngine.Object) component.TimedGrabSettings && (bool) (UnityEngine.Object) component) && !component.grabValues.isCloneable;
  }

  public void SetHoverTimeModifier(float modifier, float duration)
  {
    this.hoverTimeModifier = modifier;
    this.hoverTimeModifierDuration = duration;
  }

  private void _ClearHoverTimeModifier()
  {
    this.hoverTimeModifierDuration = 0.0f;
    this.hoverTimeModifier = 1f;
  }

  private void _UpdateHoverTimeModifier()
  {
    if (this._MultiplayerImGrabbed())
      this.SetHoverTimeModifier(this.MultiplayerGrabSettings.IGotGrabbedHoverTimeBoost, this.MultiplayerGrabSettings.DurationHoverTimeBoost);
    if ((double) this.hoverTimeModifierDuration <= 0.0)
      return;
    this.hoverTimeModifierDuration -= Time.deltaTime;
    if ((double) this.hoverTimeModifierDuration > 0.0)
      return;
    this._ClearHoverTimeModifier();
  }

  private bool _GrabCountdownHasPassed()
  {
    if ((bool) (UnityEngine.Object) this.lastHoverObject)
    {
      DropTriggerScript component = this.lastHoverObject.GetComponent<DropTriggerScript>();
      if ((bool) (UnityEngine.Object) component && (bool) (UnityEngine.Object) component.TimedGrabSettings && !component.grabValues.isCloneable)
        return component.TimeGrabCanGrab(this.hoverTimeModifier);
    }
    return true;
  }

  private void _UpdateWaitingToGrabCountdown(GameObject hoverObject, float deltaTime)
  {
    if (this._MultiplayerImGrabbed())
      hoverObject = (GameObject) null;
    this._SetLastHoverObject(!this.isGrabbing ? hoverObject : (GameObject) null);
  }

  private void _SetLastHoverObject(GameObject hoverObject)
  {
    if (!((UnityEngine.Object) hoverObject != (UnityEngine.Object) this.lastHoverObject))
      return;
    if ((bool) (UnityEngine.Object) this.lastHoverObject)
      this.lastHoverObject.GetComponent<DropTriggerScript>().IsHovered = false;
    this.lastHoverObject = hoverObject;
    if (!(bool) (UnityEngine.Object) this.lastHoverObject)
      return;
    this.lastHoverObject.GetComponent<DropTriggerScript>().IsHovered = true;
  }

  public float? GetPercentWaitingToGrab()
  {
    if ((bool) (UnityEngine.Object) this.lastHoverObject)
    {
      DropTriggerScript component = this.lastHoverObject.GetComponent<DropTriggerScript>();
      if ((bool) (UnityEngine.Object) component && (bool) (UnityEngine.Object) component.TimedGrabSettings && !component.grabValues.isCloneable)
        return new float?(component.GetHoverGrabProgress() / this.hoverTimeModifier);
    }
    return new float?();
  }

  private bool _InGrabRecovery(GameObject aboutToGrab) => !this.isGrabbing && (double) this.grabRecoveryCountdown > 0.0 && this._IsGrabRestricted(aboutToGrab);

  private void _UpdateGrabRecovery()
  {
    if (!(bool) (UnityEngine.Object) this.MultiplayerGrabSettings)
      return;
    if (this.isGrabbing && (bool) (UnityEngine.Object) this.grabbedObject && this._IsGrabRestricted(this.grabbedObject))
    {
      this.grabRecoveryTime = this.MultiplayerGrabSettings.PostGrabRecovery;
      this.grabRecoveryCountdown = this.grabRecoveryTime;
    }
    else
    {
      double recoveryCountdown = (double) this.grabRecoveryCountdown;
      this.grabRecoveryCountdown -= Time.deltaTime;
      if (recoveryCountdown <= 0.0 || (double) this.grabRecoveryCountdown > 0.0)
        return;
      this._SetLastHoverObject((GameObject) null);
    }
  }

  public float? GetShouldShowGrabRecoveryProgress() => !this.isGrabbing && (bool) (UnityEngine.Object) this.lastHoverObject && (this._IsGrabRestricted(this.lastHoverObject) && (double) this.grabRecoveryCountdown > 0.0) ? new float?(this.grabRecoveryCountdown / this.grabRecoveryTime) : new float?();

  public float? GetForceLetGoProgress() => (double) this.forceLetGoTime > 0.0 ? new float?(this.forceLetGoCountdown / this.forceLetGoTime) : new float?();

  private bool _ForcedToDrop() => (double) this.forceLetGoTime > 0.0 && (double) this.forceLetGoCountdown <= 0.0;

  private void _UpdateForceLetGo(float deltaTime)
  {
    if ((bool) (UnityEngine.Object) this.grabbedObject && this.isGrabbing)
    {
      if ((UnityEngine.Object) this.grabbedObject == (UnityEngine.Object) this.lastGrabbedObject)
      {
        this.forceLetGoCountdown = Mathf.Max(0.0f, this.forceLetGoCountdown - deltaTime);
      }
      else
      {
        this.forceLetGoTime = 0.0f;
        if (this._IsGrabRestricted(this.grabbedObject))
          this.forceLetGoTime = this.grabbedObject.GetComponent<DropTriggerScript>().TimedGrabSettings.MaxGrabTime;
        this.forceLetGoCountdown = this.forceLetGoTime;
      }
    }
    else
    {
      this.forceLetGoTime = 0.0f;
      this.forceLetGoCountdown = 0.0f;
    }
    this.lastGrabbedObject = this.isGrabbing ? this.grabbedObject : (GameObject) null;
  }

  private void Update()
  {
    this._UpdateGrabRecovery();
    this._UpdateHoverTimeModifier();
    if (this.keyTracker.Check())
      this.RayCastType = (GrabObjectRayCastType) ((int) (this.RayCastType + 1) % 3);
    if (!GameManager.GM.PM.canControl)
      return;
    if (this.isGrabbing && !(bool) (UnityEngine.Object) this.grabbedObject)
      this.isGrabbing = false;
    this._UpdateGrabSizeStuffWhenGrabbing();
    this._UpdateForceLetGo(Time.deltaTime);
    this.isReadyToGrab = false;
    this.isObjectBlocked = false;
    this.isRejectProject = false;
    this.isObjectReadyToReturn = false;
    this.justDroppedThisFrame = false;
    if ((bool) (UnityEngine.Object) this.mouseLook1)
      this.mouseLook1.skipUpdate = false;
    if ((bool) (UnityEngine.Object) this.mouseLook2)
      this.mouseLook2.skipUpdate = false;
    bool supressDeniedSound = false;
    bool shouldScroll = false;
    Portal crossedPortal = (Portal) null;
    if (!this.isGrabbing && !this.isScrolling)
    {
      this.grabbedObject = (GameObject) null;
      this.isReadyToGrab = false;
      if (this.AllowScrollPlacement)
        GameManager.GM.guiCamera.GetComponent<DrawCursorScriptHand>().TurnOffPointLeftAndRightAndUpAndDownGUI();
      GameObject firstGrabbableObject = this.getFirstGrabbableObject(out crossedPortal, out supressDeniedSound);
      if ((UnityEngine.Object) firstGrabbableObject != (UnityEngine.Object) null)
      {
        DropTriggerScript component1 = firstGrabbableObject.GetComponent<DropTriggerScript>();
        if ((bool) (UnityEngine.Object) component1)
        {
          this.isPointingAtInstantProjectObj = component1.grabValues.instantProject;
          this.grabbedObject = firstGrabbableObject;
          DreamObjectDropTriggerScript component2 = component1.GetComponent<DreamObjectDropTriggerScript>();
          if (this.AllowScrollPlacement && (bool) (UnityEngine.Object) component2 && component2.CanUseScrollPlacement())
          {
            if (this.ShouldUseVerticalHandCursor(firstGrabbableObject))
              GameManager.GM.guiCamera.GetComponent<DrawCursorScriptHand>().DrawPointLeftAndRightGUI();
            else
              GameManager.GM.guiCamera.GetComponent<DrawCursorScriptHand>().DrawPointUpAndDownGUI();
            shouldScroll = true;
          }
          else
            this.isReadyToGrab = true;
          if (this.grabbedObject.GetComponent<DropTriggerScript>().toReturn)
            this.isObjectReadyToReturn = true;
        }
      }
      else if (ReInput.isReady && ReInput.controllers.GetLastActiveController().type == ControllerType.Joystick)
      {
        GameObject hitObject;
        if (ResizeScript._CastSphereForObject(new Ray(this.transform.position, this.transform.forward), this.AssistCastRadius, this.AssistCastDistance, this._layerMaskIgnorePlayer, out hitObject, out GameObject _))
        {
          this.mouseLook1.IsNearGrabbableObject = true;
          this.mouseLook2.IsNearGrabbableObject = true;
          this.mouseLook1.NearbyGrabbleObject = hitObject;
          this.mouseLook2.NearbyGrabbleObject = hitObject;
        }
        else
        {
          this.mouseLook1.IsNearGrabbableObject = false;
          this.mouseLook2.IsNearGrabbableObject = false;
          this.mouseLook1.NearbyGrabbleObject = (GameObject) null;
          this.mouseLook2.NearbyGrabbleObject = (GameObject) null;
        }
      }
    }
    this._UpdateWaitingToGrabCountdown(this.grabbedObject, Time.deltaTime);
    if ((bool) (UnityEngine.Object) this.grabbedObject && (this.notAllowedToGrab || this._MultiplayerImGrabbed() || (this._InGrabRecovery(this.grabbedObject) || this._StillWaitingToGrab(this.grabbedObject.GetComponent<DropTriggerScript>()))))
    {
      if (this.isGrabbing)
        this.DoDropDownObject();
      if (this.isScrolling)
        this.EndScrolling();
      this.grabbedObject = (GameObject) null;
      this.isReadyToGrab = false;
      shouldScroll = false;
    }
    if (!(bool) (UnityEngine.Object) this.grabbedObject)
    {
      if (!GameManager.GM.playerInput.GetButtonDown("Grab") || this.isGrabbing || (!(bool) (UnityEngine.Object) this.soundEffectScript || supressDeniedSound) || this.turnOffGrabDeniedSoundNextFrame)
        return;
      this.soundEffectScript.play_denied_sound();
    }
    else
    {
      if (!this._GrabCountdownHasPassed())
        return;
      if (this.isLerpingToPosition)
      {
        if ((UnityEngine.Object) this.grabbedObject == (UnityEngine.Object) null || !this.isGrabbing)
          this.isLerpingToPosition = false;
        else if ((double) this.curLerpingTime < 0.800000011920929)
        {
          this.toResizeWithoutDropping = true;
          this.curLerpingTime += Time.deltaTime;
        }
        else
        {
          this.isLerpingToPosition = false;
          this.toResizeWithoutDropping = true;
        }
      }
      this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>();
      if (GameManager.GM.playerInput.GetButtonDown("Grab") && !this.isGrabbing && !this.isScrolling || this.grabbedObject.GetComponent<DropTriggerScript>().doesRepeatInstantProject && this.repeatInstantProjectCount < this.repeatInstantProjectMax)
      {
        DropTriggerScript component = this.grabbedObject.GetComponent<DropTriggerScript>();
        if (component.toReturn)
        {
          if (!GameManager.GM.TM.isFmodTest)
            this.soundEffectScript.play_return_sound();
          else
            this.soundEffectScript.play_fmod_return_sound(this.grabbedObject.transform);
          component.ReturnOriginal();
        }
        else if (component.IsCloneButTooManyClones())
        {
          if ((bool) (UnityEngine.Object) this.soundEffectScript)
            this.soundEffectScript.play_denied_sound();
        }
        else
        {
          if ((UnityEngine.Object) this.grabbedObject.GetComponent<ProjectThroughThisObjWhenCloning>() != (UnityEngine.Object) null)
            this.grabbedObject.GetComponent<BoxCollider>().enabled = false;
          if (!this.dontLerpObjectsToCenter && !shouldScroll)
          {
            this.isLerpingToPosition = true;
            this.curLerpingTime = 0.0f;
          }
          this.DoGrabObject(crossedPortal, shouldScroll);
          if (component.grabValues.instantProject)
          {
            this.DoDropDownObject();
            if (component.grabValues.instaBridge)
              this.CreateInstaBridge(crossedPortal);
            component.hasBeenInstantProjected = true;
            if (this.repeatInstantProjectCount < this.repeatInstantProjectMax)
              ++this.repeatInstantProjectCount;
          }
          else if ((UnityEngine.Object) this.grabbedObject != (UnityEngine.Object) null && this.isGrabbing)
            this.DoDynamicProjectObject();
          if ((UnityEngine.Object) this.grabbedObject.GetComponent<ProjectThroughThisObjWhenCloning>() != (UnityEngine.Object) null)
          {
            this.grabbedObject.GetComponent<BoxCollider>().enabled = true;
            component.grabValues.instantProject = false;
            component.grabValues.isCloneable = false;
            this.oldObj.GetComponent<BoxCollider>().enabled = true;
            UnityEngine.Object.Destroy((UnityEngine.Object) this.grabbedObject.GetComponent<ProjectThroughThisObjWhenCloning>());
          }
          if ((UnityEngine.Object) this.SpinInstruction != (UnityEngine.Object) null && component.grabValues.canSpin)
            this.spinGUIStartinPoint = (Vector3) this.GetBottomRightBoundingInScreenSpace(this.grabbedObject);
          if ((bool) (UnityEngine.Object) this.DropInstruction)
            this.dropGUIStartinPoint = (Vector3) this.GetBottomRightBoundingInScreenSpace(this.grabbedObject);
        }
      }
      else if (GameManager.GM.playerInput.GetButtonDown("Grab") && (this.isGrabbing || this.isScrolling))
      {
        if (this.isScrolling)
          this.EndScrolling();
        else
          this.DoDropDownObject();
      }
      else if (GameManager.GM.playerInput.GetButtonDown("Grab") && this.isGrabbing && this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.canFollow)
        this.DoDropDownObject();
      else if (this.isGrabbing && this._ForcedToDrop())
        this.DoDropDownObject();
      else if (this.isGrabbing && this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.canSpin)
      {
        if (GameManager.GM.playerInput.GetButton("Rotate"))
        {
          DreamObjectDropTriggerScript component = this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>();
          if ((bool) (UnityEngine.Object) component && component.FreezeRotation)
          {
            this.SetRotationAsCurrent(this.grabbedObject.transform.rotation);
            component.FreezeRotation = false;
          }
          this.mouseLook1.skipUpdate = true;
          this.mouseLook2.skipUpdate = true;
          this.RotateObjectByLocalAxis();
        }
        if (GameManager.GM.playerInput.GetButtonDown("Rotate") && this.doRotateTutInThisLevel)
          this.StartHoldRotateTimer();
        this.toResizeWithoutDropping = true;
      }
      else if (this.isGrabbing && this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.canFreeze)
      {
        if (GameManager.GM.playerInput.GetButton("Rotate"))
        {
          this.grabbedObject.layer = MoSTLayer.Default;
          this.grabbedObject.GetComponent<DropTriggerScript>().returnChildrenColliderLayers();
          this.SetRotationAsCurrent(this.grabbedObject.transform.rotation);
          this.toResizeWithoutDropping = false;
        }
        else
        {
          if (this.grabbedObject.layer != MoSTLayer.Grabbed)
          {
            this.grabbedObject.layer = MoSTLayer.Grabbed;
            this.grabbedObject.GetComponent<DropTriggerScript>().setChildrenColliderLayers(MoSTLayer.Grabbed);
          }
          this.toResizeWithoutDropping = true;
        }
      }
      else if (this.isGrabbing)
        this.toResizeWithoutDropping = true;
      else if (!this.isGrabbing && this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.isCloneable && GameManager.GM.playerInput.GetButtonDown("Rotate"))
      {
        DropTriggerScript component = this.grabbedObject.GetComponent<DropTriggerScript>();
        if ((!((UnityEngine.Object) component.cloneChild == (UnityEngine.Object) null) || !((UnityEngine.Object) component.cloneParent == (UnityEngine.Object) null)) && !component.ObjectIsPerPlayer && (!this.IsMultiplayerPlayer || this.isCampaign))
        {
          this.soundEffectScript.play_clone_retrieve_sound();
          this.RetractClone(component);
        }
      }
      if ((double) this.holdRotateTutorialTimer > 0.0)
        this.holdRotateTutorialTimer -= Time.deltaTime;
      else if ((double) this.holdRotateTutorialTimer <= 0.0 && (double) this.holdRotateTutorialTimer > -1000.0)
      {
        if ((UnityEngine.Object) this.rotateTut != (UnityEngine.Object) null)
          this.rotateTut.enabled = false;
        this.holdRotateTutorialTimer = -1001f;
      }
      this.UpdateScrollThing();
    }
  }

  private void FixedUpdate()
  {
    this.notAllowedToGrab = false;
    this.turnOffGrabDeniedSoundNextFrame = false;
    if (this.notAllowedToGrabNextFrame)
      this.notAllowedToGrab = true;
    this.notAllowedToGrabNextFrame = false;
  }

  private void CreateInstaBridge(Portal crossedPortal)
  {
    for (int index = 0; index < this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.clonesInBridge - 1; ++index)
    {
      this.DoGrabObject(crossedPortal, false);
      this.DoDropDownObject();
    }
  }

  private GrabResult ResizeWithoutDropping()
  {
    if (this.isEnableDebug)
      GameManager.GM.MyLog("Grab Distance:" + (object) this._GetMinGrabDistance() + ",");
    this.ResetObjectToMinDistance(this.grabbedObject, 1f);
    DropTriggerScript component = this.grabbedObject.GetComponent<DropTriggerScript>();
    if (component.grabValues.isAlwaysSameScale)
    {
      this.grabbedObject.transform.localScale *= Mathf.Lerp(1f, component.optionalAlwaysScaleX / this.grabbedObject.transform.lossyScale.x, 0.1f);
      component.UpdateMassBasedOnScale();
    }
    GrabResult grabResult = this.DoDynamicProjectObject();
    if (component.grabValues.hasMaxSize)
    {
      float x = this.grabbedObject.transform.lossyScale.x;
      float optionalMaxScaleX = component.optionalMaxScaleX;
      if ((double) x > (double) optionalMaxScaleX)
        this.grabbedObject.transform.localScale *= optionalMaxScaleX / x;
    }
    if (this.isRejectProject)
    {
      this.isObjectBlocked = true;
      component.setSelfAndChildrenMaterials(this.blockedMat);
    }
    else
      component.returnSelfAndChildrenRenderMaterials();
    this.lastCrossedPortal = grabResult.CrossedPortal;
    if (component.OnGrabbing != null)
      component.OnGrabbing.Invoke();
    if (this.immediatelyDropObjects)
      this.DoDropDownObject();
    return grabResult;
  }

  public bool ProjectedThroughPortal() => (UnityEngine.Object) this.lastCrossedPortal != (UnityEngine.Object) null;

  private GrabResult DoDynamicProjectObject()
  {
    Portal crossedPortal;
    float reductionRatio;
    float distance = this.getResizeDistance(this.grabbedObject, out crossedPortal, out reductionRatio);
    if ((double) distance == 3.40282346638529E+38)
      distance = this._maxGrabDistance;
    if ((double) distance == 3.40282346638529E+38)
    {
      if (this.isEnableDebug)
        GameManager.GM.MyLog("Edge case!");
    }
    else if ((double) distance > 0.0)
    {
      this._EnsureObjectDetached();
      this.UpdateObjectTransformAndPropertyByDistance(this.grabbedObject, distance, crossedPortal, reductionRatio);
      this.DrawIndicatorIfObjectTooSmall(reductionRatio);
      if (this.isEnableDebug)
        GameManager.GM.MyLog("resize dist: " + (object) distance);
    }
    else
      GameManager.GM.MyLog("Return value of resize ratio is <= 0");
    return new GrabResult()
    {
      CrossedPortal = crossedPortal
    };
  }

  private void OnDestroy()
  {
    if (this.rayCastCommands.IsCreated)
      this.rayCastCommands.Dispose();
    if (this.rayCastResults.IsCreated)
      this.rayCastResults.Dispose();
    if (this.rayCastCommandsPortal.IsCreated)
      this.rayCastCommandsPortal.Dispose();
    if (this.rayCastResultsPortal.IsCreated)
      this.rayCastResultsPortal.Dispose();
    if (this.filteredRayIndices.IsCreated)
      this.filteredRayIndices.Dispose();
    if (this.fadeMaterialPool == null)
      return;
    this.fadeMaterialPool.Destroy();
    this.fadeMaterialPool = (MaterialPool) null;
  }

  private void MakeMaterialFade(Material material)
  {
    material.SetInt("_SrcBlend", 5);
    material.SetInt("_DstBlend", 10);
    material.SetInt("_ZWrite", 0);
    material.DisableKeyword("_ALPHATEST_ON");
    material.EnableKeyword("_ALPHABLEND_ON");
    material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    material.renderQueue = 3000;
    material.SetOverrideTag("RenderType", "Fade");
    if (!material.HasProperty("_Color"))
      return;
    Color color = material.color;
    color.a *= 0.5f;
    material.color = color;
  }

  private void DrawIndicatorIfObjectTooSmall(float reductionRatio)
  {
    bool flag = false;
    float num = 1f;
    float objectTooSmallAmount = this.GetGrabbedObjectTooSmallAmount();
    if ((double) objectTooSmallAmount < 1.0)
    {
      num = 1f / objectTooSmallAmount;
      flag = true;
    }
    if ((double) reductionRatio < 1.0)
    {
      num = 1f / reductionRatio;
      flag = true;
    }
    if (!flag || this.fadeMaterialPool == null)
      return;
    FakeObjectModifiers modifiers = new FakeObjectModifiers()
    {
      ShadowCastingMode = new ShadowCastingMode?(ShadowCastingMode.Off)
    };
    this.fadeMaterialPool.FrameReset();
    DrawFakeObjectHelper.DrawGameObject(this.grabbedObject, GameManager.GM.playerCamera, new Vector3(num, num, num), this.fadeMaterialPool, ref modifiers);
  }

  private void EnlargenIfTooSmall()
  {
    float objectTooSmallAmount = this.GetGrabbedObjectTooSmallAmount();
    if ((double) objectTooSmallAmount >= 1.0)
      return;
    this.grabbedObject.transform.localScale *= 1f / objectTooSmallAmount;
  }

  private float GetGrabbedObjectTooSmallAmount()
  {
    float minimumSize = this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.MinimumSize;
    Mesh mesh = this.GetMesh(this.grabbedObject);
    Vector3 a;
    if ((bool) (UnityEngine.Object) mesh)
    {
      a = mesh.bounds.size;
    }
    else
    {
      ReducedMeshForRayCasting component = this.grabbedObject.GetComponent<ReducedMeshForRayCasting>();
      a = !(bool) (UnityEngine.Object) component ? new Vector3() : component.GetLocalBoundsSize();
    }
    Vector3 vector3 = Vector3.Scale(a, this.grabbedObject.transform.lossyScale);
    return Mathf.Max(0.0001f, Mathf.Max(vector3.x / minimumSize, Mathf.Max(vector3.y / minimumSize, vector3.z / minimumSize)));
  }

  private void SetRotationAsCurrent(Quaternion grabbedObjectRotation)
  {
    this.grabbedObjectRotationInCameraSpaceOriginal = this.transform.worldToLocalMatrix.rotation * grabbedObjectRotation;
    this.accumulatedPlayerRotationCameraSpaceSelfRightingLock = Vector3.zero;
    this.grabbedObjectRotationInWorldSpaceOriginal = grabbedObjectRotation;
  }

  private void SetPositionAsOriginal(
    Vector3 worldPosition,
    Portal crossedPortal,
    DropTriggerScript dts)
  {
    if ((bool) (UnityEngine.Object) crossedPortal && (bool) (UnityEngine.Object) crossedPortal.Destination)
      worldPosition = PortalHelper.TransformPointRelativeToPortal(crossedPortal.Destination, crossedPortal, worldPosition);
    this.positionInCameraSpaceOriginal = this.transform.InverseTransformPoint(worldPosition);
    Vector3 cameraSpaceOriginal = this.positionInCameraSpaceOriginal;
    float t = dts.grabValues.AnchorWhereGrabbed;
    DreamObjectDropTriggerScript component = dts.GetComponent<DreamObjectDropTriggerScript>();
    if ((bool) (UnityEngine.Object) component && component.ShouldAnchorToGrabPoint())
      t = 1f;
    else
      cameraSpaceOriginal.x = 0.0f;
    this.positionInCameraSpaceOriginalFinal = Vector3.Slerp(Vector3.forward, cameraSpaceOriginal, t);
  }

  private void LateUpdate()
  {
    this.continueInLateLateUpdate = false;
    if (this.RayCastType == GrabObjectRayCastType.MultiThreadDeferred)
    {
      this._UpdateGrabSizeStuffWhenGrabbing();
      if (!this.isGrabbing)
        return;
      this.ResetObjectToMinDistance(this.grabbedObject, 1f);
      DropTriggerScript component = this.grabbedObject.GetComponent<DropTriggerScript>();
      if (component.grabValues.isAlwaysSameScale)
      {
        this.grabbedObject.transform.localScale *= Mathf.Lerp(1f, component.optionalAlwaysScaleX / this.grabbedObject.transform.lossyScale.x, 0.1f);
        component.UpdateMassBasedOnScale();
      }
      this.getResizeDistanceWorker_Parallel2(this.grabbedObject, 1f);
      this.continueInLateLateUpdate = true;
    }
    else
      this._LateUpdateWorker();
  }

  private void _MaybeSnap(GameObject theObject, bool justDraw)
  {
    DreamObjectDropTriggerScript component = theObject.GetComponent<DreamObjectDropTriggerScript>();
    if (!(bool) (UnityEngine.Object) component || !component.ShouldBeMagnetic())
      return;
    this.snapWorker.Clear();
    SmartSnapHelper.Snap(GameManager.GM.GetComponent<DreamManagerProxy>().DreamManager, (IEnumerable<DreamObjectDefinition>) new DreamObjectDefinition[1]
    {
      theObject.GetComponent<DreamObjectDefinition>()
    }, true, this.snapWorker);
    if (!this.snapWorker[0].Snapped)
      return;
    if (justDraw)
    {
      if (this.fadeMaterialPool == null)
        return;
      FakeObjectModifiers modifiers = new FakeObjectModifiers()
      {
        ShadowCastingMode = new ShadowCastingMode?(ShadowCastingMode.Off),
        Material = this.SnapMaterial
      };
      Matrix4x4 preMatrix = Matrix4x4.TRS(this.snapWorker[0].Position, this.snapWorker[0].Rotation, this.snapWorker[0].LocalScale) * theObject.transform.worldToLocalMatrix;
      DrawFakeObjectHelper.DrawGameObject2(theObject, GameManager.GM.playerCamera, preMatrix, ref modifiers);
    }
    else
      this.snapWorker[0].Apply();
  }

  private void _LateUpdateWorker()
  {
    GrabResult grabResult = new GrabResult();
    this._UpdateGrabSizeStuffWhenGrabbing();
    if (this.isGrabbing && (bool) (UnityEngine.Object) this.grabbedObject)
    {
      this.prevPosition = this.grabbedObject.transform.position;
      if (this.toResizeWithoutDropping)
        grabResult = this.ResizeWithoutDropping();
      this._MaybeSnap(this.grabbedObject, true);
    }
    this.toResizeWithoutDropping = false;
    if (!(bool) (UnityEngine.Object) this.outlinerCamera)
      return;
    if ((bool) (UnityEngine.Object) this.grabbedObject && this.isGrabbing && (bool) (UnityEngine.Object) grabResult.CrossedPortal)
    {
      PortalHelper.PositionObjectRelativeToPortal(grabResult.CrossedPortal, GameManager.GM.playerCamera.transform, this.outlinerCamera.transform);
    }
    else
    {
      this.outlinerCamera.transform.localPosition = Vector3.zero;
      this.outlinerCamera.transform.localRotation = Quaternion.identity;
      this.outlinerCamera.transform.localScale = Vector3.one;
    }
  }

  public void LateLateUpdate()
  {
    if (!this.continueInLateLateUpdate || this.RayCastType != GrabObjectRayCastType.MultiThreadDeferred)
      return;
    this._LateUpdateWorker();
  }

  private void OnGUI()
  {
    if (!((UnityEngine.Object) this.SpinInstruction != (UnityEngine.Object) null) || !this.isGrabbing || !this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.canSpin)
      return;
    Vector2 vector2 = new Vector2((float) Screen.width * 0.07f, (float) Screen.width * 0.07f);
    GUI.DrawTexture(new Rect(this.spinGUIStartinPoint.x, this.spinGUIStartinPoint.y, vector2.x, vector2.y), this.SpinInstruction);
  }

  private Vector2 GetBottomRightBoundingInScreenSpace(GameObject targetObject)
  {
    Vector3 center = targetObject.GetComponent<Collider>().bounds.center;
    Vector3 vector3 = this.transform.right.normalized * targetObject.GetComponent<Collider>().bounds.extents.magnitude;
    if (this.isEnableDebug)
      UnityEngine.Debug.DrawLine(center, center + vector3, Color.cyan);
    Vector3 position = center + vector3 * 0.5f;
    return (Vector2) this.GetComponent<Camera>().WorldToScreenPoint(position);
  }

  private void RotateObjectByLocalAxis()
  {
    float f = GameManager.GM.playerInput.GetAxis("Look Horizontal") * InvertAxis.GetInvertXAxisMultiplier();
    float num = GameManager.GM.playerInput.GetAxis("Look Vertical") * InvertAxis.GetInvertYAxisMultiplier();
    Vector3 direction;
    if (this.grabbedObject.GetComponent<DropTriggerScript>().optionalSpinYAxisOnly)
    {
      direction = new Vector3(0.0f, -f, 0.0f) * (Time.deltaTime * 150f);
    }
    else
    {
      direction = (double) Mathf.Abs(num) <= (double) Mathf.Abs(f) * 3.0 ? ((double) Mathf.Abs(num) * 3.0 >= (double) Mathf.Abs(f) ? new Vector3(num, -f, 0.0f) * 1f : new Vector3(0.0f, -f, 0.0f)) : new Vector3(num, 0.0f, 0.0f);
      direction = this.transform.TransformDirection(direction);
      direction *= Time.deltaTime * 100f;
    }
    this.accumulatedPlayerRotationCameraSpaceSelfRightingLock += direction;
    if (this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.selfRightingLock)
      return;
    Vector3 axis = this.transform.worldToLocalMatrix.rotation * Vector3.up;
    this.grabbedObjectRotationInCameraSpaceOriginal = Quaternion.AngleAxis(direction.y, axis) * this.grabbedObjectRotationInCameraSpaceOriginal;
  }

  public void RetractClone(DropTriggerScript dts)
  {
    this._RetractClone(dts, false);
    if (!(bool) (UnityEngine.Object) dts || !this.IsMultiplayerPlayer || !PhotonNetwork.IsConnected)
      return;
    PhotonView component = dts.GetComponent<PhotonView>();
    if (!(bool) (UnityEngine.Object) component)
      return;
    component.RPC("PhotonRetractClones", RpcTarget.Others);
  }

  public void RetractCloneRemote(DropTriggerScript dts) => this._RetractClone(dts, true);

  private void _RetractClone(DropTriggerScript dts, bool remotePlayerIsRetracting)
  {
    if (dts.isCloneRetracting)
      return;
    if (!remotePlayerIsRetracting && PhotonNetwork.IsConnected && (this.IsMultiplayerPlayer && (UnityEngine.Object) dts.cloneRoot != (UnityEngine.Object) dts))
      dts.TransferOwnershipToMe();
    if ((UnityEngine.Object) dts.cloneParent != (UnityEngine.Object) null)
    {
      this.StartCoroutine(this.LerpCloneToParent(dts, remotePlayerIsRetracting));
      dts.isCloneRetracting = true;
    }
    if ((UnityEngine.Object) dts.cloneChild != (UnityEngine.Object) null)
      this._RetractClone(dts.cloneChild, remotePlayerIsRetracting);
    if (!((UnityEngine.Object) dts.cloneParent != (UnityEngine.Object) null))
      return;
    this._RetractClone(dts.cloneParent, remotePlayerIsRetracting);
  }

  private IEnumerator LerpCloneToParent(
    DropTriggerScript dts,
    bool remotePlayerIsRetracting)
  {
    foreach (Collider componentsInChild in dts.GetComponentsInChildren<Collider>())
      componentsInChild.enabled = false;
    dts.ResetCollisionDetection();
    dts.SetIsKinematic(true);
    Transform myTransform = dts.transform;
    float maxLerpTime = 0.7f;
    float currentLerpTime = 0.0f;
    Vector3 initialPosition = myTransform.position;
    Vector3 initialScale = myTransform.localScale;
    Quaternion initialRotation = myTransform.rotation;
    while ((double) currentLerpTime < (double) maxLerpTime)
    {
      currentLerpTime += Time.deltaTime;
      float t = Mathf.Pow(currentLerpTime / maxLerpTime, 1.3f);
      if ((bool) (UnityEngine.Object) dts)
      {
        Transform transform = dts.cloneParent.transform;
        myTransform.position = Vector3.Lerp(initialPosition, transform.position, t);
        myTransform.localScale = Vector3.Lerp(initialScale, transform.localScale, t);
        myTransform.rotation = Quaternion.Lerp(initialRotation, transform.rotation, t);
      }
      yield return (object) new WaitForEndOfFrame();
    }
    if ((bool) (UnityEngine.Object) dts)
      dts.gameObject.SetActive(false);
    yield return (object) new WaitForSeconds(1f);
    if ((bool) (UnityEngine.Object) dts)
    {
      if (this.IsMultiplayerPlayer && PhotonNetwork.IsConnected)
      {
        if (!remotePlayerIsRetracting)
          PhotonNetwork.Destroy(dts.gameObject);
      }
      else
        UnityEngine.Object.Destroy((UnityEngine.Object) dts.gameObject);
    }
    yield return (object) null;
  }

  private void _EnsureObjectDetached()
  {
    if (!((UnityEngine.Object) this.grabbedObject.transform.root != (UnityEngine.Object) this.grabbedObject.transform))
      return;
    this.grabbedObject.transform.parent = (Transform) null;
  }

  private void _MaybeClaimThisPerPlayerObject(DropTriggerScript dts)
  {
    if (!dts.ObjectIsPerPlayer || !PhotonNetwork.IsConnected)
      return;
    dts.PerPlayerActorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
  }

  private bool _ImTheLastPlayerToGrabObject(DropTriggerScript dtsIn)
  {
    int length = GameManager.GM.GetComponent<MultiplayerMode>().GetPlayersInCurrentRoom().Length;
    int num = 0;
    for (DropTriggerScript dropTriggerScript = dtsIn.cloneRoot; (bool) (UnityEngine.Object) dropTriggerScript; dropTriggerScript = dropTriggerScript.cloneChild)
    {
      if (dropTriggerScript.PerPlayerActorNumber != -1)
        ++num;
    }
    return num >= length - 1;
  }

  private bool _HaveIGrabbedThisObjectYet(DropTriggerScript dtsIn)
  {
    int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
    for (DropTriggerScript dropTriggerScript = dtsIn.cloneRoot; (bool) (UnityEngine.Object) dropTriggerScript; dropTriggerScript = dropTriggerScript.cloneChild)
    {
      if (dropTriggerScript.PerPlayerActorNumber == actorNumber)
        return true;
    }
    return false;
  }

  private bool _IsPerPlayerMPObjectAndIHaventGrabbedItYet(DropTriggerScript dts) => dts.ObjectIsPerPlayer && PhotonNetwork.IsConnected && !this._HaveIGrabbedThisObjectYet(dts) && !this._ImTheLastPlayerToGrabObject(dts);

  private void DoGrabObject(Portal crossedPortal, bool shouldScroll)
  {
    if (!(this.isReadyToGrab | shouldScroll))
      return;
    DropTriggerScript component1 = this.grabbedObject.GetComponent<DropTriggerScript>();
    DreamObjectDropTriggerScript component2 = this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>();
    CloneOnce component3 = this.grabbedObject.GetComponent<CloneOnce>();
    bool flag1 = (bool) (UnityEngine.Object) component3 && component3.CloneMe;
    bool flag2 = (bool) (UnityEngine.Object) component2 && component2.ShouldClone();
    bool flag3 = this._IsPerPlayerMPObjectAndIHaventGrabbedItYet(component1);
    bool counterZFighting = false;
    if (component1.grabValues.isCloneable | flag2 | flag1 | flag3)
    {
      DropTriggerScript dtsParent = component1;
      component1.ResetCollisionDetection();
      counterZFighting = true;
      if ((UnityEngine.Object) this.grabbedObject.GetComponent<ProjectThroughThisObjWhenCloning>() == (UnityEngine.Object) null)
      {
        if (PhotonNetwork.IsConnected)
        {
          Vector3 localScale = this.grabbedObject.transform.localScale;
          this.grabbedObject = !(bool) (UnityEngine.Object) this.grabbedObject.GetComponent<MultiplayerPlayer>() ? PhotonNetwork.Instantiate(component1.cloneRoot.GetComponent<PhotonView>().sceneViewId.ToString(), this.grabbedObject.transform.position, this.grabbedObject.transform.rotation, data: MultiplayerHelper.CreateCloneInstanceData(this.grabbedObject)) : PhotonNetwork.Instantiate("Multiplayer/PlayerControllerPrefabMP", this.grabbedObject.transform.position, this.grabbedObject.transform.rotation, data: MultiplayerHelper.CreateCloneInstanceData(this.grabbedObject));
          this.grabbedObject.transform.localScale = localScale;
        }
        else
        {
          PhotonView component4 = this.grabbedObject.GetComponent<PhotonView>();
          if ((bool) (UnityEngine.Object) component4)
            component4.ViewID = 0;
          this.grabbedObject = UnityEngine.Object.Instantiate<GameObject>(this.grabbedObject, this.grabbedObject.transform.position, this.grabbedObject.transform.rotation);
          PhotonView component5 = this.grabbedObject.GetComponent<PhotonView>();
          if ((bool) (UnityEngine.Object) component5)
            component5.ViewID = 0;
        }
        component1 = this.grabbedObject.GetComponent<DropTriggerScript>();
        if (flag2)
        {
          this.grabbedObject.GetComponent<DreamObjectDropTriggerScript>().OnClone();
        }
        else
        {
          if (flag3)
            dtsParent.TurnOffGrabPermanentlyForMe();
          component1.InsertIntoCloneChain(dtsParent);
          HueModifier component4 = this.grabbedObject.GetComponent<HueModifier>();
          if ((bool) (UnityEngine.Object) component4)
            component4.Modify();
          if (component1.IsCloneButTooManyClones())
          {
            if ((bool) (UnityEngine.Object) this.CloneAlotAchievement)
              this.CloneAlotAchievement.Grant();
            if ((bool) (UnityEngine.Object) component4)
              component4.BonusMakeEmissive();
          }
        }
        if (this.OnCloneCreated != null)
          this.OnCloneCreated(this.grabbedObject);
      }
      else
      {
        GameObject theClone = UnityEngine.Object.Instantiate<GameObject>(this.grabbedObject, this.grabbedObject.transform.position, this.grabbedObject.transform.rotation);
        theClone.GetComponent<BoxCollider>().enabled = true;
        this.oldObj = this.grabbedObject;
        this.grabbedObject = theClone;
        component1 = this.grabbedObject.GetComponent<DropTriggerScript>();
        if (this.OnCloneCreated != null)
          this.OnCloneCreated(theClone);
      }
    }
    if (shouldScroll)
    {
      this.StartScrolling(counterZFighting);
    }
    else
    {
      this._MaybeClaimThisPerPlayerObject(component1);
      this.grabbedObject.layer = MoSTLayer.Grabbed;
      component1.setChildrenColliderLayers(MoSTLayer.Grabbed);
      Vector3 vector3_1 = this.grabbedObject.transform.position;
      this.SetPositionAsOriginal(vector3_1, crossedPortal, component1);
      if ((bool) (UnityEngine.Object) crossedPortal && (bool) (UnityEngine.Object) crossedPortal.Destination)
        vector3_1 = PortalHelper.TransformPointRelativeToPortal(crossedPortal.Destination, crossedPortal, vector3_1);
      Vector3 vector3_2 = vector3_1 - this.transform.position;
      float initialRatio = this._GetMinGrabDistance() / vector3_2.magnitude;
      if ((bool) (UnityEngine.Object) this.soundEffectScript)
        this.soundEffectScript.play_pop_sound_grab(component1.SizeEstimate());
      if (!this.isGrabbing)
        component1.SpawnGrabParticle();
      this._EnsureObjectDetached();
      this.SetScaleAtMinDistance(this.grabbedObject, initialRatio, crossedPortal);
      Quaternion quaternion = this.grabbedObject.transform.rotation;
      if ((bool) (UnityEngine.Object) crossedPortal && (bool) (UnityEngine.Object) crossedPortal.Destination)
        quaternion = PortalHelper.TransformRotation(crossedPortal.Destination, quaternion);
      this.SetRotationAsCurrent(quaternion);
      if (PhotonNetwork.IsConnected && this.IsMultiplayerPlayer)
        component1.TransferOwnershipToMe();
      if ((bool) (UnityEngine.Object) component1.TimedGrabSettings)
        this._ClearHoverTimeModifier();
      if (component1.OnGrabbedLocalPre != null)
        component1.OnGrabbedLocalPre.Invoke();
      component1.SetObjectPhysicsByIsGrabbed(true);
      this.isGrabbing = true;
      if ((bool) (UnityEngine.Object) this.DrawOutlineMat)
        this.DrawOutlineMat.color = !component1.grabValues.canSpin ? (!component1.grabValues.canFollow ? this.cannotDoAnythingColor : this.canFollowColor) : this.canSpinColor;
      this.outlinerCamera.LerpOutlineDist();
      if (component1.OnGrabbed != null)
        component1.OnGrabbed.Invoke();
      if (component1.OnGrabbedLocal != null)
        component1.OnGrabbedLocal.Invoke();
      if (this.OnGrabbed != null)
        this.OnGrabbed.Invoke();
      this.OnGrabbedParam?.Invoke(component1);
      if ((UnityEngine.Object) this._ChallengeMode != (UnityEngine.Object) null && this._ChallengeMode.ChallengeModeEnabled)
        ++this._ChallengeMode._Grabs;
      if ((UnityEngine.Object) this._MiniChallengeMode != (UnityEngine.Object) null && this._MiniChallengeMode.MiniChallengeModeEnabled)
        this._MiniChallengeMode.AddToGrabs();
      DreamManagerProxy component4 = GameManager.GM.GetComponent<DreamManagerProxy>();
      if (!((UnityEngine.Object) component4 != (UnityEngine.Object) null) || !component4.IsInDream())
        return;
      component4.AddToChallengeModeGrabs();
    }
  }

  public void CheckIfGrabbingThenDoDropDownObject()
  {
    if (!this.isGrabbing)
      return;
    this.DoDropDownObject();
  }

  private void DoDropDownObject(bool objectWasStolen = false)
  {
    this.justDroppedThisFrame = true;
    Portal crossedPortal;
    float reductionRatio;
    float distance = this.getResizeDistance(this.grabbedObject, out crossedPortal, out reductionRatio);
    if ((double) distance == 3.40282346638529E+38)
    {
      distance = this._maxGrabDistance;
      this.isObjectInSky = true;
    }
    else
      this.isObjectInSky = false;
    if ((double) distance == 3.40282346638529E+38 || this.isRejectProject)
    {
      if (!(bool) (UnityEngine.Object) this.soundEffectScript)
        return;
      this.soundEffectScript.play_denied_sound();
    }
    else
    {
      Vector3 position = this.grabbedObject.transform.position;
      this._EnsureObjectDetached();
      this.UpdateObjectTransformAndPropertyByDistance(this.grabbedObject, distance, crossedPortal, reductionRatio);
      this.EnlargenIfTooSmall();
      this.ReturnObjectToWorld(objectWasStolen);
      if (this.grabbedObject.GetComponent<DropTriggerScript>().grabValues.canFollow)
        this.setFollowVelocity(position);
      double num = (double) Vector3.Distance(this.transform.position, this.grabbedObject.transform.position);
      if (!(bool) (UnityEngine.Object) this.soundEffectScript)
        return;
      this.soundEffectScript.play_pop_sound_put(this.grabbedObject.GetComponent<DropTriggerScript>().SizeEstimate());
    }
  }

  public void CallReturnObjectToWorld() => this.ReturnObjectToWorld(false);

  private int GetPhotonViewID() => GameManager.GM.player.GetComponent<PhotonView>().ViewID;

  private void ReturnObjectToWorld(bool objectWasStolen)
  {
    this.grabbedObject.layer = MoSTLayer.CanGrab;
    DropTriggerScript component1 = this.grabbedObject.GetComponent<DropTriggerScript>();
    if (component1.grabValues.isGrabOnce)
    {
      this.grabbedObject.layer = MoSTLayer.Default;
      component1.GrayOut();
    }
    if (component1.grabValues.canReturn)
      component1.toReturn = true;
    component1.returnChildrenColliderLayers();
    component1.SetObjectPhysicsByIsGrabbed(false);
    if (this.isObjectInSky)
    {
      component1.SetIsKinematic(true);
    }
    else
    {
      if (component1.AllowRandomDropTorque)
      {
        Rigidbody component2 = this.grabbedObject.GetComponent<Rigidbody>();
        if ((bool) (UnityEngine.Object) component2)
        {
          Vector3 vector3 = this.LimitRandomTorqueToCameraPlane ? this.transform.forward : UnityEngine.Random.onUnitSphere;
          if (UnityEngine.Random.Range(0, 2) == 0)
            vector3 = -vector3;
          component2.AddTorque(vector3 * UnityEngine.Random.Range(this.RandomTorqueOnDrop.x, this.RandomTorqueOnDrop.y), ForceMode.VelocityChange);
        }
      }
      if ((bool) (UnityEngine.Object) component1.RandomEjection)
      {
        Rigidbody component2 = this.grabbedObject.GetComponent<Rigidbody>();
        if ((bool) (UnityEngine.Object) component2)
        {
          Vector3 axis = Quaternion.AngleAxis(UnityEngine.Random.Range(0.0f, 360f), component1.RandomEjection.forward) * component1.RandomEjection.right;
          Vector3 vector3 = Quaternion.AngleAxis(UnityEngine.Random.Range(0.0f, component1.RandomEjectionAngle), axis) * component1.RandomEjection.forward;
          float num = UnityEngine.Random.Range(0.0f, component1.RandomEjectionAcceleration);
          component2.AddForce(vector3.normalized * num, ForceMode.VelocityChange);
        }
      }
    }
    this.isGrabbing = false;
    this._MaybeSnap(this.grabbedObject, false);
    this._InvokeOnDroppedEvents(component1);
  }

  private void _InvokeOnDroppedEvents(DropTriggerScript dts)
  {
    dts.OnDropped?.Invoke();
    this.OnDropped?.Invoke();
    this.OnDroppedParam?.Invoke(dts);
    dts.OnDroppedLocal?.Invoke();
  }

  public static bool _CastRayOrSphereForObject(
    Ray ray,
    float sphereRadius,
    out RaycastHit hitInfo,
    int layerMask,
    out GameObject hitObject,
    out GameObject grabObject,
    out bool wasSingleRay)
  {
    hitObject = (GameObject) null;
    grabObject = (GameObject) null;
    wasSingleRay = true;
    bool flag = false;
    if (Physics.Raycast(ray, out hitInfo, float.PositiveInfinity, layerMask))
    {
      flag = true;
      grabObject = ResizeScript.getNearestCanGrabAncestor(hitInfo.collider.gameObject);
      if ((bool) (UnityEngine.Object) grabObject)
      {
        hitObject = hitInfo.collider.gameObject;
        flag = false;
      }
    }
    if (flag)
    {
      int num = Physics.SphereCastNonAlloc(ray, sphereRadius, ResizeScript.hitWorker, hitInfo.distance + 0.1f, layerMask);
      for (int index = 0; index < num; ++index)
      {
        GameObject nearestCanGrabAncestor = ResizeScript.getNearestCanGrabAncestor(ResizeScript.hitWorker[index].collider.gameObject);
        if ((bool) (UnityEngine.Object) nearestCanGrabAncestor)
        {
          Vector3 vector3 = ResizeScript.hitWorker[index].point - ray.origin;
          RaycastHit hitInfo1;
          if (!Physics.Raycast(new Ray(ray.origin, vector3.normalized), out hitInfo1, vector3.magnitude, layerMask) || (UnityEngine.Object) hitInfo1.collider.gameObject == (UnityEngine.Object) ResizeScript.hitWorker[index].collider.gameObject)
          {
            hitObject = ResizeScript.hitWorker[index].collider.gameObject;
            grabObject = nearestCanGrabAncestor;
            wasSingleRay = false;
            break;
          }
        }
      }
      if (!(bool) (UnityEngine.Object) hitObject)
        hitObject = hitInfo.collider.gameObject;
    }
    return (UnityEngine.Object) hitObject != (UnityEngine.Object) null;
  }

  private static bool _CastSphereForObject(
    Ray ray,
    float sphereRadius,
    float distanceToCast,
    int layerMask,
    out GameObject hitObject,
    out GameObject grabObject)
  {
    hitObject = (GameObject) null;
    grabObject = (GameObject) null;
    int num = Physics.SphereCastNonAlloc(ray, sphereRadius, ResizeScript.hitWorker, distanceToCast, layerMask);
    GameObject gameObject = (GameObject) null;
    float maxValue = float.MaxValue;
    for (int index = 0; index < num; ++index)
    {
      if ((bool) (UnityEngine.Object) ResizeScript.getNearestCanGrabAncestor(ResizeScript.hitWorker[index].collider.gameObject))
      {
        Vector3 vector3 = ResizeScript.hitWorker[index].point - ray.origin;
        RaycastHit hitInfo;
        if (!Physics.Raycast(new Ray(ray.origin, vector3.normalized), out hitInfo, vector3.magnitude, layerMask) || (UnityEngine.Object) hitInfo.collider.gameObject == (UnityEngine.Object) ResizeScript.hitWorker[index].collider.gameObject)
        {
          if ((double) vector3.magnitude < (double) maxValue)
          {
            gameObject = ResizeScript.hitWorker[index].collider.gameObject;
            float magnitude = vector3.magnitude;
            break;
          }
          break;
        }
      }
    }
    hitObject = gameObject;
    return (UnityEngine.Object) hitObject != (UnityEngine.Object) null;
  }

  private GameObject getFirstGrabbableObject(
    out Portal crossedPortal,
    out bool supressDeniedSound)
  {
    supressDeniedSound = false;
    crossedPortal = (Portal) null;
    float sphereRadius = !ReInput.isReady || ReInput.controllers.GetLastActiveController().type != ControllerType.Joystick ? this.CastRadius : this.CastRadiusForController;
    RaycastHit hitInfo;
    GameObject hitObject1;
    GameObject grabObject1;
    bool wasSingleRay;
    if (ResizeScript._CastRayOrSphereForObject(new Ray(this.transform.position, this.transform.forward), sphereRadius, out hitInfo, this._layerMaskIgnorePlayer, out hitObject1, out grabObject1, out wasSingleRay))
    {
      Portal hitPortal = this._MaybeGetHitPortal(ref hitInfo);
      GameObject hitObject2;
      GameObject grabObject2;
      if ((bool) (UnityEngine.Object) hitPortal & wasSingleRay && ResizeScript._CastRayOrSphereForObject(PortalHelper.TransformRay(hitPortal, new Ray(hitInfo.point, this.transform.forward)), sphereRadius, out hitInfo, -5, out hitObject2, out grabObject2, out wasSingleRay))
      {
        hitObject1 = hitObject2;
        if ((bool) (UnityEngine.Object) grabObject2 && !hitPortal.transform.IsChildOf(grabObject2.transform) && !hitPortal.Destination.transform.IsChildOf(grabObject2.transform))
        {
          grabObject1 = grabObject2;
          crossedPortal = hitPortal;
        }
      }
    }
    if ((bool) (UnityEngine.Object) grabObject1)
    {
      MultiplayerPlayer component = grabObject1.GetComponent<MultiplayerPlayer>();
      if ((bool) (UnityEngine.Object) component && !component.CanClonePlayer_AndMaybeDestroy())
      {
        grabObject1 = (GameObject) null;
        hitObject1 = (GameObject) null;
        crossedPortal = (Portal) null;
      }
    }
    MOSTTriggerBase mostTriggerBase = (MOSTTriggerBase) null;
    if ((bool) (UnityEngine.Object) hitObject1)
    {
      MOSTTriggerOnClick component = hitObject1.GetComponent<MOSTTriggerOnClick>();
      mostTriggerBase = (MOSTTriggerBase) component;
      if (!(bool) (UnityEngine.Object) mostTriggerBase)
        mostTriggerBase = (MOSTTriggerBase) hitObject1.GetComponentInParent<MOSTTriggerOnClickChildren>();
      if ((bool) (UnityEngine.Object) component && component.DenyGrabInParent)
        grabObject1 = (GameObject) null;
    }
    supressDeniedSound = (bool) (UnityEngine.Object) mostTriggerBase && (!mostTriggerBase.hasTriggered || mostTriggerBase.repeatableTrigger);
    if ((bool) (UnityEngine.Object) grabObject1 && this.DenyGrab != null && this.DenyGrab(grabObject1))
      grabObject1 = (GameObject) null;
    return grabObject1;
  }

  public static GameObject getNearestCanGrabAncestor(GameObject obj)
  {
    if (obj.layer == MoSTLayer.CanGrab)
      return obj;
    if ((UnityEngine.Object) obj.transform.parent == (UnityEngine.Object) null)
      return (GameObject) null;
    if (obj.layer == MoSTLayer.CannotGrab)
      return (GameObject) null;
    return obj.CompareTag(ResizeScript.ChildThatIgnoresGrabTag) ? (GameObject) null : ResizeScript.getNearestCanGrabAncestor(obj.transform.parent.gameObject);
  }

  private float _EstimateObjectSize(GameObject obj)
  {
    Vector3 size = this._EstimateObjectBounds(obj).size;
    return Mathf.Max(size.x, Mathf.Max(size.y, size.z));
  }

  private Bounds _EstimateObjectBounds(GameObject obj)
  {
    Transform transform = obj.transform;
    Bounds bounds = new Bounds(transform.position, Vector3.zero);
    Collider component = obj.GetComponent<Collider>();
    if ((bool) (UnityEngine.Object) component)
      bounds.Encapsulate(component.bounds);
    int childCount = transform.childCount;
    for (int index = 0; index < childCount; ++index)
    {
      Transform child = transform.GetChild(index);
      if (child.gameObject.activeSelf)
        bounds.Encapsulate(this._EstimateObjectBounds(child.gameObject));
    }
    return bounds;
  }

  private float _GetSmallObjectThreshold(GameObject obj)
  {
    float overlapThreshold = this.SmallObjectIgnoreOverlapThreshold;
    DropTriggerScript component = obj.GetComponent<DropTriggerScript>();
    if ((bool) (UnityEngine.Object) component && (double) component.CustomSmallObjectIgnoreOverlapThreshold != 0.0)
      overlapThreshold = component.CustomSmallObjectIgnoreOverlapThreshold;
    return overlapThreshold;
  }

  private float _EnsureObjectDoesntColliderWithPlayerByTestingOverlap(
    GameObject obj,
    float resizeDistance)
  {
    if ((double) resizeDistance == double.PositiveInfinity || (double) resizeDistance == 3.40282346638529E+38)
      return 1f;
    int num1 = 0;
    CharacterController component = GameManager.GM.player.GetComponent<CharacterController>();
    Vector3 center = component.center;
    Vector3 position1 = component.center - Vector3.up * (component.height * 0.5f - component.radius);
    Vector3 position2 = component.center + Vector3.up * (component.height * 0.5f - component.radius);
    float radius = component.radius * component.transform.localScale.x;
    Vector3 point0 = component.transform.TransformPoint(position1);
    Vector3 point1 = component.transform.TransformPoint(position2);
    float num2 = 1f;
    float b1 = 0.0f;
    float b2 = 1f;
    this.UpdateObjectTransformAndPropertyByDistance(obj, resizeDistance, (Portal) null, num2);
    float num3 = 0.0f;
    float smallObjectThreshold = this._GetSmallObjectThreshold(obj);
    if ((double) smallObjectThreshold > 0.0)
    {
      float num4 = this._EstimateObjectSize(obj);
      if ((double) num4 < (double) smallObjectThreshold)
        return 1f;
      num3 = smallObjectThreshold / num4;
    }
    for (; num1 < 10; ++num1)
    {
      int num4 = Physics.OverlapCapsuleNonAlloc(point0, point1, radius, ResizeScript.lotsOfColliders, this._layerMaskGrabbed);
      if (num4 != 0 || num1 != 0)
      {
        if (num4 > 0)
        {
          b2 = num2;
          num2 = Mathf.Lerp(num2, b1, 0.5f);
        }
        else
        {
          b1 = num2;
          num2 = Mathf.Lerp(num2, b2, 0.5f);
        }
        this.UpdateObjectTransformAndPropertyByDistance(obj, resizeDistance, (Portal) null, num2);
      }
      else
        break;
    }
    if ((double) num2 < (double) num3)
      num2 = num3;
    return num2;
  }

  private float _EnsureObjectDoesntColliderWithPlayer(
    GameObject obj,
    List<Vector3> objVertices,
    float resizeDistance,
    float furtherestDistance)
  {
    if ((double) resizeDistance == double.PositiveInfinity)
      return 1f;
    Vector3 directionToObject = this._GetDirectionToObject();
    float num = resizeDistance / this._GetMinGrabDistance();
    Matrix4x4 matrix4x4 = Matrix4x4.TRS(this.transform.position + directionToObject * resizeDistance, this._GetCurrentObjectRotationWorldSpace(), this.scaleAtMinDistance * num);
    for (int index = 0; index < objVertices.Count; ++index)
      objVertices[index] = matrix4x4.MultiplyPoint(objVertices[index]);
    Vector3 origin = this.transform.position + directionToObject * resizeDistance;
    float a = 1f;
    foreach (Vector3 objVertex in objVertices)
    {
      Vector3 direction = objVertex - origin;
      float magnitude = direction.magnitude;
      RaycastHit hitInfo;
      if (Physics.Raycast(origin, direction, out hitInfo, magnitude, this._layerMaskOnlyPlayer))
        a = Mathf.Min(a, hitInfo.distance / magnitude);
    }
    return a;
  }

  private void _PopulateRaysScreenspace(
    Camera theCamera,
    List<Vector3> objWorldSpacePoints,
    bool parallel)
  {
    Vector3 pos1 = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
    Vector3 pos2 = new Vector3(float.MinValue, float.MinValue, float.MinValue);
    foreach (Vector3 objWorldSpacePoint in objWorldSpacePoints)
    {
      Vector3 screenPoint = theCamera.WorldToScreenPoint(objWorldSpacePoint);
      if ((double) screenPoint.x < (double) pos1.x)
        pos1.x = screenPoint.x;
      if ((double) screenPoint.y < (double) pos1.y)
        pos1.y = screenPoint.y;
      if ((double) screenPoint.x > (double) pos2.x)
        pos2.x = screenPoint.x;
      if ((double) screenPoint.y > (double) pos2.y)
        pos2.y = screenPoint.y;
    }
    Ray ray1 = theCamera.ScreenPointToRay(pos1);
    Ray ray2 = theCamera.ScreenPointToRay(pos2);
    UnityEngine.Debug.DrawRay(ray1.origin, ray1.direction, Color.red);
    UnityEngine.Debug.DrawRay(ray2.origin, ray2.direction, Color.red);
    int num1 = (int) (((double) pos2.x - (double) pos1.x) / 20.0);
    int num2 = (int) (((double) pos2.y - (double) pos1.y) / 20.0);
    int num3 = Mathf.Clamp(num1, 20, 40);
    int num4 = Mathf.Clamp(num2, 20, 40);
    float num5 = (pos2.x - pos1.x) / (float) num3;
    float num6 = (pos2.y - pos1.y) / (float) num4;
    for (int index1 = 0; index1 < num4; ++index1)
    {
      float y = pos1.y + (float) index1 * num6;
      for (int index2 = 0; index2 < num3; ++index2)
      {
        Vector3 pos3 = new Vector3(pos1.x + (float) index2 * num5, y, 0.0f);
        Ray ray3 = theCamera.ScreenPointToRay(pos3);
        if (parallel)
          this.rayDirectionsWorkerPrelim.Add(ray3.direction);
        else
          this.rayListWorker.Add(ray3);
      }
    }
  }

  private void _PopulateRaysSpherical(
    Camera theCamera,
    List<Vector3> objWorldSpacePoints,
    Vector3 cameraToObjectDirection,
    bool parallel)
  {
    Vector3 position = this.transform.position;
    Vector3 right = this.transform.right;
    Vector3 up = this.transform.up;
    float a1 = float.MaxValue;
    float a2 = float.MaxValue;
    float num1 = float.MinValue;
    float num2 = float.MinValue;
    Vector3 from1 = Vector3.ProjectOnPlane(cameraToObjectDirection, right);
    Vector3 from2 = Vector3.ProjectOnPlane(cameraToObjectDirection, up);
    foreach (Vector3 objWorldSpacePoint in objWorldSpacePoints)
    {
      float b1 = Vector3.SignedAngle(from1, Vector3.ProjectOnPlane(objWorldSpacePoint - position, right), right);
      a2 = Mathf.Min(a2, b1);
      num2 = Mathf.Max(num2, b1);
      float b2 = Vector3.SignedAngle(from2, Vector3.ProjectOnPlane(objWorldSpacePoint - position, up), up);
      a1 = Mathf.Min(a1, b2);
      num1 = Mathf.Max(num1, b2);
    }
    float num3 = 0.5f;
    int min = Mathf.CeilToInt(20f);
    int max = Mathf.CeilToInt(40f);
    float num4 = num1 - a1;
    int num5 = Mathf.Clamp(Mathf.CeilToInt(num4 * num3), min, max);
    double num6 = (double) num2 - (double) a2;
    int num7 = Mathf.Clamp(Mathf.CeilToInt((float) (num6 * 0.5)), min, max);
    double num8 = (double) num4 / (double) num5;
    double num9 = num6 / (double) num7;
    for (int index1 = 0; index1 <= num7; ++index1)
    {
      Vector3 vector3 = Quaternion.AngleAxis(Mathf.Lerp(a2, num2, (float) index1 / (float) num7), right) * cameraToObjectDirection;
      for (int index2 = 0; index2 <= num5; ++index2)
      {
        Vector3 direction = Quaternion.AngleAxis(Mathf.Lerp(a1, num1, (float) index2 / (float) num5), up) * vector3;
        if (parallel)
          this.rayDirectionsWorkerPrelim.Add(direction);
        else
          this.rayListWorker.Add(new Ray(position, direction));
      }
    }
  }

  private void _PopulateRaysSphericalOLD(
    Camera theCamera,
    List<Vector3> objWorldSpacePoints,
    Vector3 cameraToObjectDirection,
    bool parallel)
  {
    Vector3 position = this.transform.position;
    Vector3 right = this.transform.right;
    Vector3 up = this.transform.up;
    float a1 = float.MaxValue;
    float a2 = float.MaxValue;
    float num1 = float.MinValue;
    float num2 = float.MinValue;
    foreach (Vector3 objWorldSpacePoint in objWorldSpacePoints)
    {
      float b1 = Vector3.SignedAngle(cameraToObjectDirection, objWorldSpacePoint - position, right);
      a2 = Mathf.Min(a2, b1);
      num2 = Mathf.Max(num2, b1);
      float b2 = Vector3.SignedAngle(cameraToObjectDirection, objWorldSpacePoint - position, up);
      a1 = Mathf.Min(a1, b2);
      num1 = Mathf.Max(num1, b2);
    }
    float num3 = 0.5f * this.TestingRayReduction;
    int min = Mathf.CeilToInt(20f * this.TestingRayReduction);
    int max = Mathf.CeilToInt(40f * this.TestingRayReduction);
    float num4 = num1 - a1;
    int num5 = Mathf.Clamp(Mathf.CeilToInt(num4 * num3), min, max);
    double num6 = (double) num2 - (double) a2;
    int num7 = Mathf.Clamp(Mathf.CeilToInt((float) (num6 * 0.5)), min, max);
    double num8 = (double) num4 / (double) num5;
    double num9 = num6 / (double) num7;
    for (int index1 = 0; index1 <= num7; ++index1)
    {
      Vector3 vector3 = Quaternion.AngleAxis(Mathf.Lerp(a2, num2, (float) index1 / (float) num7), right) * cameraToObjectDirection;
      for (int index2 = 0; index2 <= num5; ++index2)
      {
        Vector3 direction = Quaternion.AngleAxis(Mathf.Lerp(a1, num1, (float) index2 / (float) num5), up) * vector3;
        if (parallel)
          this.rayDirectionsWorkerPrelim.Add(direction);
        else
          this.rayListWorker.Add(new Ray(position, direction));
      }
    }
  }

  private float getResizeDistance(
    GameObject obj,
    out Portal crossedPortal,
    out float reductionRatio)
  {
    float num = 0.0f;
    crossedPortal = (Portal) null;
    reductionRatio = 1f;
    switch (this.RayCastType)
    {
      case GrabObjectRayCastType.SingleThread:
        num = this.getResizeDistanceWorker(obj, out crossedPortal, out reductionRatio, 1f);
        break;
      case GrabObjectRayCastType.MultiThreadImmediate:
        num = this.getResizeDistanceWorker_Parallel(obj, out crossedPortal, out reductionRatio, 1f);
        break;
      case GrabObjectRayCastType.MultiThreadDeferred:
        num = this.FinishOffTheThing(obj, out crossedPortal, out reductionRatio);
        break;
    }
    if ((double) num == double.PositiveInfinity || (double) num == 3.40282346638529E+38)
    {
      num = this.getResizeDistanceWorker(obj, out crossedPortal, out reductionRatio, 2f);
      if (((double) num == double.PositiveInfinity || (double) num == 3.40282346638529E+38) && obj.GetComponent<DropTriggerScript>().grabValues.isCloneable)
        num = this._GetMinGrabDistance();
    }
    return num;
  }

  private Mesh GetMesh(GameObject go)
  {
    Mesh mesh = (Mesh) null;
    MeshFilter component = go.GetComponent<MeshFilter>();
    if ((bool) (UnityEngine.Object) component)
      mesh = component.sharedMesh;
    return mesh;
  }

  private float getResizeDistanceWorker_Parallel(
    GameObject obj,
    out Portal crossedPortal,
    out float reductionRatio,
    float minDistanceScale)
  {
    if (!this.rayCastResults.IsCreated)
    {
      int num = 1881;
      this.rayCastResults = new NativeArray<RaycastHit>(num, Allocator.Persistent);
      this.rayCastCommands = new NativeList<RaycastCommand>(num, Allocator.Persistent);
      this.rayCastResultsPortal = new NativeArray<RaycastHit>(num, Allocator.Persistent);
      this.rayCastCommandsPortal = new NativeList<RaycastCommand>(num, Allocator.Persistent);
    }
    this.swHitGrab.Reset();
    this.swTotal.Reset();
    this.swTotal.Start();
    this.Info.DidntHitBack = 0;
    this.Info.DidntHitWall = 0;
    this.Info.DidntHitGrabbed = 0;
    this.Info.DidntHitGrabbedObjVert = 0;
    reductionRatio = 1f;
    Vector3 minDistance = this.ResetObjectToMinDistance(obj, minDistanceScale);
    this.rayDirectionsWorkerPrelim.Clear();
    this.rayDirectionsWorkerFinal.Clear();
    this.portalCommandToOriginalIndex.Clear();
    this.portalsWeHit.Clear();
    Mesh mesh = this.GetMesh(obj);
    this.swCalcBounds.Reset();
    this.swCalcBounds.Start();
    this.objWorldSpacePoints.Clear();
    this.objPoints.Clear();
    ReducedMeshForRayCasting component1 = obj.GetComponent<ReducedMeshForRayCasting>();
    Transform objToWorldTransform = obj.transform;
    if ((bool) (UnityEngine.Object) component1)
      component1.GetObjectSpaceVertices(this.objPoints, out objToWorldTransform);
    else
      mesh.GetVertices(this.objPoints);
    this.objWorldSpacePoints.AddRange((IEnumerable<Vector3>) this.objPoints);
    bool flag = this.objWorldSpacePoints.Count < 200;
    Camera component2 = this.GetComponent<Camera>();
    for (int index = 0; index < this.objWorldSpacePoints.Count; ++index)
    {
      this.objWorldSpacePoints[index] = objToWorldTransform.TransformPoint(this.objWorldSpacePoints[index]);
      if (flag)
        this.rayDirectionsWorkerPrelim.Add(this.objWorldSpacePoints[index] - this.transform.position);
    }
    this.Info.ObjectVertexCount = this.rayDirectionsWorkerPrelim.Count;
    if (this.UseSphericalBounds)
      this._PopulateRaysSpherical(component2, this.objWorldSpacePoints, minDistance, true);
    else
      this._PopulateRaysScreenspace(component2, this.objWorldSpacePoints, true);
    this.swCalcBounds.Stop();
    this.Info.CalcBoundsMS = (float) (this.swCalcBounds.Elapsed.TotalSeconds * 1000.0);
    this.Info.ScreenSpaceVertexCount = this.rayDirectionsWorkerPrelim.Count - this.Info.ObjectVertexCount;
    if (GameManager.GM.debugModeOn)
      GameManager.GM.MyLog("Rays shot: " + (object) this.rayDirectionsWorkerPrelim.Count);
    int num1 = 0;
    float resizeDistance = float.MaxValue;
    float num2 = float.MaxValue;
    crossedPortal = (Portal) null;
    float furtherestDistance = 0.0f;
    float minGrabDistance = this._GetMinGrabDistance();
    this.rayCastCommands.Clear();
    Vector3 position = this.transform.position;
    int count = this.rayDirectionsWorkerPrelim.Count;
    Physics.SyncTransforms();
    for (int index = 0; index < count; ++index)
      this.rayCastCommands.Add(new RaycastCommand(position, this.rayDirectionsWorkerPrelim[index], float.PositiveInfinity, this._layerMaskGrabbed));
    JobHandle jobHandle = RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1);
    jobHandle.Complete();
    this.rayCastCommands.Clear();
    RaycastHit rayCastResult1;
    for (int index = 0; index < count; ++index)
    {
      rayCastResult1 = this.rayCastResults[index];
      if ((UnityEngine.Object) rayCastResult1.collider != (UnityEngine.Object) null)
        this.rayCastCommands.Add(new RaycastCommand(position, this.rayDirectionsWorkerPrelim[index], float.PositiveInfinity, this._layerMaskIgnoreGrabbed));
    }
    int length1 = this.rayCastCommands.Length;
    jobHandle = RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1);
    jobHandle.Complete();
    this.rayCastCommands.Clear();
    this.rayCastCommandsPortal.Clear();
    this.forwardHitDistances.Clear();
    for (int index1 = 0; index1 < length1; ++index1)
    {
      RaycastHit rayCastResult2 = this.rayCastResults[index1];
      if ((UnityEngine.Object) rayCastResult2.collider != (UnityEngine.Object) null)
      {
        Portal hitPortal = this._MaybeGetHitPortal(ref rayCastResult2);
        if ((bool) (UnityEngine.Object) hitPortal)
        {
          if (!this.portalsWeHit.Contains(hitPortal))
          {
            PortalHelper.GetConversionMatrix(hitPortal, out this.portalMatrices[this.portalsWeHit.Count]);
            this.portalsWeHit.Add(hitPortal);
          }
          int index2 = this.portalsWeHit.IndexOf(hitPortal);
          Ray ray = new Ray(this.portalMatrices[index2].MultiplyPoint(rayCastResult2.point), this.portalMatrices[index2].MultiplyVector(rayCastResult2.point - position));
          ray.origin += Vector3.Normalize(ray.direction) * 0.1f;
          this.rayCastCommandsPortal.Add(new RaycastCommand(ray.origin, ray.direction, float.PositiveInfinity, this._layerMaskIgnoreGrabbed));
          this.portalCommandToOriginalIndex.Add(new ResizeScript.PortalAndIndex()
          {
            PortalIndex = index2,
            BackRayIndex = this.rayCastCommands.Length
          });
        }
        Vector3 point = rayCastResult2.point;
        Vector3 direction = this.transform.position - point;
        this.rayCastCommands.Add(new RaycastCommand(point - direction * 0.0f, direction, float.PositiveInfinity, this._layerMaskGrabbed));
        this.forwardHitDistances.Add(rayCastResult2.distance);
      }
    }
    int length2 = this.rayCastCommandsPortal.Length;
    int length3 = this.rayCastCommands.Length;
    if (length2 > 0)
    {
      JobHandle job0 = RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommandsPortal, this.rayCastResultsPortal, 1);
      jobHandle = RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1);
      JobHandle job1 = jobHandle;
      JobHandle.CombineDependencies(job0, job1).Complete();
    }
    else
    {
      jobHandle = RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1);
      jobHandle.Complete();
    }
    int index3 = 0;
    int num3 = 0;
    for (int index1 = 0; index1 < length3; ++index1)
    {
      int index2 = -1;
      if (index3 < length2 && this.portalCommandToOriginalIndex[index3].BackRayIndex == index1)
      {
        index2 = index3;
        ++index3;
      }
      RaycastHit rayCastResult2 = this.rayCastResults[index1];
      if ((bool) (UnityEngine.Object) rayCastResult2.collider)
      {
        Portal portal = (Portal) null;
        float num4 = 0.0f;
        if (index2 != -1)
        {
          rayCastResult1 = this.rayCastResultsPortal[index2];
          if ((bool) (UnityEngine.Object) rayCastResult1.collider)
          {
            rayCastResult1 = this.rayCastResultsPortal[index2];
            num4 = (float) (0.100000001490116 + (double) rayCastResult1.distance);
            portal = this.portalsWeHit[this.portalCommandToOriginalIndex[index2].PortalIndex];
            ++num1;
          }
        }
        ++num3;
        float forwardHitDistance = this.forwardHitDistances[index1];
        float num5 = rayCastResult2.distance - 0.0f;
        float num6 = (float) ((double) minGrabDistance * ((double) forwardHitDistance + (double) num4) / ((double) forwardHitDistance - (double) num5));
        float num7 = (float) ((double) minGrabDistance * (double) forwardHitDistance / ((double) forwardHitDistance - (double) num5));
        if ((bool) (UnityEngine.Object) portal && portal.AllowObjectsOnBoundary)
          num7 = num6;
        if ((double) num6 < (double) resizeDistance && (double) num6 > 0.0)
        {
          resizeDistance = num6;
          crossedPortal = portal;
        }
        if ((double) num7 < (double) num2 && (double) num7 > 0.0)
          num2 = num7;
      }
    }
    if ((bool) (UnityEngine.Object) crossedPortal && num1 < num3 || !(bool) (UnityEngine.Object) crossedPortal)
    {
      crossedPortal = (Portal) null;
      if ((double) num2 != double.PositiveInfinity && (double) num2 < 3.40282346638529E+38)
        resizeDistance = num2;
    }
    this.swEnsureNoPlayerCollide.Reset();
    this.swEnsureNoPlayerCollide.Start();
    if (!(bool) (UnityEngine.Object) crossedPortal)
      reductionRatio = !this.UseOverlapForAvoidingPlayerCollision ? this._EnsureObjectDoesntColliderWithPlayer(obj, this.objPoints, resizeDistance, furtherestDistance) : this._EnsureObjectDoesntColliderWithPlayerByTestingOverlap(obj, resizeDistance);
    this.swEnsureNoPlayerCollide.Stop();
    this.Info.PlayerNoCollideMS = (float) (this.swEnsureNoPlayerCollide.Elapsed.TotalSeconds * 1000.0);
    this.Info.ReductionRatio = reductionRatio;
    this.swTotal.Stop();
    this.Info.TotalMS = (float) (this.swTotal.Elapsed.TotalSeconds * 1000.0);
    this.Info.TotalMSInclusive = this.Info.TotalMS;
    this.Info.HitGrabMS = (float) (this.swHitGrab.Elapsed.TotalSeconds * 1000.0);
    return resizeDistance;
  }

  private void getResizeDistanceWorker_Parallel2(GameObject obj, float minDistanceScale)
  {
    if (!this.rayCastResults.IsCreated)
    {
      this.rayCastResults = new NativeArray<RaycastHit>(1881, Allocator.Persistent);
      this.rayCastCommands = new NativeList<RaycastCommand>(1881, Allocator.Persistent);
      this.rayCastResultsPortal = new NativeArray<RaycastHit>(1881, Allocator.Persistent);
      this.rayCastCommandsPortal = new NativeList<RaycastCommand>(1881, Allocator.Persistent);
    }
    if (!this.filteredRayIndices.IsCreated)
      this.filteredRayIndices = new NativeList<int>(1881, Allocator.Persistent);
    this.swHitGrab.Reset();
    this.swTotal.Reset();
    this.swTotal.Start();
    this.swInclusive.Reset();
    this.swInclusive.Start();
    this.Info.DidntHitBack = 0;
    this.Info.DidntHitWall = 0;
    this.Info.DidntHitGrabbed = 0;
    this.Info.DidntHitGrabbedObjVert = 0;
    Vector3 minDistance = this.ResetObjectToMinDistance(obj, minDistanceScale);
    this.rayDirectionsWorkerPrelim.Clear();
    this.rayDirectionsWorkerFinal.Clear();
    this.portalCommandToOriginalIndex.Clear();
    this.portalsWeHit.Clear();
    this.filteredRayIndices.Clear();
    Mesh mesh = this.GetMesh(obj);
    this.swCalcBounds.Reset();
    this.swCalcBounds.Start();
    this.objWorldSpacePoints.Clear();
    this.objPoints.Clear();
    ReducedMeshForRayCasting component1 = obj.GetComponent<ReducedMeshForRayCasting>();
    Transform objToWorldTransform = obj.transform;
    if ((bool) (UnityEngine.Object) component1)
      component1.GetObjectSpaceVertices(this.objPoints, out objToWorldTransform);
    else
      mesh.GetVertices(this.objPoints);
    this.objWorldSpacePoints.AddRange((IEnumerable<Vector3>) this.objPoints);
    bool flag = this.objWorldSpacePoints.Count < 200;
    Camera component2 = this.GetComponent<Camera>();
    for (int index = 0; index < this.objWorldSpacePoints.Count; ++index)
    {
      this.objWorldSpacePoints[index] = objToWorldTransform.TransformPoint(this.objWorldSpacePoints[index]);
      if (flag)
        this.rayDirectionsWorkerPrelim.Add(this.objWorldSpacePoints[index] - this.transform.position);
    }
    this.Info.ObjectVertexCount = this.rayDirectionsWorkerPrelim.Count;
    if (this.UseSphericalBounds)
      this._PopulateRaysSpherical(component2, this.objWorldSpacePoints, minDistance, true);
    else
      this._PopulateRaysScreenspace(component2, this.objWorldSpacePoints, true);
    this.swCalcBounds.Stop();
    this.Info.CalcBoundsMS = (float) (this.swCalcBounds.Elapsed.TotalSeconds * 1000.0);
    this.Info.ScreenSpaceVertexCount = this.rayDirectionsWorkerPrelim.Count - this.Info.ObjectVertexCount;
    if (GameManager.GM.debugModeOn)
      GameManager.GM.MyLog("Rays shot: " + (object) this.rayDirectionsWorkerPrelim.Count);
    this.rayCastCommands.Clear();
    Vector3 position = this.transform.position;
    int count = this.rayDirectionsWorkerPrelim.Count;
    Physics.SyncTransforms();
    for (int index = 0; index < count; ++index)
      this.rayCastCommands.Add(new RaycastCommand(position, this.rayDirectionsWorkerPrelim[index], float.PositiveInfinity, this._layerMaskGrabbed));
    new ResizeScript.FilterRayHitsJob()
    {
      PrelimResults = this.rayCastResults
    }.ScheduleAppend<ResizeScript.FilterRayHitsJob>(this.filteredRayIndices, this.rayCastCommands.Length, 1, RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1)).Complete();
    int length = this.filteredRayIndices.Length;
    NativeArray<RaycastCommand> commands = new NativeArray<RaycastCommand>(length, Allocator.TempJob);
    JobHandle dependsOn = new ResizeScript.ConstructMainRaysJob()
    {
      LayerMask = this._layerMaskIgnoreGrabbed,
      Origin = position,
      FilteredIndices = ((NativeArray<int>) this.filteredRayIndices),
      UnfilteredResults = this.rayCastResults,
      MainRays = commands
    }.Schedule<ResizeScript.ConstructMainRaysJob>(length, 1);
    RaycastCommand.ScheduleBatch(commands, this.rayCastResults, 1, dependsOn).Complete();
    this.rayCastCommands.Clear();
    this.rayCastCommandsPortal.Clear();
    this.forwardHitDistances.Clear();
    for (int index1 = 0; index1 < length; ++index1)
    {
      RaycastHit rayCastResult = this.rayCastResults[index1];
      if ((UnityEngine.Object) rayCastResult.collider != (UnityEngine.Object) null)
      {
        Portal hitPortal = this._MaybeGetHitPortal(ref rayCastResult);
        if ((bool) (UnityEngine.Object) hitPortal)
        {
          if (!this.portalsWeHit.Contains(hitPortal))
          {
            PortalHelper.GetConversionMatrix(hitPortal, out this.portalMatrices[this.portalsWeHit.Count]);
            this.portalsWeHit.Add(hitPortal);
          }
          int index2 = this.portalsWeHit.IndexOf(hitPortal);
          Ray ray = new Ray(this.portalMatrices[index2].MultiplyPoint(rayCastResult.point), this.portalMatrices[index2].MultiplyVector(rayCastResult.point - position));
          ray.origin += Vector3.Normalize(ray.direction) * 0.1f;
          this.rayCastCommandsPortal.Add(new RaycastCommand(ray.origin, ray.direction, float.PositiveInfinity, this._layerMaskIgnoreGrabbed));
          this.portalCommandToOriginalIndex.Add(new ResizeScript.PortalAndIndex()
          {
            PortalIndex = index2,
            BackRayIndex = this.rayCastCommands.Length
          });
        }
        Vector3 point = rayCastResult.point;
        Vector3 direction = this.transform.position - point;
        this.rayCastCommands.Add(new RaycastCommand(point - direction * 0.0f, direction, float.PositiveInfinity, this._layerMaskGrabbed));
        this.forwardHitDistances.Add(rayCastResult.distance);
      }
    }
    commands.Dispose();
    this.portalRayCount = this.rayCastCommandsPortal.Length;
    this.returnRayCount = this.rayCastCommands.Length;
    this.handleToWaitFor = this.portalRayCount <= 0 ? RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1) : JobHandle.CombineDependencies(RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommandsPortal, this.rayCastResultsPortal, 1), RaycastCommand.ScheduleBatch((NativeArray<RaycastCommand>) this.rayCastCommands, this.rayCastResults, 1));
    this.swInclusive.Stop();
  }

  private float FinishOffTheThing(
    GameObject obj,
    out Portal crossedPortal,
    out float reductionRatio)
  {
    this.swInclusive.Start();
    this.handleToWaitFor.Complete();
    int num1 = 0;
    float minGrabDistance = this._GetMinGrabDistance();
    float resizeDistance = float.MaxValue;
    float num2 = float.MaxValue;
    crossedPortal = (Portal) null;
    reductionRatio = 1f;
    float furtherestDistance = 0.0f;
    int index1 = 0;
    int num3 = 0;
    for (int index2 = 0; index2 < this.returnRayCount; ++index2)
    {
      int index3 = -1;
      if (index1 < this.portalRayCount && this.portalCommandToOriginalIndex[index1].BackRayIndex == index2)
      {
        index3 = index1;
        ++index1;
      }
      RaycastHit rayCastResult = this.rayCastResults[index2];
      if ((bool) (UnityEngine.Object) rayCastResult.collider)
      {
        Portal portal = (Portal) null;
        float num4 = 0.0f;
        if (index3 != -1)
        {
          RaycastHit raycastHit = this.rayCastResultsPortal[index3];
          if ((bool) (UnityEngine.Object) raycastHit.collider)
          {
            raycastHit = this.rayCastResultsPortal[index3];
            num4 = (float) (0.100000001490116 + (double) raycastHit.distance);
            portal = this.portalsWeHit[this.portalCommandToOriginalIndex[index3].PortalIndex];
            ++num1;
          }
        }
        ++num3;
        float forwardHitDistance = this.forwardHitDistances[index2];
        float num5 = rayCastResult.distance - 0.0f;
        float num6 = (float) ((double) minGrabDistance * ((double) forwardHitDistance + (double) num4) / ((double) forwardHitDistance - (double) num5));
        float num7 = (float) ((double) minGrabDistance * (double) forwardHitDistance / ((double) forwardHitDistance - (double) num5));
        if ((bool) (UnityEngine.Object) portal && portal.AllowObjectsOnBoundary)
          num7 = num6;
        if ((double) num6 < (double) resizeDistance && (double) num6 > 0.0)
        {
          resizeDistance = num6;
          crossedPortal = portal;
        }
        if ((double) num7 < (double) num2 && (double) num7 > 0.0)
          num2 = num7;
      }
    }
    if ((bool) (UnityEngine.Object) crossedPortal && num1 < num3 || !(bool) (UnityEngine.Object) crossedPortal)
    {
      crossedPortal = (Portal) null;
      if ((double) num2 != double.PositiveInfinity && (double) num2 < 3.40282346638529E+38)
        resizeDistance = num2;
    }
    this.swEnsureNoPlayerCollide.Reset();
    this.swEnsureNoPlayerCollide.Start();
    if (!(bool) (UnityEngine.Object) crossedPortal)
      reductionRatio = !this.UseOverlapForAvoidingPlayerCollision ? this._EnsureObjectDoesntColliderWithPlayer(obj, this.objPoints, resizeDistance, furtherestDistance) : this._EnsureObjectDoesntColliderWithPlayerByTestingOverlap(obj, resizeDistance);
    this.swEnsureNoPlayerCollide.Stop();
    this.Info.PlayerNoCollideMS = (float) (this.swEnsureNoPlayerCollide.Elapsed.TotalSeconds * 1000.0);
    this.Info.ReductionRatio = reductionRatio;
    this.swTotal.Stop();
    this.swInclusive.Stop();
    this.Info.TotalMS = (float) (this.swTotal.Elapsed.TotalSeconds * 1000.0);
    ref ResizeInfo local1 = ref this.Info;
    TimeSpan elapsed = this.swInclusive.Elapsed;
    double num8 = elapsed.TotalSeconds * 1000.0;
    local1.TotalMSInclusive = (float) num8;
    ref ResizeInfo local2 = ref this.Info;
    elapsed = this.swHitGrab.Elapsed;
    double num9 = elapsed.TotalSeconds * 1000.0;
    local2.HitGrabMS = (float) num9;
    return resizeDistance;
  }

  private float getResizeDistanceWorker(
    GameObject obj,
    out Portal crossedPortal,
    out float reductionRatio,
    float minDistanceScale)
  {
    this.swHitGrab.Reset();
    this.swTotal.Reset();
    this.swTotal.Start();
    this.Info.DidntHitBack = 0;
    this.Info.DidntHitWall = 0;
    this.Info.DidntHitGrabbed = 0;
    this.Info.DidntHitGrabbedObjVert = 0;
    reductionRatio = 1f;
    Vector3 minDistance = this.ResetObjectToMinDistance(obj, minDistanceScale);
    this.rayListWorker.Clear();
    Mesh mesh = this.GetMesh(obj);
    this.swCalcBounds.Reset();
    this.swCalcBounds.Start();
    this.objWorldSpacePoints.Clear();
    this.objPoints.Clear();
    ReducedMeshForRayCasting component1 = obj.GetComponent<ReducedMeshForRayCasting>();
    Transform objToWorldTransform = obj.transform;
    if ((bool) (UnityEngine.Object) component1)
      component1.GetObjectSpaceVertices(this.objPoints, out objToWorldTransform);
    else
      mesh.GetVertices(this.objPoints);
    this.objWorldSpacePoints.AddRange((IEnumerable<Vector3>) this.objPoints);
    bool flag = this.objWorldSpacePoints.Count < 200;
    Camera component2 = this.GetComponent<Camera>();
    for (int index = 0; index < this.objWorldSpacePoints.Count; ++index)
    {
      this.objWorldSpacePoints[index] = objToWorldTransform.TransformPoint(this.objWorldSpacePoints[index]);
      if (flag)
        this.rayListWorker.Add(new Ray(this.transform.position, this.objWorldSpacePoints[index] - this.transform.position));
    }
    this.Info.ObjectVertexCount = this.rayListWorker.Count;
    if (this.UseSphericalBounds)
      this._PopulateRaysSpherical(component2, this.objWorldSpacePoints, minDistance, false);
    else
      this._PopulateRaysScreenspace(component2, this.objWorldSpacePoints, false);
    this.swCalcBounds.Stop();
    this.Info.CalcBoundsMS = (float) (this.swCalcBounds.Elapsed.TotalSeconds * 1000.0);
    this.Info.ScreenSpaceVertexCount = this.rayListWorker.Count - this.Info.ObjectVertexCount;
    if (GameManager.GM.debugModeOn)
      GameManager.GM.MyLog("Rays shot: " + (object) this.rayListWorker.Count);
    int num1 = 0;
    int num2 = 0;
    float resizeDistance = float.MaxValue;
    float num3 = float.MaxValue;
    crossedPortal = (Portal) null;
    float maxCastDistance = 0.0f;
    float minGrabDistance = this._GetMinGrabDistance();
    for (int index = 0; index < this.rayListWorker.Count; ++index)
    {
      Ray forwardRay = this.rayListWorker[index];
      float distance;
      float distanceNonPortal;
      Portal crossedPortal1;
      if (this.getCurrentRayResizeDistance(minGrabDistance, forwardRay, out distance, out distanceNonPortal, out crossedPortal1, ref maxCastDistance, index < this.Info.ObjectVertexCount))
      {
        if ((bool) (UnityEngine.Object) crossedPortal1)
          ++num1;
        ++num2;
        if ((bool) (UnityEngine.Object) crossedPortal1 && crossedPortal1.AllowObjectsOnBoundary)
          distanceNonPortal = distance;
        if ((double) distance < (double) resizeDistance && (double) distance > 0.0)
        {
          resizeDistance = distance;
          crossedPortal = crossedPortal1;
        }
        if ((double) distanceNonPortal < (double) num3 && (double) distanceNonPortal > 0.0)
          num3 = distanceNonPortal;
      }
    }
    if ((bool) (UnityEngine.Object) crossedPortal && num1 < num2 || !(bool) (UnityEngine.Object) crossedPortal)
    {
      crossedPortal = (Portal) null;
      if ((double) num3 != double.PositiveInfinity && (double) num3 < 3.40282346638529E+38)
        resizeDistance = num3;
    }
    this.swEnsureNoPlayerCollide.Reset();
    this.swEnsureNoPlayerCollide.Start();
    if (!(bool) (UnityEngine.Object) crossedPortal)
      reductionRatio = !this.UseOverlapForAvoidingPlayerCollision ? this._EnsureObjectDoesntColliderWithPlayer(obj, this.objPoints, resizeDistance, maxCastDistance) : this._EnsureObjectDoesntColliderWithPlayerByTestingOverlap(obj, resizeDistance);
    this.swEnsureNoPlayerCollide.Stop();
    this.Info.PlayerNoCollideMS = (float) (this.swEnsureNoPlayerCollide.Elapsed.TotalSeconds * 1000.0);
    this.Info.ReductionRatio = reductionRatio;
    this.swTotal.Stop();
    this.Info.TotalMS = (float) (this.swTotal.Elapsed.TotalSeconds * 1000.0);
    this.Info.TotalMSInclusive = this.Info.TotalMS;
    this.Info.HitGrabMS = (float) (this.swHitGrab.Elapsed.TotalSeconds * 1000.0);
    return resizeDistance;
  }

  private Portal _MaybeGetHitPortal(ref RaycastHit hit)
  {
    Portal portal = (Portal) null;
    if (hit.collider.gameObject.layer == MoSTLayer.PortalHitTest)
    {
      PortalHitTestLink component = hit.collider.GetComponent<PortalHitTestLink>();
      if ((bool) (UnityEngine.Object) component && (bool) (UnityEngine.Object) component.Portal && component.Portal.CanProjectThroughMe)
        portal = component.Portal;
    }
    return portal;
  }

  private bool getCurrentRayResizeDistance(
    float minGrabDistance,
    Ray forwardRay,
    out float distance,
    out float distanceNonPortal,
    out Portal crossedPortal,
    ref float maxCastDistance,
    bool isObjVert)
  {
    this.swHitGrab.Start();
    if (Physics.Raycast(this.transform.position, forwardRay.direction, float.PositiveInfinity, this._layerMaskGrabbed))
    {
      this.swHitGrab.Stop();
      RaycastHit hitInfo1;
      if (Physics.Raycast(this.transform.position, forwardRay.direction, out hitInfo1, float.PositiveInfinity, this._layerMaskIgnoreGrabbed))
      {
        maxCastDistance = Mathf.Max(hitInfo1.distance, maxCastDistance);
        if (hitInfo1.collider.CompareTag(ResizeScript.StopProjectionTag))
          this.isRejectProject = true;
        if (this.isEnableDebug)
          UnityEngine.Debug.DrawLine(this.transform.position, hitInfo1.point, Color.blue);
        Vector3 point = hitInfo1.point;
        Vector3 direction = this.transform.position - point;
        float num1 = 0.0f;
        Portal hitPortal = this._MaybeGetHitPortal(ref hitInfo1);
        crossedPortal = (Portal) null;
        if ((bool) (UnityEngine.Object) hitPortal)
        {
          Ray ray = PortalHelper.TransformRay(hitPortal, new Ray(hitInfo1.point, forwardRay.direction));
          ray.origin += Vector3.Normalize(ray.direction) * 0.1f;
          RaycastHit hitInfo2;
          if (Physics.Raycast(ray.origin, ray.direction, out hitInfo2, float.PositiveInfinity, this._layerMaskIgnoreGrabbed))
          {
            crossedPortal = hitPortal;
            num1 = 0.1f + hitInfo2.distance;
          }
          else
          {
            distance = float.PositiveInfinity;
            distanceNonPortal = float.PositiveInfinity;
            return false;
          }
        }
        RaycastHit hitInfo3;
        if (Physics.Raycast(point - direction * 0.0f, direction, out hitInfo3, float.PositiveInfinity, this._layerMaskGrabbed))
        {
          float num2 = hitInfo3.distance - 0.0f;
          distance = (float) ((double) minGrabDistance * ((double) hitInfo1.distance + (double) num1) / ((double) hitInfo1.distance - (double) num2));
          distanceNonPortal = (float) ((double) minGrabDistance * (double) hitInfo1.distance / ((double) hitInfo1.distance - (double) num2));
          return true;
        }
        ++this.Info.DidntHitBack;
        distance = float.PositiveInfinity;
        distanceNonPortal = float.PositiveInfinity;
        return false;
      }
      ++this.Info.DidntHitWall;
      distance = float.PositiveInfinity;
      distanceNonPortal = float.PositiveInfinity;
      crossedPortal = (Portal) null;
      return false;
    }
    this.swHitGrab.Stop();
    ++this.Info.DidntHitGrabbed;
    if (isObjVert)
      ++this.Info.DidntHitGrabbedObjVert;
    distance = -1f;
    distanceNonPortal = float.PositiveInfinity;
    crossedPortal = (Portal) null;
    return false;
  }

  private void setFollowVelocity(Vector3 grabbed_Pos)
  {
    Vector3 vector3 = this.transform.parent.GetComponent<CharacterMotor>().GetVelocity();
    vector3 = vector3.normalized;
    Vector3 vector = (this.grabbedObject.transform.position - this.prevPosition) * 65f;
    float maxLength = 20f;
    Rigidbody component = this.grabbedObject.GetComponent<Rigidbody>();
    if (!(bool) (UnityEngine.Object) component)
      return;
    component.velocity = Vector3.ClampMagnitude(vector, maxLength);
  }

  public void ScaleObject(float scaleFactor) => this.scaleAtMinDistance *= scaleFactor;

  private void SetScaleAtMinDistance(GameObject obj, float initialRatio, Portal crossedPortal)
  {
    float num = 1f;
    if ((bool) (UnityEngine.Object) crossedPortal)
      num = 1f / PortalHelper.CalculateFromToPortalScale(crossedPortal);
    this.scaleAtMinDistance = obj.transform.localScale * initialRatio * num;
    Rigidbody component1 = this.grabbedObject.GetComponent<Rigidbody>();
    this.massAtMinDistance = !(bool) (UnityEngine.Object) component1 ? 0.0f : Mathf.Pow(initialRatio, 3f) * component1.mass;
    this.grabbedMinGrabDistance = this._GetMinGrabDistance();
    DropTriggerScript component2 = obj.GetComponent<DropTriggerScript>();
    if ((double) component2.maximumAllowedMass <= 0.0)
      return;
    this.massAtMinDistance = Mathf.Pow(initialRatio, 3f) * component2.hiddenMassIgnoringMaximum;
  }

  private float _GetLerpProgress()
  {
    float num = (float) (1.0 - (double) this.curLerpingTime / 0.800000011920929);
    return (float) (1.0 - (double) num * (double) num);
  }

  private Vector3 _GetDirectionToObject()
  {
    Vector3 b = this.transform.TransformVector(Vector3.Normalize(this.positionInCameraSpaceOriginalFinal));
    return this.isLerpingToPosition ? Vector3.Slerp(this.transform.TransformVector(Vector3.Normalize(this.positionInCameraSpaceOriginal)), b, this._GetLerpProgress()).normalized : b.normalized;
  }

  private Vector3 ResetObjectToMinDistance(GameObject obj, float minDistanceScale)
  {
    Vector3 directionToObject = this._GetDirectionToObject();
    obj.transform.rotation = this._GetCurrentObjectRotationWorldSpace();
    obj.transform.position = this.transform.position + directionToObject * this._GetMinGrabDistance() * minDistanceScale;
    obj.transform.localScale = this.scaleAtMinDistance;
    obj.GetComponent<DropTriggerScript>().UpdateMassBasedOnScale();
    return directionToObject;
  }

  private void UpdateObjectTransformAndPropertyByDistance(
    GameObject obj,
    float distance,
    Portal crossedPortal,
    float reductionRatio)
  {
    DropTriggerScript component1 = obj.GetComponent<DropTriggerScript>();
    distance *= 0.99f * component1.grabValues.DistanceScaleModifier;
    Vector3 directionToObject = this._GetDirectionToObject();
    if ((bool) (UnityEngine.Object) crossedPortal)
    {
      float num1 = distance;
      Vector3 position = this.transform.position;
      Vector3 direction1 = directionToObject;
      Quaternion rotationWorldSpace = this._GetCurrentObjectRotationWorldSpace();
      if (this.isEnableDebug)
        UnityEngine.Debug.DrawRay(position, direction1 * 3f, Color.magenta);
      Ray ray1 = new Ray(position, direction1);
      float enter;
      if (!crossedPortal.GetPortalPlane().Raycast(ray1, out enter))
        enter = num1;
      if (this.isEnableDebug)
        UnityEngine.Debug.DrawRay(position, ray1.direction * enter, Color.green);
      Vector3 origin1 = ray1.origin + ray1.direction * enter;
      double num2 = 0.0 + (double) enter * (double) PortalHelper.CalculateFromToPortalScale(crossedPortal);
      float num3 = num1 - enter;
      Ray ray2 = PortalHelper.TransformRay(crossedPortal, new Ray(origin1, direction1));
      Vector3 origin2 = ray2.origin;
      Vector3 direction2 = ray2.direction;
      Quaternion quaternion = PortalHelper.TransformRotation(crossedPortal, rotationWorldSpace);
      if (this.isEnableDebug)
        UnityEngine.Debug.DrawRay(origin2, num3 * direction2, Color.green);
      double num4 = (double) num3;
      float num5 = (float) (num2 + num4) / this._GetMinGrabDistance();
      obj.transform.rotation = quaternion;
      obj.transform.position = origin2 + num3 * direction2;
      obj.transform.localScale = this.scaleAtMinDistance * num5;
    }
    else
    {
      float num = distance / this._GetMinGrabDistance();
      obj.transform.rotation = this._GetCurrentObjectRotationWorldSpace();
      obj.transform.position = this.transform.position + distance * directionToObject;
      obj.transform.localScale = this.scaleAtMinDistance * num * reductionRatio;
    }
    component1.UpdateMassBasedOnScale();
    Rigidbody component2 = obj.GetComponent<Rigidbody>();
    if (!(bool) (UnityEngine.Object) component2)
      return;
    component2.position = obj.transform.position;
  }

  public float getGrabDistance() => this._GetMinGrabDistance();

  private void _UpdateGrabSizeStuffWhenGrabbing()
  {
    if ((double) this.grabbedMinGrabDistance == (double) this._GetMinGrabDistance())
      return;
    float num = this._GetMinGrabDistance() / this.grabbedMinGrabDistance;
    this.grabbedMinGrabDistance = this._GetMinGrabDistance();
    this.scaleAtMinDistance *= num;
    this.massAtMinDistance *= num;
  }

  public void setGrabDistance(float f)
  {
  }

  public void TurnPlayerGrabOffNextFrame() => this.notAllowedToGrab = true;

  public void TurnOffGrabDeniedSoundNextFrame() => this.turnOffGrabDeniedSoundNextFrame = true;

  public void ToggleImmediateDropAndNoLerp()
  {
    this.dontLerpObjectsToCenter = !this.dontLerpObjectsToCenter;
    this.immediatelyDropObjects = !this.immediatelyDropObjects;
  }

  public void StartHoldRotateTimer() => this.holdRotateTutorialTimer = 3f;

  public bool GetGrabbedObject_ButtonPromptBool() => !((UnityEngine.Object) this.grabbedObject == (UnityEngine.Object) null) && this.grabbedObject.GetComponent<DropTriggerScript>().showsButtonPromptForConsoles;

  public bool JustDroppedThisFrame() => this.justDroppedThisFrame;

  private bool ShouldUseVerticalHandCursor(GameObject obj)
  {
    Vector3 possibleAxis0;
    Vector3 possibleAxis1;
    Plane facingPlaneOut;
    this.GetPossibleAxes(obj, out possibleAxis0, out possibleAxis1, out facingPlaneOut);
    Vector3 finalAxis = this.GetFinalAxis(facingPlaneOut, obj, possibleAxis0, possibleAxis1);
    float num = Mathf.Abs(Vector3.Dot(finalAxis, this.transform.right));
    return (double) Mathf.Abs(Vector3.Dot(finalAxis, this.transform.up)) < (double) num;
  }

  private void GetPossibleAxes(
    GameObject grabbedObjectIn,
    out Vector3 possibleAxis0,
    out Vector3 possibleAxis1,
    out Plane facingPlaneOut)
  {
    float num1 = Mathf.Abs(Vector3.Dot(this.transform.forward, grabbedObjectIn.transform.right));
    float num2 = Mathf.Abs(Vector3.Dot(this.transform.forward, grabbedObjectIn.transform.up));
    float num3 = Mathf.Abs(Vector3.Dot(this.transform.forward, grabbedObjectIn.transform.forward));
    if ((double) num1 > (double) num2)
    {
      possibleAxis0 = grabbedObjectIn.transform.up;
      if ((double) num1 > (double) num3)
      {
        facingPlaneOut = new Plane(grabbedObjectIn.transform.right, grabbedObjectIn.transform.position);
        possibleAxis1 = grabbedObjectIn.transform.forward;
      }
      else
      {
        facingPlaneOut = new Plane(grabbedObjectIn.transform.forward, grabbedObjectIn.transform.position);
        possibleAxis1 = grabbedObjectIn.transform.right;
      }
    }
    else
    {
      possibleAxis0 = grabbedObjectIn.transform.right;
      if ((double) num2 > (double) num3)
      {
        facingPlaneOut = new Plane(grabbedObjectIn.transform.up, grabbedObjectIn.transform.position);
        possibleAxis1 = grabbedObjectIn.transform.forward;
      }
      else
      {
        facingPlaneOut = new Plane(grabbedObjectIn.transform.forward, grabbedObjectIn.transform.position);
        possibleAxis1 = grabbedObjectIn.transform.up;
      }
    }
  }

  private Vector3 GetFinalAxis(
    Plane facingPlaneIn,
    GameObject grabbedObjectIn,
    Vector3 possibleAxis0,
    Vector3 possibleAxis1)
  {
    Vector3 vector3 = Vector3.right;
    Ray ray = new Ray(this.transform.position, this.transform.forward);
    float enter;
    if (facingPlaneIn.Raycast(ray, out enter))
    {
      Vector3 normalized = (ray.GetPoint(enter) - grabbedObjectIn.transform.position).normalized;
      vector3 = (double) Mathf.Abs(Vector3.Dot(possibleAxis0, normalized)) > (double) Mathf.Abs(Vector3.Dot(possibleAxis1, normalized)) ? possibleAxis0 : possibleAxis1;
    }
    return vector3;
  }

  private void StartScrolling(bool counterZFighting)
  {
    this.isScrolling = true;
    Vector3 possibleAxis0;
    Vector3 possibleAxis1;
    this.GetPossibleAxes(this.grabbedObject, out possibleAxis0, out possibleAxis1, out this.facingPlane);
    this.scrollWorldAxis = this.GetFinalAxis(this.facingPlane, this.grabbedObject, possibleAxis0, possibleAxis1);
    Rigidbody component = this.grabbedObject.GetComponent<Rigidbody>();
    if ((bool) (UnityEngine.Object) component)
    {
      this.wasKinematic = component.isKinematic;
      component.isKinematic = true;
    }
    if (counterZFighting)
      this.grabbedObject.transform.position += this.facingPlane.normal * (1f / 1000f);
    this.originalGrabbObjectPosition = this.grabbedObject.transform.position;
    this.mouseOffset = this.GetPointOnScrollAxis().Value - this.originalGrabbObjectPosition;
  }

  private void EndScrolling()
  {
    Rigidbody component = this.grabbedObject.GetComponent<Rigidbody>();
    if ((bool) (UnityEngine.Object) component)
      component.isKinematic = this.wasKinematic;
    this.isScrolling = false;
    this._InvokeOnDroppedEvents(this.grabbedObject.GetComponent<DropTriggerScript>());
  }

  private Vector3 GetPointOnLine(Vector3 p, Vector3 a, Vector3 b) => a + Vector3.Project(p - a, b - a);

  private Vector3? GetPointOnScrollAxis()
  {
    Ray ray = new Ray(this.transform.position, this.transform.forward);
    float enter;
    return this.facingPlane.Raycast(ray, out enter) ? new Vector3?(this.GetPointOnLine(ray.GetPoint(enter), this.originalGrabbObjectPosition, this.originalGrabbObjectPosition + this.scrollWorldAxis)) : new Vector3?();
  }

  private void UpdateScrollThing()
  {
    if (!this.isScrolling)
      return;
    Vector3? pointOnScrollAxis = this.GetPointOnScrollAxis();
    if (!pointOnScrollAxis.HasValue)
      return;
    this.grabbedObject.transform.position = pointOnScrollAxis.Value - this.mouseOffset;
  }

  public void OnOwnershipRequest(PhotonView targetView, Photon.Realtime.Player requestingPlayer)
  {
  }

  public void OnOwnershipTransfered(PhotonView targetView, Photon.Realtime.Player previousOwner)
  {
    targetView.GetComponent<DropTriggerScript>()?.Photon_OnOwnershipTransfered(previousOwner);
    FollowMouseThroughForces component = targetView.GetComponent<FollowMouseThroughForces>();
    if (!(bool) (UnityEngine.Object) component || targetView.IsMine)
      return;
    component.SetOnOff(false);
  }

  public void OnOwnershipTransferFailed(PhotonView targetView, Photon.Realtime.Player senderOfFailedRequest) => targetView.GetComponent<DropTriggerScript>()?.Photon_OnOwnershipTransferFailed(senderOfFailedRequest);

  private struct PortalAndIndex
  {
    public int PortalIndex;
    public int BackRayIndex;
  }

  [BurstCompile]
  private struct FilterRayHitsJob : IJobParallelForFilter
  {
    [ReadOnly]
    public NativeArray<RaycastHit> PrelimResults;

    public bool Execute(int index) => this.PrelimResults[index].point != Vector3.zero;
  }

  [BurstCompile]
  private struct ConstructMainRaysJob : IJobParallelFor
  {
    [ReadOnly]
    public int LayerMask;
    [ReadOnly]
    public Vector3 Origin;
    [ReadOnly]
    public NativeArray<int> FilteredIndices;
    [ReadOnly]
    public NativeArray<RaycastHit> UnfilteredResults;
    [WriteOnly]
    public NativeArray<RaycastCommand> MainRays;

    public void Execute(int i)
    {
      int filteredIndex = this.FilteredIndices[i];
      this.MainRays[i] = new RaycastCommand(this.Origin, this.UnfilteredResults[filteredIndex].point - this.Origin, float.PositiveInfinity, this.LayerMask);
    }
  }
}

SaveAndCheckpointManager

Commands mentioned: ao

using Photon.Pun;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SaveAndCheckpointManager : MonoBehaviour
{
  private const string SaveFolderName = "Clouds";
  private const string SaveGameFilename = "Avocado";
  private const string UnlockedLevelsFilename = "ExitSignPerson";
  private const string PlayerActionTrackingFilename = "DrPierceARealDr";
  private const string AchievementTrackingFilename = "SaturdayBeans";
  private const string ChallengeModeFilename = "RysanShipping";
  private const string MiniChallengeModeFilename = "MiniRysanShipping";
  private const string MultiplayerSaveDataFilename = "LoagieSonic";
  public bool startTestTimer;
  public float testTimer;
  public float savingIconTimerBase;
  public float savingIconTimer;
  public AchievementTracker AchievementTracker;
  public PlayerActionTracker PlayerActionTracker;
  public AchievementDefinition WinGameAchievement;
  public AchievementDefinition WinGame60Achievement;
  public AchievementDefinition WinGame30Achievement;
  public AchievementDefinition BiggestFanAchievement;
  public bool showSaveIconWhileSaving = true;
  public double elapsedTimeSinceStart;
  private bool isCountingPlayTimeOverall;
  private bool isCountingPlayTimeThisScene;
  [HideInInspector]
  public float TimeSinceLastCheckpoint;
  [HideInInspector]
  public bool HitCheckpointThisLevel;
  [HideInInspector]
  public GameObject MyPauseMenu;
  [HideInInspector]
  public bool freezeSpeedRunTimer;
  private string saveFolder;
  public LevelInfo LevelInfo;
  private LevelUnlockState LevelUnlockStatus = new LevelUnlockState(-1);
  private PlayerActionSaveData playerActionSaveData = new PlayerActionSaveData();
  private AchievementSaveData achievementSaveData = new AchievementSaveData();
  private ChallengeModeSaveData challengeModeSaveData = new ChallengeModeSaveData();
  private MiniChallengeModeSaveData miniChallengeModeSaveData = new MiniChallengeModeSaveData();
  private MultiplayerSaveData multiplayerSaveData = new MultiplayerSaveData();
  private readonly KeystrokeTracker tracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[2]{ KeyCode.A, KeyCode.O }
  };
  private List<SaveAndCheckpointManager.RoomCheckpointSyncers> checkpointSyncerTracker = new List<SaveAndCheckpointManager.RoomCheckpointSyncers>();
  private SaveGameState? lastSaveGameState;
  private string resetMiniChallenge;
  private List<string> unlockedLevels = new List<string>();
  public static int XORKey = 129;
  private int[] realLevelsBuildsIndices;
  [NonSerialized]
  public PlayerActionChangedEvent PlayerActionChanged;

  public void StartPlayTimeTimer()
  {
    this.isCountingPlayTimeOverall = true;
    this.elapsedTimeSinceStart = 0.0;
  }

  public void StopPlayTimeTimer() => this.isCountingPlayTimeOverall = false;

  public void CalculatePlayTime()
  {
    if (this.isCountingPlayTimeOverall && this.isCountingPlayTimeThisScene)
    {
      if (this.elapsedTimeSinceStart < 3600.0)
        this.OnGrantAchievement(this.WinGame60Achievement);
      if (this.elapsedTimeSinceStart < 1800.0)
        this.OnGrantAchievement(this.WinGame30Achievement);
    }
    this.StopPlayTimeTimer();
  }

  private string GetSaveFolder()
  {
    if (this.saveFolder == null)
    {
      this.saveFolder = Path.Combine(Application.persistentDataPath, "Clouds");
      try
      {
        Directory.CreateDirectory(this.saveFolder);
      }
      catch (Exception ex)
      {
      }
    }
    return this.saveFolder;
  }

  private void OnEnable() => SceneManager.sceneLoaded += new UnityAction<Scene, LoadSceneMode>(this.OnSceneLoaded);

  private void OnDisable() => SceneManager.sceneLoaded -= new UnityAction<Scene, LoadSceneMode>(this.OnSceneLoaded);

  private void CheckWinGame()
  {
    if (!this.playerActionSaveData.HasCompletedGame)
      return;
    this.OnGrantAchievement(this.WinGameAchievement);
  }

  private void _ReadInitialPlayerSaveData()
  {
    this._ReadLevelUnlocked();
    this._LoadPlayerActions();
    this._LoadAchievements();
    this._LoadChallengeModeStats();
    this._LoadMiniChallengeModeStats();
    this._LoadMultiplayerSaveData();
  }

  private void Awake()
  {
    if (!Debug.isDebugBuild)
      return;
    HashSet<string> stringSet = new HashSet<string>();
    foreach (CheckPoint checkPoint in UnityEngine.Object.FindObjectsOfType<CheckPoint>())
    {
      stringSet.Contains(checkPoint.GetName());
      stringSet.Add(checkPoint.GetName());
    }
  }

  private void Start()
  {
    this.achievementSaveData.LoadSteamworksOnStart();
    this.MyPauseMenu = GameObject.Find("UI_PAUSE_MENU");
  }

  private void _ReadLevelUnlocked()
  {
    if (!File.Exists(Path.Combine(this.GetSaveFolder(), "ExitSignPerson")))
      return;
    this.LevelUnlockStatus.Load(new BinaryReader((Stream) this._ReadStreamFromFile("ExitSignPerson")));
    int levelIndex = this.LevelInfo.GetLevelIndex(this.LevelUnlockStatus.UnlockLevelName);
    if (levelIndex <= this.LevelUnlockStatus.MaxUnlockedLevel)
      return;
    this.LevelUnlockStatus.MaxUnlockedLevel = levelIndex;
  }

  private void _SetLevelUnlocked()
  {
    string currentSceneSaveName = this.LevelInfo.GetCurrentSceneSaveName();
    if (currentSceneSaveName.Length <= 0)
      return;
    int levelIndex = this.LevelInfo.GetLevelIndex(currentSceneSaveName);
    if (levelIndex <= this.LevelUnlockStatus.MaxUnlockedLevel)
      return;
    this.LevelUnlockStatus.MaxUnlockedLevel = levelIndex;
    this.LevelUnlockStatus.UnlockLevelName = currentSceneSaveName;
    MemoryStream stream = new MemoryStream();
    this.LevelUnlockStatus.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "ExitSignPerson");
  }

  public bool ShouldShowSpeedRunTimer() => this.IsInSpeedRun() || this.freezeSpeedRunTimer;

  public bool IsInSpeedRun() => this.isCountingPlayTimeOverall && this.isCountingPlayTimeThisScene && (!GameManager.GM.GetComponent<MiniChallengeMode>().MiniChallengeModeEnabled && !GameManager.GM.GetComponent<CommentaryMode>().CommentaryModeEnabled) && !GameManager.GM.GetComponent<MultiplayerMode>().MultiplayerEnabled;

  private void Update()
  {
    if (this.isCountingPlayTimeOverall && this.isCountingPlayTimeThisScene)
      this.elapsedTimeSinceStart += (double) Time.deltaTime;
    if ((double) this.savingIconTimer > 0.0)
      this.savingIconTimer -= Time.deltaTime;
    else if ((double) this.savingIconTimer <= 0.0 && (double) this.savingIconTimer > -100.0)
    {
      if ((UnityEngine.Object) GameObject.Find("UI_PAUSE_MENU") != (UnityEngine.Object) null)
        GameObject.Find("UI_PAUSE_MENU").transform.Find("Canvas").gameObject.transform.Find("SavingIcon").gameObject.GetComponent<Image>().enabled = false;
      this.savingIconTimer = -1000f;
    }
    if (GameManager.GM.enableDebugFunctions && this.tracker.Check())
      AmbientOcclusion.ModeOverride = AmbientOcclusion.ModeOverride != AmbientOcclusionMode.ScalableAmbientObscurance ? AmbientOcclusionMode.ScalableAmbientObscurance : AmbientOcclusionMode.MultiScaleVolumetricObscurance;
    this.TimeSinceLastCheckpoint += Time.deltaTime;
  }

  private void _GrabPlayerTransform(ref SaveGameState state)
  {
    if ((UnityEngine.Object) GameManager.GM.player == (UnityEngine.Object) null)
      return;
    state.PlayerPosition = GameManager.GM.player.transform.position;
    state.PlayerRotation = GameManager.GM.player.transform.rotation;
    state.PlayerScale = GameManager.GM.player.transform.localScale;
    this._GrabPlayerMovementValues(ref state);
  }

  private void _GrabPlayerMovementValues(ref SaveGameState state) => GameManager.GM.player.GetComponent<PlayerResizer>().Poke();

  private void _SaveGame(CheckPoint checkpoint)
  {
    MemoryStream stream = new MemoryStream();
    this._SaveGameHelper(new BinaryWriter((Stream) stream), checkpoint);
    stream.Seek(0L, SeekOrigin.Begin);
    if (!GameManager.GM.GetComponent<MultiplayerMode>().MultiplayerEnabled && !GameManager.GM.GetComponent<ChallengeMode>().ChallengeModeEnabled && (!GameManager.GM.GetComponent<CommentaryMode>().CommentaryModeEnabled && !GameManager.GM.GetComponent<MiniChallengeMode>().MiniChallengeModeEnabled))
      this._SaveStreamToFile(stream, "Avocado");
    this.TimeSinceLastCheckpoint = 0.0f;
    this.HitCheckpointThisLevel = true;
    if (!((UnityEngine.Object) this.MyPauseMenu != (UnityEngine.Object) null))
      return;
    this.MyPauseMenu.transform.Find("Canvas").gameObject.transform.Find("Pause Menu").gameObject.GetComponent<PauseMenu>().SetTimeSinceLastCheckpoint();
  }

  public void TriggerSaveIcon()
  {
    GameObject.Find("UI_PAUSE_MENU").transform.Find("Canvas").gameObject.transform.Find("SavingIcon").gameObject.GetComponent<Image>().enabled = true;
    this.savingIconTimer = this.savingIconTimerBase;
  }

  private void _SaveGameHelper(BinaryWriter writer, CheckPoint checkpoint)
  {
    SaveGameState state = new SaveGameState();
    state.LevelName = this.LevelInfo.GetCurrentSceneSaveName();
    state.CheckpointName = (bool) (UnityEngine.Object) checkpoint ? checkpoint.GetName() : string.Empty;
    this._GrabPlayerTransform(ref state);
    state.Save(writer);
    this.lastSaveGameState = new SaveGameState?(state);
    if (!this.showSaveIconWhileSaving || GameManager.GM.GetComponent<ChallengeMode>().ChallengeModeEnabled || (GameManager.GM.GetComponent<CommentaryMode>().CommentaryModeEnabled || GameManager.GM.GetComponent<MiniChallengeMode>().MiniChallengeModeEnabled) || GameManager.GM.GetComponent<MultiplayerMode>().MultiplayerEnabled)
      return;
    this.TriggerSaveIcon();
  }

  private void _RestoreSaveGameState(SaveGameState loadedGame)
  {
    if (PhotonNetwork.IsConnected)
      return;
    string currentSceneSaveName = this.LevelInfo.GetCurrentSceneSaveName();
    if (loadedGame.LevelName != currentSceneSaveName)
      return;
    CheckPoint checkPoint1 = (CheckPoint) null;
    if (loadedGame.CheckpointName != null)
    {
      foreach (CheckPoint checkPoint2 in UnityEngine.Object.FindObjectsOfType<CheckPoint>())
      {
        if (checkPoint2.GetName() == loadedGame.CheckpointName)
        {
          checkPoint1 = checkPoint2;
          break;
        }
      }
      if (!(bool) (UnityEngine.Object) checkPoint1)
      {
        int length = loadedGame.CheckpointName.Length;
      }
    }
    GameObject player = GameManager.GM.player;
    if (loadedGame.HasFullInfo)
    {
      player.transform.position = loadedGame.PlayerPosition;
      player.transform.rotation = loadedGame.PlayerRotation;
      player.transform.localScale = loadedGame.PlayerScale;
      player.GetComponent<PlayerResizer>().Poke();
    }
    else if ((bool) (UnityEngine.Object) checkPoint1)
    {
      player.transform.position = checkPoint1.transform.position;
      player.transform.rotation = checkPoint1.transform.rotation;
      player.transform.localScale = checkPoint1.transform.lossyScale;
      player.GetComponent<PlayerResizer>().Poke();
    }
    if (!(bool) (UnityEngine.Object) checkPoint1)
      return;
    this._TriggerPreviousCheckpointSyncers(checkPoint1.transform);
  }

  private void _RestorePositionAfterResetMiniChallenge(string miniChallengeCheckPointName)
  {
    MiniChallenge miniChallenge1 = (MiniChallenge) null;
    if (miniChallengeCheckPointName != null)
    {
      foreach (MiniChallenge miniChallenge2 in UnityEngine.Object.FindObjectsOfType<MiniChallenge>())
      {
        if ((bool) (UnityEngine.Object) miniChallenge2.Data && miniChallenge2.Data.name == miniChallengeCheckPointName)
        {
          miniChallenge1 = miniChallenge2;
          break;
        }
      }
      if (!(bool) (UnityEngine.Object) miniChallenge1)
      {
        int length = miniChallengeCheckPointName.Length;
      }
    }
    GameObject player = GameManager.GM.player;
    player.transform.position = miniChallenge1.ResetPoint.transform.position;
    player.transform.rotation = miniChallenge1.ResetPoint.transform.rotation;
    player.transform.localScale = miniChallenge1.ResetPoint.transform.lossyScale;
    player.GetComponent<PlayerResizer>().Poke();
    this._TriggerPreviousCheckpointSyncers(miniChallenge1.ResetPoint);
    this.GetComponent<MiniChallengeMode>().MiniChallengeToResetTo = miniChallenge1;
  }

  private void _TriggerPreviousCheckpointSyncers(Transform checkpoint)
  {
    RoomOrder objectOfType = UnityEngine.Object.FindObjectOfType<RoomOrder>();
    if (!(bool) (UnityEngine.Object) objectOfType)
      return;
    int roomIndex = objectOfType.GetRoomIndex(checkpoint.root);
    if (roomIndex == -1)
      return;
    foreach (SaveAndCheckpointManager.RoomCheckpointSyncers checkpointSyncers in this.checkpointSyncerTracker)
    {
      if (objectOfType.GetRoomIndex(checkpointSyncers.Room) < roomIndex)
      {
        foreach (MOSTTriggerBase syncer in checkpointSyncers.Syncers)
          syncer.Trigger();
      }
    }
  }

  private void GatherTopLevelCheckpointSyncers()
  {
    this.checkpointSyncerTracker.Clear();
    foreach (MOSTTriggerCheckpointSyncer checkpointSyncer in UnityEngine.Object.FindObjectsOfType<MOSTTriggerCheckpointSyncer>())
    {
      Transform root = checkpointSyncer.transform.root;
      SaveAndCheckpointManager.RoomCheckpointSyncers checkpointSyncers = this.checkpointSyncerTracker.Find((Predicate<SaveAndCheckpointManager.RoomCheckpointSyncers>) (room => (UnityEngine.Object) room.Room == (UnityEngine.Object) root));
      if (checkpointSyncers == null)
      {
        checkpointSyncers = new SaveAndCheckpointManager.RoomCheckpointSyncers()
        {
          Room = root,
          Syncers = new List<MOSTTriggerCheckpointSyncer>()
        };
        this.checkpointSyncerTracker.Add(checkpointSyncers);
      }
      checkpointSyncers.Syncers.Add(checkpointSyncer);
    }
    RoomOrder roomOrder = UnityEngine.Object.FindObjectOfType<RoomOrder>();
    if ((bool) (UnityEngine.Object) roomOrder)
      this.checkpointSyncerTracker.Sort((Comparison<SaveAndCheckpointManager.RoomCheckpointSyncers>) ((x, y) => Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, x.Room).CompareTo(Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, y.Room))));
    else
      this.LevelInfo.DoesCurrentLevelSupportSaves();
  }

  private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
  {
    this._ReadInitialPlayerSaveData();
    this.CheckWinGame();
    this.GatherTopLevelCheckpointSyncers();
    int num = scene.isLoaded ? 1 : 0;
    bool flag = this.LevelInfo.DoesCurrentLevelSupportSaves();
    this.isCountingPlayTimeThisScene = flag;
    SaveGameState? nullable = new SaveGameState?();
    if (flag)
    {
      MovePlayerHereOnStart[] objectsOfType = UnityEngine.Object.FindObjectsOfType<MovePlayerHereOnStart>();
      foreach (Component component in objectsOfType)
        component.gameObject.SetActive(false);
      if (!string.IsNullOrEmpty(this.resetMiniChallenge) && this.GetComponent<MiniChallengeMode>().MiniChallengeModeEnabled)
      {
        nullable = new SaveGameState?(this.lastSaveGameState.Value);
        this._RestorePositionAfterResetMiniChallenge(this.resetMiniChallenge);
        this.resetMiniChallenge = (string) null;
      }
      else if (this.lastSaveGameState.HasValue)
      {
        nullable = new SaveGameState?(this.lastSaveGameState.Value);
        this._RestoreSaveGameState(this.lastSaveGameState.Value);
      }
      else if (GameManager.GM.SaveGameStateHandoff.HasValue)
      {
        nullable = new SaveGameState?(GameManager.GM.SaveGameStateHandoff.Value);
        this._RestoreSaveGameState(GameManager.GM.SaveGameStateHandoff.Value);
      }
      else if (objectsOfType.Length != 0)
        objectsOfType[0].MoveThePlayerManually();
      GameManager.GM.SaveGameStateHandoff = new SaveGameState?();
      this._SetLevelUnlocked();
    }
    this.lastSaveGameState = nullable;
    if (flag && !this.lastSaveGameState.HasValue)
      this._SaveGame((CheckPoint) null);
    this.TimeSinceLastCheckpoint = 0.0f;
    this.HitCheckpointThisLevel = false;
    this.MyPauseMenu = GameObject.Find("UI_PAUSE_MENU");
    this.freezeSpeedRunTimer = false;
  }

  public void EnteredCheckpoint(CheckPoint checkpoint) => this._SaveGame(checkpoint);

  public void FreezeSpeedRunTimer()
  {
    GameObject.Find("UI_PAUSE_MENU").transform.Find("Canvas").transform.Find("Pause Menu").gameObject.GetComponent<PauseMenu>().UpdateFinalTimeTranslation();
    this.freezeSpeedRunTimer = true;
  }

  public void RestartLevel()
  {
    this.lastSaveGameState = new SaveGameState?();
    this.resetMiniChallenge = (string) null;
    this.GetComponent<ChallengeMode>().SummaryScreenStatus = 0;
    GameManager.GM.GetComponent<MiniChallengeMode>().TurnOffUI();
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
  }

  public void ResetMiniChallenge(string miniChallengeName)
  {
    this.resetMiniChallenge = miniChallengeName;
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
  }

  public void ResetToLastCheckpoint()
  {
    if (MultiplayerHelper.InMultiplayerMatch())
    {
      if (!this.lastSaveGameState.HasValue || this.lastSaveGameState.Value.CheckpointName == null || !MultiplayerHelper.IsMine(GameManager.GM.player))
        return;
      this._RestoreSaveGameState(this.lastSaveGameState.Value);
    }
    else
    {
      if (!this.lastSaveGameState.HasValue)
        return;
      GameObject gameObject = GameObject.Find("UI_PAUSE_MENU");
      if ((bool) (UnityEngine.Object) gameObject)
        gameObject.transform.Find("Canvas").gameObject.transform.Find("ResettingToCheckpoint").gameObject.GetComponent<Text>().enabled = true;
      SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
    }
  }

  public bool HasLastCheckpoint() => this.lastSaveGameState.HasValue;

  public void ManuallyTriggerPreviousCheckpointSyncers(CheckPoint checkPoint)
  {
    CheckPoint[] objectsOfType = UnityEngine.Object.FindObjectsOfType<CheckPoint>();
    RoomOrder roomOrder = UnityEngine.Object.FindObjectOfType<RoomOrder>();
    if (!(bool) (UnityEngine.Object) roomOrder)
      return;
    Array.Sort<CheckPoint>(objectsOfType, (Comparison<CheckPoint>) ((x, y) => Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, x.transform.root).CompareTo(Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, y.transform.root))));
    int index = Array.IndexOf<CheckPoint>(objectsOfType, checkPoint);
    if (index == -1)
      return;
    this._TriggerPreviousCheckpointSyncers(objectsOfType[index].transform);
  }

  public void TeleportToCheckpointIndexDebug(int index)
  {
    CheckPoint[] objectsOfType = UnityEngine.Object.FindObjectsOfType<CheckPoint>();
    RoomOrder roomOrder = UnityEngine.Object.FindObjectOfType<RoomOrder>();
    if (!(bool) (UnityEngine.Object) roomOrder)
      return;
    Array.Sort<CheckPoint>(objectsOfType, (Comparison<CheckPoint>) ((x, y) => Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, x.transform.root).CompareTo(Array.IndexOf<Transform>(roomOrder.TopLevelRoomOrder, y.transform.root))));
    if (index >= objectsOfType.Length)
      return;
    this.TeleportToCheckpoint(objectsOfType[index]);
    this._TriggerPreviousCheckpointSyncers(objectsOfType[index].transform);
  }

  public void LoadToCheckpoint(SaveGameState state)
  {
    this.lastSaveGameState = new SaveGameState?(state);
    this.StartCoroutine(LevelLoadHelper.LoadSceneAsync(SceneManager.GetActiveScene().path, true, new SaveGameState?()));
  }

  public void TeleportToCheckpoint(CheckPoint checkpoint)
  {
    GameManager.GM.player.transform.position = checkpoint.transform.position;
    GameManager.GM.player.transform.rotation = checkpoint.transform.rotation;
    GameManager.GM.player.transform.localScale = checkpoint.transform.lossyScale;
  }

  public bool CanContinue() => File.Exists(Path.Combine(this.GetSaveFolder(), "Avocado"));

  public void Continue()
  {
    BinaryReader reader = new BinaryReader((Stream) this._ReadStreamFromFile("Avocado"));
    SaveGameState saveGameState = new SaveGameState();
    saveGameState.Load(reader);
    this.StartCoroutine(LevelLoadHelper.LoadSceneAsync(this.LevelInfo.GetScenePathFromSaveName(saveGameState.LevelName), false, new SaveGameState?(saveGameState)));
  }

  public bool CanViewCredits() => this.LevelUnlockStatus.HasCompletedGame;

  public void UnlockLevel(string scenePath)
  {
  }

  public void OnGameCompleted()
  {
    this.LevelUnlockStatus.HasCompletedGame = true;
    MemoryStream stream = new MemoryStream();
    this.LevelUnlockStatus.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "ExitSignPerson");
    this.playerActionSaveData.HasCompletedGame = true;
    this._SavePlayerActions();
    if (!this.GetComponent<CommentaryMode>().CommentaryModeEnabled)
      return;
    this.OnGrantAchievement(this.BiggestFanAchievement);
  }

  public static void XOREncryptDecrypt(byte[] dataToEncrypt)
  {
    for (int index = 0; index < dataToEncrypt.Length; ++index)
      dataToEncrypt[index] = (byte) ((uint) dataToEncrypt[index] ^ (uint) SaveAndCheckpointManager.XORKey);
  }

  private void _SaveStreamToFile(MemoryStream stream, string fileTurd)
  {
    string path = Path.Combine(this.GetSaveFolder(), fileTurd);
    try
    {
      byte[] array = stream.ToArray();
      SaveAndCheckpointManager.XOREncryptDecrypt(array);
      File.WriteAllBytes(path, array);
    }
    catch (Exception ex)
    {
    }
  }

  private MemoryStream _ReadStreamFromFile(string fileTurd)
  {
    string path = Path.Combine(this.GetSaveFolder(), fileTurd);
    try
    {
      byte[] numArray = File.ReadAllBytes(path);
      SaveAndCheckpointManager.XOREncryptDecrypt(numArray);
      return new MemoryStream(numArray);
    }
    catch (Exception ex)
    {
      return (MemoryStream) null;
    }
  }

  private void _DeleteFile(string fileTurd)
  {
    string path = Path.Combine(this.GetSaveFolder(), fileTurd);
    try
    {
      File.Delete(path);
    }
    catch (Exception ex)
    {
    }
  }

  public void DeleteAllSaves() => this._DeleteFile("Avocado");

  public void DeleteUnlockedLevels() => this._DeleteFile("ExitSignPerson");

  public void DeletePlayerActions()
  {
    this.playerActionSaveData.DeleteAllPlayerActions();
    this._SavePlayerActions();
  }

  public void DeleteLocalAchievements()
  {
    this.achievementSaveData.DeleteAllAchievements();
    this._SaveAchievements();
  }

  public void DeleteMultiplayerSaveData()
  {
    this.multiplayerSaveData.DeleteAllCosmeticsAndDreamPoints();
    this._SaveMultiplayerData();
  }

  public void UnlockAll()
  {
    this.LevelUnlockStatus.HasCompletedGame = true;
    this.LevelUnlockStatus.MaxUnlockedLevel = 9;
    MemoryStream stream = new MemoryStream();
    this.LevelUnlockStatus.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "ExitSignPerson");
    Debug.Log((object) "All levels unlocked.");
    foreach (AchievementDefinition allAchievement in this.AchievementTracker.AllAchievements)
      this.DebugSetAchievement(allAchievement, true);
    Debug.Log((object) "All achievements unlocked.");
    foreach (ActionAndItemNames uniqueObjectCounter in this.PlayerActionTracker.UniqueObjectCounters)
    {
      foreach (string objectName in uniqueObjectCounter.ObjectNames)
        this.OnPlayerAction_Debug(uniqueObjectCounter.Action, objectName, true);
    }
    Debug.Log((object) "All player actions unlocked.");
  }

  public void StartSpecificLevel(string levelSaveName, int? debugLoadingScreen)
  {
    this.lastSaveGameState = new SaveGameState?();
    this.resetMiniChallenge = (string) null;
    this.StartCoroutine(LevelLoadHelper.LoadSceneAsync(this.LevelInfo.GetScenePathFromSaveName(levelSaveName), false, new SaveGameState?(), debugLoadingScreen));
  }

  public void DebugReloadLevelWithLoadingScreen(int loadingScreen)
  {
    this.lastSaveGameState = new SaveGameState?();
    this.resetMiniChallenge = (string) null;
    this.StartCoroutine(LevelLoadHelper.LoadSceneAsync(SceneManager.GetActiveScene().path, false, new SaveGameState?(), new int?(loadingScreen)));
  }

  private void _FillInBuildIndices()
  {
    if (this.realLevelsBuildsIndices != null)
      return;
    this.realLevelsBuildsIndices = new int[this.LevelInfo.RealLevels.Length];
    for (int index = 0; index < this.LevelInfo.RealLevels.Length; ++index)
      this.realLevelsBuildsIndices[index] = SceneUtility.GetBuildIndexByScenePath(this.LevelInfo.RealLevels[index].Scene.ScenePath);
  }

  public List<string> GetUnlockedLevelList()
  {
    this._FillInBuildIndices();
    List<string> stringList = new List<string>();
    int maxUnlockedLevel = this.LevelUnlockStatus.MaxUnlockedLevel;
    for (int index = 0; index < this.LevelInfo.RealLevels.Length && index <= maxUnlockedLevel; ++index)
    {
      if (this.LevelInfo.RealLevels[index].IsActualLevel && this.realLevelsBuildsIndices[index] != -1)
        stringList.Add(this.LevelInfo.RealLevels[index].Name);
    }
    return stringList;
  }

  public List<string> GetLockedLevelList()
  {
    this._FillInBuildIndices();
    List<string> stringList = new List<string>();
    for (int index = this.LevelUnlockStatus.MaxUnlockedLevel + 1; index < this.LevelInfo.RealLevels.Length; ++index)
    {
      if (this.LevelInfo.RealLevels[index].IsActualLevel && this.realLevelsBuildsIndices[index] != -1)
        stringList.Add(this.LevelInfo.RealLevels[index].Name);
    }
    return stringList;
  }

  public void OnPlayerAction(PlayerActionDefinition action, string name)
  {
    if (this.GetComponent<MultiplayerMode>().MultiplayerEnabled || !this.playerActionSaveData.OnPlayerAction(action, name))
      return;
    this._SavePlayerActions();
    this._EvaluateAchievementsDependingOn(action);
    PlayerActionChangedEvent playerActionChanged = this.PlayerActionChanged;
    if (playerActionChanged == null)
      return;
    playerActionChanged(action);
  }

  public void OnPlayerAction_Debug(PlayerActionDefinition action, string name, bool on)
  {
    if (!this.playerActionSaveData.OnPlayerAction(action, name, on))
      return;
    this._SavePlayerActions();
    this._EvaluateAchievementsDependingOn(action);
    PlayerActionChangedEvent playerActionChanged = this.PlayerActionChanged;
    if (playerActionChanged == null)
      return;
    playerActionChanged(action);
  }

  public bool IsPlayerActionComplete(PlayerActionDefinition action, string name) => !this.GetComponent<MultiplayerMode>().MultiplayerEnabled && this.playerActionSaveData.IsPlayerActionComplete(action, name);

  public int GetCompletedActionCount(PlayerActionDefinition action) => this.GetComponent<MultiplayerMode>().MultiplayerEnabled ? 0 : this.playerActionSaveData.GetCompletedActionCount(action);

  public void GetPlayerActionCompletionStatus(
    PlayerActionDefinition action,
    string canonicalLevelName,
    out int completed,
    out int total,
    out bool anyComplete)
  {
    this.playerActionSaveData.GetPlayerActionCompletionStatus(action, canonicalLevelName, out completed, out total, out anyComplete);
  }

  public SerializedTransform GetSavedTransform(string name, bool createIfNone = false) => this.playerActionSaveData.GetSavedTransform(name, createIfNone);

  public void SavePlayerActions() => this._SavePlayerActions();

  private void _LoadPlayerActions()
  {
    if (File.Exists(Path.Combine(this.GetSaveFolder(), "DrPierceARealDr")))
      this.playerActionSaveData.Load(new BinaryReader((Stream) this._ReadStreamFromFile("DrPierceARealDr")));
    else
      this.playerActionSaveData.Load((BinaryReader) null);
  }

  private void _SavePlayerActions()
  {
    MemoryStream stream = new MemoryStream();
    this.playerActionSaveData.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "DrPierceARealDr");
  }

  public void OnGrantAchievement(AchievementDefinition achievement)
  {
    if (!this.achievementSaveData.OnGrantAchievement(achievement))
      return;
    this._SaveAchievements();
  }

  public bool HasAchievement(AchievementDefinition achievement) => this.achievementSaveData.HasAchievement(achievement);

  public void DebugSetAchievement(AchievementDefinition achievement, bool granted)
  {
    if (granted)
      this.OnGrantAchievement(achievement);
    else
      this.achievementSaveData.DebugSetAchievement(achievement, granted);
    this._SaveAchievements();
  }

  private void _LoadAchievements()
  {
    if (File.Exists(Path.Combine(this.GetSaveFolder(), "SaturdayBeans")))
      this.achievementSaveData.Load(new BinaryReader((Stream) this._ReadStreamFromFile("SaturdayBeans")));
    else
      this.achievementSaveData.Load((BinaryReader) null);
  }

  private void _LoadMultiplayerSaveData()
  {
    if (File.Exists(Path.Combine(this.GetSaveFolder(), "LoagieSonic")))
      this.multiplayerSaveData.Load(new BinaryReader((Stream) this._ReadStreamFromFile("LoagieSonic")));
    else
      this.multiplayerSaveData.Load((BinaryReader) null);
  }

  public string GetPreviousCosmeticDataOfType(CosmeticData.Type type) => this.multiplayerSaveData.GetRecentlyChosen(type);

  public void SetPreviousCosmetic(CosmeticData data)
  {
    this.multiplayerSaveData.SetRecentlyChosen(data.type, data.name);
    this._SaveMultiplayerData();
  }

  public int GetDreamPoints() => this.multiplayerSaveData.DreamPoints;

  public void SetDreamPoints(int dreamPoints)
  {
    if (this.multiplayerSaveData.DreamPoints == dreamPoints)
      return;
    this.multiplayerSaveData.DreamPoints = dreamPoints;
    this._SaveMultiplayerData();
  }

  public void UnlockCosmetic(string cosmeticName)
  {
    this.multiplayerSaveData.UnlockCosmetic(cosmeticName);
    this._SaveMultiplayerData();
  }

  public bool IsCosmeticUnlocked(string cosmeticName) => this.multiplayerSaveData.HasCosmetic(cosmeticName);

  public void RegrantAchievedAchievements()
  {
    foreach (AchievementDefinition allAchievement in this.AchievementTracker.AllAchievements)
    {
      if (this.HasAchievement(allAchievement))
        this.OnGrantAchievement(allAchievement);
    }
  }

  private bool IsWorkshopAvailable() => true;

  private void _LoadChallengeModeStats()
  {
    if (File.Exists(Path.Combine(this.GetSaveFolder(), "RysanShipping")))
      this.challengeModeSaveData.Load(new BinaryReader((Stream) this._ReadStreamFromFile("RysanShipping")));
    else
      this.challengeModeSaveData.Load((BinaryReader) null);
  }

  private void _SaveChallengeModeStats()
  {
    MemoryStream stream = new MemoryStream();
    this.challengeModeSaveData.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "RysanShipping");
  }

  public PerLevelChallengeModeSaveData GetChallengeModeStatsForLevel(
    string levelSaveName)
  {
    return this.challengeModeSaveData.GetChallengeModeSaveData(levelSaveName);
  }

  public PerLevelChallengeModeSaveData GetChallengeModeStatsForCurrentLevel() => this.challengeModeSaveData.GetChallengeModeSaveData(this.LevelInfo.GetCurrentSceneSaveName());

  public void SetChallengeModeStatsForCurrentLevel(PerLevelChallengeModeSaveData data)
  {
    this.challengeModeSaveData.SetChallengeModeSaveData(this.LevelInfo.GetCurrentSceneSaveName(), data);
    this._SaveChallengeModeStats();
  }

  private void _SaveAchievements()
  {
    MemoryStream stream = new MemoryStream();
    this.achievementSaveData.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "SaturdayBeans");
  }

  private void _SaveMultiplayerData()
  {
    MemoryStream stream = new MemoryStream();
    this.multiplayerSaveData.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "LoagieSonic");
  }

  private void _EvaluateAchievementsDependingOn(PlayerActionDefinition action)
  {
    foreach (AchievementDefinition allAchievement in this.AchievementTracker.AllAchievements)
    {
      if (this._EvaluateAchievement(allAchievement))
        this.OnGrantAchievement(allAchievement);
    }
  }

  private bool _EvaluateAchievement(AchievementDefinition achievement)
  {
    bool flag1 = false;
    if ((uint) achievement.ActionCountConditions.Length > 0U)
    {
      flag1 = true;
      foreach (ActionCountCondition actionCountCondition in achievement.ActionCountConditions)
      {
        int completedActionCount = this.playerActionSaveData.GetCompletedActionCount(actionCountCondition.Action);
        bool flag2 = false;
        switch (actionCountCondition.Comparison)
        {
          case ActionComparison.GreaterThanOrEqualTo:
            flag2 = completedActionCount >= actionCountCondition.Number;
            break;
          case ActionComparison.AllObjectsSatisfied:
            int uniqueObjectCount = PlayerActionTracker.Instance.GetUniqueObjectCount(actionCountCondition.Action.name);
            flag2 = completedActionCount >= uniqueObjectCount;
            break;
        }
        if (!flag2)
          flag1 = false;
      }
    }
    return flag1;
  }

  public void DeleteChallengeModeStats()
  {
    this._DeleteFile("RysanShipping");
    this._DeleteFile("MiniRysanShipping");
  }

  private void _LoadMiniChallengeModeStats()
  {
    if (File.Exists(Path.Combine(this.GetSaveFolder(), "MiniRysanShipping")))
      this.miniChallengeModeSaveData.Load(new BinaryReader((Stream) this._ReadStreamFromFile("MiniRysanShipping")));
    else
      this.miniChallengeModeSaveData.Load((BinaryReader) null);
  }

  private void _SaveMiniChallengeModeStats()
  {
    MemoryStream stream = new MemoryStream();
    this.miniChallengeModeSaveData.Save(new BinaryWriter((Stream) stream));
    this._SaveStreamToFile(stream, "MiniRysanShipping");
  }

  public void WinMiniChallenge(MiniChallengeData miniChallengeData)
  {
    this.miniChallengeModeSaveData.SetChallengeModeSaveData(this.LevelInfo.GetCurrentSceneSaveName(), miniChallengeData.name);
    this._SaveMiniChallengeModeStats();
  }

  public int GetMiniChallengeWonCount() => this.miniChallengeModeSaveData.GetMiniChallengeWonCount();

  public PerLevelMiniChallengeModeSaveData GetMiniChallengeModeStatsForLevel(
    string levelSaveName)
  {
    return this.miniChallengeModeSaveData.GetChallengeModeSaveData(levelSaveName);
  }

  public PerLevelMiniChallengeModeSaveData GetMiniChallengeModeStatsForCurrentLevel() => this.miniChallengeModeSaveData.GetChallengeModeSaveData(this.LevelInfo.GetCurrentSceneSaveName());

  public void TurnOffNewModesPromptAndSave() => PlayerPrefs.SetInt("NewModesPrompt", 1);

  public void DeleteNewModesPromptSaveStatus() => PlayerPrefs.SetInt("NewModesPrompt", 0);

  private class RoomCheckpointSyncers
  {
    public Transform Room;
    public List<MOSTTriggerCheckpointSyncer> Syncers;
  }
}

ToggleReflection

Commands mentioned: ref

using UnityEngine;

public class ToggleReflection : MonoBehaviour
{
  public static bool UseMirror = true;
  private KeystrokeTracker tracker = new KeystrokeTracker()
  {
    KeyCodes = new KeyCode[3]
    {
      KeyCode.R,
      KeyCode.E,
      KeyCode.F
    }
  };

  private void Update()
  {
    if (!this.tracker.Check())
      return;
    ToggleReflection.UseMirror = !ToggleReflection.UseMirror;
  }
}