SetAsync on PlayerRemoving function not saving to DataStore

Hello, I’m a new user to this forum trying to make a script looking for some help. I have prior coding experience, but I’m a beginner to Roblox’s system/language, so please bear with me. I think this is a simple problem but I have no idea, lol

Here is the code I have thus far:

local DataStoreService = game:GetService("DataStoreService")

local DataStore = DataStoreService:GetDataStore("ObbyDataStore")

game.Players.PlayerAdded:Connect(function(player)
	
	local data
	
	local success, errorMessage = pcall(function()
		data = DataStore:GetAsync(player.UserId.."-stage")
	end)
	
	if success then
		print "Success"
		if data then
			print "Data Found"
			player.Team = game.Teams[data]
		else
			print "Default"
			player.Team = game.Teams.Stage1
		end
		
	else
		player.Team = game.Teams.Stage1
	end
	
	player:LoadCharacter()
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	print "Did this"
	local teamName = player.Team.Name
	print "Did that"
	
	local success, errorMessage = pcall(function()
		DataStore:SetAsync(player.UserId.."-stage",teamName)
	end)
	
	print "got past that"
	
	if success then
		print "All good"
	else
		print(errorMessage)
	end
	
	print "finished??"
end)

I’ve placed a bunch of test messages in there which are to print when the functions happen.

  1. What do you want to achieve?
    Trying to have a spawn checkpoint be saved upon leaving the game. I’ve followed a YouTube tutorial, but despite the code matching perfectly, it doesn’t want to match the work. Perhaps the tutorial was too outdated? Here’s the tutorial I was using: Tutorial

  2. What is the issue?
    The code just… doesn’t seem to do anything upon getting to the “success” function. I’ve placed test messages in there, but it doesn’t print anything within that function, nor after that function. Also doesn’t throw any errors, which is what pcall is supposed to do, to my understanding.

Here is the output:

image

  1. What solutions have you tried so far?
    Have tried searching the dev forum extensively, have found things close to my error but upon trying them, didn’t work/made it worse, such as trying BindToClose() instead of PlayerRemoving(). Those print messages were my attempts at troubleshooting but… just don’t know enough to fix things yet lol.

This is my understanding of how it’s supposed to work:

Player joins>Code checks store for existing data, if it exists it spawns the player at the data’s checkpoint, if not it sets the player to stage 1. (this part is working seemingly…)

Player leaves>Code grabs player’s current team (stage), then sends it to the datastore.

Any help is very appreciated!

Are you testing the code for .PlayerRemoving by just killing the studio’s test run? Doing that will also shut down the internal server which will shut down the Datastore API. Try emulating a server test run with multiple clients so the server stays alive.

image

You might notice this being a problem of itself where data don’t get saved when a server shuts down. You will also need to write code to handle that using the game:BindToClose() function.

4 Likes

Add a return, otherwise data from SetAsync isn’t being returned from the function and back to the variables success & errorMessage

local success, errorMessage = pcall(function()
	return DataStore:SetAsync(player.UserId.."-stage",teamName)
end)

Nvm, confused myself with return being used for GetAsync, just tried your code, if you use VERON Enumerator’s suggestion, you should see it function successfully.

1 Like

Assuming you have only conducted testing in studio, it is likely that the studio session completely shuts down before your PlayerRemoving function can finish executing. There is a solution to this which is normally used for saving player data as a best practice anyway called game:BindToClose

Essentially how it works is whenever the game is shutting down it will execute the code in the block, example:

function onShutdown()
--Iterate thru player(s) and save their data
end

game:BindToClose(onShutdown)
2 Likes

Thank you very much everyone, I didn’t know about the local server testing so that’s been very helpful, thank you Veron, and thanks for the proper explanation of the BindToClose function Scripty, I’ve got that function working properly and it’s actually saving things now when stopping in studio!

Buuuuut I still can’t seem to get the player removing function working. When I test it with the local server, I’m now getting the following error:
" ServerScriptService.PlayerTeam:36: attempt to index nil with ‘Name’ "

I’m not entirely sure why I’m getting this problem because as far as I can tell it shouldn’t be a nil value at all. I’ll post a smaller version of my code with some of the things I’ve changed:

local Players = game:GetService("Players") 
--[[ read some official documentation, have adjusted entire code 
to follow the above instead of game.players to try and get around the 
nil value problem, didn't seem to work though...
]]
Players.PlayerRemoving:Connect(function(player)
	
	local teamName = player.Team.Name --This is the spot it gets stuck at
	
	local success, errorMessage = pcall(function()
		DataStore:SetAsync(player.UserId.."-stage",teamName)
	end)
	
	if success then
		print "All good"
	else
		print(errorMessage)
	end

end)

I think once I can get this fixed, I shouldn’t have any other troubles and should be able to finish my experience without further problems. Any ideas?

I do not see any errors in your code and this brings it up to the real issue. Roblox Datastore API does not save while in studio test plays, It deletes the data that it saved in that play.

Try testing this out in a real game server and there’s a good chance it’ll work!

As for this error, The player.Team property refers to the Team the player is currently on; If the player isn’t on a team, or the team has an invalid color it’ll default as nil.

Are you sure the player was in a team before they left, and or you might’ve removed it once they left?

I also rarely use the Team property for anything I’ve made so there may be some stuff that do know now of that ties into this error.

As far as I can tell, the player should NEVER have a nil team. Upon loading into the game if they don’t have a team in their datastore, they are automatically placed at stage 1.

I went and tested it through a real game server as requested, but now neither the bindtoclose function nor the playerremoving functions work. Hmmm… I’ll worry about the bindtoclose one later, just going to focus on playerremoving for now, I figure solving one will solve the other.

As proof, here’s what it looks like when someone spawns into the game with no data. There’s code that sets their team to stage 1, they also spawn right on top of the checkpoint for stage 1 by default, so it definitely shouldn’t be blank… The only other script I have just changes the color of checkpoints to match team color (and every team has a valid color) so I’m not removing the player’s team either…


Photo is from just pressing play but the result is the same for testing with local server. As you can see the value is definitely there, but still won’t save.

I am thinking it’s weird that I use player.Team.Name, since when in the studio, it appears to be player.Team.Team as a field, but whenever I tried putting that into the code, it just didn’t recognize it at all.

Just to be clear, when someone says “real server,” does that mean opening it through the roblox player? Or is it a different method? Because I tested it assuming the former. I’m also assuming that it being private wouldn’t affect the saving function of it.

Just a Roblox player server, make sure your API services are on as well. Check through the game settings to do that.

Screen Shot 2024-02-01 at 3.00.15 PM
API services are on, was one of the first things I did while making this. Still no luck, still getting same error in studio and player server doesn’t save anything.

Would really like to have a solution for this soon as i’m making this project with a deadline and this is the only thing preventing me from finishing this experience. If there’s not a way to solve this problem, perhaps there’s a different way I could code this? I keep reading people saying they don’t use the Teams property, but I don’t know a better method for a checkpoint system.

Perhaps someone would be willing to collaborate with me on this and see the code directly from my studio?

Do you have the SignalBehavior Property in Workspace set to "Deferred" or "Default"? That’s probably the reason. Since events are placed in a queue and happen after the scripts have been executed. So when the player is destroyed, the Player argument is nil, because the player was already gone and the PlayerRemoving event happened last.

If it is, set SignalBehavior to immediate.

1 Like

YES IT WORKED, thank you SO much, I really appreciate it.

I also think part of the reason it wasn’t saving in the player server was because I was saving it but not publishing it… such a silly mistake :sweat_smile: but now there’s 0 errors happening in studio and it’s working on player server too. Thanks everyone!!!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.