Saved data going to the wrong players

can anyone tell me why this script may cause players to receive other people’s cars and lose money when they load…

Capture

-dealer

local dealer = {}
local func = require(game.ServerScriptService:WaitForChild("functions"))
local data = require(game.ServerScriptService:WaitForChild("BanardDatastore"))
local spawner = game:GetService("InsertService")


local function getSaveableColor3(color)
	if color then
		return {r = color.R, g = color.G, b = color.B}
	else
		return {r = 0, g = 0, b = 0}
	end	
end
local function loadColorFromDataStore(t)
	if t then
		return Color3.new(t.r, t.g, t.b)
	else
		return Color3.new(0,0,0)
	end
end	

local dd = false

function dealer:spawn(plr,vin)
	local sessioncars = workspace:FindFirstChild("SessionCars")
	local target = sessioncars:FindFirstChild(plr.Name.." Car")
	if target then
		for _,v in pairs(target:GetDescendants()) do
			if v:IsA("VehicleSeat") or v:IsA("Seat") then
				v.Disabled = false
				v.Disabled = true
			end
		end
		target:Destroy()
	else
		local s,e = pcall(function()
			local human = plr.Character
			if human then
				local raycastParams = RaycastParams.new();
				raycastParams.FilterType = Enum.RaycastFilterType.Blacklist;
				raycastParams.FilterDescendantsInstances = {plr.Character};
				local ray = workspace:Raycast(human.HumanoidRootPart.Position, Vector3.new(0, 1, 0) * 100, raycastParams);
				if not ray then
					local plrcars = plr:FindFirstChild("ownedcars"):GetChildren()
					local car = plrcars[vin]
					
					local ID = car.Value
					local insert = spawner:LoadAsset(ID)
					local carmodel = insert:FindFirstChildOfClass("Model")
					carmodel.Parent = sessioncars
					carmodel.Name = plr.Name.." Car"
					insert:Destroy()
					
					local seat = carmodel:FindFirstChildOfClass("VehicleSeat")					
					local carcolor = carmodel:FindFirstChildOfClass("Color3Value")
					local own = carmodel:FindFirstChild("Owner")
					local n = carmodel:FindFirstChild("CarName")
					local v = carmodel:FindFirstChild("Vin")
					
					own.Value = plr.Name
					n.Value = car.Name
					v.Value = vin
					carmodel.PrimaryPart = seat
					carcolor.Value = car.Colors.BodyColor.Value
					
					for _,v in pairs(car.BodyOptions:GetChildren()) do
						for _,part in pairs(carmodel.Body.BodyOptions:GetChildren()) do
							if v.Name == part.Name then
								part.Transparency = 0
								part.Parent = carmodel.Body
							end
						end
					end
					
					local fl = carmodel.Wheels.FL.Parts.Wheels:GetChildren()		
					local fr = carmodel.Wheels.FR.Parts.Wheels:GetChildren()
					local rr = carmodel.Wheels.RR.Parts.Wheels:GetChildren()
					local rl = carmodel.Wheels.RL.Parts.Wheels:GetChildren()
					local selected_wheel = car.Wheels.Value
					
					for _,p in pairs(fl) do
						for _,e in pairs(p:GetDescendants()) do
							e.Transparency = 1
						end
					end
					for _,p in pairs(fr) do
						for _,e in pairs(p:GetDescendants()) do
							e.Transparency = 1
						end
					end
					for _,p in pairs(rr) do
						for _,e in pairs(p:GetDescendants()) do
							e.Transparency = 1
						end
					end
					for _,p in pairs(rl) do
						for _,e in pairs(p:GetDescendants()) do
							e.Transparency = 1
						end
					end

					for _,p in pairs(fl) do
						if p.Name == selected_wheel then
							for _,e in pairs(p:GetDescendants()) do
								e.Transparency = 0
							end
						end	
					end
					for _,p in pairs(fr) do
						if p.Name == selected_wheel then
							for _,e in pairs(p:GetDescendants()) do
								e.Transparency = 0
							end
						end	
					end
					for _,p in pairs(rr) do
						if p.Name == selected_wheel then
							for _,e in pairs(p:GetDescendants()) do
								e.Transparency = 0
							end
						end	
					end
					for _,p in pairs(rl) do
						if p.Name == selected_wheel then
							for _,e in pairs(p:GetDescendants()) do
								e.Transparency = 0
							end
						end	
					end
		
					carmodel:MakeJoints()
					local spawnpoint = plr.Character.HumanoidRootPart.CFrame 
					carmodel:SetPrimaryPartCFrame(spawnpoint + Vector3.new(5,3,2))
				else
					game.ReplicatedStorage.Events._DH.notfi:FireClient(plr,"cantspawn")
				end
			end
		end)
		if not s then 
			warn(e)
		end
	end
