Players getting other players' stats

Recently, I decided to transfer my Datastore System from three separate keys for each leaderstat to a single key with a table to help optimize the queue. During this transition, sometimes when players join for the first time with the new system they will get a random player in the server’s data.

Code:

local DataStoreService = game:GetService("DataStoreService")
local LogsEvent = game.ReplicatedStorage:WaitForChild("LogsEvent")

local LBoard = DataStoreService:GetOrderedDataStore("LBoard")
local KBoard = DataStoreService:GetOrderedDataStore("KBoard")

local SFAFYTOldData = DataStoreService:GetDataStore("SFAFYTDataStoreNew")
local SFAFYTData = DataStoreService:GetDataStore("sfafyt_data")
local HighestTimeData = DataStoreService:GetOrderedDataStore("HighestTimeData")
local KillsData = DataStoreService:GetOrderedDataStore("KillsData")

local AmountToSubtractOnLeave = workspace.Config.AmountToSubtractOnLeave.Value

local Start = workspace.Config.RequiredPlayers.Value

function GetPlayerCount()
	local players = game.Players:GetChildren()
	return #players
end

local DefaultData = {
	CurrentTime = 0;
	HighestTime = 0;
	Kills = 0;
}

game.Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		wait(.5)
		Character.Humanoid.Died:Connect(function()
			if GetPlayerCount() >= Start  then
				if Character.Humanoid:FindFirstChild("creator") then
					LogsEvent:FireAllClients(Player.Name.." was killed by ".. Character.Humanoid.creator.Value.Name.." with ".. Player.leaderstats.Time.Value .. " time")
					game.Players[Character.Humanoid.creator.Value.Name].leaderstats.Kills.Value = game.Players[Character.Humanoid.creator.Value.Name].leaderstats.Kills.Value + 1
				end
				Player.leaderstats.Time.Value = 0
			end
		end)
	end)
end)

game.Players.PlayerAdded:Connect(function(Player)
	if Player then
		local Leaderstats = Instance.new("Folder",Player)
		Leaderstats.Name = "leaderstats"
		local HighestTimeVal = Instance.new("IntValue",Leaderstats)
		HighestTimeVal.Name = "HighestTime"
		local TimeVal = Instance.new("IntValue",Leaderstats)
		TimeVal.Name = "Time"
		local KillsVal = Instance.new("IntValue",Leaderstats)
		KillsVal.Name = "Kills"

		local PlayerData

		local OldCurrentTimeData
		local OldHighestTimeData
		local OldKillsData

		local success, errorMessage = pcall(function()
			PlayerData = SFAFYTData:GetAsync(Player.UserId.."-playerdata")
			if not PlayerData then -- Hasn't joined with new data system
				local success2, errorMessage2 = pcall(function()
					OldCurrentTimeData = SFAFYTOldData:GetAsync(Player.UserId.."-time")
					OldHighestTimeData = SFAFYTOldData:GetAsync(Player.UserId.."-highesttime")
					OldKillsData = SFAFYTOldData:GetAsync(Player.UserId.."-kills")
				end)
				if success2 then -- Successfully retrieved old data
					if OldCurrentTimeData and OldHighestTimeData and OldKillsData then -- Player has old data
						PlayerData = {}
						PlayerData.CurrentTime = OldCurrentTimeData
						PlayerData.HighestTime = OldHighestTimeData
						PlayerData.Kills = OldKillsData
					else
						PlayerData = DefaultData
					end
				else
					print("Error getting old data for " .. tostring(Player.Name))
					warn(errorMessage2)
					PlayerData = DefaultData
				end
			end
		end)

		if success then
			print("Data successfully retrieved for ".. tostring(Player.Name))
			if PlayerData.CurrentTime < 0 then
				PlayerData.CurrentTime = 0
			end
			TimeVal.Value = PlayerData.CurrentTime
			HighestTimeVal.Value = PlayerData.HighestTime
			KillsVal.Value = PlayerData.Kills
			--	HighestTimeData:SetAsync(Player.UserId,PlayerData.HighestTime)
			--	KillsData:SetAsync(Player.UserId,PlayerData.Kills)
			spawn(function()
				TimeVal.Value = PlayerData.CurrentTime
				HighestTimeVal.Value = PlayerData.HighestTime
				wait(.5)
				TimeVal.Value = PlayerData.CurrentTime
				HighestTimeVal.Value = PlayerData.HighestTime
			end)
		else
			print("Error receiving data for ".. tostring(Player.Name))
			warn(errorMessage)
		end
	end
end)

