-
Notifications
You must be signed in to change notification settings - Fork 333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added CallOnRemove on entity to stop emitting sound on entity deletion #2952
Added CallOnRemove on entity to stop emitting sound on entity deletion #2952
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to do something like this before but never got around to it since I had some efficiency considerations, but this is probably fine.
Otherwise good first contribution, thanks for making this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E2_emitting_sounds table can grow indefinitely. Need to find a way to limit its size or have it only contain playing sounds
There's not really any way to know if a sound is still playing unfortunately. I believe |
You can actually play a sound multiple times or even different sounds simultaneously. This will work
And since we can't get a kind of length property on the sound, I guess the best idea to reduce the size of the table is to use a key, value pair like "sound" -> "number of times played" |
This is a bit more ideal. |
You don't need to count the number of times a sound is played and StopSound that many times. I'm pretty sure one StopSound for each sound path will do. |
I forgot to mention this, but actually no it does not work. If I take this script
and edit the CallOnRemove to call ent:CallOnRemove("E2_EmitSound_stop_all", function()
local emitting_sounds = ent:GetVar("E2_emitting_sounds")
if not emitting_sounds then return end
for snd, count in pairs(emitting_sounds) do
ent:StopSound(snd)
end
end) It will only stop one of these two sounds playing, the second one will not stop upon deletion |
Unfortunately cryx is right, I discovered this in my own testing. |
Yeesh, then we need to limit the counter to however many is the max sounds source-engine will play. If someone runs emitsound a million times, they can make a lagspike calling Stopsound that many times. |
See if 32 is a good limit? |
@@ -304,7 +304,7 @@ local function EmitSound(e2, ent, snd, level, pitch, volume) | |||
end | |||
|
|||
local emitting_sounds = ent:GetVar("E2_emitting_sounds", {}) | |||
emitting_sounds[snd] = (emitting_sounds[snd] or 0) + 1 | |||
emitting_sounds[snd] = math.min((emitting_sounds[snd] or 0) + 1, 32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to ensure you can't emit sounds past this point as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this limit should be applied on the total number of sounds played, not specifically for each sound.
I could play bird1.wav, bird2.wav, ..., bird9999999.wav and still cause the lagspike no? I guess we should work with a queue to remove the oldest sound played if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case you should go back to the array of strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a function that returns if a sound loops? If we can just keep track of the looping sounds playing, we'll know what needs to get cleaned up when the entity is deleted.
I made this. Not sure how well it works. local timerLinkedList = {
makeNode = function(prev, next, time, func)
local node = {time = time, func = func}
if prev then prev.next = node end
if next then node.next = next end
return node
end,
__index = {
add = function(self, time, func)
if self.length==0 then
self.root = timerLinkedList.makeNode(nil, nil, time, func)
elseif time<=self.root.time then
self.root = timerLinkedList.makeNode(nil, self.root, time, func)
else
local prevnode = self.root
local node = prevnode.next
while node and time>node.time do
prevnode = node
node = node.next
end
timerLinkedList.makeNode(prevnode, node, time, func)
end
self.length = self.length + 1
end,
delete = function(self)
while self.root do
self.root.func()
self.root = self.root.next
end
end,
pop = function(self)
self.root = self.root.next
self.length = self.length - 1
return self.length==0
end,
think = function(self, t)
if self.length==0 then return true end
while t>self.root.time do
self.root.func()
if self:pop() then return true end
end
end
},
__call = function(t)
return setmetatable({length = 0}, t)
end
}
setmetatable(timerLinkedList, timerLinkedList)
local soundcleaner_timers = setmetatable({},{__index=function(t,k) local r=timerLinkedList() t[k]=r return r end})
local function soundcleaner_cleanup(ent)
soundcleaner_timers[ent] = nil
if next(soundcleaner_timers)==nil then
hook.Remove("Think","Wire_E2_CleanupEmitSounds")
end
end
local function soundcleaner_think()
local curtime = CurTime()
for ent, timer in pairs(soundcleaner_timers) do
if timer:think(curtime) then
soundcleaner_cleanup(ent)
end
end
end
local function soundcleaner_soundPlayed(ent, sound)
local timer = soundcleaner_timers[ent]
if timer.length == 32 then return end
local duration = SoundLoops(sound) and math.huge or SoundDuration(sound)
timer:add(CurTime()+duration+0.001, function()
ent:SoundSound(sound)
end)
hook.Add("Think","Wire_E2_CleanupEmitSounds", soundcleaner_think)
end
local function soundcleaner_soundStopped(ent, sound)
local timer = rawget(soundcleaner_timers, ent)
if timer and timer:pop() then
soundcleaner_cleanup(ent)
end
end
local function soundcleaner_entityDeleted(ent)
soundcleaner_timers[ent]:delete()
soundcleaner_cleanup(ent)
end
-- in EmitSound function
soundcleaner_soundPlayed(ent, snd)
ent:CallOnRemove("E2_EmitSound_stop_all", soundcleaner_entityDeleted) |
This pull request has been marked as stale as there haven't been any changes in the past month. It will be closed in 15 days. |
I think an array of strings would be sufficient if limited to 32. A whole class and linked list is too much complexity for this task. |
This pull request has been marked as stale as there haven't been any changes in the past month. It will be closed in 15 days. |
This will fix the issue where props do not stop their current emitting sounds when deleted.
Having a table to store every sounds is useful when you have to delete two or more sounds playing simultaneously. If we had something like :
It would not have worked since CallOnRemove overwrites the last call with the same identifier.
By the way, even though the rule on indentation is to use Tab instead of Space, I used Space since this is the indentation used in the EmitSound function declaration.
Fixes #2815