public void RpcAlignWithTargetObject(WhichTargetPoint whichTargetPoint)
    {
        ControllerParent controllerParent = whichTargetPoint == WhichTargetPoint.Left ? LeftControllerParent : RightControllerParent;

        if (CurrentControllerParent == controllerParent) // check to make sure we aren't using Left controller to align with Right-controller-spawned object, and vice versa
        {
            // callbacks
            CurrentControllerParent.TargetPoint.OnAlignmentConfirmed();
            CurrentSpawnedPoseParent.TargetPoint.OnAlignmentConfirmed();

            LeftControllerParent.TargetPoint.Stick.gameObject.SetActive(false);
            RightControllerParent.TargetPoint.Stick.gameObject.SetActive(false);

            // compute alignment
            float distanceMeters = Vector3.Distance(CurrentControllerParent.transform.position, CurrentSpawnedPoseParent.transform.position);
            float angleDegrees   = Quaternion.Angle(CurrentControllerParent.transform.rotation, CurrentSpawnedPoseParent.transform.rotation);

            Debug.Log("distance: " + distanceMeters + " meters, angle: " + angleDegrees + " degrees");

            DestroyCurrentSpawnedPose();

            CurrentControllerParent     = null;
            CurrentFreeModeControlState = FreeModeControlState.PlacingTargetObject;
        }
    }
    public override void OnStartServer()
    {
        base.OnStartServer();

        Debug.Log("ViveControllerInputManager: OnStartServer");

        CurrentFreeModeControlState = FreeModeControlState.PlacingTargetObject;
        SetCurrentAlignmentInterfaceType(CurrentAlignmentInterfaceType);
        SetCurrentControllerTargetPointLocation(CurrentControllerTargetPointLocation);
        SetCurrentControllerVisibility(CurrentControllerVisibility);
    }
    public void DoClearAnySpawnedFreeModePose()
    {
        Debug.Log("start DoClearAnySpawnedFreeModePose");
        // callbacks
        if (CurrentControllerParent != null && CurrentControllerParent.TargetPoint != null)
        {
            CurrentControllerParent.TargetPoint.OnAlignmentConfirmed();
        }

        if (CurrentSpawnedPoseParent != null && CurrentSpawnedPoseParent.TargetPoint != null)
        {
            CurrentSpawnedPoseParent.TargetPoint.OnAlignmentConfirmed();
        }

        DestroyCurrentSpawnedPose();

        CurrentControllerParent = null;

        CurrentFreeModeControlState = FreeModeControlState.PlacingTargetObject;
    }
    public void RpcPlaceTargetObjectAtCustomPose(WhichTargetPoint whichTargetPoint, Vector3 positionInViveSpace, Quaternion rotationInViveSpace)
    {
        ControllerParent controllerParent = whichTargetPoint == WhichTargetPoint.Left ? LeftControllerParent : RightControllerParent;

        CurrentSpawnedPoseParent = Instantiate(SpawnedPoseParentPrefab, ViveOrigin);
        CurrentSpawnedPoseParent.transform.localPosition = positionInViveSpace;
        CurrentSpawnedPoseParent.transform.localRotation = rotationInViveSpace;

        CurrentControllerParent = controllerParent;

        // callbacks
        CurrentControllerParent.TargetPoint.OnTargetSpawned(CurrentSpawnedPoseParent.TargetPoint, CurrentAlignmentInterfaceType, CurrentControllerTargetPointLocation);
        CurrentSpawnedPoseParent.TargetPoint.OnTargetSpawned(CurrentControllerParent.TargetPoint, CurrentAlignmentInterfaceType, CurrentControllerTargetPointLocation);

        CurrentFreeModeControlState = FreeModeControlState.AligningWithTargetObject;

        LeftControllerParent.TargetPoint.Stick.gameObject.SetActive(false);
        RightControllerParent.TargetPoint.Stick.gameObject.SetActive(false);

        if (!ObjectManager.Instance.SessionManager.IsInFreeMode())
        {
            ObjectManager.Instance.SessionManager.Log_OnPoseSpawned();
        }
    }