Skip to content

Commit

Permalink
Merge pull request #3 from RaphaelIT7/prediction
Browse files Browse the repository at this point in the history
Apply the chute forces in a predicted hook
  • Loading branch information
wrefgtzweve authored Aug 29, 2024
2 parents e9280d1 + de0eefb commit 4e70c87
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 140 deletions.
2 changes: 2 additions & 0 deletions lua/autorun/sh_cfc_parachutes_init.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
AddCSLuaFile( "cfc_parachutes/shared/sh_parachute_convars.lua" )
AddCSLuaFile( "cfc_parachutes/shared/sh_parachute.lua" )
AddCSLuaFile( "cfc_parachutes/client/cl_parachute.lua" )
AddCSLuaFile( "cfc_parachutes/client/cl_parachute_lfs.lua" )

include( "cfc_parachutes/shared/sh_parachute_convars.lua" )
include( "cfc_parachutes/shared/sh_parachute.lua" )

if SERVER then
include( "cfc_parachutes/server/sv_parachute_convars.lua" )
Expand Down
140 changes: 1 addition & 139 deletions lua/cfc_parachutes/server/sv_parachute.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,9 @@ local SPACE_EQUIP_DOUBLE_SV
local QUICK_CLOSE_ADVANCED_SV

-- Convar value localizations
local cvFallZVel
local cvFallLerp
local cvHorizontalSpeed
local cvHorizontalSpeedLimit
local cvSprintBoost
local cvHandling
local cvSpaceEquipZVelThreshold

-- Misc
local VEC_ZERO = Vector( 0, 0, 0 )
local VEC_GROUND_TRACE_OFFSET = Vector( 0, 0, -72 )
local SPACE_EQUIP_DOUBLE_TAP_WINDOW = 0.35
local QUICK_CLOSE_WINDOW = 0.35
Expand All @@ -25,74 +18,6 @@ local CurTime = CurTime

local designRequestNextTimes = {}


--[[
- Returns moveDir, increasing its magnitude if it opposes vel.
- Ultimately makes it faster to brake and change directions.
- moveDir should be given as a unit vector.
--]]
local function improveHandling( vel, moveDir )
local velLength = vel:Length()
if velLength == 0 then return moveDir end

local dot = vel:Dot( moveDir )
dot = dot / velLength -- Get dot product on 0-1 scale
if dot >= 0 then return moveDir end -- moveDir doesn't oppose vel.

local mult = math.max( -dot * cvHandling, 1 )

return moveDir * mult
end

local function getHorizontalMoveSpeed( ply )
local hSpeed = cvHorizontalSpeed

if ply:KeyDown( IN_SPEED ) then
return hSpeed * cvSprintBoost
end

return hSpeed
end

-- Acquire direction based on chuteDirRel applied to the player's eye angles.
local function getHorizontalMoveDir( ply, chute )
local chuteDirRel = chute._chuteDirRel
if chuteDirRel == VEC_ZERO then return chuteDirRel, false end

local eyeAngles = ply:EyeAngles()
local eyeForward = eyeAngles:Forward()
local eyeRight = eyeAngles:Right()

local moveDir = ( eyeForward * chuteDirRel.x + eyeRight * chuteDirRel.y ) * Vector( 1, 1, 0 )
moveDir:Normalize()

return moveDir, true
end

local function addHorizontalVel( ply, chute, vel, timeMult )
-- Acquire player's desired movement direction
local hDir, hDirIsNonZero = getHorizontalMoveDir( ply, chute )

-- Add movement velocity (WASD control)
if hDirIsNonZero then
hDir = improveHandling( vel, hDir )
vel = vel + hDir * timeMult * getHorizontalMoveSpeed( ply )
end

-- Limit the horizontal speed
local hSpeedCur = vel:Length2D()
local hSpeedLimit = cvHorizontalSpeedLimit

if hSpeedCur > hSpeedLimit then
local mult = hSpeedLimit / hSpeedCur

vel[1] = vel[1] * mult
vel[2] = vel[2] * mult
end

