This is my current jumping script:
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor() and not Input.is_action_pressed("crouch"):
velocity.y = jump_velocity

I want to be able to press the jump key in the air and when the player lands within a certain amount of time (let's say 0.5 seconds) then I want the player to automatically jump. How may I go about doing this?

You're looking to write (or find, if someone else has written) an input buffer. Basically when the player presses an action, instead of doing it immediately, you put it in a queue-like list with a "timeout" associated with it. Then in _process or wherever you're doing your movement, loop through the queue. decrement the timeouts, get rid of any actions that have timed out, and when you get to an action that you can perform in your current state, you flush it and everything in front of it and then perform that action.

Say your character can punch in the air but can only jump on the ground. The player jumps and hits "jump" again just before touching the ground. "jump" goes in the queue. It isn't usable right away, because you're airborne, but within the timeout window the character becomes grounded.

Your player does the same thing again, only this time between hitting "jump" and touching the ground, they hit "punch". Punch can be done while airborne, so the loop sees it, flushes the jump in front of it, and performs the aerial punch. The second jump doesn't happen, because that's the opposite the order of inputs and would feel weird. But if the player hit "jump" again while they were punching, "jump" would go back in the queue and end up being performed when they landed.

(Edit: the flushing isn't always necessary. In a game where punching doesn't affect your movement at all, less necessary. It's a design decision to make.)

You can use this same pattern for chaining attacks and other actions as well.

The way I did it is to use a timer. The timer starts counting when the player presses the jump button when falling i.e velocity.y > 0. If the timer is less than a predetermined threshold e.g 0.5, then the player can jump.

A sample code
`var input_buffer: float = 0.5
var jump_input_timer: float = 0.5

func physics_process(delta);
if Input.is_action_just_pressed("Jump"):
if velocity.y > 0:
jump_input_timer += delta

if player.is_on_floor():
if jump_input_timer <= input_buffer:
Jump() ##Call or insert jump code here
jump_input_timer = 0.0 ##Make sure to reset timer
`

This is just code I wrote on my phone so there might be some mistakes but it should give you the idea how to do it.

Also, you can use an actuall timer node instead of using delta to calculate time passed