I figured it out!
Well, I did so a long time ago. Gonna tell you all now.
!!!(Edit: short explanation at the bottom of the post. My ways of explaining have thankfully improved, the code below is laid out quite ruff)!!!
Basically what I did, is I gave the player back his velocity, that was lost from the previous frame.
I ALSO had to write extra code to handle movement in air, which makes it “slippery” mid-air. But it works perfectly!
– edit:
You also have to do some checks, for when NOT to keep velocity. How I did it, is:
if (Re.vec3.noY(CData.vel.prev).Unit - Re.vec3.noY(humR.AssemblyLinearVelocity).Unit).Magnitude > 0.4
or (CData.vel.prev.Unit.Y - humR.AssemblyLinearVelocity.Unit.Y) > 0.42 then return end
It’s done so when you hit a wall, you don’t keep velocity INTO the wall
. You can adjust the value “0.4” and the “0.42” values. It’s the max allowed difference between the velocities 
NOTE:
“Re
” - is a module script with functions that are used in almost all scripts
“Re.vec3.noY
” function just returns a vector without the “Y” value:
local vec3 = Vector3.new(3, 4, 5)
local newVec3 = Re.vec3.noY(vec3) -- Vector3.new(3, 0, 5)
CData - is a module script for the character
In it, there is “CData.vel.prev
”, which is the velocity on the previous frame. The only problem with keeping it, is that when you do a move such as jump, or a “parkour” move mid-air, you need to set the value (CData.vel.prev
) to humR.AssemblyLinearVelocity
Example:
local function Jump()
humR.AssemblyLinearVelocity += Vector3.new(0, 40, 0)
CData.vel.prev = humR.AssemblyLinearVelocity
end
Also, for simplicity, I made a function “CData.vel.changeHumRVel
” that basically does what the test function “Jump” does above. Also added “CData.vel.changeHumRVelHor” for change of horizontal velocity (with a limit), and ALSO updates the “CData.vel.prev”
Examples:
local function Jump()
CData.vel.changeHumR(Vector3.new(0, 40, 0)) -- changes velocity, and updates the 'CData.vel.prev' value, to fix the velocity keeping mid-air
CData.vel.changeHumRHor(humR.CFrame.LookVector * 5, 50) -- adds velocity to the player. If it goes over the limit, it doesn't add any more. If already over the limit, just slightly changes direction
end
Here is the ‘CData.vel.changeHumRHor’ function for those curious (it’s located in a ModuleScript, so I didn’t add the “local
” thing):
changeHumRVelHor = function(velChange: Vector3, maxMag: number)
maxMag *= CData.char.scale
local startMag = Re.vec3.noY(humR.AssemblyLinearVelocity).Magnitude
humR.AssemblyLinearVelocity += velChange * CData.char.scale
local newMag = Re.vec3.noY(humR.AssemblyLinearVelocity).Magnitude
if startMag < newMag then
humR.AssemblyLinearVelocity = ((Re.vec3.noY(humR.AssemblyLinearVelocity).Unit) * math.max(maxMag, startMag))
+ Re.vec3.onlyY(humR.AssemblyLinearVelocity)
CData.vel.updatePrevVel()
end
end;
Hope if helped someone!
Sorry if I didn’t show all the code. I still want to keep some stuff private from everyone, which is hopefully understandable, but if you request something, I’ll think about it 
QUICK EDIT. Simple explanation for those wanting to understand how it essentially works:
We essentially just cancel out Roblox’s character physics by removing all of their changes in velocity by storing the previous speed, while not doing that in case the change in angle is too much.
For that to work properly, I had to create some simple function to manage the speed, which would at the same time reset the previous velocity value.
If you’re confused about the random 0.4 or 0.42 in the code above where I talked the check when the velocity should not get restored, that’s just a random value that fit me well. You can instead replace it with an actual angle calculator between two vectors, using this function:
-- Returns the angle in degrees between two vectors
getAngle = function(vec1: Vector3, vec2: Vector3)
return math.deg(2 * math.asin(math.clamp((vec1 - vec2).Magnitude / 2, 0, 1)))
end;
Lots of people liked the post, and I highly appreciate that! I really hope my answer helped you guys.