Help with DataStore (read for info)

Hello!
(Please read linked post for more info)
Post

This is my first time using DataStore. I’ve added only one value to make it more simple, I will add more once I get the hang of it. My problem is that it wasn’t saving. So I decide to look at the DevHub.

Article
Then I thought I could try to autosave
And so I copied the code and modified it so it would fit what I am trying to do.

Yet while running the code I got this error:
ServerScriptService.SaveData:25: invalid argument #2 (string expected, got nil)

Here’s my autosave code:
I highly reccomend you see my post and read everything to know everything of what’s going on.
local DataStoreService = game:GetService(“DataStoreService”)
local DataStore1 = DataStoreService:GetDataStore(“DataStore1”)

local function saveData(dataStoreKey, value)
	local setSuccess, errorMessage = pcall(function()
		DataStore1:SetAsync(dataStoreKey, value)
	end)
	print(value)
	if not setSuccess then
		warn(errorMessage)
	end
end

local function Saving(player)
	-- Update data store key
	local playerUserID = player.UserId
	if DataStore1[playerUserID] then
		saveData(playerUserID, DataStore1[playerUserID])
	end
end

while true do
	wait(5)
	local Players = game:GetService("Players")
	local Player = Players:GetPlayers()
	Saving(Player)
end

If this code is bad/not effective or there’s a better way of doing my inital goal (Autosave Data (all values)) then please tell me.

Thanks for reading.

1 Like

It means that ‘value’ is being passed as nil, rather than a string. Try printing ‘value’. Also, I’m not sure why you want to autosave, when you can save when the player enters/leaves the game. Seems like a waste of computer power to me.

1 Like

The reason I am not using that when the player leaves, is as mentionned in the previous post not working. So an autosave every 5-20 seconds would be good. Or even a mannual autosave.

So how should I fix this. Yes this is my first time using DataStore.

What did ‘value’ print as? .PlayerAdded/.PlayerRemoved not working doesn’t really make sense and is symptomatic of something else going on with your code.

1 Like

It’s mostly me having problems with PlayerRemoved (as mentionned in previous post). I also tried to use BindToClose since my game is a single player game. I will print everything and comeback quickly.

@PerilousPanther I tried a new script. Here it is. bad news: STILL DOESN’T SAVE.

local DataStoreService = game:GetService("DataStoreService")
local DataStore1 = DataStoreService:GetDataStore("DataStore1")

local success, currentData = pcall(function()
	return DataStore1:GetAsync("Player_1234")
end)

if success then
	print("Current Data:", currentData)
end


local function saveData(dataStoreKey, value)
	local setSuccess, errorMessage = pcall(function()
		DataStore1:SetAsync(dataStoreKey, value)
	end)
	print(value)
	if not setSuccess then
		warn(errorMessage)
	end
end

local function Saving(player, Data)
	-- Update data store key
	local playerUserID = player.UserId
	if Data then
		saveData(playerUserID, Data)
		print(playerUserID, Data)
	end
end

while true do
	wait(20)
	local Players = game:GetService("Players")
	local Player = Players:GetPlayers()
	local players = Players:GetPlayers()
	for _, player in pairs(players) do
	local playerData = {
		NickName = player.leaderstats.NickName.Value

	}

	local userId = player.UserId
		local data = playerData[userId]

	--print(playerData)
		Saving(player, playerData)
	end	
end

If it could help I can send every scripts. While they are in my previous post it may just save a bit of time.

Ok, so what did it print? I looked at the other post and I’m not sure why you’re using multiple scripts for data loading/saving, or where a potential data leak is coming from. In this kind of situation I think you should start using a datastore module that does a lot of the heavy lifting for you. One of the better ones is ProfileService.

It’s comprehensive, easy to use and enables you to not to worry (generally) about data leaks.

Copied and pasted (I did something in the base script if the value is nil it will be the player’s name)
In order:

