Something I didn’t understand in my music player is that the SoundService seems to play locally. Try changing the position of the sound object to the workspace.
I’ll try that. Not sure if it will fix the problem, but let’s hope.
I have good news and bad news: It fixed the previous error, but now this is happening:
Still no sound.
You need to change the music variable in your script to be game.Workspace.Music
Just did that, now we are back to the first error. Looks like you might have to change it a lot…
Can you show me your current script?
Yes! Here you go:
local music = game.Workspace.Music -- The path to the sound object you created in the SoundService. If that doesn't work, try replacing Soundscape with SoundService.
local songs = game.ServerStorage.Songs:GetChildren() -- The :GetChildren() method returns a lua table containing the objects inside the instance we used it on. In this case, that's the Songs folder we created in the ServerStorage.
local queue = {} -- Here, we will be putting all the songs in the songs folder and play them all in order. We will also "shuffle" the queue.
script.addSongs.OnInvoke:Connect(function()
for _,song in pairs(songs) do -- This for loop will iterate over every object in our songs folder.
if song:IsA("IntValue") then -- We check if the song is an IntValue to make sure it's a song.
table.insert(queue, {
["songName"] = song.Name, -- The name of the song. As we mentioned, it is the name of the IntValue.
["songID"] = "rbxassetid://"..tostring(song.Value) -- The ID of the song. As we mentioned, it is the value of the IntValue. We add rbxassetid:// before it because sound objects have it in that format.
}) -- This will insert a table inside our queue table containing the information for our song.
end
end
for i = 1, #queue - 1 do
local r = math.random(i,#queue)
queue[i], queue[r] = queue[r], queue[i]
end -- This shuffles the table. This method of shuffling is called the "Fisher-Yates Shuffle". If you wish to find out how it works, go search it up!
return true
end)
script.playSong.OnInvoke:Connect(function()
if #queue == 0 then script.addSongs:Invoke() end -- Here, we check if there are no more songs in the queue table. If there aren't, then we add them again.
local songToPlay = queue[1] -- This is the next song in the queue table. Further into this function, we remove that from the table as it's already playing.
music.SoundId = songToPlay.songID -- We set the sound ID property of the sound object to the songID we defined in the song to play.
music:Play() -- This plays the song.
table.remove(queue, 1) -- This removes the song from the table as it's already playing.
music.Ended:Wait() -- We wait for the song to finish, and then we play the next one.
local delayBeforeNextSongPlays = 3 -- The amount of time we will wait before the next song plays after the current one is done.
wait(delayBeforeNextSongPlays)
script.playSong:Invoke() -- We run this function again.
return true
end)
script.addSongs:Invoke() -- Calls the addSongs() function which as we said, adds the songs into the queue table.
script.playSong:Invoke() -- Plays the next song available in the queue. :)
local allowedPlayers = {"FxllenCode", "Iostrxses"} -- The people who are allowed to execute the !skip command. If you want, you can also check for a rank instead.
game.Players.PlayerAdded:Connect(function(player) -- The code inside this event listener will happen when a player joins. It passes in the player parameter which is the player who joined.
player.Chatted:Connect(function(msg) -- The code inside this event listener will happen when the player who joined chats. The msg parameter is the message they chatted.
if string.lower(msg) == "!skip" then -- We check if the lowercase version of the message they chatted is "!skip". string.lower(string) returns the lowercase version of the string.
if table.find(allowedPlayers, player.Name) then -- We check if the player's name exists in the allowedPlayers table we created earlier.
-- IF YOU WANT TO CHECK FOR A RANK, you can easily replace table.find(allowedPlayers, player.Name) with player:GetRankInGroup(groupID) which will return the numerical rank of the player in that group instead of checking if their username exists in the table.
--[[ Example:
if player:GetRankInGroup(000000) > 5 then
nice code
end
--]]
table.remove(queue, 1) -- This will remove the currently playing song from the queue table to be able to play the next one.
script.playSong:Invoke() -- We then simply fire the playSong() function as we already know that handles everything.
end
end
end)
end)
Try changing the BindableFunctions addSongs and playSong to BindableEvents (you can use Reclass or a similar plugin to do it quickly).
EDIT: It should look like this:
As I mentioned, BindableEvents don’t yield when they get called. However, Bindable Functions do yield and wait for you to return a value.
Hm, now that I see, it would be impossible to use Bindable Functions due to its returning method. As @AwesomePossum212 mentioned, you should try using Bindable Events instead. Replace any OnInvoke()
to Event
and any :Invoke()
to :Fire()
But in this case (correct me if I’m wrong), the Bindable doesn’t need to yield? It just needs to be fired.
Event()
or just Event
? Thank you so much, I am checking now.
Just Event
.
Example:
script.addSongs.Event:Connect(function()
end)
Oh and one more thing, place the PlayerAdded event code before calling the addSongs() and playSong().
Got it. I recommend changing the tutorial as well.
Still not done checking though. Don’t update it yet.
This is very simple, for functions you need to do this.
bindable.OnInvoke = function test()
end
That worked! It’s working well and commands work as well. Thank you all!
Can you mark my post as the solution?
That wasn’t the solution, I had to convert from BindableFunctions to BindableEvents.
Okay, mark that as the solution. When using remote functions or bindable functions you have to write the functions like that.