How to Move Player in Direction of Joystick+Camera?

So I have a script that, not necessarily moves the player in world directions, but only in the up down left right of the left joystick. I want this script to act like super mario 64, where the player’s “forward” is generally wherever the camera is facing. (P.S. ignore my double jumping script lol)

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

public class PlayerManager : MonoBehaviour
{
    Vector3 moveVector;
    Vector3 direction;
    Vector3 lastMove;
    public int speed = 8;
    public float maxJumpForce = 8f;
    public int gravity = 25;
    public Vector3 Velocity;
    CharacterController controller;
    public AudioClip jump;
    public AudioClip land;
    public bool isLanded;
    public bool hasJumped;
    public bool doubleJumpOK;
    public float doubleJumpTimer;
    public GameObject mainCam;
    public GameObject forwardObject;

    void Start() {
        controller = GetComponent<CharacterController>();
    }

    void Update() {
        //moveVector = Vector3.zero;
        moveVector.x = InputManager.MainHorizontal();
        moveVector.z = InputManager.MainVertical();

        //reset variables
        doubleJumpTimer += Time.deltaTime;

        if(doubleJumpTimer > 0.70f) doubleJumpOK = false;
        if(!controller.isGrounded) isLanded = false;
        if(controller.isGrounded && Velocity.y < 0f) Velocity.y = 0f;

        //check for when the player lands
        if(controller.isGrounded) {
            //if the CharController detects you landed, but isLanded is false:
            if(!isLanded) {
                AudioSource.PlayClipAtPoint(land, transform.position);
                isLanded = true;
                hasJumped = false;
                //doubleJumpOK = false;
                doubleJumpTimer = 0;
            }

            //while grounded, check if A is pressed
            if(InputManager.AButton()) {
                //if isLanded hasnt been updated yet, update that, so that the LANDING sound is PLAYED
                if(isLanded && doubleJumpOK) {
                    Velocity.y = maxJumpForce*2;
                    hasJumped = true;
                    AudioSource.PlayClipAtPoint(jump, transform.position);
                    doubleJumpTimer = 0;
                //if the timer is after .3 seconds, then you can't doubleJump
                }else if(isLanded && !doubleJumpOK) {
                    Velocity.y = maxJumpForce;
                    hasJumped = true;
                    //since you single jumped, its OK for the next jump to be a double
                    doubleJumpOK = true;
                    AudioSource.PlayClipAtPoint(jump, transform.position);
                    doubleJumpTimer = 0;
                }else{
                    print("tried an invalid jump");
                }
            }
        }else{
            //while in the air, this updates
            moveVector = lastMove;
        }
        //just generally, the rest of this code happens.
        Velocity.y -= gravity * Time.deltaTime;

        moveVector.y = 0;
        moveVector.Normalize();
        moveVector *= speed;
        moveVector.y = Velocity.y;

        if(moveVector != Vector3.zero && controller.isGrounded) {
            transform.forward += InputManager.MainJoystick();
            //==> this is kinda what i want? transform.forward = forwardObject.transform.forward;
        }
       
        //this line right here is the ONLY line that tells the player where to go. basically the script calculates where to go, and this line *tells* the CharController to Move()
        controller.Move(moveVector * Time.deltaTime);
        lastMove = moveVector;
    }

    void OnControllerColliderHit(ControllerColliderHit other) {
        if(!controller.isGrounded && other.normal.y < 0.1f) {
            if(InputManager.AButton()) {
                Velocity.y = maxJumpForce*0.75f;
                transform.forward = -transform.forward;
                moveVector = other.normal * speed;
            }
        }
    }
}

The camera moves according to the right joystick and can zoom in and out, so it hasn’t the transform.forward I need. My plan is to have an empty object which rotates toward the camera but only in the Y direction. Therefore, since the object is pointing toward the camera, I just reverse that and use it as the transform.forward. This script updates moveVector so that controller.Move() moves the player in the direction of the moveVector, so my next concern is how would I rotate a moveVector to include where the camera is facing? (Remember I want this like super mario 64!)

Here’s the code for InputManager if you’re curious:
Main = Left joystick
Other = Right joystick
For reference, this is mapped to a Logitech F310 controller.

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

public static class InputManager {

    //Axis
  
    public static float MainHorizontal() {
        float r = 0.0f;
        r += Input.GetAxis("J_MainHorizontal");
        r += Input.GetAxis("K_MainHorizontal");
        return Mathf.Clamp(r, -1f, 1f);
    }
    public static float MainVertical() {
        float r = 0.0f;
        r += Input.GetAxis("J_MainVertical");
        r += Input.GetAxis("K_MainVertical");
        return Mathf.Clamp(r, -1f, 1f);
    }
    public static float OtherHorizontal() {
        float r = 0.0f;
        r += Input.GetAxis("J_OtherHorizontal");
        return Mathf.Clamp(r, -1f, 1f);
    }
    public static float OtherVertical() {
        float r = 0.0f;
        r += Input.GetAxis("J_OtherVertical");
        return Mathf.Clamp(r, -1f, 1f);
    }

    public static Vector3 MainJoystick() {
        return new Vector3(MainHorizontal(), 0, MainVertical());
    }
    public static Vector3 OtherJoystick() {
        return new Vector3(OtherHorizontal(), 0, OtherVertical());
    }

    // Buttons
    public static bool AButton() {
        return Input.GetButtonDown ("A_Button");
    }
    public static bool BButton() {
        return Input.GetButtonDown ("B_Button");
    }
    public static bool XButton() {
        return Input.GetButtonDown ("X_Button");
    }
    public static bool YButton() {
        return Input.GetButtonDown ("Y_Button");
    }
    public static bool L1Button() {
        return Input.GetButtonDown ("L1_Button");
    }
    public static bool L2Button() {
        return Input.GetButtonDown ("L2_Button");
    }
    public static bool R1Button() {
        return Input.GetButtonDown ("R1_Button");
    }
    public static bool R2Button() {
        return Input.GetButtonDown ("R2_Button");
    }
}

I have a nice clean “camera-relative controls” type demo scene in my proximity buttons package, works on mobile and PC / Web.

Look for the DemoCameraRotatedControls scene.

proximity_buttons is presently hosted at these locations:

https://bitbucket.org/kurtdekker/proximity_buttons

https://github.com/kurtdekker/proximity_buttons

https://gitlab.com/kurtdekker/proximity_buttons

https://sourceforge.net/projects/proximity-buttons/