18:51:37.717 Current Data: nil - Server - SaveData:9
18:51:37.717 Current Data is: 16Thunderstorm - Server - Data:24
18:51:58.200 ▼ {
[“NickName”] = “16Thunderstorm”
} - Server - SaveData:17
18:51:58.201 484327688 ▼ {
[“NickName”] = “16Thunderstorm”
} - Server - SaveData:28

I’ll try to put everything in one script (base)

What are you doing here?

local success, currentData = pcall(function()
	return DataStore1:GetAsync("Player_1234")
end)

You’re trying to index a DataStore object with a player id. This is NOT how you use datastores. DataStore:GetAsync() is what you should be using. Also, you shouldn’t be saving the data every 5 seconds, since the maximum rate you can save the same value is every 6 seconds, and you should wait every 60 seconds to autosave. Also, this wont be doing anything regardless since you save the exact same data to the data store.

So as of right now I made this:

(I think there are some things I should redo but I’m in a bit of a rush)
@iiPotatoFlamesii
@PerilousPanther

The Script
local DataStoreService = game:GetService("DataStoreService")
local DataStore1 = DataStoreService:GetDataStore("DataStore1")

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Name = Instance.new("StringValue")
	Name.Name = "NickName"
	Name.Parent = leaderstats

	local PlayerUserid = "Player_"..player.UserId

	local Data
	
	
	local success, errormessage = pcall(function()
		Data = DataStore1:GetAsync(PlayerUserid)
	end)
	if success then
		local leaderstats = player:WaitForChild("leaderstats")
		local NickName = leaderstats.NickName
		NickName.Value = Data
		if Data ~= nil then
			Name.Value = Data
			print("Current Data is: "..Name.Value)
			
			print("Data: "..Data)
		else
			Name.Value = Data
			print("Data: "..Data)
			
			print(Name.Value)
			
		end
	else
		print(errormessage)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local PlayerUserid = "Player_"..player.UserId
	local Data = player.leaderstats.NickName.Value
	
	local success, errormessage = pcall(function()
		DataStore1:SetAsync(PlayerUserid, Data)
	end)
	if success then
		print("Data was saved")
	else 
		print("There was an error")
		warn(errormessage)
	end
end)



--CHANGE NICKNAME

--CHANGE NICKNAME

--CHANGE NICKNAME

local Event = game.ReplicatedStorage.DumbInfo.NickName -- Put RemoteEvent here

Event.OnServerEvent:Connect(function(Player, Text)

	local NickName = Player.leaderstats.NickName
	NickName.Value = Text

	local success, newName = pcall(function()
		return DataStore1:UpdateAsync("Player_1234", Text)
	end)

	if success then
		print("New NickName:", NickName.Value)
	end

	print("New NickName: "..NickName.Value)

end)

--CHANGE NICKNAME

--CHANGE NICKNAME

--CHANGE NICKNAME

--DEFAULT TEXT

--DEFAULT TEXT

--DEFAULT TEXT

print("TESTING")
game.Players.PlayerAdded:Connect(function(player)
	local PlayerUserid = "Player_"..player.UserId

	local Data
	

	local success, errormessage = pcall(function()
		Data = DataStore1:GetAsync(PlayerUserid)
	end)
	local GUI = player.PlayerGui:WaitForChild("PlayersCard").Frame.NNFrame
	local TextLabel = GUI.Default
	local TextBox = GUI.ChangeNickName
	print("PLAYER JOINED")
	print(player.Name.." is crazy") --I usually write dumb stuff
	local leaderstats = player:WaitForChild("leaderstats")
	local NickName = leaderstats.NickName
	
	print(NickName.Value, Data)
	if Data == "" or nil then
		print("There is no text")
		TextLabel.Visible = false

	else
		print("THERE IS TEXT")
		TextLabel.Visible = true
		TextLabel.Text = NickName.Value
		TextBox.Text = NickName.Value
	end
end)
-- This part I think a lot of it should be redone.
--DEFAULT TEXT

