From 70bb9550e0faa94662786d69897a3a7220ed80dd Mon Sep 17 00:00:00 2001 From: thecraftianman <64441307+thecraftianman@users.noreply.github.com> Date: Thu, 2 Nov 2023 17:38:49 -0400 Subject: [PATCH 1/2] Add new sound library - Added a new sound library to network sounds to the client - Replaced all instances of sound playing with sound library uses - Fully clientsided all sounds - Removed the serverside volume setting - Added a volume setting to the sound replacer tool (controlled by acfsound_volume) - Added sound pitch settings to guns and sound volume settings to guns/engines - Moved the function ACF.IsValidSound to ACF.Utilities.Sounds.IsValidSound --- lua/acf/core/utilities/sounds/sounds_cl.lua | 116 ++++++++++++++++++++ lua/acf/core/utilities/sounds/sounds_sv.lua | 57 ++++++++++ lua/acf/core/utilities/util_cl.lua | 24 +--- lua/acf/entities/ammo_types/refill.lua | 11 +- lua/acf/menu/data_callbacks.lua | 9 -- lua/acf/menu/items_cl/settings.lua | 18 +-- lua/effects/acf_explosion.lua | 6 +- lua/effects/acf_muzzle_flash.lua | 12 +- lua/effects/acf_penetration.lua | 3 +- lua/effects/acf_ricochet.lua | 3 +- lua/entities/acf_ammo/init.lua | 3 +- lua/entities/acf_engine/init.lua | 42 ++++--- lua/entities/acf_fueltank/init.lua | 9 +- lua/entities/acf_gearbox/init.lua | 6 +- lua/entities/acf_gun/init.lua | 21 ++-- lua/entities/acf_piledriver/init.lua | 7 +- lua/weapons/acf_base/init.lua | 5 +- lua/weapons/acf_torch/shared.lua | 29 +++-- lua/weapons/gmod_tool/stools/acfsound.lua | 107 ++++++++++++------ 19 files changed, 343 insertions(+), 145 deletions(-) create mode 100644 lua/acf/core/utilities/sounds/sounds_cl.lua create mode 100644 lua/acf/core/utilities/sounds/sounds_sv.lua diff --git a/lua/acf/core/utilities/sounds/sounds_cl.lua b/lua/acf/core/utilities/sounds/sounds_cl.lua new file mode 100644 index 000000000..963045e45 --- /dev/null +++ b/lua/acf/core/utilities/sounds/sounds_cl.lua @@ -0,0 +1,116 @@ +local Sounds = ACF.Utilities.Sounds + +do -- Valid sound check + local file = file + local isstring = isstring + local Folder = "sound/%s" + local ValidSounds = {} + + function Sounds.IsValidSound(Name) + if not isstring(Name) then return false end + + local Path = Folder:format(Name:Trim()) + local Valid = ValidSounds[Path] + + if Valid == nil then + Valid = file.Exists(Path, "GAME") + + ValidSounds[Path] = Valid + end + + return Valid + end +end + +do -- Playing regular sounds + function Sounds.PlaySound(Origin, Path, Level, Pitch, Volume) + Volume = ACF.Volume * Volume + + if isentity(Origin) and IsValid(Origin) then + Origin:EmitSound(Path, Level, Pitch, Volume) + elseif isvector(Origin) then + sound.Play(Path, Origin, Level, Pitch, Volume) + end + end + + net.Receive("ACF_Sounds", function() + local IsEnt = net.ReadBool() + local Origin = IsEnt and net.ReadEntity() or net.ReadVector() + local Path = net.ReadString() + local Level = net.ReadUInt(7) + local Pitch = net.ReadUInt(8) + local Volume = net.ReadFloat() + + if not Sounds.IsValidSound(Path) then return end + + Sounds.PlaySound(Origin, Path, Level, Pitch, Volume) + end) +end + +do -- Processing adjustable sounds (for example, engine noises) + local IsValid = IsValid + + function Sounds.UpdateAdjustableSound(Origin, Pitch, Volume) + if not IsValid(Origin) then return end + + local Sound = Origin.Sound + if not Sound then return end + + Volume = Volume * ACF.Volume + + if Sound:IsPlaying() then + Sound:ChangePitch(Pitch, 0) + Sound:ChangeVolume(Volume, 0) + else + Sound:PlayEx(Volume, Pitch) + end + end + + function Sounds.CreateAdjustableSound(Origin, Path, Pitch, Volume) + if not IsValid(Origin) then return end + if Origin.Sound then return end + + local Sound = CreateSound(Origin, Path) + Origin.Sound = Sound + + -- Ensuring that the sound can't stick around if the server doesn't properly ask for it to be destroyed + Origin:CallOnRemove("ACF_ForceStopAdjustableSound", function(Entity) + Sounds.DestroyAdjustableSound(Entity) + end) + + Sounds.UpdateAdjustableSound(Origin, Pitch, Volume) + end + + function Sounds.DestroyAdjustableSound(Origin) + local Current = Origin.Sound + if not Current then return end + + Current:Stop() + Origin.Sound = nil + end + + net.Receive("ACF_Sounds_Adjustable", function() + local Origin = net.ReadEntity() + local ShouldStop = net.ReadBool() + + if ShouldStop then + Sounds.DestroyAdjustableSound(Origin) + else + local Pitch = net.ReadUInt(8) + local Volume = net.ReadFloat() + + Sounds.UpdateAdjustableSound(Origin, Pitch, Volume) + end + end) + + net.Receive("ACF_Sounds_AdjustableCreate", function() + local Origin = net.ReadEntity() + local Path = net.ReadString() + local Pitch = net.ReadUInt(8) + local Volume = net.ReadFloat() + + if not Sounds.IsValidSound(Path) then return end + + Sounds.CreateAdjustableSound(Origin, Path, Pitch, Volume) + end) +end \ No newline at end of file diff --git a/lua/acf/core/utilities/sounds/sounds_sv.lua b/lua/acf/core/utilities/sounds/sounds_sv.lua new file mode 100644 index 000000000..1099045a5 --- /dev/null +++ b/lua/acf/core/utilities/sounds/sounds_sv.lua @@ -0,0 +1,57 @@ +local Sounds = ACF.Utilities.Sounds + +util.AddNetworkString("ACF_Sounds") +util.AddNetworkString("ACF_Sounds_Adjustable") +util.AddNetworkString("ACF_Sounds_AdjustableCreate") + +function Sounds.SendSound(Origin, Path, Level, Pitch, Volume) + if not IsValid(Origin) then return end + + local IsEnt = isentity(Origin) + local Pos + + -- Set default Gmod level/pitch values if not present + Level = Level or 75 + Pitch = Pitch or 100 + + net.Start("ACF_Sounds") + net.WriteBool(IsEnt) + if IsEnt then + net.WriteEntity(Origin) + Pos = Origin:GetPos() + else + net.WriteVector(Origin) + Pos = Origin + end + net.WriteString(Path) + net.WriteUInt(Level, 7) + net.WriteUInt(Pitch, 8) + net.WriteFloat(Volume) + net.SendPAS(Pos) +end + +function Sounds.CreateAdjustableSound(Origin, Path, Pitch, Volume) + if not IsValid(Origin) then return end + + net.Start("ACF_Sounds_AdjustableCreate") + net.WriteEntity(Origin) + net.WriteString(Path) + net.WriteUInt(Pitch, 8) + net.WriteFloat(Volume) + net.SendPAS(Origin:GetPos()) +end + +function Sounds.SendAdjustableSound(Origin, ShouldStop, Pitch, Volume) + if not IsValid(Origin) then return end + + ShouldStop = ShouldStop or false + + net.Start("ACF_Sounds_Adjustable") + net.WriteEntity(Origin) + net.WriteBool(ShouldStop) + if not ShouldStop then + net.WriteUInt(Pitch, 8) + net.WriteFloat(Volume) + end + net.SendPAS(Origin:GetPos()) +end \ No newline at end of file diff --git a/lua/acf/core/utilities/util_cl.lua b/lua/acf/core/utilities/util_cl.lua index 72bf79665..16fa152ac 100644 --- a/lua/acf/core/utilities/util_cl.lua +++ b/lua/acf/core/utilities/util_cl.lua @@ -74,28 +74,6 @@ do -- Panel helpers end end -do -- Valid sound check - local file = file - local isstring = isstring - local Folder = "sound/%s" - local Sounds = {} - - function ACF.IsValidSound(Name) - if not isstring(Name) then return false end - - local Path = Folder:format(Name:Trim()) - local Valid = Sounds[Path] - - if Valid == nil then - Valid = file.Exists(Path, "GAME") - - Sounds[Path] = Valid - end - - return Valid - end -end - do -- Default gearbox menus local Values = {} @@ -473,4 +451,4 @@ do -- Default gearbox menus end end end -end +end \ No newline at end of file diff --git a/lua/acf/entities/ammo_types/refill.lua b/lua/acf/entities/ammo_types/refill.lua index db3bf8e1c..e4d774501 100644 --- a/lua/acf/entities/ammo_types/refill.lua +++ b/lua/acf/entities/ammo_types/refill.lua @@ -1,6 +1,7 @@ -local ACF = ACF -local Types = ACF.Classes.AmmoTypes -local Ammo = Types.Register("Refill", "AP") +local ACF = ACF +local Types = ACF.Classes.AmmoTypes +local Sounds = ACF.Utilities.Sounds +local Ammo = Types.Register("Refill", "AP") function Ammo:OnLoaded() @@ -93,8 +94,8 @@ if SERVER then Crate:Consume(-Transfer) Refill:Consume(Transfer) - Crate:EmitSound("items/ammo_pickup.wav", 70, 100, 0.5 * ACF.Volume) - Refill:EmitSound("items/ammo_pickup.wav", 70, 100, 0.5 * ACF.Volume) + Sounds.SendSound(Crate, "items/ammo_pickup.wav", 70, 100, 0.5) + Sounds.SendSound(Refill, "items/ammo_pickup.wav", 70, 100, 0.5) elseif Refill.SupplyingTo[Crate] then Refill.SupplyingTo[Crate] = nil diff --git a/lua/acf/menu/data_callbacks.lua b/lua/acf/menu/data_callbacks.lua index 5465d993f..96acec860 100644 --- a/lua/acf/menu/data_callbacks.lua +++ b/lua/acf/menu/data_callbacks.lua @@ -175,13 +175,4 @@ local Settings = { for Key, Function in pairs(Settings) do ACF.AddServerDataCallback(Key, "Global Variable Callback", Function) -end - -do -- Volume setting callback - local Realm = SERVER and "Server" or "Client" - local Callback = ACF["Add" .. Realm .. "DataCallback"] - - Callback("Volume", "Volume Variable Callback", function(_, _, Value) - ACF.Volume = math.Clamp(tonumber(Value) or 1, 0, 1) - end) end \ No newline at end of file diff --git a/lua/acf/menu/items_cl/settings.lua b/lua/acf/menu/items_cl/settings.lua index 5604cb8fa..db1858ff9 100644 --- a/lua/acf/menu/items_cl/settings.lua +++ b/lua/acf/menu/items_cl/settings.lua @@ -51,12 +51,14 @@ do -- Clientside settings local Volume = Base:AddSlider("Client Sound Volume", 0, 1, 2) Volume:SetClientData("Volume", "OnValueChanged") Volume:DefineSetter(function(Panel, _, _, Value) + Value = math.Clamp(tonumber(Value) or 1, 0, 1) + Panel:SetValue(Value) + ACF.Volume = Value + return Value end) - - Base:AddHelp("For the moment, this will only affect sounds that are played from the clientside.") end) ACF.AddClientSettings(101, "Effects and Visual Elements", function(Base) @@ -196,18 +198,6 @@ do -- Serverside settings end) end) - ACF.AddServerSettings(100, "Sound Volume", function(Base) - local Volume = Base:AddSlider("Server Sound Volume", 0, 1, 2) - Volume:SetServerData("Volume", "OnValueChanged") - Volume:DefineSetter(function(Panel, _, _, Value) - Panel:SetValue(Value) - - return Value - end) - - Base:AddHelp("Will affect a handful of sounds that are played from the serverside. This will be deprecated in the future.") - end) - ACF.AddServerSettings(101, "Entity Pushing", function(Base) local HEPush = Base:AddCheckBox("Push entities due to HE forces.") HEPush:SetServerData("HEPush", "OnChange") diff --git a/lua/effects/acf_explosion.lua b/lua/effects/acf_explosion.lua index 86caff1c4..88e719a78 100644 --- a/lua/effects/acf_explosion.lua +++ b/lua/effects/acf_explosion.lua @@ -2,6 +2,7 @@ local TraceData = { start = true, endpos = true, mask = MASK_SOLID } local TraceLine = util.TraceLine local GetIndex = ACF.GetAmmoDecalIndex local GetDecal = ACF.GetRicochetDecal +local Sounds = ACF.Utilities.Sounds local White = Color(255, 255, 255) local Yellow = Color(255, 255, 0) @@ -60,10 +61,9 @@ end function EFFECT:Core(Origin, Radius) local Pitch = math.Clamp(123 - Radius * 3, 60, 120) - local Volume = ACF.Volume - sound.Play("ambient/explosions/explode_9.wav", Origin, 105, Pitch, Volume) - sound.Play("ambient/levels/streetwar/city_battle19.wav", Origin, 105, Pitch, Volume) + Sounds.PlaySound(Origin, "ambient/explosions/explode_9.wav", 105, Pitch, 1) + Sounds.PlaySound(Origin, "ambient/levels/streetwar/city_battle19.wav", 105, Pitch, 1) end function EFFECT:GroundImpact(Emitter, Origin, Radius, HitNormal, SmokeColor, Mult) diff --git a/lua/effects/acf_muzzle_flash.lua b/lua/effects/acf_muzzle_flash.lua index 5d2eebbd7..b634d26d0 100644 --- a/lua/effects/acf_muzzle_flash.lua +++ b/lua/effects/acf_muzzle_flash.lua @@ -1,4 +1,5 @@ local Weapons = ACF.Classes.Weapons +local Sounds = ACF.Utilities.Sounds function EFFECT:Init(Data) local Gun = Data:GetEntity() @@ -8,6 +9,8 @@ function EFFECT:Init(Data) local Propellant = Data:GetScale() local ReloadTime = Data:GetMagnitude() local Sound = Gun:GetNWString("Sound") + local Pitch = Gun:GetNWString("SoundPitch") + local Volume = Gun:GetNWString("SoundVolume") local Class = Gun:GetNWString("Class") local ClassData = Weapons.Get(Class) if not ClassData then return end @@ -18,7 +21,7 @@ function EFFECT:Init(Data) Attachment = LongBarrel.NewPos end - if not ACF.IsValidSound(Sound) then + if not Sounds.IsValidSound(Sound) then Sound = ClassData.Sound end @@ -27,15 +30,16 @@ function EFFECT:Init(Data) if Sound ~= "" then local SoundPressure = (Propellant * 1000) ^ 0.5 + Pitch = math.Clamp(Pitch * 100, 1, 255) -- NOTE: Wiki documents level tops out at 180, but seems to fall off past 127 - sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100, ACF.Volume) + Sounds.PlaySound(GunPos, Sound, math.Clamp(SoundPressure, 75, 127), Pitch, Volume) if not (Class == "MG" or Class == "RAC") then - sound.Play(Sound, GunPos, math.Clamp(SoundPressure, 75, 127), 100, ACF.Volume) + Sounds.PlaySound(GunPos, Sound, math.Clamp(SoundPressure, 75, 127), Pitch, Volume) if SoundPressure > 127 then - sound.Play(Sound, GunPos, math.Clamp(SoundPressure - 127, 1, 127), 100, ACF.Volume) + Sounds.PlaySound(GunPos, Sound, math.Clamp(SoundPressure - 127, 1, 127), Pitch, Volume) end end end diff --git a/lua/effects/acf_penetration.lua b/lua/effects/acf_penetration.lua index d7f0d07bf..9e22badba 100644 --- a/lua/effects/acf_penetration.lua +++ b/lua/effects/acf_penetration.lua @@ -3,6 +3,7 @@ local TraceLine = util.TraceLine local ValidDecal = ACF.IsValidAmmoDecal local GetDecal = ACF.GetPenetrationDecal local GetScale = ACF.GetDecalScale +local Sounds = ACF.Utilities.Sounds local Sound = "acf_base/fx/penetration%s.mp3" local White = Color(255, 255, 255) @@ -38,7 +39,7 @@ function EFFECT:Init(Data) util.DecalEx(GetDecal(Type), Trace.Entity, Trace.HitPos, HitNormal, White, Size, Size) end - sound.Play(Sound:format(math.random(1, 6)), Trace.HitPos, Level, Pitch, ACF.Volume) + Sounds.PlaySound(Trace.HitPos, Sound:format(math.random(1, 6)), Level, Pitch, 1) end function EFFECT:Metal(Emitter, Origin, Scale, HitNormal) diff --git a/lua/effects/acf_ricochet.lua b/lua/effects/acf_ricochet.lua index 86a9e730f..41425b2b2 100644 --- a/lua/effects/acf_ricochet.lua +++ b/lua/effects/acf_ricochet.lua @@ -3,6 +3,7 @@ local TraceLine = util.TraceLine local ValidDecal = ACF.IsValidAmmoDecal local GetDecal = ACF.GetRicochetDecal local GetScale = ACF.GetDecalScale +local Sounds = ACF.Utilities.Sounds local Sound = "acf_base/fx/ricochet%s.mp3" function EFFECT:Init(Data) @@ -28,7 +29,7 @@ function EFFECT:Init(Data) local Level = math.Clamp(Mass * 200, 65, 500) local Pitch = math.Clamp(Velocity * 0.01, 25, 255) - sound.Play(Sound:format(math.random(1, 4)), Origin, Level, Pitch, ACF.Volume) + Sounds.PlaySound(Origin, Sound:format(math.random(1, 4)), Level, Pitch, 1) end function EFFECT:Think() diff --git a/lua/entities/acf_ammo/init.lua b/lua/entities/acf_ammo/init.lua index 4fc673bc2..c5b266011 100644 --- a/lua/entities/acf_ammo/init.lua +++ b/lua/entities/acf_ammo/init.lua @@ -419,6 +419,7 @@ end --------------------------------------------- do -- ACF Activation and Damage ----------------- local Clock = Utilities.Clock + local Sounds = Utilities.Sounds local Damage = ACF.Damage local Objects = Damage.Objects @@ -438,7 +439,7 @@ do -- ACF Activation and Damage ----------------- local Speed = ACF.MuzzleVelocity(BulletData.PropMass, BulletData.ProjMass * 0.5, BulletData.Efficiency) local Pitch = math.max(255 - BulletData.PropMass * 100,60) - Entity:EmitSound("ambient/explosions/explode_4.wav", 140, Pitch, ACF.Volume) + Sounds.SendSound(Entity, "ambient/explosions/explode_4.wav", 140, Pitch, 1) BulletData.Pos = Entity:LocalToWorld(Entity:OBBCenter() + VectorRand() * Entity:GetSize() * 0.5) BulletData.Flight = VectorRand():GetNormalized() * Speed * 39.37 + ACF_GetAncestor(Entity):GetVelocity() diff --git a/lua/entities/acf_engine/init.lua b/lua/entities/acf_engine/init.lua index 3871d0c81..f0b363f3a 100644 --- a/lua/entities/acf_engine/init.lua +++ b/lua/entities/acf_engine/init.lua @@ -106,6 +106,7 @@ end local Damage = ACF.Damage local Utilities = ACF.Utilities local Clock = Utilities.Clock +local Sounds = Utilities.Sounds local MaxDistance = ACF.LinkDistance * ACF.LinkDistance local UnlinkSound = "physics/metal/metal_box_impact_bullet%s.wav" local IsValid = IsValid @@ -125,7 +126,7 @@ local function GetPitchVolume(Engine) local Throttle = Engine.RevLimited and 0 or Engine.Throttle local Volume = 0.25 + (0.1 + 0.9 * ((RPM / Engine.LimitRPM) ^ 1.5)) * Throttle * 0.666 - return Pitch, Volume * ACF.Volume + return Pitch, Volume * Engine.SoundVolume end local function GetNextFuelTank(Engine) @@ -150,8 +151,8 @@ local function CheckDistantFuelTanks(Engine) if EnginePos:DistToSqr(Tank:GetPos()) > MaxDistance then local Sound = UnlinkSound:format(math.random(1, 3)) - Engine:EmitSound(Sound, 70, 100, ACF.Volume) - Tank:EmitSound(Sound, 70, 100, ACF.Volume) + Sounds.SendSound(Engine, Sound, 70, 100, 1) + Sounds.SendSound(Tank, Sound, 70, 100, 1) Engine:Unlink(Tank) end @@ -289,6 +290,7 @@ do -- Spawn and Update functions Entity.ClassData = Class Entity.DefaultSound = Engine.Sound Entity.SoundPitch = Engine.Pitch or 1 + Entity.SoundVolume = Engine.SoundVolume or 1 Entity.TorqueCurve = Engine.TorqueCurve Entity.PeakTorque = Engine.Torque Entity.PeakPower = Engine.PeakPower @@ -593,36 +595,30 @@ function ENT:UpdateSound() end if Path == "" then return end - - local Sound = self.Sound - - if not Sound then - Sound = CreateSound(self, Path) - - self.Sound = Sound - end - if not self.Active then return end local Pitch, Volume = GetPitchVolume(self) - if Sound:IsPlaying() then - Sound:ChangePitch(Pitch, 0) - Sound:ChangeVolume(Volume, 0) + if Pitch == self.LastPitch or Volume == self.LastVolume then return end + + self.LastPitch = Pitch + self.LastVolume = Volume + + if self.Sound then + Sounds.SendAdjustableSound(self, false, Pitch, Volume) else - Sound:PlayEx(Volume, Pitch) + Sounds.CreateAdjustableSound(self, Path, Pitch, Volume) + self.Sound = true end end function ENT:DestroySound() - local Current = self.Sound - - if Current then - Current:Stop() - end + Sounds.SendAdjustableSound(self, true) - self.LastSound = nil - self.Sound = nil + self.LastSound = nil + self.LastPitch = nil + self.LastVolume = nil + self.Sound = nil end -- specialized calcmassratio for engines diff --git a/lua/entities/acf_fueltank/init.lua b/lua/entities/acf_fueltank/init.lua index 68963c0e5..b54f2a8c2 100644 --- a/lua/entities/acf_fueltank/init.lua +++ b/lua/entities/acf_fueltank/init.lua @@ -12,6 +12,7 @@ local Objects = Damage.Objects local ActiveTanks = ACF.FuelTanks local Utilities = ACF.Utilities local Clock = Utilities.Clock +local Sounds = Utilities.Sounds local RefillDist = ACF.RefillDistance * ACF.RefillDistance local TimerCreate = timer.Create local TimerExists = timer.Exists @@ -467,11 +468,11 @@ function ENT:Think() Tank:Consume(-Exchange) if self.FuelType == "Electric" then - self:EmitSound("ambient/energy/newspark04.wav", 70, 100, 0.5 * ACF.Volume) - Tank:EmitSound("ambient/energy/newspark04.wav", 70, 100, 0.5 * ACF.Volume) + Sounds.SendSound(self, "ambient/energy/newspark04.wav", 70, 100, 0.5) + Sounds.SendSound(Tank, "ambient/energy/newspark04.wav", 70, 100, 0.5) else - self:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5 * ACF.Volume) - Tank:EmitSound("vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5 * ACF.Volume) + Sounds.SendSound(self, "vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5) + Sounds.SendSound(Tank, "vehicles/jetski/jetski_no_gas_start.wav", 70, 120, 0.5) end end end diff --git a/lua/entities/acf_gearbox/init.lua b/lua/entities/acf_gearbox/init.lua index 554b08381..b5cfb52eb 100644 --- a/lua/entities/acf_gearbox/init.lua +++ b/lua/entities/acf_gearbox/init.lua @@ -700,6 +700,8 @@ do -- Overlay Text ------------------------------------- end ---------------------------------------------------- do -- Gear Shifting ------------------------------------ + local Sounds = Utilities.Sounds + -- Handles gearing for automatic gearboxes. 0 = Neutral, 1 = Drive, 2 = Reverse function ENT:ChangeDrive(Value) Value = Clamp(math.floor(Value), 0, 2) @@ -721,8 +723,8 @@ do -- Gear Shifting ------------------------------------ self.GearRatio = self.Gears[Value] * self.FinalDrive self.ChangeFinished = Clock.CurTime + self.SwitchTime - if self.SoundPath ~= "" and file.Exists("sound/" .. self.SoundPath, "GAME") then - self:EmitSound(self.SoundPath, 70, 100, 0.5 * ACF.Volume) + if self.SoundPath ~= "" then + Sounds.SendSound(self, self.SoundPath, 70, 100, 0.5) end WireLib.TriggerOutput(self, "Current Gear", Value) diff --git a/lua/entities/acf_gun/init.lua b/lua/entities/acf_gun/init.lua index fff8fa019..44e9a32dc 100644 --- a/lua/entities/acf_gun/init.lua +++ b/lua/entities/acf_gun/init.lua @@ -10,6 +10,7 @@ local Classes = ACF.Classes local AmmoTypes = Classes.AmmoTypes local Utilities = ACF.Utilities local Clock = Utilities.Clock +local Sounds = Utilities.Sounds local TimerCreate = timer.Create local HookRun = hook.Run local EMPTY = { Type = "Empty", PropMass = 0, ProjMass = 0, Tracer = 0 } @@ -96,12 +97,12 @@ do -- Spawn and Update functions -------------------------------- local function GetSound(Caliber, Class, Weapon) local Result = Weapon and Weapon.Sound or Class.Sound - local Sounds = Class.Sounds + local ClassSounds = Class.Sounds - if Sounds then + if ClassSounds then local Lowest = math.huge - for Current, Sound in pairs(Sounds) do + for Current, Sound in pairs(ClassSounds) do if Caliber <= Current and Current <= Lowest then Lowest = Current Result = Sound @@ -152,6 +153,8 @@ do -- Spawn and Update functions -------------------------------- Entity.Spread = Class.Spread Entity.DefaultSound = GetSound(Caliber, Class) Entity.SoundPath = Entity.SoundPath or Entity.DefaultSound + Entity.SoundPitch = Entity.SoundPitch or 1 + Entity.SoundVolume = Entity.SoundVolume or 1 Entity.HitBoxes = ACF.GetHitboxes(Model, Scale) Entity.Long = Class.LongBarrel Entity.NormalMuzzle = Entity:WorldToLocal(Entity:GetAttachment(Entity:LookupAttachment("muzzle")).Pos) @@ -163,6 +166,8 @@ do -- Spawn and Update functions -------------------------------- -- Set NWvars Entity:SetNWString("WireName", "ACF " .. Entity.Name) Entity:SetNWString("Sound", Entity.SoundPath) + Entity:SetNWString("SoundPitch", Entity.SoundPitch) + Entity:SetNWString("SoundVolume", Entity.SoundVolume) Entity:SetNWString("Class", Entity.Class) -- Adjustable barrel length @@ -464,7 +469,7 @@ do -- Metamethods -------------------------------- if self.State ~= "Loaded" then -- Weapon is not loaded if self.State == "Empty" and not self.Retry then if not self:Load() then - self:EmitSound("weapons/pistol/pistol_empty.wav", 70, 100, ACF.Volume) -- Click! + Sounds.SendSound(self, "weapons/pistol/pistol_empty.wav", 70, 100, 1) -- Click! end self.Retry = true @@ -598,7 +603,7 @@ do -- Metamethods -------------------------------- self:ReloadEffect(Reload and Time * 2 or Time) self:SetState("Unloading") - self:EmitSound("weapons/357/357_reload4.wav", 70, 100, ACF.Volume) + Sounds.SendSound(self, "weapons/357/357_reload4.wav", 70, 100, 1) self.CurrentShot = 0 self.BulletData = EMPTY @@ -686,7 +691,7 @@ do -- Metamethods -------------------------------- self:SetState("Loading") if self.MagReload then -- Mag-fed/Automatically loaded - self:EmitSound("weapons/357/357_reload4.wav", 70, 100, ACF.Volume) + Sounds.SendSound(self, "weapons/357/357_reload4.wav", 70, 100, 1) self.NextFire = Clock.CurTime + self.MagReload @@ -814,8 +819,8 @@ do -- Metamethods -------------------------------- if Crate:GetPos():DistToSqr(Pos) > MaxDistance then local Sound = UnlinkSound:format(math.random(1, 3)) - Crate:EmitSound(Sound, 70, 100, ACF.Volume) - self:EmitSound(Sound, 70, 100, ACF.Volume) + Sounds.SendSound(Crate, Sound, 70, 100, 1) + Sounds.SendSound(self, Sound, 70, 100, 1) self:Unlink(Crate) end diff --git a/lua/entities/acf_piledriver/init.lua b/lua/entities/acf_piledriver/init.lua index 4152ed207..4c662480d 100644 --- a/lua/entities/acf_piledriver/init.lua +++ b/lua/entities/acf_piledriver/init.lua @@ -315,6 +315,7 @@ do -- Entity Overlay ---------------------------- end --------------------------------------------- do -- Firing ------------------------------------ + local Sounds = ACF.Utilities.Sounds local Impact = "physics/metal/metal_barrel_impact_hard%s.wav" -- The entity won't even attempt to shoot if this function returns false @@ -343,8 +344,8 @@ do -- Firing ------------------------------------ local Sound = self.SoundPath or Impact:format(math.random(5, 6)) local Bullet = self.BulletData - if Sound ~= "" and file.Exists("sound/" .. Sound, "GAME") then - self:EmitSound(Sound, 70, math.Rand(98, 102), ACF.Volume) + if Sound ~= "" then + Sounds.SendSound(self, Sound, 70, math.Rand(98, 102), 1) end self:SetSequence("load") @@ -365,7 +366,7 @@ do -- Firing ------------------------------------ self:SetSequence("idle") end) else - self:EmitSound("weapons/pistol/pistol_empty.wav", 70, math.Rand(98, 102), ACF.Volume) + Sounds.SendSound(self, "weapons/pistol/pistol_empty.wav", 70, math.Rand(98, 102), 1) Delay = 1 end diff --git a/lua/weapons/acf_base/init.lua b/lua/weapons/acf_base/init.lua index 5de0bdb10..d012f415e 100644 --- a/lua/weapons/acf_base/init.lua +++ b/lua/weapons/acf_base/init.lua @@ -4,6 +4,7 @@ AddCSLuaFile("shared.lua") include("shared.lua") local AmmoTypes = ACF.Classes.AmmoTypes +local Sounds = ACF.Utilities.Sounds SWEP.AutoSwitchTo = false SWEP.AutoSwitchFrom = false @@ -30,7 +31,7 @@ end function SWEP:Reload() if (self:Clip1() < self.Primary.ClipSize and self:GetOwner():GetAmmoCount(self.Primary.Ammo) > 0) then - self:EmitSound("weapons/AMR/sniper_reload.wav", 70, 110, ACF.Volume) + Sounds.SendSound(self, "weapons/AMR/sniper_reload.wav", 70, 110, 1) self:DefaultReload(ACT_VM_RELOAD) end end @@ -49,7 +50,7 @@ end function SWEP:MuzzleEffect() local Owner = self:GetOwner() - self:EmitSound("weapons/AMR/sniper_fire.wav", nil, nil, ACF.Volume) + Sounds.SendSound(self, "weapons/AMR/sniper_fire.wav", nil, nil, 1) Owner:MuzzleFlash() Owner:SetAnimation(PLAYER_ATTACK1) diff --git a/lua/weapons/acf_torch/shared.lua b/lua/weapons/acf_torch/shared.lua index 3a97032b0..68e251749 100644 --- a/lua/weapons/acf_torch/shared.lua +++ b/lua/weapons/acf_torch/shared.lua @@ -3,6 +3,7 @@ AddCSLuaFile("shared.lua") local ACF = ACF local Clock = ACF.Utilities.Clock +local Sounds = ACF.Utilities.Sounds local Network = ACF.Networking local Damage = ACF.Damage local Objects = Damage.Objects @@ -114,7 +115,11 @@ end function SWEP:Deploy() self:SetCurrentAnim("none") -- Prevents nil anim value - self:EmitSound("ambient/energy/zap2.wav", nil, nil, ACF.Volume) + + if CLIENT then + Sounds.PlaySound(self, "ambient/energy/zap2.wav", nil, nil, 1) + end + return true end @@ -207,10 +212,14 @@ function SWEP:PrimaryAttack() self:SetAnim("fire_windup", true, 3) end self:SetAnim("fire_loop", true, 2) - self:EmitSound(Zap:format(math.random(1, 3)), nil, 115, ACF.Volume) self:SetNextPrimaryFire(Clock.CurTime + 0.05) - if CLIENT then return end + if CLIENT then + Sounds.PlaySound(self, Zap:format(math.random(1, 3)), nil, 115, 1) + + return + end + if self.LastDistance > self.MaxDistance then return end local Entity = self.LastEntity @@ -236,7 +245,7 @@ function SWEP:PrimaryAttack() Effect:SetEntity(self) util.Effect("thruster_ring", Effect, true, true) - Entity:EmitSound("items/medshot4.wav", nil, nil, ACF.Volume) + Sounds.SendSound(self, "items/medshot4.wav", nil, nil, 1) else local OldHealth = Entity.ACF.Health local MaxHealth = Entity.ACF.MaxHealth @@ -258,7 +267,7 @@ function SWEP:PrimaryAttack() Entity:ACF_OnRepaired(OldArmor, OldHealth, Armor, Health) end - Entity:EmitSound(Spark:format(math.random(3, 5)), nil, nil, ACF.Volume) + Sounds.SendSound(self, Spark:format(math.random(3, 5)), nil, nil, 1) TeslaSpark(Trace.HitPos, 1) end end @@ -270,10 +279,14 @@ function SWEP:SecondaryAttack() self:SetAnim("fire_windup", true, 3) end self:SetAnim("fire_loop", true, 2) - self:EmitSound(Zap:format(math.random(1, 2)), nil, nil, ACF.Volume) self:SetNextPrimaryFire(Clock.CurTime + 0.05) - if CLIENT then return end + if CLIENT then + Sounds.PlaySound(self, Zap:format(math.random(1, 2)), nil, nil, 1) + + return + end + if self.LastDistance > self.MaxDistance then return end local Entity = self.LastEntity @@ -321,7 +334,7 @@ function SWEP:SecondaryAttack() util.Effect("Sparks", Effect, true, true) - Entity:EmitSound(Zap:format(math.random(1, 4)), nil, nil, ACF.Volume) + Sounds.SendSound(Entity, Zap:format(math.random(1, 4)), nil, nil, 1) end end end diff --git a/lua/weapons/gmod_tool/stools/acfsound.lua b/lua/weapons/gmod_tool/stools/acfsound.lua index fdd71417a..ec8373b9d 100644 --- a/lua/weapons/gmod_tool/stools/acfsound.lua +++ b/lua/weapons/gmod_tool/stools/acfsound.lua @@ -3,60 +3,77 @@ TOOL.Category = cat TOOL.Name = "#Tool.acfsound.name" TOOL.Command = nil TOOL.ConfigName = "" -TOOL.ClientConVar["pitch"] = "1" +TOOL.ClientConVar["pitch"] = "1" +TOOL.ClientConVar["volume"] = "1" +TOOL.Information = { + { name = "left" }, + { name = "right" }, + { name = "reload" }, + { name = "info" } +} if CLIENT then language.Add("Tool.acfsound.name", "ACF Sound Replacer") - language.Add("Tool.acfsound.desc", "Change sound of guns/engines.") - language.Add("Tool.acfsound.0", "Left click to apply sound. Right click to copy sound. Reload to set default sound. Use an empty sound path to disable sound.") + language.Add("Tool.acfsound.desc", "Change sounds of ACF entities") + language.Add("Tool.acfsound.left", "Apply sound") + language.Add("Tool.acfsound.right", "Copy sound") + language.Add("Tool.acfsound.reload", "Set default sound") + language.Add("Tool.acfsound.0", "Use an empty sound path to disable sound") end ACF.SoundToolSupport = ACF.SoundToolSupport or {} local Sounds = ACF.SoundToolSupport -local Messages = ACF.Utilities.Messages Sounds.acf_gun = { GetSound = function(ent) return { - Sound = ent.SoundPath + Sound = ent.SoundPath, + Pitch = ent.SoundPitch, + Volume = ent.SoundVolume } end, SetSound = function(ent, soundData) - ent.SoundPath = soundData.Sound + ent.SoundPath = soundData.Sound + ent.SoundPitch = soundData.Pitch + ent.SoundVolume = soundData.Volume + ent:SetNWString("Sound", soundData.Sound) + ent:SetNWString("SoundPitch", soundData.Pitch) + ent:SetNWString("SoundVolume", soundData.Volume) end, ResetSound = function(ent) - ent.SoundPath = ent.DefaultSound + ent.SoundPath = ent.DefaultSound + ent.SoundPitch = 1 + ent.SoundVolume = 1 + ent:SetNWString("Sound", ent.DefaultSound) + ent:SetNWString("SoundPitch", 1) + ent:SetNWString("SoundVolume", 1) end } Sounds.acf_engine = { GetSound = function(ent) return { - Sound = ent.SoundPath, - Pitch = ent.SoundPitch + Sound = ent.SoundPath, + Pitch = ent.SoundPitch, + Volume = ent.SoundVolume } end, SetSound = function(ent, soundData) - local Sound = soundData.Sound:Trim():lower() - local Extension = string.GetExtensionFromFilename(Sound) - - if (Sound ~= "" and not Extension) or not file.Exists("sound/" .. Sound, "GAME") then - local Owner = ent:GetPlayer() + local Sound = soundData.Sound:Trim():lower() - return Messages.SendChat(Owner, "Error", "Couldn't change engine sound, does not exist on server: ", Sound) - end - - ent.SoundPath = Sound - ent.SoundPitch = soundData.Pitch + ent.SoundPath = Sound + ent.SoundPitch = soundData.Pitch + ent.SoundVolume = soundData.Volume ent:UpdateSound() end, ResetSound = function(ent) - ent.SoundPath = ent.DefaultSound - ent.SoundPitch = 1 + ent.SoundPath = ent.DefaultSound + ent.SoundPitch = 1 + ent.SoundVolume = 1 ent:UpdateSound() end @@ -90,16 +107,17 @@ local function ReplaceSound(_, Entity, Data) if not IsValid(Entity) then return end local Support = Sounds[Entity:GetClass()] - local Sound, Pitch = unpack(Data) + local Sound, Pitch, Volume = unpack(Data) if not Support then return end Support.SetSound(Entity, { - Sound = Sound, - Pitch = Pitch or 1, + Sound = Sound, + Pitch = Pitch or 1, + Volume = Volume or 1, }) - duplicator.StoreEntityModifier(Entity, "acf_replacesound", { Sound, Pitch or 1 }) + duplicator.StoreEntityModifier(Entity, "acf_replacesound", { Sound, Pitch or 1, Volume or 1 }) end duplicator.RegisterEntityModifier("acf_replacesound", ReplaceSound) @@ -125,25 +143,37 @@ end function TOOL:LeftClick(trace) if CLIENT then return true end - if not IsReallyValid(trace, self:GetOwner()) then return false end - local sound = self:GetOwner():GetInfo("wire_soundemitter_sound") - local pitch = self:GetOwner():GetInfo("acfsound_pitch") - ReplaceSound(self:GetOwner(), trace.Entity, {sound, pitch}) + + local owner = self:GetOwner() + + if not IsReallyValid(trace, owner) then return false end + local sound = owner:GetInfo("wire_soundemitter_sound") + local pitch = owner:GetInfo("acfsound_pitch") + local volume = owner:GetInfo("acfsound_volume") + + ReplaceSound(owner, trace.Entity, { sound, pitch, volume }) return true end function TOOL:RightClick(trace) if CLIENT then return true end - if not IsReallyValid(trace, self:GetOwner()) then return false end + + local owner = self:GetOwner() + + if not IsReallyValid(trace, owner) then return false end local class = trace.Entity:GetClass() local support = ACF.SoundToolSupport[class] if not support then return false end local soundData = support.GetSound(trace.Entity) - self:GetOwner():ConCommand("wire_soundemitter_sound " .. soundData.Sound) + owner:ConCommand("wire_soundemitter_sound " .. soundData.Sound) if soundData.Pitch then - self:GetOwner():ConCommand("acfsound_pitch " .. soundData.Pitch) + owner:ConCommand("acfsound_pitch " .. soundData.Pitch) + end + + if soundData.Volume then + owner:ConCommand("acfsound_volume " .. soundData.Volume) end return true @@ -205,7 +235,7 @@ function TOOL.BuildCPanel(panel) SoundPreStop:SetVisible(true) SoundPreStop.DoClick = function() - RunConsoleCommand("play", "common/NULL.wav") --Playing a silent sound will mute the preview but not the sound emitters. + RunConsoleCommand("play", "common/NULL.wav") -- Playing a silent sound will mute the preview but not the sound emitters. end panel:AddItem(SoundPre) @@ -224,7 +254,16 @@ function TOOL.BuildCPanel(panel) Type = "Float", Min = "0.1", Max = "2" - }):SetTooltip("Works only for engines.") + }):SetTooltip("Works only for guns and engines.") + + panel:AddControl("Slider", { + Label = "Volume:", + Command = "acfsound_volume", + Type = "Float", + Min = "0.1", + Max = "2" + }):SetTooltip("Works only for guns and engines.") + --[[ local SoundPitch = vgui.Create("DNumSlider") SoundPitch:SetMin( 0.1 ) From 4347c8a48bd2910c1a461a9423848c11ab053ae0 Mon Sep 17 00:00:00 2001 From: thecraftianman <64441307+thecraftianman@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:51:47 -0500 Subject: [PATCH 2/2] Attempt at ratelimiting certain spammy sounds --- lua/acf/core/utilities/sounds/sounds_sv.lua | 22 +++++++++++------ lua/weapons/acf_torch/shared.lua | 27 +++++++++++++++++++-- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/lua/acf/core/utilities/sounds/sounds_sv.lua b/lua/acf/core/utilities/sounds/sounds_sv.lua index 1099045a5..5ef5d67b9 100644 --- a/lua/acf/core/utilities/sounds/sounds_sv.lua +++ b/lua/acf/core/utilities/sounds/sounds_sv.lua @@ -45,13 +45,19 @@ function Sounds.SendAdjustableSound(Origin, ShouldStop, Pitch, Volume) if not IsValid(Origin) then return end ShouldStop = ShouldStop or false - - net.Start("ACF_Sounds_Adjustable") - net.WriteEntity(Origin) - net.WriteBool(ShouldStop) - if not ShouldStop then - net.WriteUInt(Pitch, 8) - net.WriteFloat(Volume) + local Time = CurTime() + Origin.ACF.SoundTimer = Origin.ACF.SoundTimer or Time + + -- Slowing down the rate of sending a bit + if Origin.ACF.SoundTimer <= Time or ShouldStop then + net.Start("ACF_Sounds_Adjustable") + net.WriteEntity(Origin) + net.WriteBool(ShouldStop) + if not ShouldStop then + net.WriteUInt(Pitch, 8) + net.WriteFloat(Volume) + end + net.SendPAS(Origin:GetPos()) + Origin.ACF.SoundTimer = Time + 0.1 end - net.SendPAS(Origin:GetPos()) end \ No newline at end of file diff --git a/lua/weapons/acf_torch/shared.lua b/lua/weapons/acf_torch/shared.lua index 68e251749..f82d9216f 100644 --- a/lua/weapons/acf_torch/shared.lua +++ b/lua/weapons/acf_torch/shared.lua @@ -245,7 +245,14 @@ function SWEP:PrimaryAttack() Effect:SetEntity(self) util.Effect("thruster_ring", Effect, true, true) - Sounds.SendSound(self, "items/medshot4.wav", nil, nil, 1) + -- Sound ratelimiting + local Time = CurTime() + self.SoundTimer = self.SoundTimer or Time + + if self.SoundTimer <= Time then + Sounds.SendSound(self, "items/medshot4.wav", nil, nil, 1) + self.SoundTimer = Time + 0.1 + end else local OldHealth = Entity.ACF.Health local MaxHealth = Entity.ACF.MaxHealth @@ -269,6 +276,15 @@ function SWEP:PrimaryAttack() Sounds.SendSound(self, Spark:format(math.random(3, 5)), nil, nil, 1) TeslaSpark(Trace.HitPos, 1) + + -- Sound ratelimiting + local Time = CurTime() + self.SoundTimer = self.SoundTimer or Time + + if self.SoundTimer <= Time then + Sounds.SendSound(self, Spark:format(math.random(3, 5)), nil, nil, 1) + self.SoundTimer = Time + 0.1 + end end end @@ -334,7 +350,14 @@ function SWEP:SecondaryAttack() util.Effect("Sparks", Effect, true, true) - Sounds.SendSound(Entity, Zap:format(math.random(1, 4)), nil, nil, 1) + -- Sound ratelimiting + local Time = CurTime() + self.SoundTimer = self.SoundTimer or Time + + if self.SoundTimer <= Time then + Sounds.SendSound(Entity, Zap:format(math.random(1, 4)), nil, nil, 1) + self.SoundTimer = Time + 0.1 + end end end end