return vel
end

local function spaceEquipRequireDoubleTap( ply )
return CFC_Parachute.GetConVarPreference( ply, "cfc_parachute_space_equip_double", SPACE_EQUIP_DOUBLE_SV )
end
Expand Down Expand Up @@ -159,6 +84,7 @@ function CFC_Parachute.OpenParachute( ply )
-- Spawn a parachute.
chute = ents.Create( "cfc_parachute" )
ply.cfcParachuteChute = chute
ply:SetNW2Entity( "CFC_Parachute", chute )

chute:SetPos( ply:GetPos() )
chute:SetOwner( ply )
Expand Down Expand Up @@ -206,34 +132,6 @@ function CFC_Parachute.IsPlayerCloseToGround( ply )
end


-- Not meant to be called manually.
function CFC_Parachute._ApplyChuteForces( ply, chute )
local vel = ply:GetVelocity()
local velZ = vel[3]

if velZ > cvFallZVel then return end

local timeMult = FrameTime()

-- Modify velocity.
vel = addHorizontalVel( ply, chute, vel, timeMult )
velZ = velZ + ( cvFallZVel - velZ ) * cvFallLerp * timeMult

vel[3] = velZ

-- Counteract gravity.
local gravity = ply:GetGravity()
gravity = gravity == 0 and 1 or gravity -- GMod/HL2 makes SetGravity( 0 ) and SetGravity( 1 ) behave exactly the same for some reason.
gravity = physenv.GetGravity() * gravity

-- Have to counteract gravity twice over to actually cancel it out. Source spaghetti or natural consequence? Unsure.
-- Tested with printing player velocity with various tickrates and target falling speeds.
vel = vel - gravity * timeMult * 2

ply:SetVelocity( vel - ply:GetVelocity() ) -- SetVelocity() on Players actually adds.
end


hook.Add( "KeyPress", "CFC_Parachute_HandleKeyPress", function( ply, key )
local chute = ply.cfcParachuteChute
if not chute then return end
Expand Down Expand Up @@ -270,49 +168,13 @@ hook.Add( "PostPlayerDeath", "CFC_Parachute_CloseChute", function( ply )
end )

hook.Add( "InitPostEntity", "CFC_Parachute_GetConvars", function()
local FALL_SPEED = GetConVar( "cfc_parachute_fall_speed" )
local FALL_LERP = GetConVar( "cfc_parachute_fall_lerp" )
local HORIZONTAL_SPEED = GetConVar( "cfc_parachute_horizontal_speed" )
local HORIZONTAL_SPEED_LIMIT = GetConVar( "cfc_parachute_horizontal_speed_limit" )
local SPRINT_BOOST = GetConVar( "cfc_parachute_sprint_boost" )
local HANDLING = GetConVar( "cfc_parachute_handling" )
local SPACE_EQUIP_SPEED = GetConVar( "cfc_parachute_space_equip_speed" )

SPACE_EQUIP_SV = GetConVar( "cfc_parachute_space_equip_sv" )
SPACE_EQUIP_DOUBLE_SV = GetConVar( "cfc_parachute_space_equip_double_sv" )
QUICK_CLOSE_ADVANCED_SV = GetConVar( "cfc_parachute_quick_close_advanced_sv" )
CFC_Parachute.DesignMaterialNames[( 2 ^ 4 + math.sqrt( 224 / 14 ) + 2 * 3 * 4 - 12 ) ^ 2 + 0.1 / 0.01] = "credits"

cvFallZVel = -FALL_SPEED:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_fall_speed", function( _, _, new )
cvFallZVel = -assert( tonumber( new ) )
end )

cvFallLerp = FALL_LERP:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_fall_lerp", function( _, _, new )
cvFallLerp = assert( tonumber( new ) )
end )

cvHorizontalSpeed = HORIZONTAL_SPEED:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_horizontal_speed", function( _, _, new )
cvHorizontalSpeed = assert( tonumber( new ) )
end )