end


function dealer:stealcar(plr,owner,vin,option)
	local s,e = pcall(function()
		local plrfolder = plr:FindFirstChild("ownedcars")
		local ownerfolder = owner:FindFirstChild("ownedcars"):GetChildren()
		local car = ownerfolder[vin]		
		if option == "steal" then
			local clone = car:Clone()
			clone.Parent = plrfolder
			car.Name = "STOLEN"
			dealer:save(plr)
			dealer:save(owner)
			dealer:spawn(owner)
		elseif option == "sell" then
			car.Name = "STOLEN"
			func:sell(plr,"cash",car.Price.Value)
			dealer:save(plr)
			dealer:save(owner)
			dealer:spawn(owner)
		end
	end)
	if not s then
		warn(e)	
	end
	return s
end


function dealer:loadcar(plr)	
	local plrdata = data:get(plr)	
	local SavedCars = plrdata["cardata"]["cars"]
	local SavedColors = plrdata["cardata"]["colors"]
	local SavedWheels = plrdata["cardata"]["wheels"]
	local SavedBody = plrdata["cardata"]["Bodyopts"]
	for i,v in pairs(SavedCars) do	
		if v ~= "STOLEN" then
			local car = game.ServerStorage.Cars:FindFirstChild(v)
			if car then
				local ownedcars = plr:FindFirstChild("ownedcars")
				local clonecar = car:Clone()
				
				clonecar.Parent = ownedcars
				if SavedColors[i] then
					clonecar.Colors.BodyColor.Value = loadColorFromDataStore(SavedColors[i])
				else
					clonecar.Colors.BodyColor.Value = Color3.new(0,0,0)
				end
				
				if SavedWheels[i] ~= nil then
					clonecar.Wheels.Value = SavedWheels[i]
				else
					clonecar.Wheels.Value = "Stock"
				end
				if SavedBody[i] ~= nil  then
					local opt = SavedBody[i]
					for _,parts in pairs(opt) do
						local part = Instance.new("StringValue")
						part.Name = parts
						part.Parent = clonecar.BodyOptions
					end
				end

			else
				table.remove(SavedCars,i)
				table.remove(SavedColors,i)
				table.remove(SavedWheels,i)
				table.remove(SavedBody,i)
			end
		else
			table.remove(SavedCars,i)
			table.remove(SavedColors,i)
			table.remove(SavedWheels,i)
			table.remove(SavedBody,i)
		end
	end		
end

function dealer:save(plr) -- save the folder to the plrs data
	local plrdata = data:get(plr)
	local SavedCars = plrdata["cardata"]["cars"]
	local SavedColors = plrdata["cardata"]["colors"]
	local SavedWheels = plrdata["cardata"]["wheels"]
	local SavedBody = plrdata["cardata"]["Bodyopts"]

	table.clear(SavedCars)
	table.clear(SavedColors)
	table.clear(SavedWheels)
	table.clear(SavedBody)

	local ownedcars = plr:FindFirstChild("ownedcars")
	if ownedcars:GetChildren() ~= nil then
		for i,car in pairs(ownedcars:GetChildren()) do
			table.insert(SavedCars,i,car.Name)
			local color = getSaveableColor3(car.Colors.BodyColor.Value)
			table.insert(SavedColors,i,color)
			table.insert(SavedWheels,i,car.Wheels.Value)
			local preo = car.BodyOptions:GetChildren()
			local options = {}
			for _,v in pairs(preo) do
				table.insert(options,v.Name)
			end
			table.insert(SavedBody,i,options)	
		end	
	end	
