private void UpdateDragPlane()
        {
            Refl.Invoke(EditorLogic.fetch, "CenterDragPlane", EditorLogic.SelectedPart.transform.position + EditorLogic.fetch.selPartGrabOffset);
            var args = new object[] { new Vector3() };

            Refl.Invoke(EditorLogic.fetch, "dragOverPlane", args);
            EditorLogic.SelectedPart.transform.position = (Vector3)args [0];
        }
        private IEnumerator <object> TurnSmoothingOffForOneFrame(object camBehaviour)
        {
            var oldValue = (float)Refl.GetValue(camBehaviour, "sharpness");

            Refl.SetValue(camBehaviour, "sharpness", float.MaxValue);
            yield return(null);

            Refl.SetValue(camBehaviour, "sharpness", oldValue);
        }
        public void Start()
        {
            log = new Log(this.GetType().Name);
            log.Debug("Start");

            if (gui == null)
            {
                gui = this.gameObject.AddComponent <MainMenuGui> ();
                gui.UpdateToolbarStock();
                gui.SetVisible(false);
            }

            config = readConfig();

            KspIssue3838Fix.ApplyFix(config.enableExperimentalEditorExtensionsCompatibility);

            editorFSM = (KerbalFSM)Refl.GetValue(EditorLogic.fetch, "\u0001");

            cursorLocker = Application.platform == RuntimePlatform.WindowsPlayer ? new WinCursorLocker() : (CursorLocker) new UnityLocker();

            movementBounds = new Bounds();
            if (EditorDriver.editorFacility == EditorFacility.VAB)
            {
                movementBounds = config.vab.bounds;
            }
            else if (EditorDriver.editorFacility == EditorFacility.SPH)
            {
                movementBounds = config.sph.bounds;
            }
            if (!config.enforceBounds)
            {
                movementBounds = new Bounds(Vector3.zero, Vector3.one * float.MaxValue);
            }

            var restartListener = new EventVoid.OnEvent(this.OnEditorRestart);

            GameEvents.onEditorRestart.Add(restartListener);
            OnCleanup += () => GameEvents.onEditorRestart.Remove(restartListener);

            var partEventListener = new EventData <ConstructionEventType, Part> .OnEvent(this.OnPartEvent);

            GameEvents.onEditorPartEvent.Add(partEventListener);
            OnCleanup += () => GameEvents.onEditorPartEvent.Remove(partEventListener);

            if (config.defaultCamera)
            {
                SwitchMode(false);
                ResetCamera();
            }
        }
        public void LateUpdate()
        {
            if (Input.GetKeyDown(config.keySwitchMode))
            {
                SwitchMode();
            }
            if (selectedPart && EditorLogic.SelectedPart == null)
            {
                SwitchMode(false, false);
            }
            if (!cameraEnabled)
            {
                return;
            }
            if (EditorLogic.SelectedPart != null)
            {
                SwitchMode(false, true);
                return;
            }

            cursorLocker.LockUpdate();

            bool isDown   = Input.GetKey(KeyCode.Mouse1);
            bool goneDown = isDown && !mouseWasDown;
            bool goneUp   = !isDown && mouseWasDown;

            mouseWasDown = isDown;

            bool shiftIsDown = Input.GetKey(KeyCode.LeftShift);

            var isTweaking = (Input.GetMouseButton(0) &&
                              (editorFSM.currentStateName == "st_offset_tweak" || editorFSM.currentStateName == "st_rotate_tweak"));

            if (isTweaking)
            {
                return;
            }

            float dx = 0, dy = 0;

            if (isDown)
            {
                dx     = Input.GetAxis("Mouse X");
                dy     = Input.GetAxis("Mouse Y");
                yaw   += 0.22f * dx * config.sensitivity;
                yaw   %= 360;
                pitch += -0.22f * dy * config.sensitivity;
                pitch  = Mathf.Clamp(pitch, -90, 90);
            }

            if (goneDown)
            {
                // Locks part rotation with WASD keys. Doesn't actually seem to affect gizmos.
                InputLockManager.SetControlLock(ControlTypes.EDITOR_GIZMO_TOOLS, this.GetType().Name);

                if (EditorLogic.SelectedPart != null)
                {
                    partOffset  = EditorLogic.SelectedPart.transform.position - EditorLogic.fetch.editorCamera.transform.position;
                    partOffset += EditorLogic.fetch.selPartGrabOffset;
                    partOffset  = EditorLogic.fetch.editorCamera.transform.InverseTransformVector(partOffset);
                }

                Screen.showCursor = false;
                cursorLocker.PrepareLock();
                cursorLocker.LockCursor();
            }

            if (goneUp)
            {
                InputLockManager.RemoveControlLock(this.GetType().Name);

                Screen.showCursor = true;
                cursorLocker.UnlockCursor();

                if (movePart)
                {
                    EditorBounds.Instance.constructionBounds = movementBounds;
                    UpdateDragPlane();
                }
                movePart = false;
            }

            if (EditorLogic.SelectedPart == null)
            {
                movePart = false;
            }

            // WASD in place mode is part rotation.
            var simpleMove = EditorLogic.SelectedPart == null || EditorLogic.fetch.EditorConstructionMode != ConstructionMode.Place;

            if (isDown || simpleMove)
            {
                var rot  = Quaternion.AngleAxis(yaw, Vector3.up) * Quaternion.AngleAxis(pitch, Vector3.right);
                var fwd  = rot * Vector3.forward;
                var side = rot * Vector3.right;

                Vector3 acc = Vector3.zero;
                if (Input.GetKey(config.keyForward))
                {
                    acc += fwd;
                }
                if (config.mouseWheelActive && Input.GetAxis("Mouse ScrollWheel") > 0 && shiftIsDown)
                {
                    acc += fwd * config.mouseWheelAcceleration;
                }
                if (Input.GetKey(config.keyBack))
                {
                    acc -= fwd;
                }
                if (config.mouseWheelActive && Input.GetAxis("Mouse ScrollWheel") < 0 && shiftIsDown)
                {
                    acc -= fwd * config.mouseWheelAcceleration;
                }
                if (Input.GetKey(config.keyRight))
                {
                    acc += side;
                }
                if (Input.GetKey(config.keyLeft))
                {
                    acc -= side;
                }
                if (Input.GetKey(config.keyDown))
                {
                    acc -= Vector3.up;
                }
                if (config.mouseWheelActive && Input.GetAxis("Mouse ScrollWheel") < 0 && !shiftIsDown)
                {
                    acc -= Vector3.up * config.mouseWheelAcceleration;
                }
                if (Input.GetKey(config.keyUp))
                {
                    acc += Vector3.up;
                }
                if (config.mouseWheelActive && Input.GetAxis("Mouse ScrollWheel") > 0 && !shiftIsDown)
                {
                    acc += Vector3.up * config.mouseWheelAcceleration;
                }
                if (Input.GetKey(config.keyRun))
                {
                    acc *= config.runMultiplier;
                }
                if (Input.GetKey(config.keySneak))
                {
                    acc *= config.sneakMultiplier;
                }
                acc *= config.acceleration;
                vel += (acc - config.friction * vel) * Time.deltaTime;
                var delta = vel * Time.deltaTime;

                EditorLogic.fetch.editorCamera.transform.rotation = rot;

                if (!movePart && EditorLogic.SelectedPart != null && EditorLogic.fetch.EditorConstructionMode == ConstructionMode.Place &&
                    (delta != Vector3.zero || dx != 0 || dy != 0))
                {
                    movePart = true;
                    // A convenient trick to prevent EditorLogic::dragOverPlane from updating the part position.
                    EditorBounds.Instance.constructionBounds = ZERO_BOUNDS;
                }

                if (movePart || simpleMove)
                {
                    pos += delta;

                    float distance = 0;
                    movementBounds.IntersectRay(new Ray(pos, -delta), out distance);
                    //distance = -1;
                    //log.Debug("POS {0} {1} {2}", pos, yaw, pitch);
                    if (distance < 0)
                    {
                        EditorLogic.fetch.editorCamera.transform.position = pos;
                    }
                    else
                    {
                        EditorLogic.fetch.editorCamera.transform.position = GetClosestPointOnBounds(movementBounds, pos);
                        pos = EditorLogic.fetch.editorCamera.transform.position;
                    }

                    if (movePart)
                    {
                        Refl.Invoke(EditorLogic.fetch, "displayAttachNodeIcons", false, false, false);

                        var offset = EditorLogic.fetch.editorCamera.transform.TransformPoint(partOffset);
                        EditorLogic.SelectedPart.transform.position = offset - EditorLogic.fetch.selPartGrabOffset;
                    }
                }
            }
        }