"Unable to cast value to function" error

i believe that the PlayerRemoving event has some time before the player actually leaves that game but why not just save the data when it changes? plus, you already have the player parameter, why use a for i, v loop to look for it? you put it in a PlayerRemoving event

1 Like

I would say change when the player leaves, because sometimes changes happen too often.

It’s way more reliable to save when the player leaves or disconnects.

2 Likes

GlobalDataStore:UpdateAsync takes a function that returns the new as the second argument, not the new data itself. Use :SetAsync.

3 Likes

I changed it to :SetAsync and it no longer reports an error, however it still doesn’t change the data being stored.

I’m using the for i,v loop to make sure I’m saving the data on the correct player, since It’s a server script, not looking for the player. (I’m pretty sure there’s an easier way to do this, but this is the way I figured out how to do it.)

1 Like

Two things I had noticed. For starters, you nested an event, which should be avoided unless the second event is a dependent of the first. The second one was that if you test in Studio, it might not save anyways because the game closes before the data can save. You can fix this by testing in Team Test and using the following code:

local plrs = game:GetService("Players")
function saveData(plr, newData)
	local plrId = "Player_"..plr.UserId
	local success, err = pcall(function()
		expDataStore:SetAsync(plrId, newData)
	end)
	if err then
		warn(err)
	end
end
plrs.PlayerRemoving:Connect(function(plr)
	saveData(plr, Define.Whatever.You.Want.To.Save)
end)

game:BindToClose(function()
	if game:GetService("RunService"):IsStudio() then return end
	for index, plr in pairs(plrs:GetPlayers()) do
		saveData(plr, Define.Whatever.You.Want.To.Save)
	end
end)

:BindToClose() is an event that will keep the server open until the handler has finished executing.

1 Like

Thanks for the help, at the moment I am unable to open Studio and test the code, but if it’s not a problem, would you mind giving me an example of when you would combine two events?

The variable newData is not a function, therefor Roblox cannot call that “function”. Try using SetAsync() instead of UpdateAsync(), as it doesn’t need a function as the second parameter. UpdateAsync() calls the second parameter (which is meant to be a function) and sets the value of the store to what the function returns.

1 Like

Of course! You should only use nested events when the second event comes from a parameter in the first event. For example:

game.Players.PlayerAdded:Connect(function(plr) --Plr is the variable we will use for the second event
	plr.CharacterAdded:Connect(function(char) --This events uses the first param of "plr" as its base
		--Char here represents the character of the player
	end)
end)

If the variables are needed in the global scope, then you can create separate event handlers. An example of that would be:

local data --I left it undefined so we can give it a value later

game.ReplicatedStorage.SomeRemoteEvent.OnClientEvent:Connect(function(text)
	data = text --Change the value of "data" to what was recieved from the server
end)

game.Players.PlayerRemoving:Connect(function(plr)
	if plr == game.Players.LocalPlayer then
		print(plr.Name.. "'s text was: ".. tostring(data))
	end
end)
1 Like

So there still an issue with the code. So I have to store a table, and I tried to do the thing you explained with using the remote event to define an undefined variable then using that variable, but it didn’t work. I have already made sure that the table is being sent to the server.


local data

dataEvent.OnServerEvent:Connect(function(plr,newData)
	data = newData
end)

local plrs = game:GetService("Players")
function saveData(plr, newData)
	local plrId = "Player_"..plr.UserId
	local success, err = pcall(function()
		expDataStore:SetAsync(plrId, newData)
	end)
	if err then
		warn(err)
	end
end
plrs.PlayerRemoving:Connect(function(plr)
	saveData(plr, data)
end)

game:BindToClose(function()
	if game:GetService("RunService"):IsStudio() then return end
	for index, plr in pairs(plrs:GetPlayers()) do
		saveData(plr, data)
	end
end)

Are you running this in Roblox Studio play test?

Nevermind, it just wasn’t printing inside of the team test, so I had to switch over to a regular test to confirm it. Thanks for the help!

-Edit: It works in studio but not the Roblox player, is it not supposed to?

[Original Content Removed] (Deprecated code used)

Does the line table.remove(plrData, index) need to change plrData to data? Cuz it’s telling me plrData is unknown.

Now it no longer works in team test and still doesn’t work in the Roblox player.

Ok, I am going to try to run the full code in Studio and see what happens

Mkay, and here’s the local script that sends the data if you need it for testing. It’s inside of StarterPlayerScripts.

local data = {
	newlvl = lvl,
	newexp = exp,
	newexpToNextLvl = expToNextLvl,
	newlvlMult = lvlMult
}

coroutine.resume(coroutine.create(function()
	while wait(.1) do
		dataEvent:FireServer(data)
	end
end))

Try again with a new edit I made… if that doesn’t work then the problem has to do with the tables

It didn’t work in team test, but I can’t test on the Roblox player at the moment.

Ok, I will be away at the moment to look into this. I will let you know when I come to a solution