Attempt To Index Number With "ID" | Music Request Script

  1. What do you want to achieve?

Music Request GUI Button / Event

  1. What is the issue?

ServerScriptService.MusicPlayerSystem:42: attempt to index number with 'ID'

I am having troubles sending the ID requested from the gui box to the serverscriptservice request event.

  1. What solutions have you tried so far?

I have tried looking for multiple solutions and ways of sending ID’s up to the table but still wont work.

Code for request button -

local TextBox = script.Parent.Parent.SongBox
local Button = script.Parent
local productId = 1163067984 -- Change to the ID of your developer product.
local player = game.Players.LocalPlayer
local UserInputService = game:GetService("UserInputService")


Button.Activated:Connect(function()
	game.MarketplaceService:PromptProductPurchase(player, productId)
end)


game.MarketplaceService.PromptProductPurchaseFinished:Connect(function(isPurchased)
	UserInputService.TextBoxFocusReleased:Connect(function()
		
		local id = TextBox.Text
		print("player entered id" .. id)
		
		if productId and isPurchased then
			game.ReplicatedStorage.MusicEvents.RequestSong:FireServer(id)
			print("player bought product" .. productId)
		end
		
	end)
end)

Code for Request Song Event Part of Music System -

--[ SONG REQUEST FUNCTION ]--

events.RequestSong.OnServerEvent:Connect(function(player, id)
	local song -- We create our "song" variable and will later be properly declared by the for loop, if it finds the song the player is trying to request.

	for _, s in ipairs(songs) do
		if s.ID == id then
			song = s
		end
	end -- For every song we have stored in the songs table, we will check if its ID index is equivalent to the ID the player is trying to request. If so, we declare the song variable as that song.

	if song then
		table.insert(queue, song)
		print(song.. " : was added to queue")
		events.RefreshQueue:FireAllClients(queue)		
	end -- If the song was found, we will insert it into the requested queue table. We will also fire the RefreshQueue remote event upon all clients.
end)

Also if anyone has an Idea how I can like fix the request button, dev product part lmk. It works but is a little bugged.

In the second script, s.ID may not exist, or s is nil.
Try checking before you index ID to avoid errors.

Just curious, what’s in this table?

Heres the full script -

--[[
	@author TwinPlayzDev_YT
	@credit SlipperySpelunky (Dev Forum)
	@since 4/4/2021
	This script basically controls the music player.
--]]


--[ SERVICES ]--

local rep = game:GetService("ReplicatedStorage") -- The ReplicatedStorage service.

--[ MAIN LOCALS ]--

local events = rep.MusicEvents -- This variable is the folder in which the remote events/functions are stored in.

local queue = {} -- This table is where we will store/remove requested songs.
local songs = {1608398085,4924940868} -- This table is where all the songs will be stored.

local currentSong = "No song playing"

local sound = game.Workspace:FindFirstChild("Sound")

--[ SIGN LOCALS ]--

local gui = game.StarterGui.SurfaceGui.SongPart -- grabbing the gui
local SongId = gui.Frame.SongID -- grabbing the id text part
local SongName = gui.Frame.SongName -- grabbing the song name text part

--[ GET PLAYING SONG FUNCTION ]--

events.GetPlayingSong.OnServerInvoke = function()
	return currentSong -- When the GetPlayingSong remote function gets invoked, we will return the currently playing song name back to the client who invoked it.
end

--[ SONG REQUEST FUNCTION ]--

events.RequestSong.OnServerEvent:Connect(function(player, id)
	local song -- We create our "song" variable and will later be properly declared by the for loop, if it finds the song the player is trying to request.

	for _, s in ipairs(songs) do
		if s.ID == id then
			song = s
		end
	end -- For every song we have stored in the songs table, we will check if its ID index is equivalent to the ID the player is trying to request. If so, we declare the song variable as that song.

	if song then
		table.insert(queue, song)
		print(song.. " : was added to queue")
		events.RefreshQueue:FireAllClients(queue)		
	end -- If the song was found, we will insert it into the requested queue table. We will also fire the RefreshQueue remote event upon all clients.
end)

--[ MAIN PLAYER ]--

