Can someone guide me through this Datastore?

A while ago I had a datastore scripted for me but I’m trying to make it save something else that is in the player. However, I what any of the code is doing.

If someone could just make some comments on the code for each line then it would be most appreciated.

NOTE: This isn’t the full script, just the bit I don’t understand the most and don’t worry about the first 6 variables.

     --} Reference services:

local RS = game:GetService("ReplicatedStorage");
local DSS = game:GetService("DataStoreService");
local P = game:GetService("Players");

local remotes = RS:WaitForChild("RemoteFunctions")
local datastoreRemote = remotes:WaitForChild("Datastore")
local storedHats = {}

--} Reference variables:

local bytes = {
 {97, 122}; --! a-z:
 {65, 90}; --! A-Z:
 {48, 57}; --! 0-9:
};

local overwrite = true;

local vault = DSS:GetDataStore("Test");

--} Reference functions:

function GetRandomCharacter()
 local charset = bytes[math.random(1, 3)];
 return string.char(math.random(charset[1], charset[2]));
end;

function GenerateID(len)
 local id;
 for i = 1, len do
  local char = GetRandomCharacter();
  if not id then
   id = char;
  else
   id = id .. char;
  end;
 end;

 return id;
end;



function SaveData(plr, uid)
 local pack = plr:WaitForChild("Backpack");
 local gear = plr:WaitForChild("StarterGear");
 
 
 
 local keys = {};
 if #gear:GetChildren() > 0 then
  for i, v in next, gear:GetChildren() do
   keys[GenerateID(20)] = v.Name;
  end;
end;
local hats = plr:WaitForChild("Hats");
local hatKeys = {};
end;


function LoadData(plr, uid)
 local pack = plr:WaitForChild("Backpack");
 local gear = plr:WaitForChild("StarterGear");
 local hats = plr:WaitForChild("Hats");

 for i, v in next, vault:GetAsync(uid) do
  for x, y in next, RS:GetChildren() do
   if v == y.Name then
    y:Clone().Parent = pack;
    y:Clone().Parent = gear;

    

end;
  end;
 end;
end;

GetRandomCharacter() returns just that, a random character from the byte list above. It can be any alphabetical character (upper or lower case), or a number.

GenerateID() returns a random string of random characters of a specified length using the above function.

SaveData() generates a relatively random key for each gear name in the players startergear. I assume those keys are saved to the datastore, but that part of the code isn’t shown.

LoadData() (I assume) takes in the key/value pairs previously saved, loops through each one, and checks if the gear name exists within replicated storage. If it does it then copies that gear back into the player.

So this just seems like a generic item saving/loading script, where any item in your game that is given to the player can be saved and reloaded when they join. Though I’m not sure why the random character stuff is even needed. I don’t know why your scripter didn’t just index starting from 1. But not all the code is shown; there may be a reason.

For some reason my Datastore is not Getting Async which means it’s not loading the player’s items. Why is the if statement returning false for?

I made a comment on the if statement near the bottom of the script.

     --} Reference services:

local RS = game:GetService("ReplicatedStorage");
local DSS = game:GetService("DataStoreService");
local P = game:GetService("Players");
local hatShop = RS:WaitForChild("HatShop")
local hatShopItem = hatShop:WaitForChild("ShopItem")

local remotes = RS:WaitForChild("RemoteFunctions")
local datastoreRemote = remotes:WaitForChild("Datastore")
local storedHats = {}

--} Reference variables:

local bytes = {
 {97, 122}; --! a-z:
 {65, 90}; --! A-Z:
 {48, 57}; --! 0-9:
};

local overwrite = true;

local vault = DSS:GetDataStore("Test");

--} Reference functions:

function GetRandomCharacter()
 local charset = bytes[math.random(1, 3)];
 return string.char(math.random(charset[1], charset[2]));
end;

function GenerateID(len)
 local id;
 for i = 1, len do
  local char = GetRandomCharacter();
  if not id then
   id = char;
  else
   id = id .. char;
  end;
 end;

 return id;
end;

