Tables are not saving

  1. What do you want to achieve? i want my tables to save

  2. What is the issue? the last table (Ownedcl) is not saving

  3. What solutions have you tried so far? i looked at devhub but nothing works, no tutorials on youtube.

local save = {}

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("datamaSnef")
local players = game:GetService("Players")



function save.playeraddede(player)

	local coindata
	pcall(function()
		coindata = ds:GetAsync(player.UserId.."Coins")
	end)
	if coindata ~= nil then
		player.leaderstats.Coins.Value = coindata 
	end

	local strndata
	local stdata
	local equippedst
	local equippped 
	local cl
	local equippedcl

	
	local ownedstr = ds:GetAsync(player.UserId.."Ownedst") or {}
	local ownedtools = ds:GetAsync(player.UserId.."Ownedtools") or {}
	local ownedcl = ds:GetAsync(player.UserId.."Ownedcl") or {}
	pcall(function()

		print("BOBOUX")


		strndata = ds:GetAsync(player.UserId.."Strength")
		stdata = ds:GetAsync(player.UserId.."Storage")
		equippedst = ds:GetAsync(player.UserId.."Equippedst")
		equippped = ds:GetAsync(player.UserId.."Equipped")
		cl = ds:GetAsync(player.UserId.."Class")
		equippedcl = ds:GetAsync(player.UserId.."Equippedcl")
		
	end)
	if strndata ~= nil then
		player.leaderstats.Strength.Value = strndata 
		
	end
	
	if cl ~= nil then
		player.leaderstats.Class.Value = cl 

	end
	
	
	if stdata ~= nil then
		player.Storage.Value = stdata 

	end
	
	if equippedst ~= nil then
		player.Equippedst.Value = equippedst 

	end

	
	if equippped ~= nil then
		player.Equipped.Value = equippped 

	end
	

	if cl ~= nil then
		player.EquippedCl.Value = cl

	end

	
	
	for i,v in pairs(ownedstr) do
		local val = Instance.new("StringValue", player.Ownedst)
		val.Name = v
	end
	

	for i,v in pairs(ownedtools) do
		local val = Instance.new("StringValue", player.Ownedtools)
		val.Name = v
	end
	
	
	for i,v in pairs(ownedcl) do
		local val = Instance.new("StringValue", player.Ownedcl)
		val.Name = v
	end

	
	local toolinplayer = game.ReplicatedStorage.Shared.Tools:FindFirstChild(equippped):Clone()
	toolinplayer.Parent = player.Backpack



	local gemdata
	pcall(function()
		gemdata = ds:GetAsync(player.UserId.."Gems")
	end)
	if gemdata ~= nil then
		player.leaderstats.Gems.Value = gemdata 
	end

end

for _,player in pairs(players:GetPlayers()) do
	coroutine.wrap(save.playeraddede)(player)
end

players.PlayerAdded:Connect(save.playeraddede)

players.PlayerRemoving:Connect(function(plr)
	pcall(function()

		local ownedstr = {}
		local ownedtools = {}
		local ownedcl = {}

		for i,v in pairs(plr.Ownedst:GetChildren()) do
			table.insert(ownedstr,v.Name)
		end
		
		for i,v in pairs(plr.Ownedtools:GetChildren()) do
			table.insert(ownedtools,v.Name)
		end
		
		for i,v in pairs(plr.Ownedcl:GetChildren()) do
			table.insert(ownedcl,v.Name)
			print(ownedcl)
		end

		ds:SetAsync(plr.UserId.."Coins", plr.leaderstats.Coins.Value)
		ds:SetAsync(plr.UserId.."Strength", plr.leaderstats.Strength.Value)
		ds:SetAsync(plr.UserId.."Gems", plr.leaderstats.Gems.Value)
		ds:SetAsync(plr.UserId.."Equippedst" ,plr.Equippedst.Value)
		ds:SetAsync(plr.UserId.."Class", plr.leaderstats.Class.Value)
		ds:SetAsync(plr.UserId.."Storage",plr.Storage.Value)
		ds:SetAsync(plr.UserId.."Equippedcl",plr.Equippedcl.Value)
		ds:SetAsync(plr.UserId.."Ownedst",ownedstr)
		ds:SetAsync(plr.UserId.."Ownedtools",ownedtools)
		ds:SetAsync(plr.UserId.."Ownedcl",ownedcl)

		ds:SetAsync(plr.UserId.."Equipped" ,plr.Equipped.Value)
	
	end)

end)