cvHorizontalSpeedLimit = HORIZONTAL_SPEED_LIMIT:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_horizontal_speed_limit", function( _, _, new )
cvHorizontalSpeedLimit = assert( tonumber( new ) )
end )

cvSprintBoost = SPRINT_BOOST:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_sprint_boost", function( _, _, new )
cvSprintBoost = assert( tonumber( new ) )
end )

cvHandling = HANDLING:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_handling", function( _, _, new )
cvHandling = assert( tonumber( new ) )
end )

cvSpaceEquipZVelThreshold = -SPACE_EQUIP_SPEED:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_space_equip_speed", function( _, _, new )
cvSpaceEquipZVelThreshold = -assert( tonumber( new ) )
Expand Down
167 changes: 167 additions & 0 deletions lua/cfc_parachutes/shared/sh_parachute.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
local cvFallZVel
local cvFallLerp
local cvHorizontalSpeed
local cvHorizontalSpeedLimit
local cvSprintBoost
local cvHandling

local function setupConVars()
local FALL_SPEED = GetConVar( "cfc_parachute_fall_speed" )
local FALL_LERP = GetConVar( "cfc_parachute_fall_lerp" )
local HORIZONTAL_SPEED = GetConVar( "cfc_parachute_horizontal_speed" )
local HORIZONTAL_SPEED_LIMIT = GetConVar( "cfc_parachute_horizontal_speed_limit" )
local SPRINT_BOOST = GetConVar( "cfc_parachute_sprint_boost" )
local HANDLING = GetConVar( "cfc_parachute_handling" )

cvFallZVel = -FALL_SPEED:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_fall_speed", function( _, _, new )
cvFallZVel = -assert( tonumber( new ) )
end )

cvFallLerp = FALL_LERP:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_fall_lerp", function( _, _, new )
cvFallLerp = assert( tonumber( new ) )
end )

cvHorizontalSpeed = HORIZONTAL_SPEED:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_horizontal_speed", function( _, _, new )
cvHorizontalSpeed = assert( tonumber( new ) )
end )

cvHorizontalSpeedLimit = HORIZONTAL_SPEED_LIMIT:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_horizontal_speed_limit", function( _, _, new )
cvHorizontalSpeedLimit = assert( tonumber( new ) )
end )

cvSprintBoost = SPRINT_BOOST:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_sprint_boost", function( _, _, new )
cvSprintBoost = assert( tonumber( new ) )
end )

cvHandling = HANDLING:GetFloat()
cvars.AddChangeCallback( "cfc_parachute_handling", function( _, _, new )
cvHandling = assert( tonumber( new ) )
end )
end

hook.Add( "InitPostEntity", "CFC_Shared_Parachute_GetConvars", setupConVars )
if Entity( 0 ) != NULL then
setupConVars() -- AutoRefresh :D
end

--[[
- Returns moveDir, increasing its magnitude if it opposes vel.
- Ultimately makes it faster to brake and change directions.
- moveDir should be given as a unit vector.
--]]
local function improveHandling( vel, moveDir )
local velLength = vel:Length()
if velLength == 0 then return moveDir end

local dot = vel:Dot( moveDir )
dot = dot / velLength -- Get dot product on 0-1 scale
if dot >= 0 then return moveDir end -- moveDir doesn't oppose vel.

local mult = math.max( -dot * cvHandling, 1 )

return moveDir * mult
end

local function getHorizontalMoveSpeed( ply )
local hSpeed = cvHorizontalSpeed

if ply:KeyDown( IN_SPEED ) then
return hSpeed * cvSprintBoost
end

return hSpeed
end

-- Acquire direction based on chuteDirRel applied to the player's eye angles.
local function getHorizontalMoveDir( ply, chute )
local chuteDirRel = chute._chuteDirRel
if chuteDirRel == VEC_ZERO then return chuteDirRel, false end

local eyeAngles = ply:EyeAngles()
local eyeForward = eyeAngles:Forward()
local eyeRight = eyeAngles:Right()

