Data duplicates itself when it isn't supposed too

I am making a Datastore system for pets in my game it works well however there’s one problem.

When you trigger the prompt in the video it spawns a pet, I only triggered it once and it creates a StringValue in the data folder, however when I rejoined studio the string value duplicated itself and then when I rejoined again there were multiple pets and multiple string values that duplicated again.

Datastore Code:

local DataHandler = {}

local DataStore2 = require(script.DataStore2)

function DataHandler:LoadData(Player)
	local PlayerData = DataStore2("PlayerData", Player)
	local Data = PlayerData:GetTable({
		PetData = {}
	});

	local PlayerData = Instance.new("Folder")
	PlayerData.Name = Player.Name.."'s PetData"
	PlayerData.Parent = Player
	
	if #Data.PetData > 0 then
		for i = 1, #Data.PetData do
			local Setting = Instance.new("StringValue")
			Setting.Name = Data.PetData[i]
			Setting.Parent = PlayerData
		end
	end
end

function DataHandler:SaveData(Player)
	local NewPetData = {}

	local PlayerData = Player:FindFirstChild(Player.Name.."'s PetData")

	if PlayerData then
		for _, SettingValue in pairs(PlayerData:GetChildren()) do
			warn(SettingValue.Name)
			table.insert(NewPetData, SettingValue.Name)
		end

		local PlayerData = DataStore2("PlayerData", Player)

		PlayerData:Set({
			PetData = NewPetData
		})
	end
end

return DataHandler

I highly believe it is caused by this line of code:

	if #Data.PetData > 0 then
		for i = 1, #Data.PetData do
			local Setting = Instance.new("StringValue")
			Setting.Name = Data.PetData[i]
			Setting.Parent = PlayerData
		end
	end

I have so far found no solution about this.

1 Like

print the data.petdata
to make sure its really 1

1 Like

1 Like

you didnt even show the print part
you only showed that there was 2 values

1 Like

I printed it the number on the output is the data unless you want me to print the whole table.

1 Like

The problem is that you’re saving data that has already been loaded. It basically means you’re saving data twice, which is why the pets duplicate themselves.

Two solutions I can think of (though I’ve never worked with DataStores before):

  1. Before saving data, check if it already exists.
  2. Split the data that is already saved, and the data that will be saved.

I, personally, would prefer the first option. It is cleaner (at least theoretically).

So, here’s an implementation:

function DataHandler:SaveData(Player)
	local NewPetData = {}

	local PlayerData = Player:FindFirstChild(Player.Name.."'s PetData")

	if PlayerData then
		for _, SettingValue in pairs(PlayerData:GetChildren()) do
			local entryAlreadyExists = table.find(NewPetData, SettingValue.Name)
			
			if entryAlreadyExists == false then
				table.insert(NewPetData, SettingValue.Name)
			end
		end

		local PlayerData = DataStore2("PlayerData", Player)

		PlayerData:Set({
			PetData = NewPetData
		})
	end
end

Take it with a grain of salt, though. I’ve never worked with DataStores, much less DataStore2. (which, by the way, you should look for an alternative)

It doesn’t save the data for some reason which causes the data to not load. (Though for some reason it still prints saved playerData)

My bad, it is because I used table.find improperly. When table.find doesn’t find a match, it returns nil, not false. To fix this issue would be to change the if statement’s condition to entryAlreadyExists == nil. Or, if you’d like, not entryAlreadyExists (a little less readable).

1 Like

It works quite well though it still duplicates one StringValue and when I want to have to multiple pets it only lets me have one.

Yes, unfortunately this was intentional in the code itself. ('tis but a feature, not a bug).

I was about to suggest you to use option 2, but shouldn’t DataStore2 provide some kind of Update function? The real fix would be for you to add new entries, not re-add existing entries.

A manual approach would look a like this:

function DataHandler:SaveData(Player, NewData: { StringValue })
	local Data = {}
	
	do
		-- Will *remember* the existing data
		
		local PlayerData = Player:FindFirstChild(Player.Name.."'s PetData")

		if PlayerData then
			for _, SettingValue in pairs(PlayerData:GetChildren()) do
				warn(SettingValue.Name)
				table.insert(Data, SettingValue.Name)
			end
		end
	end
	
	-- Will add the new data
	for _, SettingValue in ipairs(NewData) do
		table.insert(Data, SettingValue.Name)
	end
	
	-- Finally, save.
	local PlayerData = DataStore2("PlayerData", Player)

	PlayerData:Set({
		PetData = NewPetData
	})
end

You’d then have to call SaveData with the new data you want to save.

You could do this by also creating a NewData folder, and calling SaveData(player, NewDataFolder:GetChildren(). Furthermore, you would ALSO need to clear out this folder, otherwise, we will run into the same duplication issue.

Because I’m a bit of a perfectionist myself, I feel like this approach is overcomplicated, though it could be that I am inexperienced in the field. Hope this helps.

This is the script that uses the data module:

local Players = game:GetService("Players")
local DataHandler = require(script.DataHandler)

Players.PlayerAdded:Connect(function(Player)
	DataHandler:LoadData(Player)
end)

Players.PlayerRemoving:Connect(function(Player)
	DataHandler:SaveData(Player)
end)

What am I supposed to do with the save data part since it expects the new data
(Also, I assume that the NewPetData in the code is supposed to be replaced with Data at the start of the function)

1 Like

As I said before, you should create a folder called NewData inside the player (you could do this inside the Players.PlayerAdded callback).

Whenever you want to add data belonging to the player (such as by triggering the prompt, as shown in the video), you’d add a new entry to NewData.

Finally, the Players.PlayerRemoving callback would look like this:

Players.PlayerRemoving:Connect(function(Player)
	local NewData = Player:FindFirstChild("NewData")
	if not NewData then
		error("Player doesn't have a NewData folder? wtf")
	end
	
	DataHandler:SaveData(Player, NewData:GetChildren())
end)

I still think you shouldn’t do it like this (i.e., do at your own risk). Look for a better approach, and for a better DataStore module.

I have since solved this it was actually caused by one of the RemoteFunctions loading in the data as it was inserting StringValues into the folder (The data) then the game recognizes this and loads the data however this would duplicate string values when I loaded the pets in so what I did was just add a Boolean argument whether or not you want to add StringValues into the folder.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.