game:BindToClose(function(plr)
	wait(2)
	pcall(function()

		local ownedstr = {}
		local ownedtools = {}
		local ownedcl = {}

		for i,v in pairs(plr.Ownedst:GetChildren()) do
			table.insert(ownedstr,v.Name)
		end

		for i,v in pairs(plr.Ownedtools:GetChildren()) do
			table.insert(ownedtools,v.Name)
		end

		for i,v in pairs(plr.Ownedcl:GetChildren()) do
			table.insert(ownedcl,v.Name)
			print(ownedcl)
		end

		ds:SetAsync(plr.UserId.."Coins", plr.leaderstats.Coins.Value)
		ds:SetAsync(plr.UserId.."Strength", plr.leaderstats.Strength.Value)
		ds:SetAsync(plr.UserId.."Gems", plr.leaderstats.Gems.Value)
		ds:SetAsync(plr.UserId.."Equippedst" ,plr.Equippedst.Value)
		ds:SetAsync(plr.UserId.."Class", plr.leaderstats.Class.Value)
		ds:SetAsync(plr.UserId.."Storage",plr.Storage.Value)
		ds:SetAsync(plr.UserId.."Equippedcl",plr.Equippedcl.Value)
		ds:SetAsync(plr.UserId.."Ownedst",ownedstr)
		ds:SetAsync(plr.UserId.."Ownedtools",ownedtools)
		ds:SetAsync(plr.UserId.."Ownedcl",ownedcl)

		ds:SetAsync(plr.UserId.."Equipped" ,plr.Equipped.Value)

	end)
end)
return save

please help me ASAP thank you.-

It’s very absurd that you are using the SetAsync() 11 times per save when you could have compacted it all into one.

4 Likes

I recommend using Profile Service.

Actually, I recommend avoiding other peoples modules until you have no choice to do otherwise. It will often take a long time to understand how it works (which you may not) in the context of what you are trying to achieve. If at all possible you should code your own methods, this is the path to learning how to make things akin to ProfileService yourself. It is overly complicated for a basic system of writing single ‘named’ values into the stores.

3 Likes

To save all that access, just define a table and store this once in the DataStore. Then it will allow you to expand, change and adapt the data you are trying to store. There is a good example of DataStore use in the “Move It Simulator” provided by Roblox when you create a new place in Studio. Just open the example file and navigate to ServerScriptService/Data/Datastore. You will obviously have to adapt the code to your use, but that is where the knowledge comes from. It has methods of preventing data loss, auto save functionality, and gives good example methods for loading data into a temporary table indexed by a player key when players are added. This method limits the DataStore access (i.e. it only occurs during saving because the temp table is updated rather than the DataStore). It also has good and secure methods to Set/Get data using remotes or binds. I know I said using other peoples code is something to avoid, but the example I have given you requires you to bash in to shape yourself, the ProfileService module does not require editing, or even looking at to make it work, and that for me is a lazy way to code. If you can find an example of some simple code that does something similar to what you want, use that, bash into shape, and learn from it what it is that you just did to it.

1 Like

My updated code:

local save = {}

local dss = game:GetService("DataStoreService")
local ds = dss:GetDataStore("datamaSnef")
local players = game:GetService("Players")



