modify the following code using the photon pun 2 library

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Mirror;

public class PlayerController : NetworkBehaviour
{
    // =======================
    // Movement Parameters
    // =======================
    [Header("Movement Parameters")]
    public float moveSpeed = 5f;
    public float acceleration = 10f;
    public float deceleration = 10f;

    // =======================
    // Jump Parameters
    // =======================
    [Header("Jump Parameters")]
    public float maxJumpHeight = 4f;
    public float timeToJumpApex = 0.4f;
    public int extraJumps = 1;

    // =======================
    // Jump Timing
    // =======================
    [Header("Jump Timing")]
    public float coyoteTime = 0.2f;
    public float jumpBufferTime = 0.2f;

    // =======================
    //# Fall Parameters
    // =======================
    [Header("Fall Parameters")]
    public float maxFallSpeed = 20f;

    // =======================
    // Ledge Detection
    // =======================
    [Header("Ledge Detection")]
    public Transform groundCheck;
    public float groundCheckRadius = 0.1f;
    public LayerMask groundLayer;
    public Transform wallCheck;
    public float wallCheckDistance = 0.1f;

    // =======================
    // Private Variables
    // =======================
    private Rigidbody2D rb;
    private bool isFacingRight = true;

    private bool isGrounded;
    private bool isTouchingWall;
    private bool canDoubleJump;
    private float coyoteTimeCounter;
    private float jumpBufferCounter;

    private float jumpVelocity;
    private float gravity;

    // Input variables
    private float moveInput;
    private bool jumpPressed;
    private bool jumpHeld;

    // =======================
    // Mobile Control Variables
    // =======================
    [Header("Mobile Controls")]
    // Removed isLeftPressed, isRightPressed, isJumpPressed since handled via events

    // UI References
    private Canvas mobileCanvas;
    private Button leftButton;
    private Button rightButton;
    private Button jumpButton;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        // Calculate gravity and jump velocity based on desired jump height and time to apex
        gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToJumpApex, 2);
        rb.gravityScale = gravity / Physics2D.gravity.y; // Adjust gravity scale relative to Unity's default gravity
        jumpVelocity = Mathf.Abs(gravity) * timeToJumpApex;

        // Only set up mobile controls for the local player
        if (isLocalPlayer)
        {
            SetupMobileControls();
        }
    }

    void SetupMobileControls()
    {
        // Find the Canvas
        GameObject canvasObject = GameObject.Find("MobileCanvas");
        if (canvasObject != null)
        {
            mobileCanvas = canvasObject.GetComponent<Canvas>();

            // Find Buttons by name
            GameObject leftBtnObj = GameObject.Find("LeftButton");
            GameObject rightBtnObj = GameObject.Find("RightButton");
            GameObject jumpBtnObj = GameObject.Find("JumpButton");

            if (leftBtnObj != null && rightBtnObj != null && jumpBtnObj != null)
            {
                leftButton = leftBtnObj.GetComponent<Button>();
                rightButton = rightBtnObj.GetComponent<Button>();
                jumpButton = jumpBtnObj.GetComponent<Button>();

                // Subscribe to button events via UIButtonHandler
                UIButtonHandler.OnButtonPressedDown += OnButtonDown;
                UIButtonHandler.OnButtonPressedUp += OnButtonUp;
            }
            else
            {
                Debug.LogError("One or more buttons not found. Please ensure LeftButton, RightButton, and JumpButton exist in the scene.");
            }
        }
        else
        {
            Debug.LogError("MobileCanvas not found. Please ensure a Canvas named 'MobileCanvas' exists in the scene.");
        }
    }

    void OnDestroy()
    {
        // Unsubscribe from events to prevent memory leaks
        UIButtonHandler.OnButtonPressedDown -= OnButtonDown;
        UIButtonHandler.OnButtonPressedUp -= OnButtonUp;
    }

    void OnButtonDown(string buttonName)
    {
        switch (buttonName)
        {
            case "LeftButton":
                moveInput -= 1f;
                break;
            case "RightButton":
                moveInput += 1f;
                break;
            case "JumpButton":
                jumpPressed = true;
                jumpHeld = true; // To allow variable jump height while holding
                break;
        }
    }

    void OnButtonUp(string buttonName)
    {
        switch (buttonName)
        {
            case "LeftButton":
                moveInput += 1f; // Neutralize the left input
                break;
            case "RightButton":
                moveInput -= 1f; // Neutralize the right input
                break;
            case "JumpButton":
                jumpPressed = false;
                jumpHeld = false;
                break;
        }
    }

    void Update()
    {
        if (!isLocalPlayer) return;

        // Update timers
        if (isGrounded)
        {
            coyoteTimeCounter = coyoteTime;
            canDoubleJump = extraJumps > 0;
        }
        else
        {
            coyoteTimeCounter -= Time.deltaTime;
        }

        if (jumpPressed)
        {
            jumpBufferCounter = jumpBufferTime;
            jumpPressed = false; // Reset jumpPressed after buffering
        }
        else
        {
            if (jumpBufferCounter > 0)
                jumpBufferCounter -= Time.deltaTime;
        }

        // Handle jumping with Jump Buffering and Coyote Time
        if (jumpBufferCounter > 0f && coyoteTimeCounter > 0f)
        {
            PerformJump();
            jumpBufferCounter = 0f; // Reset jump buffer after jumping
        }
    }

    void FixedUpdate()
    {
        if (!isLocalPlayer) return;

        // Check ground and wall status
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
        isTouchingWall = Physics2D.Raycast(wallCheck.position, transform.right, wallCheckDistance, groundLayer);

        // Apply horizontal movement with acceleration and deceleration
        float targetSpeed = moveInput * moveSpeed;
        float speedDifference = targetSpeed - rb.velocity.x;
        float accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? acceleration : deceleration;
        float movement = Mathf.Pow(Mathf.Abs(speedDifference) * accelRate, 0.9f) * Mathf.Sign(speedDifference);
        rb.AddForce(movement * Vector2.right);

        // Clamp fall speed
        if (rb.velocity.y < -maxFallSpeed)
        {
            rb.velocity = new Vector2(rb.velocity.x, -maxFallSpeed);
        }

        // Variable jump height
        if (rb.velocity.y > 0 && !jumpHeld)
        {
            rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f);
        }

        // Flip character based on movement direction
        if (moveInput > 0 && !isFacingRight)
            Flip();
        else if (moveInput < 0 && isFacingRight)
            Flip();
    }

    /// <summary>
    /// Handles player input, including mobile buttons.
    /// </summary>
    void HandleInput()
    {
        // Handled via events
    }

    /// <summary>
    /// Executes the jump logic, including double jumps.
    /// </summary>
    void PerformJump()
    {
        if (isGrounded || coyoteTimeCounter > 0f)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpVelocity);
            // Optionally, trigger jump animation or sound here
        }
        else if (canDoubleJump && !isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpVelocity);
            canDoubleJump = false;
        }
    }

    /// <summary>
    /// Flips the character's orientation.
    /// </summary>
    void Flip()
    {
        isFacingRight = !isFacingRight;
        Vector3 localScale = transform.localScale;
        localScale.x *= -1;
        transform.localScale = localScale;
    }

    /// <summary>
    /// Visualize ground and wall checks in the Scene view.
    /// </summary>
    void OnDrawGizmosSelected()
    {
        if (groundCheck != null)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
        }

        if (wallCheck != null)
        {
            Gizmos.color = Color.red;
            Gizmos.DrawLine(wallCheck.position, wallCheck.position + transform.right * wallCheckDistance);
        }
    }
}