function saveHats(plr, uid)
	local hats = plr:WaitForChild("Hats");
	
	local hatKeys = {}
	if #hats:GetChildren() > 0 then
		for i,v in next, hats:GetChildren() do
			hatKeys[GenerateID(20)] = v.Name;
		end;
	end;
end;

function loadHats(plr, uid)
	local hats = plr:WaitForChild("Hats");
	
	for i, v in next, vault:GetAsync(uid) do
		for x, y in next, hatShopItem:GetChildren() do
			if v == y.Name then
				y:Clone().Parent = hats;
			end;
		end;
	end;
end;

function SaveData(plr, uid)
 local pack = plr:WaitForChild("Backpack");
 local gear = plr:WaitForChild("StarterGear");
 
 
 
 local keys = {};
 if #gear:GetChildren() > 0 then
  for i, v in next, gear:GetChildren() do
   keys[GenerateID(20)] = v.Name;
  end;
end;
end;


function LoadData(plr, uid)
 local pack = plr:WaitForChild("Backpack");
 local gear = plr:WaitForChild("StarterGear");
 local hats = plr:WaitForChild("Hats");

 for i, v in next, vault:GetAsync(uid) do
  for x, y in next, RS:GetChildren() do
   if v == y.Name then
    y:Clone().Parent = pack;
    y:Clone().Parent = gear;

    

end;
  end;
 end;
end;

P.PlayerAdded:connect(function(plr)
 local uid = plr.userId;
 if vault:GetAsync(uid) then  --LINE THAT IS RETURNING FALSE
  LoadData(plr, uid);
  loadHats(plr, uid);
  print("Worked - game.Workspace.Data Store")
 else
	print("something went wrong")
  return;
 end;
end);

P.PlayerRemoving:connect(function(plr)
 local uid = plr.userId;
 if overwrite then
  SaveData(plr, uid);
  saveHats(plr, uid);
print("Hats and weapons saved!")
  
 else
  return;
 end;
end);

Your save data function is preparing data to save, but not actually saving it to be read when the player rejoins.

It’s supposed to save the the player leaves

    P.PlayerRemoving:connect(function(plr)
 local uid = plr.userId;
 if overwrite then
  SaveData(plr, uid);
  saveHats(plr, uid);
print("Hats and weapons saved!")
  
 else
  return;
 end;
end);

Those functions don’t actually save any data though. They prepare it all in a table, and in the format it needs to be TO save. But never actually calls the save function for your “vault” database.

It looks like you’re never setting the data in the first place as well. Data is nil when it has never been retrived before, thus causing the vault:GetAsync(uid) to always return false. And like @orange451 said, you’re never actually setting the data in your save function.

The script worked before I added saveHats() and loadHats()

I’m just telling you what I’m observing. It doesn’t look like you’re actually ever using SetAsync based on the code you showed us.

So if I added SetAsync it would work?

It should, as long as you add it in the right places. Also make sure to check if the player has no data and if they don’t set it to some default data. What you have right now is simply printing “Something went wrong” although nothing went wrong, the player’s data has just never been set.

Would this be correct? I don’t know what I should put in the parameters.

    P.PlayerAdded:connect(function(plr)
 local uid = plr.userId;
 if vault:GetAsync(uid) then
  LoadData(plr, uid);
  loadHats(plr, uid);
  print("Worked - game.Workspace.Data Store")
 else
	vault:SetAsync(uid)
  return;
 end;
end);

You should put some sort of default data that your loading functions can handle. How is your data set up?

What do you mean by how is it set up? Sorry I don’t understand Datastores at all.

How is your data saved and loaded? Table (if so explain more), individual number, string?

Saved using IDs I think? I didn’t code it.

    function SaveData(plr, uid)
 local pack = plr:WaitForChild("Backpack");
 local gear = plr:WaitForChild("StarterGear");
 
 
 
 local keys = {};
 if #gear:GetChildren() > 0 then
  for i, v in next, gear:GetChildren() do
   keys[GenerateID(20)] = v.Name;
  end;
end;
end;

The problem with how that is written above is you could have collisions. There’s no guarantee that your key generator is always making unique keys. You could just set the if of the key to “i”? No?