function save.playeraddede(player)

	local coindata
	pcall(function()
		local tablesa = ds:GetAsync(player.UserId.."Currencies") or {}
		coindata = ds:GetAsync(tablesa[1])
	end)
	if coindata ~= nil then
		player.leaderstats.Coins.Value = coindata 
	end

	local strndata
	local stdata
	local equippedst
	local equippped 
	local cl
	local equippedcl

	
	local ownedstr = ds:GetAsync(player.UserId.."Ownedst") or {}
	local ownedtools = ds:GetAsync(player.UserId.."Ownedtools") or {}
	local ownedcl = ds:GetAsync(player.UserId.."Ownedcl") or {}
	local tablesa = ds:GetAsync(player.UserId.."Currencies") or {}
	pcall(function()

		print("BOBOUX")


		strndata = ds:GetAsync(tablesa[2])
		stdata = ds:GetAsync(tablesa[6])
		equippedst = ds:GetAsync(tablesa[4])
		equippped = ds:GetAsync(tablesa[5])
		cl = ds:GetAsync(tablesa[5])
		equippedcl = ds:GetAsync(tablesa[7])
		
	end)
	if strndata ~= nil then
		player.leaderstats.Strength.Value = strndata 
		
	end
	
	if cl ~= nil then
		player.leaderstats.Class.Value = cl 

	end
	
	
	if stdata ~= nil then
		player.Storage.Value = stdata 

	end
	
	if equippedst ~= nil then
		player.Equippedst.Value = equippedst 

	end

	
	if equippped ~= nil then
		player.Equipped.Value = equippped 

	end
	

	if cl ~= nil then
		player.EquippedCl.Value = cl

	end

	
	
	for i,v in pairs(ownedstr) do
		local val = Instance.new("StringValue", player.Ownedst)
		val.Name = v
	end
	

	for i,v in pairs(ownedtools) do
		local val = Instance.new("StringValue", player.Ownedtools)
		val.Name = v
	end
	
	
	for i,v in pairs(ownedcl) do
		local val = Instance.new("StringValue", player.Ownedcl)
		val.Name = v
	end

	
	local toolinplayer = game.ReplicatedStorage.Shared.Tools:FindFirstChild(equippped):Clone()
	toolinplayer.Parent = player.Backpack



	local gemdata
	pcall(function()
		local tablesa = ds:GetAsync(player.UserId.."Currencies") or {}
		gemdata = ds:GetAsync(tablesa[3])
	end)
	if gemdata ~= nil then
		player.leaderstats.Gems.Value = gemdata 
	end

end

for _,player in pairs(players:GetPlayers()) do
	coroutine.wrap(save.playeraddede)(player)
end

players.PlayerAdded:Connect(save.playeraddede)

players.PlayerRemoving:Connect(function(plr)
	pcall(function()

		local ownedstr = {}
		local ownedtools = {}
		local ownedcl = {}

		for i,v in pairs(plr.Ownedst:GetChildren()) do
			table.insert(ownedstr,v.Name)
		end
		
		for i,v in pairs(plr.Ownedtools:GetChildren()) do
			table.insert(ownedtools,v.Name)
		end
		
		for i,v in pairs(plr.Ownedcl:GetChildren()) do
			table.insert(ownedcl,v.Name)
			print(ownedcl)
		end
		
		local currencysave = {
			plr.leaderstats.Coins.Value,
			plr.leaderstats.Strength.Value,
			plr.leaderstats.Gems.Value,
			plr.Equippedst.Value,
			plr.leaderstats.Class.Value,
			plr.Storage.Value,
			plr.Equippedcl.Value
		}

		ds:SetAsync(plr.UserId.."Ownedst",ownedstr)
		ds:SetAsync(plr.UserId.."Ownedtools",ownedtools)
		ds:SetAsync(plr.UserId.."Ownedcl",ownedcl)

		ds:SetAsync(plr.UserId.."Currencies", currencysave)
	
	end)

end)