while true do
	if #songs > 0 then -- We first check if there are any songs implemented into the system. If so, we proceed.
		sound.TimePosition = 0 -- We set the TimePosition property of our sound object to 0. This is done so when a new song starts playing, it doesn't continue from the TimePosition of when the previous song ended at.
		local selectedSong -- We create our selectedSong variable. It will be properly declared in the following code.

		if #queue > 0 then -- We check if there are any requested songs. If so, we select the first song that was requested.
			selectedSong = queue[1] -- Sets the selected song variable as the requested song.
			table.remove(queue, 1) -- Removes the selected song from the queue table.
			events.RefreshQueue:FireAllClients(queue) -- We fire all clients with the RefreshQueue remote event to refresh the queue as it was modified.
		else
			selectedSong = songs[math.random(1, #songs)] -- If there are no requested songs, then we select a random song from our songs table.
		end

		sound.SoundId = "rbxassetid://"..tostring(selectedSong) -- We set the SoundId property of the sound object to our selected song's ID.

		if not sound.Loaded then
			sound.Loaded:Wait() -- If our song hasn't already loaded within the "nanosecond timestamp" of our setting of the sound ID, then we wait for it to load.
		end

		sound.PlaybackSpeed = 1 -- We set the PlaybackSpeed property of the sound to the Pitch index of our selected song. If there is no pitch index, then we set it to 1.
		sound:Play() -- We begin playing the song.
		events.NewSong:FireAllClients(selectedSong) -- We fire the NewSong event to all clients to indicate a new song has started playing.
		currentSong = selectedSong -- We set the currentSong variable to the name of the selected song.
		
		----------------------------------------------------- SIGN PART
		
		-- pcall since GetProductInfo can return an error.
		local success, product_info = pcall(function()
			return game:GetService("MarketplaceService"):GetProductInfo(currentSong, Enum.InfoType.Asset)
		end)
		
		local sound_name = success and product_info.Name 
		
		SongId.Text = "ID : " .. sound.SoundId -- set the song id part text
		SongName.Text = sound_name -- set the song name part text 
		----------------------------------------------------- SIGN PART
		
		sound.Ended:Wait() -- We now wait for the song to finish playing.
	else -- if no songs playing we break out of the loop at 84 and change the text of the sign
		
		----------------------------------------------------- SIGN PART
		SongId.Text = "ID : N/A "  
		SongName.Text = " NO CURRENT SONG " 
		----------------------------------------------------- SIGN PART
		break 
	end
end


--[ SONG COMMANDS ]--

local sound = game.Workspace.Sound

game.Players.PlayerAdded:Connect(function(Player)
	if Player:GetRankInGroup(8428801) >= 250 then
		Player.Chatted:Connect(function(m)
			if (m:lower() == "!skip") then
				sound:Pause()
				local old = sound.SoundId
				local newSong = songs[math.random(1, #songs)]
				while(old == newSong) do
					newSong = songs[math.random(1, #songs)]
				end
				sound:Play(newSong)
				print("skipped")
			elseif (m:lower() == "!resume") then
				sound:Resume()
				print("resumed")
			elseif (m:lower() == "!pause") then
				sound:Pause()
				print("paused")
			elseif (m:lower() == "!play") then
				sound:Play()
				print("played")
			end
		end)
	end
end)





@DalekAndrew99 Can you see in this?

@Operatik but what about,

local song -- We create our "song" variable and will later be properly declared by the for loop, if it finds the song the player is trying to request.

	for _, s in ipairs(songs) do
		if s.ID == id then
			song = s
		end
	end -- For every song we have stored in the songs table, we will check if its ID index is equivalent to the ID the player is trying to request. If so, we declare the song variable as that song.

Does that still not have a value?

Oh you mean if s == id then

Aha, we caught it. Apparently, the script mentions s.ID, but there isn’t a single dictionary inside! Now I don’t know exactly where you want to go with this, but you can modify either to fix subtables or compare s == id.

1 Like

I changed it now, but it isn’t printing the song added to queue. But yes got rid of error.

--[ SONG REQUEST FUNCTION ]--

events.RequestSong.OnServerEvent:Connect(function(id)
	local song -- We create our "song" variable and will later be properly declared by the for loop, if it finds the song the player is trying to request.

	for _, s in ipairs(songs) do
		if s == id then
			song = s
		end
	end -- For every song we have stored in the songs table, we will check if its ID index is equivalent to the ID the player is trying to request. If so, we declare the song variable as that song.

	if song then
		table.insert(queue, song)
		print(song.. " : was added to queue")
		events.RefreshQueue:FireAllClients(queue)		
	e

Looks like it skipped it completely, maybe the id was wrong entirely?

Actually, I realized that player parameter is missing from the event. So when you fire to server, the second parameter is id. If you don’t need the player parameter, just set (_, id). Question regarding why player is always first despite nothing was fired is because it is purely in-built and that’s nothing we can manipulate.

1 Like

Yes I can see that now.

The problem is its still not entering/adding the song to queue even with that (player, id).

I wonder if its the button, but everytime I enter/request it prints exactly what is needed.

The issue is pretty simple you’re returning a string value “id” from the textbox, it has to be converted into an integer value first in order to be compared with the data from the array.

Basically,

	for _, s in ipairs(songs) do
		if s == tonumber(id) then
			song = s
		end
	end

should print out correctly this time
image

Hope this helps!

1 Like