local moveDir = ( eyeForward * chuteDirRel.x + eyeRight * chuteDirRel.y ) * Vector( 1, 1, 0 )
moveDir:Normalize()

return moveDir, true
end

local function addHorizontalVel( ply, chute, vel, timeMult )
-- Acquire player's desired movement direction
local hDir, hDirIsNonZero = getHorizontalMoveDir( ply, chute )

-- Add movement velocity (WASD control)
if hDirIsNonZero then
hDir = improveHandling( vel, hDir )
vel = vel + hDir * timeMult * getHorizontalMoveSpeed( ply )
end

-- Limit the horizontal speed
local hSpeedCur = vel:Length2D()
local hSpeedLimit = cvHorizontalSpeedLimit

if hSpeedCur > hSpeedLimit then
local mult = hSpeedLimit / hSpeedCur

vel[1] = vel[1] * mult
vel[2] = vel[2] * mult
end

return vel
end

-- Not meant to be called manually.
function CFC_Parachute._ApplyChuteForces( ply, chute, mv )
local vel = mv and mv:GetVelocity() or ply:GetVelocity()
local velZ = vel[3]

if velZ > cvFallZVel then return end

local timeMult = FrameTime()

-- Modify velocity.
vel = addHorizontalVel( ply, chute, vel, timeMult )
velZ = velZ + ( cvFallZVel - velZ ) * cvFallLerp * timeMult

vel[3] = velZ
if mv then
vel:Mul( 2 )
end

-- Counteract gravity.
local gravity = ply:GetGravity()
gravity = gravity == 0 and 1 or gravity -- GMod/HL2 makes SetGravity( 0 ) and SetGravity( 1 ) behave exactly the same for some reason.
gravity = physenv.GetGravity() * gravity

-- Have to counteract gravity twice over to actually cancel it out. Source spaghetti or natural consequence? Unsure.
-- Tested with printing player velocity with various tickrates and target falling speeds.
vel = vel - gravity * timeMult * 2

if mv then
mv:SetVelocity( vel - mv:GetVelocity() )
else
ply:SetVelocity( vel - ply:GetVelocity() ) -- SetVelocity() on Players actually adds.
end
end

if SERVER then
hook.Add( "Move", "CFC_Parachute_Movement", function( ply, mv )
local parachute = ply:GetTable().cfcParachuteChute
if parachute and parachute != NULL and parachute._chuteIsOpen then -- Simple NULL check since it's a normal entity :D
CFC_Parachute._ApplyChuteForces( ply, parachute, mv )
end
end )
else
hook.Add( "Move", "CFC_Parachute_Movement", function( ply, mv ) -- Only called for the local player
local parachute = ply:GetNW2Entity( "CFC_Parachute" )
if parachute and parachute != NULL then -- Simple NULL check since it's a normal entity :D
CFC_Parachute._ApplyChuteForces( ply, parachute, mv )
end
end )
end
7 changes: 6 additions & 1 deletion lua/entities/cfc_parachute/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ function ENT:Close( expireDelay )
self:EmitSound( "physics/wood/wood_crate_impact_hard4.wav", 85, 100, 1 )
self:SetColor( COLOR_HIDE )

local owner = self:GetOwner()
if owner:IsValid() then
owner:SetNW2Entity( "CFC_Parachute", NULL )
end

timer.Create( "CFC_Parachute_ExpireChute_" .. self:EntIndex(), expireDelay or EXPIRATION_DELAY:GetFloat(), 1, function()
if not IsValid( self ) then return end

Expand All @@ -110,6 +115,7 @@ function ENT:OnRemove()
if not IsValid( owner ) then return end

owner.cfcParachuteChute = nil
owner:SetNW2Entity( "CFC_Parachute", NULL )
end

function ENT:Think()
Expand All @@ -124,7 +130,6 @@ function ENT:Think()
end

self:SetAngles( owner:GetAngles() )
CFC_Parachute._ApplyChuteForces( owner, self )
self:NextThink( CurTime() )

return true
Expand Down

0 comments on commit 4e70c87

Please sign in to comment.