game:BindToClose(function(plr)
	wait(2)
	pcall(function()

		local ownedstr = {}
		local ownedtools = {}
		local ownedcl = {}

		for i,v in pairs(plr.Ownedst:GetChildren()) do
			table.insert(ownedstr,v.Name)
		end

		for i,v in pairs(plr.Ownedtools:GetChildren()) do
			table.insert(ownedtools,v.Name)
		end

		for i,v in pairs(plr.Ownedcl:GetChildren()) do
			table.insert(ownedcl,v.Name)
			print(ownedcl)
		end

		local currencysave = {
			plr.leaderstats.Coins.Value,
			plr.leaderstats.Strength.Value,
			plr.leaderstats.Gems.Value,
			plr.Equippedst.Value,
			plr.leaderstats.Class.Value,
			plr.Storage.Value,
			plr.Equippedcl.Value
		}

		ds:SetAsync(plr.UserId.."Ownedst",ownedstr)
		ds:SetAsync(plr.UserId.."Ownedtools",ownedtools)
		ds:SetAsync(plr.UserId.."Ownedcl",ownedcl)

		ds:SetAsync(plr.UserId.."Currencies", currencysave)
	end)
end)
return save

it still doesnt save the Ownedcl table

1 Like

It might be because you are using ds:SetAsync(key, value) such so many times; there is a limit of using these functions, please go to this article and scroll down to “Limits”: Data Stores

My tip: try saving everything in just one ds:SetAsync(key, value). Good luck!

I dont think i can, i have 4 tables, one for all currencies, one for the owned tools a player has, one for the owned storage, one for the owned classes. The last table is not saving and the upper limit is 60.

You can have as many as you want, the game I am working on has about 15 different tables, there is no limit. The only limit you have is how many times you ask the server to update the DataStore. That’s why I offered you some advice to look at the example I gave (Move It Simulator). It shows you how to create a temporary copy of the DataStore during player join, and how to change that copy rather than asking the server to change the DataStore all the time, there is no need to do this. This way you are only badgering the server when a player joins, when a player leaves, or when an auto save occurs. All other changes are done to the temporary copy which has no limits on the amount of times you change it.

If your scripting a big game profileservice saves a lot of your time by securing and making your script more efficient.

Quite true, but I have an aversion to use any code that I have not coded myself. Simply because it makes it hard to debug other peoples techniques and style. Coding is an art, through and through, there are several ways to do the same thing, and different minds do it different ways. I have never drawn a picture starting with half a pencil sketch that someone else did. I always start with a blank sheet of paper.

1 Like

but then i only changed the table once and it doesnt save

Okay show me how you did it and I might be able to help you, and I am happy to help if I can.

how to i do what? saving code i gave. if you want how i give a the val, i can shows

Okay, just saw the code you already gave, give me a moment and I’ll solve this for you.

okay, thank you for staying patient!

Okay here we go. The problem with the code is that even though you are using tables to store the data you are still calling GetAsync() and SetAsync() too many times by saving each of the index’s separately. By storing all of your data in a single table it will only require single calls to those two functions.

I would recommend that you use more descriptive names for your variables too, it makes it difficult to see what they mean by someone reading your code, and even for yourself if you come back to this code in a years time.

Here is a bare bones example of a DataStore ModuleScript, it was adapted from the “Move it Simulator” example I gave earlier. You will require a method of accessing the data contained in the DataStore, i.e. with RemoteFunctions, or BindableFunctions, depends on where you need the information. I would recommend using another server Script to set up a bunch of Events that you can use to access the DataStore, that way the DataStore module is only being required in a single place, i.e. changes to it wont be running under race-conditions. There is a bare-bones example of that below the ModuleScript.

ModuleScript to put in ServerScriptService

--=================================================================================
-- Data store
--=================================================================================
local DataStore = {};
DataStore.__index = DataStore;

--=================================================================================
-- Services
--=================================================================================
local DataStoreService = game:GetService("DataStoreService");
local RunService = game:GetService("RunService");
local Players = game:GetService("Players");

--=================================================================================
-- Bool indicating whether data should save in studio (will not change during runtime)
--=================================================================================
local saveInStudio = false;

--=================================================================================
-- Creates the player data store
--=================================================================================
local playerDataStore = nil;
local DataStoreVersion = 1;
if (not saveInStudio) and game.GameId ~= 0 then
	playerDataStore = DataStoreService:GetDataStore("PlayerData"..DataStoreVersion);
