Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
if GetLocalPlayer() == Player(i) then
set Track[i] = CreateSound(s, false, false, true, 12700, 12700, "")
// s is a file path String that shows the path correctly
call StartSound(Track[i])
call KillSoundWhenDone(Track[i])
endif
Can I use that? Like we know that playing Music from a local file works, but what about playing Sounds? Can I create a Sound from a Local File, play it locally, and Destroy it?
set Track[0] = CreateSound("MyFolder\\MyTrack.mp3", ...)
set DEFAULT = CreateSound("Music\\SomeDefaultWarcraftMusic.mp3", ...)
if GetSoundFileDuration("MyFolder\\MyTrack.mp3") > 0 then
if GetLocalPlayer() == Player(0) then
call StartSound(Track[0])
endif
else
if GetLocalPlayer() == Player(0) then
call StartSound(DEFAULT)
endif
endif
set Track[0] = CreateSound("MyFolder\\MyTrack.mp3", ...)
set DEFAULT = CreateSound("Music\\SomeDefaultWarcraftMusic.mp3", ...)
if GetSoundFileDuration("MyFolder\\MyTrack.mp3") > 0 then
if GetLocalPlayer() == Player(0) then
call StartSound(Track[0])
endif
else
if GetLocalPlayer() == Player(0) then
call StartSound(DEFAULT)
endif
endif
Imagine We have 3 players with a single song each (the same filename as well, but different files). I need to play the song that the player owns. Else with yours the system will play the song that player 1 (host) has it (And likely desyncs).
That's why I say the sound has to be created locally.
I have an Idea: What about local strings? Maybe a Local string brings the Player's own song.
I don't think warcraft 3 have the ability to detect where the music/song file located from a player computer? The location of the music/song file must be constant/fixed as I see.
I need to play the song that the player owns. Else with yours the system will play the song that player 1 (host) has it (And likely desyncs).
That's why I say the sound has to be created locally.
Set the string that has the file path locally.
Then you create the sound with that string.
Be aware that one variable will contain different values then.
I don't think warcraft 3 have the ability to detect where the music/song file located from a player computer? The location of the music/song file must be constant/fixed as I see.
Set the string that has the file path locally.
Then you create the sound with that string.
Be aware that one variable will contain different values then.
I don't think warcraft 3 have the ability to detect where the music/song file located from a player's computer? The location of the music/song file must be constant/fixed as I see.
The system is supposed to play each player it's own songs in the same folder.
For Example, Player 1 has "Nightsong" renamed "Track-01" in it's Music folder.
Player 2 has "The Shattering" renamed "Track-01" in it's Music folder.
Player 3 has another random song renamed "Track-01" in it's Music folder.
When I use this not in a local block, :
JASS:
set snd = CreateSound("Music\\Track-01.mp3", ...)
"snd" Will be "Nightsong", "The Shattering", or what?
So basically the CreateSound should be in a local block to know which player's Music file it should check, like it should be like this to play "Nightsong":
JASS:
if GetLocalPlayer() == Player(0)
set snd = CreateSound("Music\\Track-01.mp3", ...) //Unhopefully Desyncs :(
endif
And alike for other players else it doesn't know which player's folder it should check.
Guessing it will always check for the Host's folder (when not in a local block), once it plays the music, the music should be downloaded for other people to be played, which it doesn't, so basically it will desync.
So if the system plays the Player's music file from it's own folder, it will be fine.
Now: I'm gonna check for some local string solution (as Wietlol and I have suggested earlier), and see whether it will work or not.
I don't think warcraft 3 have the ability to detect where the music/song file located from a player's computer? The location of the music/song file must be constant/fixed as I see.
The system is supposed to play each player it's own songs in the same folder.
For Example, Player 1 has "Nightsong" renamed "Track-01" in it's Music folder.
Player 2 has "The Shattering" renamed "Track-01" in it's Music folder.
Player 3 has another random song renamed "Track-01" in it's Music folder.
When I use this not in a local block, :
JASS:
set snd = CreateSound("Music\\Track-01.mp3", ...)
"snd" Will be "Nightsong", "The Shattering", or what?
So basically the CreateSound should be in a local block to know which player's Music file it should check, like it should be like this to play "Nightsong":
JASS:
if GetLocalPlayer() == Player(0)
set snd = CreateSound("Music\\Track-01.mp3", ...) //Unhopefully Desyncs :(
endif
And alike for other players else it doesn't know which player's folder it should check.
Guessing it will always check for the Host's folder (when not in a local block), once it plays the music, the music should be downloaded for other people to be played, which it doesn't, so basically it will desync.
So if the system plays the Player's music file from it's own folder, it will be fine.
Now: I'm gonna check for some local string solution (as Wietlol and I have suggested earlier), and see whether it will work or not.
The system is supposed to play each player it's own songs in the same folder.
For Example, Player 1 has "Nightsong" renamed "Track-01" in it's Music folder.
Player 2 has "The Shattering" renamed "Track-01" in it's Music folder.
Player 3 has another random song renamed "Track-01" in it's Music folder.
When I use this not in a local block, :
JASS:
set snd = CreateSound("Music\\Track-01.mp3", ...)
"snd" Will be "Nightsong", "The Shattering", or what?
So basically the CreateSound should be in a local block to know which player's Music file it should check, like it should be like this to play "Nightsong":
JASS:
if GetLocalPlayer() == Player(0)
set snd = CreateSound("Music\\Track-01.mp3", ...) //Unhopefully Desyncs :(
endif
And alike for other players else it doesn't know which player's folder it should check.
Guessing it will always check for the Host's folder (when not in a local block), once it plays the music, the music should be downloaded for other people to be played, which it doesn't, so basically it will desync.
So if the system plays the Player's music file from it's own folder, it will be fine.
Now: I'm gonna check for some local string solution (as Wietlol and I have suggested earlier), and see whether it will work or not.
Warcraft III has the ability.
It is fixed to "Folder//Prefix-0(0 may or may not be there, system checks it)1", "Folder//Prefix-02", and so on.
If it's a music, why don't you use PlayMusic? It won't desync when you call it locally.
In anyway, you can't create any kind of agent locally. You can force every player to create the sound no matter do they have the file or not:
JASS:
local sound s1 = CreateSound("Music\\Track-01.mp3", ...
local sound s2 = CreateSound("DefaultMusic.mp3", ...
// Then this code will run locally
if GetSoundFileDuration(s1) > 0 then // if the sound file exists
call StartSound(s1)
else
// If you want players who don't have the file to play another music
call StartSound(s2)
// If not, just delete the "else" block and s2 variable
endif
"snd" Will be "Nightsong", "The Shattering", or what?
It's depend on what song is inside the corresponding folder in each player's PC. Based on your example:
When player 1 call GetSoundFileDuration("Music\\Track-01") it will return "Nightsong"'s file duration.
When player 2 call GetSoundFileDuration("Music\\Track-01") it will return "The Shattering"'s file duration.
And player 3 is alike.
And alike for other players else it doesn't know which player's folder it should check.
Guessing it will always check for the Host's folder (when not in a local block),
The game will not desync if all players have the same sort of agents.
If you create an agent locally, you have to create an agent of the same type for all other players. Some (almost all for units) values of the agent also have to be the same.
Setting the string (filepath) in local blocks is fine, creating the actual sound in local blocks is fine... but all players require the sound.
I still think Music should be doing a better job though.
@Arad MNK:
It's you who isn't understanding us here, not the reverse.
It doesn't matter if the sound file contains a different audio file or not. The game doesn't care about how long the sound file is. Playing sound files is not synchronized at all. Only the sound handle itself matters, not that it plays or how long it plays.
For example, take the extension pack I made for Gaias:
You can replace any of the sound files inside with whatever you want, as long as you rename it to be the same as the original file. The game will plays these sounds just fine.
It doesn't even matter how long these files are for the restarting loop, as you can simply put GetSoundIsPlaying(sound) or GetSoundIsLoading(sound) as a condition in there.
Here, I just wrote the system for you:
JASS:
library CustomMusic initializer init
globals
private constant integer MAX_TRACKS = 99 //defines how many custom tracks the player can have in the folder
private constant string EMPTY = "Sound\\Units\\Human\\Rifleman\\RiflemanDeath.wav"
//this is a random default sound file that it used as a placeholder to make sure CreateSound always creates a proper sound handle
private string array Track[MAX_TRACKS]
private string array Default[MAX_TRACKS]
private sound array TrackSnd[MAX_TRACKS]
private integer currentTrack = 0 //we are working local anyway, so we don't need an array
endglobals
private function SetupTracks takes nothing returns nothing //register the names for the files here
set Track[0] = "CustomMusic\\Track-01.mp3"
set Track[1] = "CustomMusic\\Track-02.mp3"
//... you can also loop and increment the track numbers via string concatenation, but I thought it's better to actually have descriptive names for these files
set Default[0] = "Music\\SomeDefaultWC3musicInMPQ.mp3"
set Default[1] = "Music\\SomeDefaultWC3musicInMPQ.mp3"
//... these are the defaults that play if the user doesn't have any sounds in the folder
endfunction
private function update takes nothing returns nothing
if not (GetSoundIsPlaying(TrackSnd[currentTrack]) or GetSoundIsLoading(TrackSnd[currentTrack])) then
//track has finished playing, start the next one
loop
set currentTrack = currentTrack + 1
if currentTrack >= MAX_TRACKS then
set currentTrack = 0 //start again from the top
endif
if Track[currentTrack] != EMPTY or Default[currentTrack] != EMPTY then
call StartSound(TrackSnd[currentTrack])
exitwhen true
endif
endloop
endif
endfunction
private function initCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 0
local string s = EMPTY
call TimerStart(t, 1, true, function update)
set t = null
call SetupTracks()
loop
exitwhen i >= MAX_TRACKS
if GetSoundFileDuration(Track[i]) > 0 then
set s = Track[i]
elseif GetSoundFileDuration(Default[i]) > 0 then
set s = Default[i]
endif
set TrackSnd[i] = CreateSound(s, false, false, false, 12700, 12700, "")
set i = i + 1
endloop
//start the first track on map initialization
if Track[currentTrack] != EMPTY or Default[currentTrack] != EMPTY then
call StartSound(TrackSnd[currentTrack])
else
call update()
endif
endfunction
private function init takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, initCallback)
endfunction
The game will not desync if all players have the same sort of agents.
If you create an agent locally, you have to create an agent of the same type for all other players. Some (almost all for units) values of the agent also have to be the same.
Setting the string (filepath) in local blocks is fine, creating the actual sound in local blocks is fine... but all players require the sound.
I still think Music should be doing a better job though.
For Musics I can't use GetSoundIsPlaying(sound) or GetSoundIsLoading(sound), Musics aren't sound variables, as I want to remove Timers so that the timing won't fuck up once the player pauses the game. But I can create a sound system that can set the volume and stuff.
OK. Will try it real soon.
@Arad MNK:
It's you who isn't understanding us here, not the reverse.
It doesn't matter if the sound file contains a different audio file or not. The game doesn't care about how long the sound file is. Playing sound files is not synchronized at all. Only the sound handle itself matters, not that it plays or how long it plays.
For example, take the extension pack I made for Gaias:
You can replace any of the sound files inside with whatever you want, as long as you rename it to be the same as the original file. The game will plays these sounds just fine.
It doesn't even matter how long these files are, as you can simply put GetSoundIsPlaying(sound) or GetSoundIsLoading(sound) as a condition in your restart loop.
Yes, that's why I'm developing it with CreateSound as we don't have GetSoundFileIsPlaying(string) or GetSoundFileIsLoading(string) which seems dumb when thinking of them
Soooooo I need to create sounds from a string (CreateSound), to use them with GetSoundIsPlaying(sound) or GetSoundIsLoading(sound) to remove timers.
Will work on the local string version. Posting results soon, if I have enough time.
So basically using the CreateSound, we ALWAYS create it locally without GetLocalPlayer, like:
JASS:
set TrackSnd[i] = CreateSound(s, false, false, false, 12700, 12700, "") //not in GetLocalPlayer()
If we use the array that has nothing to do with the player (use track[0] for player blue for example) we'll desync. Legit enough. Thank you. Will try and post the results (again).
What? No. That's what we were constantly telling you for two pages.
The array is global. You can not create sounds locally (well, technically you can, but it will desync).
The file registered to the handle (as in the audio file on your hard drive) has nothing to do with the sound handle.
Each player will have a different audio file for TrackSnd[0], but they will still have the same handle id.
The only stuff that is local in the script above is the audio file registered to the created sound handle via GetSoundFileDuration and currentTrack, which is incremented whenever GetSoundIsPlaying or GetSoundIsLoading returns false (since this condition returns different results for every player).
This is also the reason why StartSound does not need to be in a local block. If another player is currently running a track, the condition will not allow the code on their client to reach the part where the sound is started. And since currentTrack is also different for every player, it will also run the correct track for everyone even if two players happen to finish a track at the same time.
If we use the array that has nothing to do with the player (use track[0] for player blue for example) we'll desync.
iirc i did heard about sound did bug out for first time starting a sound. It actually preload the sound instead of playing, and after second time calling the same sound, it would play s properly. Not sure if this the problem.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.