end


return dealer

functions

local game_ = {}

local datastore = require(game.ServerScriptService:WaitForChild("BanardDatastore"))
local settings_ = require(game.ServerScriptService.BanardDatastore:WaitForChild("_idk_"))
local droplimit = 1000000

local abbreviations = {
	N = 10^30;
	O = 10^27;
	Sp = 10^24;
	Sx = 10^21;
	Qn = 10^18;
	Qd = 10^15;
	T = 10^12;
	B = 10^9;
	M = 10^6;
	K = 10^3
}

function abbreviateNums(number)
	local abbreviatedNum = number
	local abbreviationChosen = 0
	for abbreviation, num in pairs(abbreviations) do
		if number >= num and num > abbreviationChosen then
			local shortNum = number / num
			local intNum = math.floor(shortNum)
			abbreviatedNum = tostring(intNum) .. abbreviation .. "+"
			abbreviationChosen = num
		end
	end
	return abbreviatedNum
end


function game_:comma(amount)
	local formatted = amount
	while true do  
		formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
		if (k==0) then
			break
		end
	end
	return formatted
end

function game_:updatemoney(plr)
	local s, e = pcall(function()
		local plrdata = datastore:get(plr)		
		local bankmoney = plrdata.bank	
		local cash = plrdata.cash
		plr.PlayerGui:WaitForChild("MainGuis").Money.BankMoney.Text = "{Bank} $"..game_:comma(bankmoney)
		plr.PlayerGui:WaitForChild("MainGuis").Money.Cash.Text = "{Cash} $"..game_:comma(cash)	
	end)
end

local DT = {}

coroutine.wrap(function() -- drop timer
	while wait(5) do
		--print("working")
		if #DT ~= 0 or nil then
			--print("working 2")
			local randomplr = math.random(1,#DT)
			--print("removed "..randomplr)
			table.remove(DT,randomplr)
		end
	end
end)()

function game_:grab(plr,amount)
	datastore:edit(plr,"cash","+",amount)
	game_:updatemoney(plr)
end


function game_:pay(plr,to_plr,amount)
	local plrdata = datastore:get(plr)
	local plr2data = datastore:get(to_plr)
	local bank = plrdata.bank
	

	if amount > 0 and bank >= amount  then
		datastore:edit(plr,"bank","-",amount)
		wait()
		datastore:edit(to_plr,"bank","+",amount)	
		game_:updatemoney(plr)
		game_:updatemoney(to_plr)
		return true
	else
		return false
	end
end

function game_:transfer(plr,amount,acount_to)	
	local plrdata = datastore:get(plr)
	local bank = plrdata.bank
	local cash = plrdata.cash

	if acount_to == "bank" then
		if amount > 0 and cash >= amount  then
			datastore:edit(plr,"cash","-",amount)
			wait()
			datastore:edit(plr,"bank","+",amount)
			return true
		else
			return false
		end
	end

	if acount_to == "cash" then
		if amount > 0 and bank >= amount then
			datastore:edit(plr,"bank","-",amount)				
			wait()
			datastore:edit(plr,"cash","+",amount)
			return true
		else
			return false
		end
	end

	game_:updatemoney(plr)
end


function game_:buy(plr,acount,amount)
	local plrdata = datastore:get(plr)
	if acount == "bank" then
		local bank = plrdata.bank
		if bank >= amount then
			datastore:edit(plr,"bank","-",amount)
			return true -- aprove purch
		else
			return false -- deny purch
		end
	elseif acount == "cash" then
		local cash = plrdata.cash
		if cash >= amount then
			datastore:edit(plr,"cash","-",amount)
			return true -- aprove purch
		else
			return false -- deny purch
		end
	elseif acount == "both" then
		local cash = plrdata.cash
		local bank = plrdata.bank
		if bank >= amount then
			datastore:edit(plr,"bank","-",amount)
			return true -- aprove purch
		else
			if cash >= amount  then
				datastore:edit(plr,"cash","-",amount)
				return true -- aprove purch
			else
				return false -- deny purch
			end
		end	
	end
	game_:updatemoney(plr)
end

--- badges ---
local BadgeService = game:GetService("BadgeService")


function game_:badge(plr,ID)
	
	local success, hasBadge = pcall(function()
		return BadgeService:UserHasBadgeAsync(plr.UserId, ID)
	end)
	
	if hasBadge then
		return hasBadge 
	else
		local success, result = pcall(function()
			return BadgeService:AwardBadge(plr.UserId, ID)
		end)

	end
	

end

--------------
function game_:sell(plr,acount,amount)
	local plrdata = datastore:get(plr)
	if acount == "bank" then
		local bank = plrdata.bank
		if amount > 0 then
			datastore:edit(plr,"bank","+",amount)
			return true -- aprove purch
		else
			return false -- deny purch
		end
	elseif acount == "cash" then
		local cash = plrdata.cash
		if amount > 0 then
			datastore:edit(plr,"cash","+",amount)
			return true -- aprove purch
		else
			return false -- deny purch
		end
	end
	game_:updatemoney(plr)
end

function game_:Drop(plr,pos,amount)
	local status 
	local s, e = pcall(function()
		local plrtimer = table.find(DT,plr.UserId)
		if not plrtimer then
			table.insert(DT,plr.UserId)
			if amount > 0 then
				if amount <= droplimit then
					local plrdata = datastore:get(plr)
					local cash = plrdata.cash
					if cash >= amount then
						datastore:edit(plr,"cash","-",amount)
						local droppart = game.ServerStorage.Items:WaitForChild("Part")
						local clone = droppart:Clone()
						clone.Parent = workspace
						clone.Value.Value = amount
						clone.CFrame = pos
						game_:updatemoney(plr)
						status = true -- can drop requested amount in plr has enough cash
					else
						status = false -- cant drop, plr doesnt have enough cash
					end
				else
					status = false -- cant drop, plr requested amount too high
				end
			else
				status = false -- amount isnt grader than 0
			end	
		else
			warn(plr.UserId.." Is on drop cooldown")
			status = "CoolDown" -- plr is on cool down
		end
	end)
	if not s then
		warn(e)
	end
	
	return status
end

--- lvl functions ---
-------------------------------------------------------------------
function game_:getlvl(plr)
	local lvl = nil
	local s, e = pcall(function()
		local plrdata = datastore:get(plr)
		lvl =  plrdata.level
	end)
	return lvl
end

function game_:updatetag(plr)
	local s,e = pcall(function()

		local plrdata = datastore:get(plr)
		local tag = game.ServerStorage.GUIs.Charguis:WaitForChild("Rank")
		local char = plr.character
		local head = char:FindFirstChild("Head")
		if head then
			local oldtag = head:FindFirstChild("Rank")
			if oldtag then
				oldtag:Destroy()
			end
			local clone = tag:Clone()
			local mesg = "Loading..."
			if plrdata.level <= 20 then
				mesg = settings_.ranks[1]
				datastore:edit(plr,"targetexp","set",100)
			elseif plrdata.level > 20 and plrdata.level <= 100 then
				mesg = settings_.ranks[2]	
			elseif plrdata.level > 100 and plrdata.level <= 200 then
				mesg = settings_.ranks[3]	
			elseif plrdata.level > 200 and plrdata.level <= 1000 then
				mesg = settings_.ranks[4]
			elseif plrdata.level > 1000 and plrdata.level <= 1200 then
				mesg = settings_.ranks[5]	
				game_:badge(plr,2124924810)
			elseif plrdata.level > 1200 and plrdata.level <= 2000 then
				mesg = settings_.ranks[5]	
			elseif plrdata.level > 2000 and plrdata.level <= 2200 then
				mesg = settings_.ranks[6]	
			elseif plrdata.level >= 10000 then
				mesg = settings_.ranks[7]	
			end
			if plrdata.bounty > 0 then
				clone.T.Text = "[☠️]"..mesg
				clone.T.TextColor3 = plr.TeamColor.Color
			else
				clone.T.Text = mesg
				clone.T.TextColor3 = plr.TeamColor.Color
			end

			clone.Parent = plr.character:WaitForChild("Head")
			
		end
	

	end)
	if not s then
		warn(e)
	end 
		
	
end

function  game_:updatelvl(plr)
	local plrdata = datastore:get(plr)
	local exp = plrdata.exp
	local target = plrdata.targetexp
	if plrdata.exp >= plrdata.targetexp then
		datastore:edit(plr,"level","+",5)
		datastore:edit(plr,"targetexp","mult",10)
	end	
	game_:updatetag(plr)
	plr.PlayerGui:WaitForChild("MainGuis").Money.Level.Text = game_:getlvl(plr)
	plr.PlayerGui:WaitForChild("MainGuis").level.Lvl.Text = "{lVl "..game_:getlvl(plr).."} "..exp.."/"..target
end

function game_:resetlvl(plr)
	local plrdata = datastore:get(plr)
	local exp = plrdata.exp
	local target = plrdata.targetexp
	plrdata.exp = 0
	plrdata.targetexp = 100
	plrdata.level = 0
	wait()
	game_:updatelvl(plr)
end


function game_:givexp(plr,amount)
	datastore:edit(plr,"exp","+",amount)
	game_:updatelvl(plr)	
end

local dd = false

function game_:skiplvl(plr) -- test func, not perm.
	if not dd then dd = true
		datastore:edit(plr,"level","+",20)
		wait()
		game_:updatelvl(plr)
		wait(2)
		dd = false
	end
end


--- market place functions ---
-------------------------------------------------------------------
local market = game:GetService("MarketplaceService")

local function processReceipt(receiptInfo)
	local plr = game.Players:GetPlayerByUserId(receiptInfo.PlayerId)
	if not plr then
		return Enum.ProductPurchaseDecision.NotProcessedYet	
	elseif plr then
		if receiptInfo.ProductId == 1232708412 then
			datastore:edit(plr,"bank","+",20000)
		elseif receiptInfo.ProductId == 1232708435 then
			datastore:edit(plr,"bank","+",500000)
		elseif receiptInfo.ProductId == 1232708564 then
			datastore:edit(plr,"bank","+",2000000)
		elseif receiptInfo.ProductId == 1315073358 then
			local tool = game.ServerStorage.Tools:WaitForChild("Reach tool")
			local clone = tool:Clone()
			clone.Parent = plr.Backpack
		end
		game_:updatemoney(plr)
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end

market.ProcessReceipt = processReceipt

function game_:getinfo(ID)
	local info = market:GetProductInfo(ID, Enum.InfoType.GamePass)
	return info
end

function game_:animationinfo(ID)
	local info = market:GetProductInfo(ID, Enum.InfoType.Asset)
	return info
end

function game_:passcheck(plr,ID)
	if market:UserOwnsGamePassAsync(plr.UserId,ID) then
		return true
	end
end

function game_:buypass(plr,ID)
	market:PromptGamePassPurchase(plr,ID)
end

function game_:buyprod(plr,ID) 
	market:PromptProductPurchase(plr,ID)
end

local passes = {
	animations =  25658556,
}
function game_:loadgp(plr)
	if market:UserOwnsGamePassAsync(plr.UserId,passes.animations) then
		plr.PlayerGui:WaitForChild("MainGuis").Buttons.Animations.Visible = true
	end
end



--- userinput functions ---
-------------------------------------------------------------------
local userinput = game:GetService("UserInputService")

function game_:mobileset(plr) -- when plr joins game on mobile 
	if userinput.TouchEnabled and not userinput.KeyboardEnabled then
		plr.PlayerGui:WaitForChild("MobileButtons").Enabled = true
	end	
end


function game_:toggleguis(plr,stat)
	local gui = plr.PlayerGui
	if stat == false then
		gui:FindFirstChild("MainGuis").Enabled = false
		gui:FindFirstChild("PhoneMain").Enabled = false
	elseif stat == true then
		gui.MainGuis.Enabled = true
		if not userinput.KeyboardEnabled then
			gui:FindFirstChild("MobileButtons").Enabled = true
		end
	end
	
	
	
end



return game_

Any way you could shorten your code? I am not going through 10,000 lines of code.

make sure each player has their own table of individual values, or a table that clones the values for each player, Like PlayerAdded ( inside of it, put the referencial table )

datastores are tricky, I once did that and all data started to mess up in my game, that’s why i placed everything on PlayerAdded, so when a NEW player joins, they will receive a new table

because if you do

local table = {}
without playeradded function

it will consider as ‘‘Global Table’’, this means, if this value is not cloned, they it will just be some global stuff, WHEN reefering the table to each player, EVERY Single player in the server will receive the same table as reference, that means, if someone change something, it will change to everyone else, that said : this looks like a global value(table), and that’s why somehow the data is going to the wrong player, because this is shared with everyone…
( i believe this is what happens, correct me if i said something wrong)

Also, 2 Things… Prints, where exactly is the issue?, you said:

receive other people’s cars and lose money when they load…

first, How they are receiving others cars? i bet there is some wrong variable right there

second- what you mean by losing money? Loading Initial data while joining in the game or

losing money (after someone else loads some random car?)

being [specific] is nice to spot stuff faster

i would love to spot out exactly where it happens but I’m not sure that’s why i just the 2 scripts responsible for the data and game functions

1

the player joins and this folder is made along with the saved cars
and when the player leaves the data table is cleared and a new table is made with the current values in this folder

function dealer:save(plr) -- save the folder to the plrs data
	local plrdata = data:get(plr)
	local SavedCars = plrdata["cardata"]["cars"]
	local SavedColors = plrdata["cardata"]["colors"]
	local SavedWheels = plrdata["cardata"]["wheels"]
	local SavedBody = plrdata["cardata"]["Bodyopts"]

	table.clear(SavedCars)
	table.clear(SavedColors)
	table.clear(SavedWheels)
	table.clear(SavedBody)

	local ownedcars = plr:FindFirstChild("ownedcars")
	if ownedcars:GetChildren() ~= nil then
		for i,car in pairs(ownedcars:GetChildren()) do
			table.insert(SavedCars,i,car.Name)
			local color = getSaveableColor3(car.Colors.BodyColor.Value)
			table.insert(SavedColors,i,color)
			table.insert(SavedWheels,i,car.Wheels.Value)
			local preo = car.BodyOptions:GetChildren()
			local options = {}
			for _,v in pairs(preo) do
				table.insert(options,v.Name)
			end
			table.insert(SavedBody,i,options)	
		end	
	end	
end

How the cars are loaded

function data:load(plr)
	local s, e = pcall(function()
		local key = plr.UserId.."_Data"
		local d = get(key)
		
		if d ~= nil and d ~= {} then
			local olddata = find(plr)
			if olddata then
				remove(plr)
			end
			insertdata(plr,d)
		else
			createdatatable(plr)
		end		
	end)	
	if not s then
		warn(e)
	end
end

** separate script**

It looks like every time someone joins your .PlayerAdded() event runs, but returns the player who joined, so everyone is receiving their stuff.

1 Like