end

--=================================================================================
-- Table containing a copy of the player's data
--=================================================================================
local sessionData = {};

--=================================================================================
-- When a players fail to load data, their key is put in a list so that
-- their data does not save and override existing data
--=================================================================================
local tempData = {}

--=================================================================================
-- Constants
--=================================================================================
local AUTOSAVE_DATAINTERVAL = 300;	-- 5 minutes auto save interval
local COINS_INDEX = 1;  -- these are some indexes for accessing values stored in the Currencies table
local GEMS_INDEX = 2;

--=================================================================================
-- The master Data store table
--=================================================================================
local NEW_PLAYER_DATA =
	{
		Strength = 0,
		Storage = 0,
		EquippedDst = 0,
		Equipped = 0,
		Class = 0,
		EquippedClass = 0,
		
		Currencies = {},
		OwnedStorage = {},
		OwnedTools = {},
		OwnedClass = {},
	};

--=================================================================================
-- Local Functions
--=================================================================================
local function load(player)

	local userId = player.UserId;
	local key = "player_" .. tostring(userId);

	-- Return data from cache if it's already loaded
	if sessionData[key] then
		return sessionData[key];
	end	

	-- Try to load data
	if playerDataStore then

		-- Data not loaded, let's go get it
		local success, data = pcall(function()
			return playerDataStore:GetAsync(key);
		end)

		-- Acces to store was successful
		if success then

			if data then

				-- Data exists for this player so assign the session data
				sessionData[key] = data;

			else

				-- Data store is working, but no current data for this player
				warn( "New player  ", key );
				sessionData[key] = NEW_PLAYER_DATA;

			end

			return true;	-- datastore working

		end

		warn( "Cannot access data store for ", key );

	end

	-- Could not load data, treat as new player
	sessionData[key] = NEW_PLAYER_DATA;

	-- When players fails to load data, their key is put in a list so that their
	-- data does not save and override existing data
	tempData[key] = true;
	return false;	-- data store failed!

end

--=================================================================================
--
--=================================================================================
local function save(player)

	local userId = player.UserId;
	local key = "player_" .. tostring(userId);

	-- Save data if it exists and is not temporary
	if sessionData[key] and not tempData[key] then

		-- now save the data.
		local tries = 0;
		local success = nil;
		repeat

			tries = tries + 1;
			success = pcall(function()
				playerDataStore:SetAsync(key,sessionData[key]);
			end)

			if not success then wait(2) end;

		until tries == 3 or success

		if not success then

			warn( "Cannot save data for ", key );

		else

			warn( "Saved data for ", key );

		end

		return success;

	end

end
--=================================================================================
--
--=================================================================================
local function saveOnExit(player)

	local userId = player.UserId;
	local key = "player_" .. tostring(userId);

	-- Save data
	save(player);

	-- Clear cached data
	sessionData[key] = nil;
	tempData[key] = nil;

end

--=================================================================================
-- Function to periodically save player data
--=================================================================================
local function autoSave()

	while wait(AUTOSAVE_DATAINTERVAL) do
		warn( "Auto saving player data..." );
		for key, data in pairs(sessionData) do
			save(key);
		end
	end

end

--=================================================================================
-- On Startup, Start running "autoSave()" function in the background
--=================================================================================
spawn(autoSave);

--=================================================================================
-- Connections
--=================================================================================
Players.PlayerAdded:Connect(function(player)

	DataStore:Load(player);

end)
--=================================================================================
Players.PlayerRemoving:Connect(function(player)

	saveOnExit(player);

end)

--=================================================================================
game:BindToClose(function()

	if RunService:IsStudio() then return end;
	for _, player in ipairs(Players:GetPlayers()) do
		saveOnExit(player);
	end

	warn( "Binding to server close, forced player save.....!" );

end)
--=================================================================================
-- Load/Save data store
--=================================================================================
function DataStore:Load(player)

	return load(player);

end

--=================================================================================
function DataStore:Save(player)

	save(player);