game.Players.PlayerRemoving:Connect(function(Player)
	local success, errorMessage = pcall(function()
		local SavedStats = Player.leaderstats:Clone()
		if SavedStats then
			local CurrentTimeVal = SavedStats.Time.Value - AmountToSubtractOnLeave
			local HighestTimeVal = SavedStats.HighestTime.Value
			local KillsVal = SavedStats.Kills.Value
			if CurrentTimeVal and HighestTimeVal and KillsVal then
				local PlayerDataToSave = DefaultData
				PlayerDataToSave.CurrentTime = CurrentTimeVal
				PlayerDataToSave.HighestTime = HighestTimeVal
				PlayerDataToSave.Kills = KillsVal

				SFAFYTData:SetAsync(Player.UserId.."-playerdata",PlayerDataToSave)
				HighestTimeData:SetAsync(Player.UserId,HighestTimeVal)
				KillsData:SetAsync(Player.UserId,KillsVal)
			end
			SavedStats:Destroy()
		end
	end)
	if success then
		print("Data successfully saved for ".. tostring(Player.Name))
	else
		print("Error saving data for ".. tostring(Player.Name))
		warn(errorMessage)
	end
end)


if not game:GetService("RunService"):IsStudio() then
	game:BindToClose(function()
		workspace.Config.RequiredPlayers.Value = 999
		workspace.Inf.CanCollide = true
		workspace.Config.AmountToSubtractOnLeave.Value = 0

		game.ServerStorage.ShuttingDown.Value = true

		for i,Player in pairs (game.Players:GetPlayers()) do
			Player.Character.Humanoid.MaxHealth = math.huge
			Player.Character.Humanoid.Health = Player.Character.Humanoid.MaxHealth
			local Clone = script.ShutdownGUI:Clone()
			Clone.Parent = Player:FindFirstChild("PlayerGui")
		end

		for i,Player in pairs (game.Players:GetPlayers()) do
			local success, errorMessage = pcall(function()
				local Leaderstats = Player:FindFirstChild("leaderstats")
				if Leaderstats then
					local SavedStats = Leaderstats:Clone()
					if SavedStats then
						local CurrentTimeVal = SavedStats.Time.Value
						local HighestTimeVal = SavedStats.HighestTime.Value
						local KillsVal = SavedStats.Kills.Value
						if CurrentTimeVal and HighestTimeVal and KillsVal then
							local PlayerDataToSave = DefaultData

							PlayerDataToSave.CurrentTime = CurrentTimeVal
							PlayerDataToSave.HighestTime = HighestTimeVal
							PlayerDataToSave.Kills = KillsVal

							SFAFYTData:SetAsync(Player.UserId.."-playerdata",PlayerDataToSave)
						end
						SavedStats:Destroy()
					end
				end
			end)
			if success then
				print("Data successfully saved for ".. tostring(p.Name))
			else
				print("Error saving data for ".. tostring(p.Name))
				warn(errorMessage)
			end
		end
	end)
end

Does anyone know why this is happening? Any help is highly appreciated. Let me know if you need any clarification on the code.

I might be TOTALLY off right now, but you declare the player data variable before, (also why are u separating it from the rest of the script…) And maybe another players data are being set to that PlayerData variable, i know on loops you can have this problem… You might wanna change your code structure…

I think I’m being really stupid? Where would I declare the data? My thought process was that I would declare it as soon as the player is added to make sure the player had at least some type of data to use.

How would other players get this data if it is all inside the PlayerAdded function?

That’s the thing? I don’t really know either. Your methods trying to get data seems fine. So that’s just the only thing I could think about.

I feel like also declaring variables for data inside the playerData table is kinda of useless.

I’ll check more of your code.

1 Like

Where did I do that? I’m so confused

Oof NVM. I got confused. Anyway, I saw you clone the leaderstats folder as a cache method… You don’t need to do that at all BUT if you want to, I have a module which basically converts tables into folders with values inside of them (object-based table) and also converts them back. You should be able to get the leaderstats folder and convert it into a table with should be more efficient. Table To Object - Module

1 Like

If you read the module info here’s how to do it;

Set module.storage to the player instance
then do
module.storage = player
local PlayerData = module.CreateTable(“leaderstats”)
module.storage = (original location)

Try setting the player’s leaderstats values right away when you get the data instead of putting them into a table just so that later you can do if sucess then… I think my theory could be right. I feel like that variable is being set everytime…

Anyways, try setting PlayerData = nil once you are finished with getting the data.

I’ll give this a try, however I’m not sure how I could set the leaderstats any earlier—as soon as it goes through all the proper checks, they get set.

If it ever fails to get data it won’t set those values anyway, I feel like your system is a bit “over” protected, but also not that well…

Right, I’ve set it to kick the player if it fails to get the data.

1 Like

Also, have like a a value inside of the player to tell the player removing script to not save. Because if they’re leaderstats are not loaded in, and if you try to save them, you’re replacing their data with nothing. So create a Bool Value like “CanNotSave” set it to true and only save data if that doesn’t exist or if it’s value it’s false.

I believe what was going on was that the data inside the player added event stayed the same every loop. So if someone didn’t have data or whatever, it would get the person who joined before data’s.

If you’re declaring playerData variable in the start and Only setting it to something if there’s data or if it loaded, then it would get past data, so hm yeah.

Instead of doing playerData before hand, just do a ds request, it will be nil anyway if there’s no data. (You would have to change the structure)

1 Like