bool PlayerMobile_GetNextTile(Position3D current, Vector2Int goal, out Direction facing, out Vector2Int nextPosition, out int nextZ)
        {
            bool moveIsOkay;

            // attempt to move in the direction specified.
            facing = getNextFacing(current, goal);
            var initialFacing = facing;

            nextPosition = MobileMovementCheck.OffsetTile(current, facing);
            moveIsOkay   = MobileMovementCheck.CheckMovement((Mobile)_entity, current, facing, out nextZ);
            // The legacy client only allows alternative direction checking when moving in a cardinal (NSEW) direction.
            // This is checked by only checked alterate directions when the initial facing modulo 2 is 1.
            // By contrast, this client allows, when enabled, alternative direction checking in any direction.
            if (NewDiagonalMovement || ((int)initialFacing % 2 == 1))
            {
                // if blocked, attempt moving in the direction 1/8 counterclockwise to the direction specified.
                if (!moveIsOkay)
                {
                    facing       = (facing - 1) & Direction.ValueMask;
                    nextPosition = MobileMovementCheck.OffsetTile(current, facing);
                    moveIsOkay   = MobileMovementCheck.CheckMovement((Mobile)_entity, current, facing, out nextZ);
                }
                // if blocked, attempt moving in the direction 1/8 clockwise to the direction specified.
                if (!moveIsOkay)
                {
                    facing       = (facing + 2) & Direction.ValueMask;
                    nextPosition = MobileMovementCheck.OffsetTile(current, facing);
                    moveIsOkay   = MobileMovementCheck.CheckMovement((Mobile)_entity, current, facing, out nextZ);
                }
            }
            // if we were able to move, then set the running flag (if necessary) and return true.
            if (moveIsOkay)
            {
                if (IsRunning)
                {
                    facing |= Direction.Running;
                }
                return(true);
            }
            // otherwise return false, indicating that the player is blocked.
            else
            {
                return(false);
            }
        }
 bool PlayerMobile_CheckForMoveEvent()
 {
     if (_playerMobile_NextMove != Direction.Nothing)
     {
         var nextMove = _playerMobile_NextMove;
         _playerMobile_NextMove = Direction.Nothing;
         // get the next tile and the facing necessary to reach it.
         Direction  facing;
         var        targetTile = MobileMovementCheck.OffsetTile(CurrentPosition, nextMove);
         int        nextZ;
         Vector2Int nextTile;
         if (PlayerMobile_GetNextTile(CurrentPosition, targetTile, out facing, out nextTile, out nextZ))
         {
             // Check facing and send change facing message to server if necessary.
             PlayerMobile_SendChangeFacingMsg(facing);
             // copy the running flag to our local facing if we are running, zero it out if we are not.
             if ((nextMove & Direction.Running) != 0)
             {
                 facing |= Direction.Running;
             }
             else
             {
                 facing &= Direction.FacingMask;
             }
             if (CurrentPosition.X != nextTile.x ||
                 CurrentPosition.Y != nextTile.y ||
                 CurrentPosition.Z != nextZ)
             {
                 _moveEvents.AddMoveEvent(nextTile.x, nextTile.y, nextZ, (int)(facing), true);
                 return(true);
             }
         }
         // blocked
         else
         {
             return(false);
         }
     }
     return(false);
 }