end
--=================================================================================
function DataStore:GetStat(player,stat)

	local userId = player.UserId;
	local key = "player_" .. tostring(userId);

	if not sessionData[key] then return nil end;
	if not sessionData[key][stat] then

		return nil;

	end

	return sessionData[key][stat];

end
--=================================================================================
function DataStore:SetStat(player,stat,value)

	local userId = player.UserId;
	local key = "player_" .. tostring(userId);

	if not sessionData[key] then return nil end;
	if not sessionData[key][stat] then

		return nil;

	end

	sessionData[key][stat] = value;
	print(stat, " changed to ", value);
	return sessionData[key][stat];

end
--=================================================================================

--=================================================================================
return DataStore;
--=================================================================================
-- EOF...
--=================================================================================

This is an event Script also in ServerScriptService that joins the DataStore Module to a bunch of events so that you can access/change the information (usually called Getters and Setters). So you could make all your LeaderStat values here, or send the info back to the client and do that there. This is just an example and is not complete so will need some editing by you to include sanity checks everytime a request is made to change the data. I have put an example for SetStat/GetStat but no examples how to do this for the tables, this will require some fixed index you can use to ensure you change the correct values (that’s what the INDEX_COINS and INDEX_GEMS is for in the ModuleScript). If you want I can help with those too.

PlayerData script:

--=================================================================================
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local ServerEvents = ReplicatedStorage:WaitForChild("ServerEvents",3);
local NotifyChange = ServerEvents:WaitForChild("NotifyChange",3); -- a data changed notify message to return info to the client, to update GUI's or Stats visible to players
local RemoteSetStat = ServerEvents:WaitForChild("SetStat",3);
local RemoteGetStat = ServerEvents:WaitForChild("GetStat",3);
local RemoteGetTable = ServerEvents:WaitForChild("GetTable",3);
local RemoteSetTableValue = ServerEvents:WaitForChild("SetTableValue",3);
local RemoteGetTableValue = ServerEvents:WaitForChild("GetTableValue",3);

local DataStore = require(script.Parent:WaitForChild("DataStore")); -- a single point to access the DataStore Module
--=================================================================================
local function SetStat(player,stat,value)

	-- this is called using a RemoteEvent like this:
	-- RemoteSetStat:FireServer("Strength",2);

	DataStore:SetStat(player,stat,value);
	NotifyChange:FireClient(player,"Some info you may want to send back to a GUI or Leaderstats");

end
--=================================================================================
local function GetStat(player,stat)

	-- this is called with a RemoteFunction like this:
	-- local strength = RemoteGetStat:InvokeServer("Strength");
	return DataStore:GetStat(player,stat);

end
--=================================================================================
local function GetTable(player,table_name)
	
	return DataStore:GetTable(player,table_name);

end
--=================================================================================
local function SetTableValue(player,table_name,value)

	return DataStore:SetTableValue(player,table_name,value);

end
--=================================================================================
local function GetTableValue(player,table_name,table_index)

	return DataStore:GetTableValue(player,table_name,table_index);

end
--=================================================================================
-- remote events (setters)
--=================================================================================
RemoteSetStat.OnServerEvent:Connect(SetStat);
RemoteSetTableValue.OnServerEvent:Connect(SetTableValue);

--=================================================================================
-- remote functions (getters)
--=================================================================================
RemoteGetStat.OnServerInvoke = GetStat;
RemoteGetTable.OnServerInvoke = GetTable;
RemoteGetTableValue.OnServerInvoke = GetTableValue;

--=================================================================================
-- EOF...
--=================================================================================

I hope this helps in some way, it means you will have to make lots of changes to your game, but it makes for easy access to data with minimal calls to SetAsync()/GetAsync().

1 Like

it shows this error : ServerScriptService.saveandloaddata:204: attempt to call a nil value

in this line

DataStore:Load(player);

I dont know if roblox change this but you cant save tables you ha e to save them with json:enconde. I was on like a 2 year haitus so might be wrong

no, u can save tables my code just doesnt work :stuck_out_tongue: