Bug with datasaving in tables with module script

I made A car dealer system where the data will be saved in a Module script as long you are in the game when you leave it will be stored to the Roblox datstore. But if someone buys a car somehow everyone gets the car. I don’t know why this is because the script changes the data only for that specific player in the module script. Could someone please help me with this issue.

My code to change the data in the module script for buying a car:

player.leaderstats[config.currency].Value -= carInfo.price
local plate = plateGen()

dataService.profiles[player.Name][carInfo.name].owned = true
dataService.profiles[player.Name][carInfo.name].plate = plate 
print(player.Name)
print(dataService.profiles)

What the output returns to me:

Player1 -  Server - CarHandler:45
{
                    ["Player1"] =  ▼  {
                       ["Car"] =  ▶ {...},
                       ["Volkswagen Golf GTI"] =  ▶ {...},
                       ["Volkswagen Golf"] =  ▶ {...},
                       ["Volkswagen Passat"] =  ▶ {...},
                       ["Volkswagen Touran"] =  ▼  {
                          ["fuel"] = 60,
                          ["owned"] = true,
                          ["plate"] = "KL-260-S"
                       }
                    },
                    ["Player2"] =  ▼  {
                       ["Car"] =  ▶ {...},
                       ["Volkswagen Golf GTI"] =  ▶ {...},
                       ["Volkswagen Golf"] =  ▶ {...},
                       ["Volkswagen Passat"] =  ▶ {...},
                       ["Volkswagen Touran"] =  ▼  {
                          ["fuel"] = 60,
                          ["owned"] = true,
                          ["plate"] = "KL-260-S"
                       }
                    }
}

You can see that Player1 as Player2 got the car. And you can see it is done it is at the same time with the same code because the license plate is the same.

1 Like

Are you iterating over every player when saving their data? It would be quite helpful if you show the DataStore module and the script that’s using the module

1 Like

It does not have something to do with de saving of the data it is just when the script changes the data of one player it is for every player.

But here is the script for the datastore.

--lua
local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local config = require(ReplicatedStorage.AdvantaCarDealer.Config)
local dataStore = DataStoreService:GetDataStore(config.dataStoreName)
local dataManager = require(script.Parent.DataManager)
local dataCategory = "cars"

local template = {}

for _, carInfo in config.cars do
	template[carInfo.name] = {owned = false, fuel = carInfo.maxFuel, plate = nil, primary = nil, secondary = nil, rim = nil}
end

game.Players.PlayerAdded:Connect(function(player)
	
	wait(1)

	dataManager.profiles[player.Name] = template

	local dataFromStore = nil

	local s, e = pcall(function()
		dataFromStore = dataStore:GetAsync(player.UserId.."-"..dataCategory)
	end)

	if s then
		if dataFromStore then
			for i, v in pairs(template) do
				dataManager.profiles[player.Name][i] = dataFromStore[i] or v
			end
		else 
			warn("Error Getting Data For: " .. player.Name)
		end
	end
	
	while wait(120) do

		local DataForStore = {}
		DataForStore = dataManager.profiles[player.Name]
		local success = pcall(dataStore.SetAsync, dataStore, player.UserId.."-"..dataCategory, DataForStore)

	end

end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local DataForStore = {}
	DataForStore = dataManager.profiles[player.Name]
	local success = pcall(dataStore.SetAsync, dataStore, player.UserId.."-"..dataCategory, DataForStore)
	dataManager.profiles[player.Name] = nil
	
end)

game:BindToClose(function()
	wait(2)
end)

The module script:

--lua
local module = {}

module.profiles = {}

return module
1 Like

I don’t understand the need to iterate over the template when storing the data received by GetAsync. Since the data is already being saved in table form, you can just directly set the player’s profile to the data retrieved, or the template if their data is nil:

--lua
local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local config = require(ReplicatedStorage.AdvantaCarDealer.Config)
local dataStore = DataStoreService:GetDataStore(config.dataStoreName)
local dataManager = require(script.Parent.DataManager)
local dataCategory = "cars"

local template = {}

for _, carInfo in config.cars do
	template[carInfo.name] = {owned = false, fuel = carInfo.maxFuel, plate = nil, primary = nil, secondary = nil, rim = nil}
end

game.Players.PlayerAdded:Connect(function(player)
	
	task.wait(1)

	local DataFromStore = nil

	local s, e = pcall(function()
		DataFromStore = dataStore:GetAsync(player.UserId.."-"..dataCategory)
	end)

	if s then
		dataManager.profiles[player.UserId] = DataFromStore or template -- If the player's data is nil, then the template will be used
	end
	
	while true do
		task.wait(120)

		local DataForStore = dataManager.profiles[player.UserId]
		if DataForStore == nil then continue end -- Don't save the player's data if it's somehow set to nil


		local success = pcall(dataStore.SetAsync, dataStore, player.UserId.."-"..dataCategory, DataForStore)

	end

end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local DataForStore = dataManager.profiles[player.UserId]
	if DataForStore == nil then return end -- Don't save the player's data if it's somehow set to nil

	local success = pcall(dataStore.SetAsync, dataStore, player.UserId.."-"..dataCategory, DataForStore)
	dataManager.profiles[player.UserId] = nil
	
end)

game:BindToClose(function()
	task.wait(2)
end)

By the way, it’s not recommended to use the player’s name when storing their data, so you should always use their user ID :slight_smile::+1:

Thank you for improving my script but this didn’t solved the issue unfortunately. I used your version of script and switched to user id’s for saving in the module script but does not solve the problem.

In that case, then the cause of the problem is most likely how you’re currently updating the player’s profile whenever they purchase or modify a car, so I’ll need to see the script that handles the purchases


What @EmberSquared said is correct, you should assign a deep copy of the template to each player, not the original template, otherwise every player will share the same exact template table. They deserve the solution for catching that


On second thought, you were creating a deep copy of the template before assigning it in your original script, I was the one that forgot to do that (sorry about that, and thank you EmberSquared for reminding me). This means that I do need to see how you’re currently handling the purchases in-order to (hopefully) find what’s causing the problem

1 Like

You are assigning the template to every player, try cloning the template rather than directly referencing it.

Maybe use a package TableUtil to DeepCopy the table :+1:

(This is more than likely your issue)

2 Likes