diff --git a/lua/acf/core/globals.lua b/lua/acf/core/globals.lua index 92cd65ba..2df77d85 100644 --- a/lua/acf/core/globals.lua +++ b/lua/acf/core/globals.lua @@ -300,6 +300,7 @@ elseif CLIENT then CreateClientConVar("acf_legalhints", 1, true, true, "If enabled, ACF will throw a warning hint whenever an entity gets disabled.", 0, 1) CreateClientConVar("acf_legalshame", 0, true, true, "If enabled, you will get a message in console from the server if someone else has an ACF entity get disabled, but only when the server has that logging enabled.", 0, 1) CreateClientConVar("acf_debris", 1, true, false, "Toggles ACF Debris.", 0, 1) + CreateClientConVar("acf_debris_autolod", 1, true, false, "Automatically disables some effects on debris if FPS is low.", 0, 1) CreateClientConVar("acf_debris_collision", 0, true, false, "Toggles debris collisions with other entities.", 0, 1) CreateClientConVar("acf_debris_gibmultiplier", 1, true, false, "The amount of gibs spawned when created by ACF debris.", 0, 1) CreateClientConVar("acf_debris_giblifetime", 60, true, false, "Defines lifetime in seconds of each debris gib.", 1, 300) diff --git a/lua/acf/damage/debris_cl.lua b/lua/acf/damage/debris_cl.lua index 969db115..8ddae344 100644 --- a/lua/acf/damage/debris_cl.lua +++ b/lua/acf/damage/debris_cl.lua @@ -2,12 +2,21 @@ local ACF = ACF local Effects = ACF.Utilities.Effects local AllowDebris = GetConVar("acf_debris") +local AutoLod = GetConVar("acf_debris_autolod") local CollideAll = GetConVar("acf_debris_collision") local DebrisLife = GetConVar("acf_debris_lifetime") local GibMult = GetConVar("acf_debris_gibmultiplier") local GibLife = GetConVar("acf_debris_giblifetime") local GibModel = "models/gibs/metal_gib%s.mdl" +local math = math + +local AutoLod_TerribleFps = 15 +local AutoLod_ReallyBadFps = 25 +local AutoLod_LowFps = 35 +local AutoLod_OkayFps = 40 +local AutoLod_GoodFps = 45 + local function Particle(Entity, Effect) return CreateParticleSystem(Entity, Effect, PATTACH_ABSORIGIN_FOLLOW) end @@ -56,33 +65,61 @@ local function Ignite(Entity, Lifetime, IsGib) end end -local function CreateDebris(Model, Position, Angles, Material, Color, Normal, Power, ShouldIgnite) +local function CreateDebris(Model, Position, Angles, Material, Color, Normal, Power, ShouldIgnite, AutoLOD) -- TODO: This fixes a crashing bug, but the underlying issue that Model can sometimes be blank ("") isn't fixed yet if not util.IsValidModel(Model) then return end + local Lifetime = DebrisLife:GetFloat() * math.Rand(0.5, 1) + local DoCollideAll = CollideAll:GetBool() + local DoParticles = true + local AllowIgnite = ShouldIgnite + local AllowSmoke = true + + if AutoLOD then + local FPS = 1 / RealFrameTime() + if FPS < AutoLod_ReallyBadFps then + if FPS < math.random(0, AutoLod_TerribleFps) then return end -- their game is basically crashing, dont add to the problem + DoParticles = false + DoCollideAll = false + Lifetime = Lifetime * math.Rand(0.01, 0.1) + elseif FPS < AutoLod_LowFps then + AllowIgnite = AllowIgnite and math.random(0, 100) < 15 + AllowSmoke = math.random(0, 100) < 25 + DoCollideAll = false + Lifetime = Lifetime * math.Rand(0.1, 0.25) + elseif FPS < AutoLod_OkayFps then + AllowIgnite = AllowIgnite and math.random(0, 100) < 25 + AllowSmoke = math.random(0, 100) < 50 + DoCollideAll = CollideAll and math.random(0, 100) < 50 + Lifetime = Lifetime * math.Rand(0.25, 0.5) + elseif FPS <= AutoLod_GoodFps then + Lifetime = Lifetime * 0.5 + end + end + local Debris = ents.CreateClientProp(Model) if not IsValid(Debris) then return end - local Lifetime = DebrisLife:GetFloat() * math.Rand(0.5, 1) - Debris:SetPos(Position) Debris:SetAngles(Angles) Debris:SetMaterial(Material) Debris:SetColor(Color) - if not CollideAll:GetBool() then - Debris:SetCollisionGroup(COLLISION_GROUP_WORLD) + if not DoCollideAll then + Debris:SetCollisionGroup(COLLISION_GROUP_WORLD) -- disable collisions end Debris:Spawn() - Debris.EmberParticle = Particle(Debris, "embers_medium_01") + if DoParticles then + Debris.EmberParticle = Particle(Debris, "embers_medium_01") - if ShouldIgnite and math.Rand(0, 0.5) < ACF.DebrisIgniteChance then - Ignite(Debris, Lifetime) - else - Debris.SmokeParticle = Particle(Debris, "smoke_exhaust_01a") + if AllowIgnite and math.Rand(0, 0.5) < ACF.DebrisIgniteChance then + Ignite(Debris, Lifetime) + elseif AllowSmoke then + Debris.SmokeParticle = Particle(Debris, "smoke_exhaust_01a") + end end local PhysObj = Debris:GetPhysicsObject() @@ -98,12 +135,31 @@ local function CreateDebris(Model, Position, Angles, Material, Color, Normal, Po return Debris end -local function CreateGib(Position, Angles, Material, Color, Normal, Power, Min, Max) +local function CreateGib(Position, Angles, Material, Color, Normal, Power, Min, Max, AutoLOD) + local DoParticles = true + local AllowIgnite = true + local Lifetime = GibLife:GetFloat() * math.Rand(0.5, 1) + if AutoLOD then + local FPS = 1 / RealFrameTime() + if FPS < AutoLod_ReallyBadFps then + if FPS < math.random(0, AutoLod_ReallyBadFps) then return end + DoParticles = false + Lifetime = Lifetime * math.Rand(0.01, 0.1) + elseif FPS < AutoLod_LowFps then + DoParticles = math.random(0, 100) < 50 + AllowIgnite = math.random(0, 100) < 15 + Lifetime = Lifetime * math.Rand(0.1, 0.25) + elseif FPS < AutoLod_OkayFps then + AllowIgnite = math.random(0, 100) < 50 + Lifetime = Lifetime * math.Rand(0.25, 0.5) + elseif FPS <= AutoLod_GoodFps then + Lifetime = Lifetime * 0.5 + end + end local Gib = ents.CreateClientProp(GibModel:format(math.random(1, 5))) if not IsValid(Gib) then return end - local Lifetime = GibLife:GetFloat() * math.Rand(0.5, 1) local Offset = ACF.RandomVector(Min, Max) Offset:Rotate(Angles) @@ -115,10 +171,12 @@ local function CreateGib(Position, Angles, Material, Color, Normal, Power, Min, Gib:SetColor(Color) Gib:Spawn() - Gib.SmokeParticle = Particle(Gib, "smoke_gib_01") + if DoParticles then + Gib.SmokeParticle = Particle(Gib, "smoke_gib_01") - if math.random() < ACF.DebrisIgniteChance then - Ignite(Gib, Lifetime, true) + if AllowIgnite and math.random() < ACF.DebrisIgniteChance then + Ignite(Gib, Lifetime, true) + end end local PhysObj = Gib:GetPhysicsObject() @@ -138,7 +196,9 @@ function ACF.CreateDebris(Model, Position, Angles, Material, Color, Normal, Powe if not AllowDebris:GetBool() then return end if not Model then return end - local Debris = CreateDebris(Model, Position, Angles, Material, Color, Normal, Power, CanGib, Ignite) + local AutoLOD = AutoLod:GetBool() + + local Debris = CreateDebris(Model, Position, Angles, Material, Color, Normal, Power, CanGib, Ignite, AutoLOD) if IsValid(Debris) then local Multiplier = GibMult:GetFloat() @@ -148,9 +208,13 @@ function ACF.CreateDebris(Model, Position, Angles, Material, Color, Normal, Powe if CanGib and Multiplier > 0 then local GibCount = math.Clamp(Radius * 0.1, 1, math.max(10 * Multiplier, 1)) + if AutoLOD then + local FPS = 1 / RealFrameTime() + GibCount = math.Clamp(GibCount, 0, FPS * 0.5) + end for _ = 1, GibCount do - if not CreateGib(Position, Angles, Material, Color, Normal, Power, Min, Max) then + if not CreateGib(Position, Angles, Material, Color, Normal, Power, Min, Max, AutoLOD) then break end end diff --git a/lua/acf/menu/items_cl/settings.lua b/lua/acf/menu/items_cl/settings.lua index f3c92702..142ab9f3 100644 --- a/lua/acf/menu/items_cl/settings.lua +++ b/lua/acf/menu/items_cl/settings.lua @@ -103,6 +103,9 @@ do -- Clientside settings local Debris = Base:AddCheckBox("#acf.menu.settings.debris.clientside") Debris:SetConVar("acf_debris") + local AutoLod = Base:AddCheckBox("#acf.menu.settings.debris.autolod") + AutoLod:SetConVar("acf_debris_autolod") + local Collisions = Base:AddCheckBox("#acf.menu.settings.debris.collision") Collisions:SetConVar("acf_debris_collision") diff --git a/resource/localization/en/acf_menu_settings.properties b/resource/localization/en/acf_menu_settings.properties index 8a95956e..f9d239cf 100644 --- a/resource/localization/en/acf_menu_settings.properties +++ b/resource/localization/en/acf_menu_settings.properties @@ -48,6 +48,8 @@ acf.menu.settings.debris=Debris acf.menu.settings.debris.clientside=Allow creation of clientside debris. +acf.menu.settings.debris.autolod=Cheaper debris when FPS is low. + acf.menu.settings.debris.collision=Allow debris to collide with entities. acf.menu.settings.debris.collision_desc=Disabling this can prevent certain types of spam-induced lag and crashes.