Parts of my Datastore aren't working and I don't know why

I’ve edited my script so that it would save player’s hats that hey have bought. But it isn’t working and no errors are turning up in the output which means an if statement is probably returning false somewhere.

     --} Reference services:

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

--} 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 hats = plr:WaitForChild("Hats")
 local keys = {};
 if #gear:GetChildren() > 0 then
  for i, v in next, gear:GetChildren() do
   keys[GenerateID(20)] = v.Name;
  end;
 end;
if #hats:GetChildren() > 0 then
	for x, y in next, hats:GetChildren() do
		keys[GenerateID(25)] = y.Name;
		
		print("Got hat keys")
	end
end
 vault:SetAsync(uid, keys);
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;

for g, l in next, RS.HatShop.ShopItem:GetChildren() do
	if v == l.Name then
		l:Clone().Parent = hats;
		
		print("Loaded hats")
   end;
  end;
	end;
end;

 end;
end;

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

P.PlayerRemoving:connect(function(plr)
 local uid = plr.userId;
 if overwrite then
  SaveData(plr, uid);
  
 else
  return;
 end;
end);

What I have done is removed loadHats() and saveHats(). I put the hat saving part in to both load and save functions however I think there may be a problem in the saving function where it says:

    if #hats:GetChildren() > 0 then
    	for x, y in next, hats:GetChildren() do
    		keys[GenerateID(25)] = y.Name;

because when loading the hats it doesn’t seem to recognise anything stored in the datastore in replicatedstorage. Which results in “Loaded Hats” not being printed and hats not being cloned.

I only have a short observation as I am on phone
there is no “local hats = plr:WaitForChild(“Hats”)”
I suppose that’s what you edited?
hats are placed in a character, unlike inactive gear (StarterGear/Backpack)

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

Yeah, it’s there (same in LoadData() function)


you placed the check for hats inside the check for gears, instead of before or after it
this makes it check for hats only when an element in the datastore matches the name of a gear

“Loaded hats” still isn’t printed and hats are not saved.

a clearer explanation is that a hat will only be loaded if it has the same name as a gear, because it’s inside the hat check is inside the gear check and a condition of that is the name to match one of a gear
that’s what I’ve seen in the load function, and I think it should look more like this

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;
				
		for g, l in next, RS.HatShop.ShopItem:GetChildren() do
			if v == l.Name then
				l:Clone().Parent = hats;
	
				print("Loaded hats")
			end;
		end;

	end;
end;

ofcourse, that won’t work either if the hats are not saved in the first place
are you sure the hats are not saved? does “got hat keys” not print?

I can’t tell because it would be printed when the player leaves. So as far as I know, no.

you could do a local server test with one player or more, and close the clients without closing the server

I’ll try it.

It does print it.

so it does save something in the datastore
have you tried using the LoadData function as I showed above? does it load anything, or nothing still?

Nope, “Loaded hats” doesn’t get printed but weapons that I have bought are loaded.

`if v == l.Name then` 

is coming back false.

you could try

print("comparing",v,"to",l.Name)

before that line to see what it has and what it expects

The hats aren’t being placed into the vault

we could then look at what is inside of “keys” before doing setasync in datastore
since you said it does print “Got hat keys”, it does try to put something in there
instead of

keys[GenerateID(25)] = y.Name;

you could try doing

local generatedID = GenerateId(25);
keys[generatedID] = y.Name;
print("saved",y.Name,"as",keys[generatedID])

this way you could check what saves and if it does get put into “keys” after the attribution
if it doesn’t get put into “keys”, it will show up as “saved (hat as”, with nothing after “as”
although I suspect it would be the datastore that doesn’t agree with a 25 characters long index, rather than the “keys” dictionary

The first thing you should do to debug this is print out all the data you are trying to load.
In LoadData do:

for i, v in next, vault:GetAsync(uid) do
  print(i, " = ", v)
  ---Rest of your code.

See if the names of your hats get printed correctly. If they do not, then you have a problem in your saving code not the loading code.

Another key problem with this datastore code is that you will save a players data even if you did not sucessfully load their data (This causes their data to be overwritten). You should keep a table of players whose data has been successfully loaded so you know whether or not to save.

Your LoadData function could also be much improved using :FindFirstChild instead of looping through everything. Also the inner for loop does not make sense to be there, it should be separate from the code for gears. Something like this would be much better:

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
  print("Loading: ", i, " = ", v)
  local tool = RS:FindFirstChild(v)
  if tool then
    tool:Clone().Parent = pack
    tool:Clone().Parent = gear
  end

  local hat = RS.HatShop.ShopItem:FindFirstChild(v)
  if hat then
    hat:Clone().Parent = hats
  end
end

considering the results of above prints, I’d assume that there’s no hat name stored in the datastore, so that’s why I went on and suggested checking of the savedata function

Sounds like the problem might be that the hats are never placed in the Hats folder, since that code works the exact same way as the gear saving code that does work. Where and how is it done @WhatZitTooyya ?

1 Like

“Where and how is the done”

I don’t understand, sorry

Is it done in a LocalScript or a Script? What is the code that actual does this?

1 Like