diff --git a/lua/effects/glide_exhaust.lua b/lua/effects/glide_exhaust.lua index 8c06fcba..8acd5387 100644 --- a/lua/effects/glide_exhaust.lua +++ b/lua/effects/glide_exhaust.lua @@ -12,6 +12,8 @@ function EFFECT:Init( data ) local scale = Clamp( data:GetScale(), 0.1, 5 ) local alpha = Clamp( data:GetColor(), 0, 255 ) local power = Clamp( data:GetMagnitude() / 1000, 0, 1 ) + local count = math.min( math.floor( Glide.GetScreenSize( origin, 6 * scale ) / 2 ), 3 ) + if count < 1 then return end local emitter = ParticleEmitter( origin, false ) if not IsValid( emitter ) then return end @@ -19,7 +21,7 @@ function EFFECT:Init( data ) alpha = ( 1 - power ) * alpha power = 0.5 + power * 1.5 - for _ = 1, 3 do + for _ = 1, count do local p = emitter:Add( EXHAUST_SMOKE_MAT .. RandomInt( 9 ), origin ) if p then p:SetDieTime( 0.6 ) diff --git a/lua/effects/glide_tire_roll.lua b/lua/effects/glide_tire_roll.lua index ba8c63eb..8774bada 100644 --- a/lua/effects/glide_tire_roll.lua +++ b/lua/effects/glide_tire_roll.lua @@ -7,12 +7,19 @@ function EFFECT:Init( data ) local velocity = data:GetStart() local matId = data:GetSurfaceProp() local scale = Clamp( data:GetScale(), 0.1, 10 ) + local fx = surfaceFX[matId] + local count = 5 + + if fx then + count = math.min( math.floor( Glide.GetScreenSize( origin, scale * math.max( fx.minSize * 1.1, fx.maxSize * 1.5 ) ) / 2 ), 5 ) + if count < 1 then return end + end local emitter = ParticleEmitter( origin, false ) if not IsValid( emitter ) then return end if surfaceFX[matId] then - self:DoSurface( emitter, origin, velocity, scale, surfaceFX[matId] ) + self:DoSurface( emitter, origin, velocity, scale, fx, count ) else self:DoSmoke( emitter, origin, velocity, scale, data:GetEntity() ) end @@ -34,11 +41,11 @@ local Config = Glide.Config local debrisGravity = Vector( 0, 0, 0 ) local debrisVelocity = Vector( 0, 0, 0 ) -function EFFECT:DoSurface( emitter, origin, velocity, scale, fx ) +function EFFECT:DoSurface( emitter, origin, velocity, scale, fx, count ) local p local lifetime = fx.lifetime * ( Config.reduceTireParticles and 0.4 or 1 ) - for _ = 1, 5 do + for _ = 1, count do p = emitter:Add( fx.mat, origin ) if p then diff --git a/lua/entities/base_glide/cl_lights.lua b/lua/entities/base_glide/cl_lights.lua index 0369077b..25c0c93b 100644 --- a/lua/entities/base_glide/cl_lights.lua +++ b/lua/entities/base_glide/cl_lights.lua @@ -26,6 +26,53 @@ function ENT:CreateHeadlight( index, offset, angles, color, texture, fovScale ) light:Update() end +local cvarMaxHeadlights = CreateClientConVar( "glide_max_projected_headlights", "8", true, false, + "How many of the nearest vehicles can cast projected headlights at once (0 = no limit)", 0, 128 ) + +local headlightVehicles = setmetatable( {}, { __mode = "k" } ) + +do + local candidates = {} + local nextBudgetUpdate = 0 + + local function SortByDistance( a, b ) + return a.glideHeadlightRank < b.glideHeadlightRank + end + + hook.Add( "Think", "Glide.HeadlightBudget", function() + local t = RealTime() + if t < nextBudgetUpdate then return end + nextBudgetUpdate = t + 0.25 + + local limit = cvarMaxHeadlights:GetInt() + local count = 0 + local myVehicle = Glide.currentVehicle + + for e in pairs( headlightVehicles ) do + if not IsValid( e ) or not e.rfMisc or not e.rfMisc.isActive or e:GetHeadlightState() < 1 then + headlightVehicles[e] = nil + + elseif limit < 1 or e == myVehicle then + e.allowProjectedHeadlights = true + + else + count = count + 1 + candidates[count] = e + e.glideHeadlightRank = e.rfMisc.lastDistance * ( e.allowProjectedHeadlights == true and 0.8 or 1 ) + end + end + + if count > limit then + table.sort( candidates, SortByDistance ) + end + + for i = 1, count do + candidates[i].allowProjectedHeadlights = i <= limit + candidates[i] = nil + end + end ) +end + function ENT:RemoveHeadlights() if not self.activeHeadlights then return end @@ -68,15 +115,19 @@ function ENT:UpdateLights( selfTbl ) local headlightState = selfTbl.GetHeadlightState( self ) if headlightState > 0 then + headlightVehicles[self] = true local colorVec = selfTbl.GetHeadlightColor( self ) colorHeadlight.r = colorVec[1] * 255 colorHeadlight.g = colorVec[2] * 255 colorHeadlight.b = colorVec[3] * 255 end + local allowProjected = selfTbl.allowProjectedHeadlights ~= false + -- Handle projected lights - if selfTbl.headlightState ~= headlightState then + if selfTbl.headlightState ~= headlightState or selfTbl.hasProjectedHeadlights ~= allowProjected then selfTbl.headlightState = headlightState + selfTbl.hasProjectedHeadlights = allowProjected selfTbl.RemoveHeadlights( self ) if headlightState == 0 then return end @@ -84,10 +135,10 @@ function ENT:UpdateLights( selfTbl ) local enable for index, v in ipairs( selfTbl.Headlights ) do - enable = true + enable = allowProjected -- Check for optional bodygroup requirement - if v.ifBodygroupId then + if enable and v.ifBodygroupId then enable = self:GetBodygroup( v.ifBodygroupId ) == ( v.ifSubModelId or 0 ) end @@ -98,7 +149,7 @@ function ENT:UpdateLights( selfTbl ) end end - if headlightState > 0 and selfTbl.shouldThinkNow then + if headlightState > 0 and selfTbl.shouldThinkNow and allowProjected then local l, hasLight for index, data in ipairs( selfTbl.Headlights ) do @@ -136,8 +187,6 @@ function ENT:UpdateLights( selfTbl ) local pos, dir, ltype, enable for _, l in ipairs( selfTbl.LightSprites ) do - pos = self:LocalToWorld( l.offset ) - dir = self:LocalToWorld( l.dir ) - myPos ltype = l.type enable = lightState[ltype] @@ -170,6 +219,12 @@ function ENT:UpdateLights( selfTbl ) enable = enable and self:GetBodygroup( l.ifBodygroupId ) == ( l.ifSubModelId or 0 ) end + if enable then + pos = self:LocalToWorld( l.offset ) + dir = self:LocalToWorld( l.dir ) + dir:Sub( myPos ) + end + if enable and ltype == "headlight" then DrawLightSprite( pos, dir, l.size or 30, l.color or colorHeadlight, l.spriteMaterial ) diff --git a/lua/entities/base_glide/sv_lights.lua b/lua/entities/base_glide/sv_lights.lua index fb090d7e..e7790260 100644 --- a/lua/entities/base_glide/sv_lights.lua +++ b/lua/entities/base_glide/sv_lights.lua @@ -43,6 +43,8 @@ local CurTime = CurTime --- Update out model's bodygroups depending on which lights are on. function ENT:UpdateLightBodygroups( selfTbl ) + if not selfTbl.LightBodygroups[1] then return end + local headlightState = selfTbl.GetHeadlightState( self ) local allowLights = selfTbl.IsEngineOn( self ) or headlightState > 0 diff --git a/lua/entities/base_glide/sv_water.lua b/lua/entities/base_glide/sv_water.lua index d75985bb..3855b0a9 100644 --- a/lua/entities/base_glide/sv_water.lua +++ b/lua/entities/base_glide/sv_water.lua @@ -51,26 +51,36 @@ local GetDevMode = Glide.GetDevMode local EntityPairs = Glide.EntityPairs function ENT:WaterThink( selfTbl, dt ) - -- Update buoyancy points - local underWaterPoints = 0 + local waterState = selfTbl.GetWaterState( self ) - for _, point in ipairs( selfTbl.buoyancyPoints ) do - point.isUnderWater = IsUnderWater( self:LocalToWorld( point.offset ) ) + local phys = self:GetPhysicsObject() + local skipPoints = waterState == 0 and selfTbl.hasValidPhysics and IsValid( phys ) and phys:IsAsleep() - if point.isUnderWater then - underWaterPoints = underWaterPoints + 1 + if not skipPoints then + -- Update buoyancy points + local underWaterPoints = 0 + + for _, point in ipairs( selfTbl.buoyancyPoints ) do + point.isUnderWater = IsUnderWater( self:LocalToWorld( point.offset ) ) + + if point.isUnderWater then + underWaterPoints = underWaterPoints + 1 + end end - end - local waterState = underWaterPoints < 1 and 0 or ( - underWaterPoints > selfTbl.buoyancyPointsCount * 0.5 and 2 or 1 - ) + local newState = underWaterPoints < 1 and 0 or ( + underWaterPoints > selfTbl.buoyancyPointsCount * 0.5 and 2 or 1 + ) - if self:WaterLevel() > 2 then - waterState = 3 - end + if self:WaterLevel() > 2 then + newState = 3 + end - selfTbl.SetWaterState( self, waterState ) + if newState ~= waterState then + waterState = newState + selfTbl.SetWaterState( self, waterState ) + end + end -- If necessary, kick passengers when underwater if selfTbl.FallWhileUnderWater and waterState > 2 then diff --git a/lua/entities/base_glide_car/init.lua b/lua/entities/base_glide_car/init.lua index 0ece1eaf..f8dc79fe 100644 --- a/lua/entities/base_glide_car/init.lua +++ b/lua/entities/base_glide_car/init.lua @@ -470,7 +470,11 @@ function ENT:OnPostThink( dt, selfTbl ) -- Update driver inputs selfTbl.UpdateSteering( self, dt, selfTbl ) - selfTbl.SetBrakeValue( self, Clamp( selfTbl.frontBrake + selfTbl.rearBrake + ( selfTbl.GetInputBool( self, 1, "handbrake" ) and 1 or 0 ), 0, 1 ) ) + local brakeValue = Clamp( selfTbl.frontBrake + selfTbl.rearBrake + ( selfTbl.GetInputBool( self, 1, "handbrake" ) and 1 or 0 ), 0, 1 ) + + if selfTbl.GetBrakeValue( self ) ~= brakeValue then + selfTbl.SetBrakeValue( self, brakeValue ) + end local phys = self:GetPhysicsObject() @@ -505,6 +509,10 @@ function ENT:UpdateSteering( dt, selfTbl ) steerCone = Clamp( steerCone, Abs( sideSlip ), 1 ) inputSteer = ExpDecay( selfTbl.inputSteer, inputSteer * steerCone, selfTbl.GetSteerConeChangeRate( self ), dt ) + if Abs( inputSteer - selfTbl.inputSteer ) < 0.0001 and Abs( inputSteer ) < 0.0001 then + inputSteer = 0 + end + selfTbl.inputSteer = inputSteer -- Counter-steer when slipping, going fast and not using steer input @@ -513,7 +521,9 @@ function ENT:UpdateSteering( dt, selfTbl ) counterSteer = Clamp( counterSteer, -1, 1 ) * selfTbl.GetCounterSteer( self ) inputSteer = Clamp( inputSteer + counterSteer, -1, 1 ) - selfTbl.SetSteering( self, inputSteer ) + if selfTbl.GetSteering( self ) ~= inputSteer then + selfTbl.SetSteering( self, inputSteer ) + end selfTbl.steerAngle[2] = -inputSteer * selfTbl.GetMaxSteerAngle( self ) -- Reduce front wheel sideways friction when trying to do a J-turn diff --git a/lua/entities/base_glide_car/shared.lua b/lua/entities/base_glide_car/shared.lua index 5b2b39ae..c6bcb67a 100644 --- a/lua/entities/base_glide_car/shared.lua +++ b/lua/entities/base_glide_car/shared.lua @@ -46,6 +46,7 @@ function ENT:SetupDataTables() local order = 0 local uneditable = self.UneditableNWVars + local tuningKeys = {} -- We add a bunch of floats here so, this utility function helps. local function AddFloatVar( key, min, max, category ) @@ -57,6 +58,7 @@ function ENT:SetupDataTables() } ) self:NetworkVar( "Float", key, editData ) + tuningKeys[#tuningKeys + 1] = key end local function AddBoolVar( key, category ) @@ -66,6 +68,8 @@ function ENT:SetupDataTables() KeyName = key, Edit = { type = "Bool", order = order, category = category } } ) + + tuningKeys[#tuningKeys + 1] = key end -- Steering parameters @@ -104,6 +108,29 @@ function ENT:SetupDataTables() AddFloatVar( "SideTractionMin", 100, 5000, "#glide.editvar.traction" ) if SERVER then + local cache = {} + + local function Invalidate( _, name ) + cache[name] = nil + end + + for _, key in ipairs( tuningKeys ) do + local getter = self["Get" .. key] + + self["Get" .. key] = function( ent ) + local value = cache[key] + + if value == nil then + value = getter( ent ) + cache[key] = value + end + + return value + end + + self:NetworkVarNotify( key, Invalidate ) + end + -- Callback used to change the wheel radius self:NetworkVarNotify( "WheelRadius", self.OnWheelRadiusChange ) diff --git a/lua/entities/base_glide_car/sv_engine.lua b/lua/entities/base_glide_car/sv_engine.lua index fce0c69c..984813f3 100644 --- a/lua/entities/base_glide_car/sv_engine.lua +++ b/lua/entities/base_glide_car/sv_engine.lua @@ -119,7 +119,9 @@ do rpm = Max( rpm, 0 ) self.flywheelVelocity = rpm * TAU / 60 - self:SetEngineRPM( rpm ) + if self:GetEngineRPM() ~= rpm then + self:SetEngineRPM( rpm ) + end end function ENT:TransmissionToEngineRPM( gear, selfTbl ) @@ -442,8 +444,15 @@ function ENT:EngineThink( dt, selfTbl ) throttle = Approach( throttle, inputThrottle, dt * 4 ) self:EngineAccelerate( selfTbl.flywheelFriction + selfTbl.flywheelTorque * throttle, dt ) - self:SetEngineThrottle( throttle ) - self:SetIsRedlining( isRedlining and inputThrottle > 0 ) + + if self:GetEngineThrottle() ~= throttle then + self:SetEngineThrottle( throttle ) + end + + isRedlining = isRedlining and inputThrottle > 0 + if self:GetIsRedlining() ~= isRedlining then + self:SetIsRedlining( isRedlining ) + end end end diff --git a/lua/entities/glide_wheel/cl_init.lua b/lua/entities/glide_wheel/cl_init.lua index 2199b28e..c477f0e2 100644 --- a/lua/entities/glide_wheel/cl_init.lua +++ b/lua/entities/glide_wheel/cl_init.lua @@ -34,10 +34,11 @@ end local IsString = isstring local Clamp = math.Clamp +local Floor = math.floor local GetVolume = Glide.Config.GetVolume function ENT:ProcessSound( vehicle, id, surfaceId, soundSet, altSurface, volume, pitch, selfTbl, vehicleTbl ) - if not selfTbl.GetSoundsEnabled( self ) then return end + if not selfTbl.soundsEnabled then return end local path = IsString( soundSet ) and soundSet or ( vehicleTbl:OverrideWheelSound( vehicle, id, surfaceId ) or soundSet[surfaceId] ) @@ -65,15 +66,30 @@ function ENT:ProcessSound( vehicle, id, surfaceId, soundSet, altSurface, volume, end end + local lastVolume = selfTbl.soundVolume or {} + local lastPitch = selfTbl.soundPitch or {} + selfTbl.soundVolume, selfTbl.soundPitch = lastVolume, lastPitch + if not snd then snd = CreateSound( self, path or soundSet[altSurface] ) snd:SetSoundLevel( 80 ) snd:PlayEx( 0, 100 ) selfTbl.sounds[id] = snd + lastVolume[id], lastPitch[id] = nil, nil + end + + volume = Floor( volume * 128 + 0.5 ) / 128 + pitch = Floor( pitch * selfTbl.soundPitchMult ) + + if volume ~= lastVolume[id] then + lastVolume[id] = volume + snd:ChangeVolume( volume ) end - snd:ChangeVolume( volume ) - snd:ChangePitch( pitch * selfTbl.soundPitchMult ) + if pitch ~= lastPitch[id] then + lastPitch[id] = pitch + snd:ChangePitch( pitch ) + end end local WHEEL_SOUNDS = Glide.WHEEL_SOUNDS @@ -133,13 +149,20 @@ function ENT:Think() local isActive = parentTbl.rfMisc.isActive if not isActive then return true end + if parentTbl.rfMisc.lastDistance > 2250000 then + self:SetNextClientThink( selfTbl.particleCD > t and selfTbl.particleCD or t + 0.05 ) + end + local velocity = parent:GetVelocity() local speed = Abs( parent:WorldToLocal( parent:GetPos() + velocity )[1] ) local baseVolume = GetVolume( "carVolume" ) + local radius = selfTbl.GetRadius( self ) + selfTbl.soundsEnabled = selfTbl.GetSoundsEnabled( self ) + local up = parent:GetUp() local surfaceId = selfTbl.GetContactSurface( self ) - local contactPos = self:GetPos() - up * selfTbl.GetRadius( self ) + local contactPos = self:GetPos() - up * radius -- Force water surface when contactPos is under water if surfaceId > 0 and IsUnderWater( contactPos ) then @@ -150,7 +173,7 @@ function ENT:Think() local muteRollSound = surfaceId == 67 and parentTbl.VehicleType == 5 -- Disable some effects when a blown tire is touching a "hard" surface - local isBlownOnHardSurface = selfTbl.IsBlown( self ) and HARD_SURFACES[surfaceId] + local isBlownOnHardSurface = selfTbl.GetTireHealth( self ) < 1 and HARD_SURFACES[surfaceId] -- Fast roll sound local fastFactor = speed / 600 @@ -212,7 +235,7 @@ function ENT:Think() if isBlownOnHardSurface then return end -- Emit side slip/tire roll particles - local particleSize = Clamp( selfTbl.GetRadius( self ), 5, 10 ) + local particleSize = Clamp( radius, 5, 10 ) local rollFactor = sideSlipFactor - 0.5 if ROLL_MARK_SURFACES[surfaceId] or surfaceId == MAT_SLOSH then @@ -252,7 +275,7 @@ function ENT:Think() if not selfTbl.enableSkidmarks then return true end -- Create skidmarks - local skidmarkSize = selfTbl.GetRadius( self ) * parentTbl.WheelSkidmarkScale + local skidmarkSize = radius * parentTbl.WheelSkidmarkScale contactPos = contactPos + velocity * 0.04 diff --git a/lua/entities/glide_wheel/init.lua b/lua/entities/glide_wheel/init.lua index efa23c8e..d235560f 100644 --- a/lua/entities/glide_wheel/init.lua +++ b/lua/entities/glide_wheel/init.lua @@ -237,17 +237,48 @@ do local Deg = math.deg local Approach = math.Approach + local Abs = math.abs + local Floor = math.floor + local steerAng = Angle() + + local function NetSideSlip( v ) + if Abs( v ) <= 0.1 then return 0 end + return Floor( v * 256 + 0.5 ) / 256 + end + + local function NetForwardSlip( v ) + local a = Abs( v ) + if a <= 1 then return 0 end + if a <= 2.5 then return v > 0 and 2 or -2 end + + local q = Floor( v * 16 + 0.5 ) / 16 + + if ( v > 25 ) ~= ( q > 25 ) then + q = v > 25 and 25.0625 or 25 + end + + return q + end + function ENT:Update( vehicle, steerAngle, isAsleep, dt, selfTbl ) local state, params = selfTbl.state, selfTbl.params -- Get the wheel rotation relative to the vehicle, while applying the steering angle - local ang = vehicle:LocalToWorldAngles( steerAngle * params.steerMultiplier ) + steerAng:Set( steerAngle ) + steerAng:Mul( params.steerMultiplier ) -- Rotate the wheel around the axle axis state.spin = ( state.spin - Deg( state.angularVelocity ) * dt ) % 360 - ang:RotateAroundAxis( ang:Right(), state.spin ) - self:SetAngles( ang ) + local p, y, r = steerAng:Unpack() + + if p ~= state.netSteerP or y ~= state.netSteerY or r ~= state.netSteerR or state.spin ~= state.netAngSpin then + state.netSteerP, state.netSteerY, state.netSteerR, state.netAngSpin = p, y, r, state.spin + + local ang = Angle( p, y, r ) + ang:RotateAroundAxis( ang:Right(), state.spin ) + self:SetLocalAngles( ang ) + end -- Do suspsension sounds local fraction = state.fraction @@ -255,11 +286,16 @@ do state.lastFraction = fraction -- Set NW variables - if isAsleep then - selfTbl.SetContactSurface( self, 0 ) - else + local surface = isAsleep and 0 or state.lastSurfaceId + + if surface ~= state.netSurface then + state.netSurface = surface + selfTbl.SetContactSurface( self, surface ) + end + + if not isAsleep and state.spin ~= state.netSpin then + state.netSpin = state.spin selfTbl.SetLastSpin( self, state.spin ) - selfTbl.SetContactSurface( self, state.lastSurfaceId ) end if isAsleep or not state.isOnGround then @@ -273,8 +309,19 @@ do state.lastSideSlip = 0 end - selfTbl.SetForwardSlip( self, state.lastForwardSlip ) - selfTbl.SetSideSlip( self, state.lastSideSlip ) + local slip = NetForwardSlip( state.lastForwardSlip ) + + if slip ~= state.netForwardSlip then + state.netForwardSlip = slip + selfTbl.SetForwardSlip( self, slip ) + end + + slip = NetSideSlip( state.lastSideSlip ) + + if slip ~= state.netSideSlip then + state.netSideSlip = slip + selfTbl.SetSideSlip( self, slip ) + end -- Run touch events on entities our trace hits local ent = state.ray.Entity @@ -329,6 +376,7 @@ do local PlaySoundSet = Glide.PlaySoundSet function ENT:DoSuspensionSounds( change, vehicle, selfTbl ) + if change <= 0.01 and change >= -0.01 then return end if not selfTbl.GetSoundsEnabled( self ) then return end local t = CurTime() @@ -380,6 +428,15 @@ local EntSetLocalPos = FindMetaTable( "Entity" ).SetLocalPos local tractionCycle = Vector() local contactPos = Vector() +local VectorMul = FindMetaTable( "Vector" ).Mul +local VectorSetUnpacked = FindMetaTable( "Vector" ).SetUnpacked +local AngleSet = FindMetaTable( "Angle" ).Set +local AngleMul = FindMetaTable( "Angle" ).Mul + +local scratchAng = Angle() +local scratchVec = Vector() +local forceVec = Vector() + function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfaceGrip, vehSurfaceResistance, vehPos, vehTbl ) local selfTbl = GetTable( self ) local state, params = selfTbl.state, selfTbl.params @@ -388,7 +445,10 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa local pos = PhysLocalToWorld( phys, params.basePos ) -- Get the wheel rotation relative to the chassis, applying the steering angle if necessary - local ang = EntLocalToWorldAngles( vehicle, vehTbl.steerAngle * params.steerMultiplier ) + AngleSet( scratchAng, vehTbl.steerAngle ) + AngleMul( scratchAng, params.steerMultiplier ) + + local ang = EntLocalToWorldAngles( vehicle, scratchAng ) -- Do the raycast local up = AngUp( ang ) @@ -398,9 +458,12 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa local traceData = state.traceData traceData.filter = traceFilter + VectorSet( scratchVec, up ) + VectorMul( scratchVec, maxLen ) + VectorSet( traceData.start, pos ) VectorSet( traceData.endpos, pos ) - VectorSub( traceData.endpos, up * maxLen ) + VectorSub( traceData.endpos, scratchVec ) -- TraceResult gets stored on the `state.ray` table TraceHull( traceData ) @@ -409,10 +472,16 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa local ray = state.ray state.fraction = Clamp( ray.Fraction, radius / maxLen, 1 ) + VectorSet( scratchVec, up ) + VectorMul( scratchVec, maxLen * state.fraction ) VectorSet( contactPos, pos ) - VectorSub( contactPos, maxLen * state.fraction * up ) + VectorSub( contactPos, scratchVec ) + + VectorSet( scratchVec, up ) + VectorMul( scratchVec, radius ) + VectorAdd( scratchVec, contactPos ) - EntSetLocalPos( self, PhysWorldToLocal( phys, contactPos + up * radius ) ) + EntSetLocalPos( self, PhysWorldToLocal( phys, scratchVec ) ) -- Update ground contact NW variables local surfaceId = ray.Hit and ( ray.MatType or 0 ) or 0 @@ -478,10 +547,10 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa VectorAdd( vehPos, linearImp / dt ) end - local force = ( springForce - damperForce ) * upAlign * up + local upAmount = ( springForce - damperForce ) * upAlign -- Rolling resistance - VectorAdd( force, ( vehSurfaceResistance[surfaceId] or 0.05 ) * -velF * fw ) + local fwAmount = ( vehSurfaceResistance[surfaceId] or 0.05 ) * -velF -- Brake and torque forces local surfaceGrip = vehSurfaceGrip[surfaceId] or 1 @@ -503,7 +572,7 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa -- Reduce the forward force by the amount of grip we lost, -- but still allow some amount of brake force to apply regardless. forwardForce = forwardForce - ( gripLoss * signForwardForce ) + Clamp( brakeForce * 0.5, -maxTraction, maxTraction ) - VectorAdd( force, fw * forwardForce ) + fwAmount = fwAmount + forwardForce -- Get how fast the wheel would be spinning if it had never lost grip local groundAngularVelocity = TAU * ( velF / ( radius * TAU ) ) @@ -527,7 +596,7 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa maxTraction = state.isBlown and maxTraction * 0.2 or maxTraction -- The "* 0.75" is to compensate for existing vehicles after a change to how slipAngle is calculated was made - local sideForce = -VectorDot( rt, vel * params.sideTractionMultiplier * state.sideTractionMult * 0.75 ) + local sideForce = -VectorDot( rt, vel ) * ( params.sideTractionMultiplier * state.sideTractionMult * 0.75 ) -- Reduce sideways traction force as the wheel slips forward sideForce = sideForce * ( 1 - Clamp( Abs( gripLoss ) * 0.1, 0, 1 ) * 0.75 ) @@ -540,14 +609,20 @@ function ENT:DoPhysics( vehicle, phys, traceFilter, outLin, outAng, dt, vehSurfa surfaceGrip = surfaceGrip * Clamp( offset, 0, 1 ) -- Apply sideways traction force - VectorAdd( force, Clamp( sideForce, -maxTraction, maxTraction ) * surfaceGrip * rt ) + local rtAmount = Clamp( sideForce, -maxTraction, maxTraction ) * surfaceGrip -- Apply an extra, small sideways force that is not clamped by maxTraction. -- This helps at lot with cornering at high speed. - VectorAdd( force, velR * params.sideTractionMultiplier * -0.1 * rt ) + rtAmount = rtAmount + velR * params.sideTractionMultiplier * -0.1 + + VectorSetUnpacked( forceVec, + up[1] * upAmount + fw[1] * fwAmount + rt[1] * rtAmount, + up[2] * upAmount + fw[2] * fwAmount + rt[2] * rtAmount, + up[3] * upAmount + fw[3] * fwAmount + rt[3] * rtAmount + ) -- Apply the forces at the axle/ground contact position - local linearImp, angularImp = PhysCalculateForceOffset( phys, force, pos ) + local linearImp, angularImp = PhysCalculateForceOffset( phys, forceVec, pos ) outLin[1] = outLin[1] + linearImp[1] / dt outLin[2] = outLin[2] + linearImp[2] / dt diff --git a/lua/glide/client/sprites.lua b/lua/glide/client/sprites.lua index f7d56139..a4fb2989 100644 --- a/lua/glide/client/sprites.lua +++ b/lua/glide/client/sprites.lua @@ -3,7 +3,9 @@ local lightCount = 0 function Glide.DrawLight( pos, color, size, brightness ) lightCount = lightCount + 1 - lights[lightCount] = { pos, color.r, color.g, color.b, size or 70, brightness or 5 } + local l = lights[lightCount] or {} + lights[lightCount] = l + l[1], l[2], l[3], l[4], l[5], l[6] = pos, color.r, color.g, color.b, size or 70, brightness or 5 end local CurTime = CurTime @@ -39,7 +41,9 @@ local spriteCount = 0 function Glide.DrawLightSprite( pos, dir, size, color, material ) spriteCount = spriteCount + 1 - sprites[spriteCount] = { pos, size, dir, material, color.r, color.g, color.b, color.a } + local s = sprites[spriteCount] or {} + sprites[spriteCount] = s + s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8] = pos, size, dir, material, color.r, color.g, color.b, color.a end local Max = math.max @@ -79,10 +83,10 @@ hook.Add( "PreDrawEffects", "Glide.DrawSprites", function() spriteColor.b = s[7] spriteColor.a = s[8] - SetMaterial( s[4] or DEFAULT_MAT ) - DrawSprite( s[1], s[2], s[2], spriteColor ) - - sprites[i] = nil + if s[2] > 0 then + SetMaterial( s[4] or DEFAULT_MAT ) + DrawSprite( s[1], s[2], s[2], spriteColor ) + end end spriteCount = 0 diff --git a/lua/glide/sh_anims.lua b/lua/glide/sh_anims.lua index c20be3ee..19dace68 100644 --- a/lua/glide/sh_anims.lua +++ b/lua/glide/sh_anims.lua @@ -57,6 +57,18 @@ local holdTypeSequences = { } local GetTable = FindMetaTable( "Entity" ).GetTable +local sequenceCache = {} + +local function GetSequenceID( ply, name ) + local model = ply:GetModel() + local ids = sequenceCache[model] or {} + sequenceCache[model] = ids + + local id = ids[name] or ply:LookupSequence( name ) + ids[name] = id + + return id +end hook.Add( "CalcMainActivity", "Glide.OverridePlayerActivity", function( ply ) local vehicle = ply:GlideGetVehicle() @@ -78,7 +90,7 @@ hook.Add( "CalcMainActivity", "Glide.OverridePlayerActivity", function( ply ) local anim = vehicle:GetPlayerSitSequence( ply:GlideGetSeatIndex() ) plyTbl.CalcIdeal = 47 -- ACT_STAND - plyTbl.CalcSeqOverride = ply:LookupSequence( anim ) + plyTbl.CalcSeqOverride = GetSequenceID( ply, anim ) -- We only apply a sit sequence when the vehicle actually uses one. if anim == "sit" and ply:GetAllowWeaponsInVehicle() then @@ -93,7 +105,7 @@ hook.Add( "CalcMainActivity", "Glide.OverridePlayerActivity", function( ply ) -- Not every hold type has a corresponding sit sequence. if sitSequence then - local sequenceID = ply:LookupSequence( sitSequence ) + local sequenceID = GetSequenceID( ply, sitSequence ) if sequenceID ~= -1 then plyTbl.CalcIdeal = 1970 -- ACT_HL2MP_SIT diff --git a/lua/glide/sh_utils.lua b/lua/glide/sh_utils.lua index 18544416..704c28fb 100644 --- a/lua/glide/sh_utils.lua +++ b/lua/glide/sh_utils.lua @@ -138,12 +138,23 @@ if CLIENT then local lastViewPos = Vector() local lastViewAng = Angle() + local lastViewPixelScale = 600 --- Get the cached position/angle of the local player's render view. function Glide.GetLocalViewLocation() return lastViewPos, lastViewAng end + local DistToSqr = FindMetaTable( "Vector" ).DistToSqr + local Sqrt = math.sqrt + + function Glide.GetScreenSize( pos, size ) + local distSqr = DistToSqr( pos, lastViewPos ) + if distSqr < 1 then return math.huge end + + return size * lastViewPixelScale / Sqrt( distSqr ) + end + local EyePos = EyePos local EyeAngles = EyeAngles @@ -156,6 +167,11 @@ if CLIENT then lastViewPos = EyePos() lastViewAng = EyeAngles() + + local setup = render.GetViewSetup and render.GetViewSetup() + local fov = setup and setup.fov or 90 + + lastViewPixelScale = ScrH() * 0.5 / ( math.tan( math.rad( fov * 0.5 ) ) * 0.75 ) end ) end