--DEFAULT TEXT

--DEFAULT TEXT

--SERVER CLOSING

--SERVER CLOSING

--SERVER CLOSING



local Players = game:GetService("Players")

local RunService = game:GetService("RunService")




game:BindToClose(function()
	
	-- if the current session is studio, do nothing
	if RunService:IsStudio() then
		print("YOU'RE IN STUDIO")
		return
	end

	print("saving player data")

	-- go through all players, saving their data
	local players = Players:GetPlayers()
	for _, player in pairs(players) do
		local playerData = {
			NickName = player.leaderstats.NickName.Value
			
		}

		local userId = player.UserId
		local data = playerData[userId]
		if data then
			-- wrap in pcall to handle any errors
			local success, result = pcall(function()
				-- SetAsync yields so will stall shutdown
				DataStore1:SetAsync(userId, data)
			end)
			if not success then
				warn(result)
			end    
		end
	end

	print("completed saving player data")

end)

--SERVER CLOSING

--SERVER CLOSING

--SERVER CLOSING




--AUTOSAVE

--AUTOSAVE

--AUTOSAVE


local success, currentData = pcall(function()
	return DataStore1:GetAsync("Player_1234")
end)

if success then
	print("Current Data:", currentData)
end


local function saveData(dataStoreKey, value)
	local setSuccess, errorMessage = pcall(function()
		DataStore1:SetAsync(dataStoreKey, value)
	end)
	print(value)
	if not setSuccess then
		warn(errorMessage)
	end
end

local function Saving(player, Data)
	-- Update data store key
	local playerUserID = player.UserId
	if Data then
		saveData(playerUserID, Data)
		print(playerUserID, Data)
	end
end

while true do
	wait(20) -- Changed it so it's not so frequent, might make it longer
	local Players = game:GetService("Players")
	local Player = Players:GetPlayers()
	local players = Players:GetPlayers()
	for _, player in pairs(players) do
		local playerData = {
			NickName = player.leaderstats.NickName.Value

		}

		local userId = player.UserId
		local data = playerData[userId]

		--print(playerData)
		Saving(player, playerData)
	end	
end

--AUTOSAVE

--AUTOSAVE

--AUTOSAVE

I really think there are parts that I have to redo.

I have to. Definetly I have to redo

Why are you updating a sync to Player_1234?

local success, newName = pcall(function()
		return DataStore1:UpdateAsync("Player_1234", Text)
	end)

This was probably made when I started to learn how DataStore works (I am still learning).

This too:

Where it says “Player_1234” put the playerID, otherwise the data will never be loaded/ updated.

1 Like

I’ll start rewriting, but please know as of writing this I am at school, so I won’t be so available. But I’ll try. So I’ll rewrite it part by part.

So this is the first part:

local DataStoreService = game:GetService("DataStoreService")
local DataStore1 = DataStoreService:GetDataStore("DataStore1")
--The basics, we get our DataStore
game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Name = Instance.new("StringValue")
	Name.Name = "NickName"
	Name.Parent = leaderstats
--There will be more

	local PlayerUserid = "Player_"..player.UserId
print(PlayerUserid)
--Just for the sake of it.

	local Data
	
	
	local success, errormessage = pcall(function()
		Data = DataStore1:GetAsync(PlayerUserid)
	end)
	if success then
--Getting our leaderstats of the player
		local leaderstats = player:WaitForChild("leaderstats")
		local NickName = leaderstats.NickName
		NickName.Value = Data --Just so the value is changed
		if Data ~= nil then --If nothing existed before

		Data = player.Name --Default NickNames will be the player’s name.
			print("Current Data is: "..Name.Value) --It will be nil
			
			print("Data: "..Data)
		else
			Name.Value = Data
			print("Data: "..Data)
			--Nothing needs to be done here
			print(Name.Value)
			
		end
	else
		print(errormessage)
	end
end)

I might rewrite this since I will have to add more values.