Skip to content

Commit

Permalink
Merge pull request #378 from thecraftianman/sound-lib
Browse files Browse the repository at this point in the history
Add sound library + fully clientsided sounds
  • Loading branch information
thecraftianman authored Jan 19, 2024
2 parents b72f40c + 4347c8a commit 4e12cc3
Show file tree
Hide file tree
Showing 19 changed files with 372 additions and 145 deletions.
116 changes: 116 additions & 0 deletions lua/acf/core/utilities/sounds/sounds_cl.lua
Original file line number Diff line number Diff line change
@@ -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
63 changes: 63 additions & 0 deletions lua/acf/core/utilities/sounds/sounds_sv.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
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
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
end
24 changes: 1 addition & 23 deletions lua/acf/core/utilities/util_cl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

Expand Down Expand Up @@ -473,4 +451,4 @@ do -- Default gearbox menus
end
end
end
end
end
11 changes: 6 additions & 5 deletions lua/acf/entities/ammo_types/refill.lua
Original file line number Diff line number Diff line change
@@ -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()
Expand Down Expand Up @@ -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
Expand Down
9 changes: 0 additions & 9 deletions lua/acf/menu/data_callbacks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,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
18 changes: 4 additions & 14 deletions lua/acf/menu/items_cl/settings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -204,18 +206,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")
Expand Down
6 changes: 3 additions & 3 deletions lua/effects/acf_explosion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
12 changes: 8 additions & 4 deletions lua/effects/acf_muzzle_flash.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local Weapons = ACF.Classes.Weapons
local Sounds = ACF.Utilities.Sounds

function EFFECT:Init(Data)
local Gun = Data:GetEntity()
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lua/effects/acf_penetration.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion lua/effects/acf_ricochet.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
Expand Down
Loading

0 comments on commit 4e12cc3

Please sign in to comment.