WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   AddOn Help/Support (https://www.wowinterface.com/forums/forumdisplay.php?f=3)
-   -   7.3 Broken PlaySoundFile()/PlaySound() (https://www.wowinterface.com/forums/showthread.php?t=55827)

ballistics1142 10-30-17 06:17 AM

7.3 Broken PlaySoundFile()/PlaySound()
 
Hi,

I did a taint log to find what was the main cause of these lua errors(I'm aware of the logout/quit functions are now protected in 7.3), and apparently it's on the 4/9th line of my small addon.

This was an addon created for me by Afterafterlife @ https://www.reddit.com/r/wowaddons/c..._addon_sounds/

which i have shown below;

Code:

    -- This file is loaded from "!Play_Addon_Sounds.toc"
   
    local BlizzPlaySoundFile = PlaySoundFile;
    function PlaySoundFile(fileName, track)
        BlizzPlaySoundFile(fileName, "MASTER");
    end
   
    local BlizzPlaySound = PlaySound;
    function PlaySound(fileName, track)
        --we don't need sounds here
        return;
    end

How do I change the arguments here on the code lines below to reference all SoundKitID's;

Code:

function PlaySoundFile(fileName, track)
Code:

function PlaySound(fileName, track)
Any help will be greatly appreciated!

MunkDev 10-30-17 08:45 AM

What you're doing is not safe. Any time the default UI calls your replacement functions the execution path becomes tainted afterwards. If the call to PlaySound is eventually followed by some protected function call from signed code down the path, then it's going to break.

In cases where you want to replace an API function, you need to make sure that the function isn't used in any execution path that ultimately does something protected.

ballistics1142 10-30-17 03:11 PM

Quote:

Originally Posted by MunkDev (Post 325680)
What you're doing is not safe. Any time the default UI calls your replacement functions the execution path becomes tainted afterwards. If the call to PlaySound is eventually followed by some protected function call from signed code down the path, then it's going to break.

In cases where you want to replace an API function, you need to make sure that the function isn't used in any execution path that ultimately does something protected.

Ok so in that case, can you think of another way of achieving the same end result i'm looking for in that addon without breaking the execution path?

MunkDev 10-30-17 04:05 PM

Unless Blizzard provides some CVar to disable PlaySound or add a dedicated UI sound channel, you can't really do much except replace sound files, if that still works. Replacing PlaySound with a tainted function will cause a ton of problems because it's used indiscriminately across the UI. As of 7.3, you probably can't even log out with this "fix" in place because of the sound played on the logout popup.

Fizzlemizz 10-30-17 04:11 PM

And as mentioned in your other thread, you can't alter the SOUNKIT table.

ballistics1142 10-30-17 04:26 PM

Quote:

Originally Posted by MunkDev (Post 325682)
As of 7.3, you probably can't even log out with this "fix" in place because of the sound played on the logout popup.

Yes that is exactly my issue at the moment.

Quote:

Originally Posted by Fizzlemizz (Post 325683)
And as mentioned in your other thread, you can't alter the SOUNKIT table.

Ok I understand that completely now after more research.

So again with another question;

Can I use Ace3 Libraries to overcome this issue? Specifically "AceHook-3.0
Including AceHook functionality"

Fizzlemizz 10-30-17 04:37 PM

No, Ace uses exactly the same API as all other addons and as noted previously, hooking is used for calling one functon after another, not instead of.

ballistics1142 10-30-17 04:50 PM

Quote:

Originally Posted by Fizzlemizz (Post 325685)
No, Ace uses exactly the same API as all other addons and as noted previously, hooking is used for calling one functon after another, not instead of.

Thank you for the clarification. So I hate to admit but i'm getting the vibe i'm just going to have to swallow this issue until blizzard potentially remedies it.

Just had an idea;

What about allowing the blizzard ui sounds to go through except spell and music? Or would that be futile?

MunkDev 10-30-17 05:09 PM

Actually, now that we're talking about sound kits, I remembered that PlaySound was replaced by PlaySoundkitID in 7.2(?) so you can actually mute sounds with a filthy little hack. PlaySoundkitID (and PlaySoundFile) both return handles in the form of an integer ID that increments on every call. So by hooking into PlaySound and playing another sound immediately after it you can figure out the sound handle ID and cancel it.


Lua Code:
  1. local mutex = false -- need this so it doesn't recurse when PlaySound is called from within
  2. hooksecurefunc('PlaySound', function(id)
  3.           if mutex then return end -- we called this time, just return
  4.           mutex = true -- flag mutex
  5.           -- play another sound to figure out the ID.
  6.           -- can't play the same sound because it's occupied by another handle.
  7.           local played, handle = PlaySound(id+1) -- just use the ID+1 to guarantee it's different
  8.           mutex = false -- unflag mutex
  9.           if played then
  10.                StopSound(handle-1) -- stop the sound you wanted to stop in the first place
  11.                StopSound(handle) -- stop your dummy sound
  12.           end
  13. end)

This should effectively do what you asked for, without replacing the function and without spreading taint.

Fizzlemizz 10-30-17 05:57 PM

That's sneaky and clever. Well done.

Kanegasi 10-30-17 06:44 PM

It was a shame PlaySoundKitID was removed. I used this hack to silence some UI sounds and the UI never, as far as I knew, didn't even use KitID, so I hooked PlaySound and then used PlaySoundKitID to generate the handle+1. Instead of the variable switch you have, I went with adding an extra argument to PlaySound.

Lua Code:
  1. local blockedsounds={
  2.     igCharacterInfoClose=840,
  3.     igCharacterInfoOpen=839,
  4.     igMainMenuClose=851,
  5.     igMainMenuOpen=850,
  6.     igPlayerInvite=880,
  7.     igQuestListClose=876,
  8.     igQuestListOpen=875,
  9.     [839]=839,
  10.     [840]=840,
  11.     [850]=850,
  12.     [851]=851,
  13.     [875]=875,
  14.     [876]=876,
  15.     [880]=880,
  16. }
  17.  
  18. local function silence(name,handle,_,_,own)
  19.     if blockedsounds[name] and not own then
  20.         _,handle=PlaySound(64,'Master',false,nil,true)
  21.         if handle then
  22.             StopSound(handle) StopSound(handle-1)
  23.         end
  24.     end
  25. end
  26.  
  27. hooksecurefunc('PlaySound',silence)

I also have a framepool I left out that skips a frame then checks for a block variable and plays the sound anyways if the block variable is false. The sound names in the table were left in from when PlaySound used those, I kept them for history's sake.

ballistics1142 10-30-17 10:14 PM

Quote:

Originally Posted by Kanegasi (Post 325691)
It was a shame PlaySoundKitID was removed. I used this hack to silence some UI sounds and the UI never, as far as I knew, didn't even use KitID, so I hooked PlaySound and then used PlaySoundKitID to generate the handle+1. Instead of the variable switch you have, I went with adding an extra argument to PlaySound.

Lua Code:
  1. local blockedsounds={
  2.     igCharacterInfoClose=840,
  3.     igCharacterInfoOpen=839,
  4.     igMainMenuClose=851,
  5.     igMainMenuOpen=850,
  6.     igPlayerInvite=880,
  7.     igQuestListClose=876,
  8.     igQuestListOpen=875,
  9.     [839]=839,
  10.     [840]=840,
  11.     [850]=850,
  12.     [851]=851,
  13.     [875]=875,
  14.     [876]=876,
  15.     [880]=880,
  16. }
  17.  
  18. local function silence(name,handle,_,_,own)
  19.     if blockedsounds[name] and not own then
  20.         _,handle=PlaySound(64,'Master',false,nil,true)
  21.         if handle then
  22.             StopSound(handle) StopSound(handle-1)
  23.         end
  24.     end
  25. end
  26.  
  27. hooksecurefunc('PlaySound',silence)

I also have a framepool I left out that skips a frame then checks for a block variable and plays the sound anyways if the block variable is false. The sound names in the table were left in from when PlaySound used those, I kept them for history's sake.


So before I go an further, is that example above a working revision?

MunkDev 10-30-17 11:15 PM

If you want to mute all sounds, use this:
Lua Code:
  1. local dummy = false
  2. hooksecurefunc('PlaySound', function(id)
  3.         if dummy then return end
  4.         dummy = true
  5.         local played, handle = PlaySound(id+1)
  6.         if played then
  7.             StopSound(handle-1)
  8.             StopSound(handle)
  9.         end
  10.         dummy = false
  11. end)

If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)

If you want to mute specific sounds use Kanegasi's solution. They all work the same way.

Resike 10-31-17 06:56 AM

Quote:

Originally Posted by MunkDev (Post 325693)
If you want to mute all sounds, use this:
Lua Code:
  1. local dummy = false
  2. hooksecurefunc('PlaySound', function(id)
  3.         if dummy then return end
  4.         dummy = true
  5.         local played, handle = PlaySound(id+1)
  6.         if played then
  7.             StopSound(handle-1)
  8.             StopSound(handle)
  9.         end
  10.         dummy = false
  11. end)

If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)

If you want to mute specific sounds use Kanegasi's solution. They all work the same way.

The SOUNDKIT table is not nearly as complete as you would like it, mostly they just throw stuff into it that's used by the default UI.

Here is a complete table with old names and IDs that you can play with PlaySound:
https://github.com/Resike/BlizzardIn...ndKitNames.lua

ballistics1142 10-31-17 11:05 AM

Hey MunkDev,

Thanks for the suggestion. I'll get back to you on that!

Hey Resike,

Thanks aswell for your contribution of the soundkit table xD!

To everyone who wants to know what my results are, I will be sure to get back to you later!

Kanegasi 10-31-17 11:27 AM

Quote:

Originally Posted by Resike (Post 325695)
Here is a complete table with old names and IDs that you can play with PlaySound:
https://github.com/Resike/BlizzardIn...ndKitNames.lua

I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?

ballistics1142 10-31-17 11:29 AM

Quote:

Originally Posted by Kanegasi (Post 325697)
I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?

I know what your talking about as I believe I got this link off "Fizzlemizz" on here;

https://docs.google.com/spreadsheets...gid=1243506593

MunkDev 10-31-17 01:44 PM

Quote:

Originally Posted by Resike (Post 325695)
The SOUNDKIT table is not nearly as complete as you would like it, mostly they just throw stuff into it that's used by the default UI.

It encompasses all the sounds used by the default UI, which was the point of copying the entries. I wasn't saying it's complete in any sense.
One of the specifications was to allow addons to play sounds, and a lot of addons will likely use sounds (alerts etc) that are not in the soundkit table.

Resike 10-31-17 04:58 PM

Quote:

Originally Posted by Kanegasi (Post 325697)
I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?

I did not generated myself since i would probably get the same table, but you can do it:

You can open the soundkitentry.db2 from the DBCFiles with WDBX then you can get the FileDataID for every SoundKitID, which would eventually point to a file name, if you crosscheck it with the lastly updated FileDataID. From there you need another table conversion from an older DBCFiles which helps with the Sound FilePath - SoundKit Name conversion, and tada.

Or you could just use the soundkitname.db2 and write the values out raw. But that's for non-masochists.

ballistics1142 11-02-17 07:02 PM

Quote:

Originally Posted by MunkDev (Post 325693)
If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)

Can I use this and then add specific blizzard sounds to be allowed through?

Or would it be easier to change this addon(http://www.wowinterface.com/download...erts.html#info) to play through the "Master" channel whilst SFX are disabled under system>>>sounds in-game?


All times are GMT -6. The time now is 12:20 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI