Player Location in datastore not saving and :BindToClose questions

Hi,

I was messing around with Datastores and was able to create a script that I am pretty sure should work for saving player locations when they leave. Except, it doesn’t and I’ve looked around the devforum a bit and have gone insane from trying to figure this out. I know I can use bindToClose(), but I am wondering does that work for if one player leaves and there is still other players in the game?

I think this error has something to do with :SetAsync():

local MainServerModuleScript = {}
local ServerData = require(script.ServerData)
local PlayerModuleScript = require(script.PlayerModuleScript)
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("Playa")


MainServerModuleScript.__index = MainServerModuleScript


game.Players.PlayerAdded:Connect(function(player) -- This I am pretty sure works as intended
	player.CharacterAdded:Wait()
	
	local HRP = player.Character.HumanoidRootPart
	local data
	local success, err = pcall(function()
		data = PlayerData:GetAsync(player.UserId)
	end)
	print(data)
	if success and data then
		HRP.Position = Vector3.new(data[1], data[2], data[3])
		print("Player Has Data!")
	else
		print("Player has no data!")
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
-- This doesnt save when players leave, I know it might be because the server
-- is shutting down before but it can save I've tried leaving a game and rejoining 
-- with still 2 players in the game and it still doesn't work
	
	player.CharacterRemoving:Connect(function(character)
		
		local playerLocation = {character.HumanoidRootPart.Position.X, character.HumanoidRootPart.Position.Y, character.HumanoidRootPart.Position.Z} 

		local success, err = pcall(function()
			print("Test") -- this prints
			PlayerData:SetAsync(player.UserId, playerLocation) -- I think this is the problem
			print("SUCCESS?")	 -- this does not print
		end)

		if success then
			print("User Data Saved")
		else
			print("User data not saved!!!")
			warn(err)
		end
	end)

Thanks, Ultan

Try this, I implemented :BindToClose:

--//Services
local Players = game:GetService("Players")
local MainServerModuleScript = {}

local ServerData = require(script.ServerData)
local PlayerModuleScript = require(script.PlayerModuleScript)

--//Variables
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("Playa")

MainServerModuleScript.__index = MainServerModuleScript

--//Functions
local function SaveData(player, data)
	local success, errorMessage = pcall(function()
		PlayerData:SetAsync(player.UserId, data)
	end)
	
	if not success then
		warn(errorMessage)
	end
end

game.Players.PlayerAdded:Connect(function(player) -- This I am pretty sure works as intended
	player.CharacterAdded:Wait()

	local HRP = player.Character.HumanoidRootPart
	
	local data = nil
	
	local success, errorMessage = pcall(function()
		data = PlayerData:GetAsync(player.UserId)
	end)
	
	if success and data then
		HRP.Position = Vector3.new(data[1], data[2], data[3])
		print("Player Has Data!")
	else
		warn(errorMessage)
		print("Player has no data!")
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	-- This doesnt save when players leave, I know it might be because the server
	-- is shutting down before but it can save I've tried leaving a game and rejoining 
	-- with still 2 players in the game and it still doesn't work

	player.CharacterRemoving:Connect(function(character)
		local playerLocation = {character.HumanoidRootPart.Position.X, character.HumanoidRootPart.Position.Y, character.HumanoidRootPart.Position.Z} 
		
		SaveData(player, playerLocation)
	end)
end)

game:BindToClose(function()
	for i, player in ipairs(Players:GetPlayers()) do
		local character = player.Character
		
		if not character then
			continue
		end
		
		local playerLocation = {character.HumanoidRootPart.Position.X, character.HumanoidRootPart.Position.Y, character.HumanoidRootPart.Position.Z}
		
		SaveData(player, playerLocation)
	end
end)
1 Like

Hi, thank you so much for the reply, I just tried this and it seems to work sometimes, I’m wondering if its something else or its just me tripping?

Have you tested ingame? Studio behaves differently with :BindToClose ingame than in studio. Could be the reason why there are inconsistencies.

2 Likes

I know that @Katrist provided you with a script, but I want to answer your question still. :BindToClose() is used when the server shuts down for x,y,z reasons. It is not used, when a player leaves, if the server is still Active. :BindToClose only fires once per server, right before it shutting down. However, if the server shuts down, sometimes Players.PlayerRemoving never fires! Meaning data loss. So its important you don’t use one or the other, you use both together.

Now I am going to adjust @Katrist script a tad, For the follwoing reasons, and what they do: If :BindToClose is fired, you have 30 seconds to save all data and excute any code that is needed. So its important to wrap the code using coroutine.wrap()() so you can call :SetAsync() on all the players instead of yielding for each one. I am also going to add a Debounce so if you save the data, it doesn’t get a second request from :BindToClose, if They are both called together (Which can happen). I am Also confused by you wrapped the PlayerRemoving and CharacterRemoving together? If Character Removing is ever fired first, then player removing, you might be in some trouble of Data loss..

--//Services
local Players = game:GetService("Players")
local MainServerModuleScript = {}

local ServerData = require(script.ServerData)
local PlayerModuleScript = require(script.PlayerModuleScript)

--//Variables
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("Playa")
local PlayersThatHaveCurrentlySavedData = {}

MainServerModuleScript.__index = MainServerModuleScript

--//Functions
local function SaveData(player, data)
if table.find(PlayersThatHaveCurrentlySavedData, player.Name) == nil then
   table.insert(PlayersThatHaveCurrentlySavedData, player.Name)
	local success, errorMessage = pcall(function()
		PlayerData:SetAsync(player.UserId, data)
	end)
	
	if not success then
		warn(errorMessage)
	end

    repeat task.wait() until game.Players:FindFirstChild(player.Name) == nil 
table.remove(PlayersThatHaveCurrentlySavedData, table.find(PlayersThatHaveCurrentlySavedData. player.Name) )
   end
end


game.Players.PlayerAdded:Connect(function(player) -- This I am pretty sure works as intended
	player.CharacterAdded:Wait()

	local HRP = player.Character.HumanoidRootPart
	
	local data = nil
	
	local success, errorMessage = pcall(function()
		data = PlayerData:GetAsync(player.UserId)
	end)
	
	if success and data then
		HRP.Position = Vector3.new(data[1], data[2], data[3])
		print("Player Has Data!")
	else
		warn(errorMessage)
		print("Player has no data!")
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	-- This doesnt save when players leave, I know it might be because the server
	-- is shutting down before but it can save I've tried leaving a game and rejoining 
	-- with still 2 players in the game and it still doesn't work

	local character = player.Character
		local playerLocation = {character.HumanoidRootPart.Position.X, character.HumanoidRootPart.Position.Y, character.HumanoidRootPart.Position.Z} 
		if not character then
			continue
		end

		SaveData(player, playerLocation)
	
end)

game:BindToClose(function()
	for i, player in ipairs(Players:GetPlayers()) do
		local character = player.Character
		
		if not character then
			continue
		end
		
		local playerLocation = {character.HumanoidRootPart.Position.X, character.HumanoidRootPart.Position.Y, character.HumanoidRootPart.Position.Z}
		
		coroutine.wrap(SaveData)(player, playerLocation)
	end
end)

~ These are my recommendations. Hope it helps!

1 Like