local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")
local carCustomizationsData = DataStoreService:GetDataStore("CarCustomizationsData")
local events = ReplicatedStorage:WaitForChild("Events")
local gameData = require(ReplicatedStorage:WaitForChild("GameData"))
local saveCarEvent = events.SaveCar
local purchasedCarsFolder = ServerStorage.PurchasedCars
events.BuyCarUpgrade.OnServerEvent:Connect(function(player, amount, selectedPart, car, whatToChange)
local moneyValue = player:WaitForChild("leaderstats"):WaitForChild("$")
for _, carPart in car:GetDescendants() do
if carPart.Name ~= selectedPart then continue end
if carPart:IsA("Model") then
for _, bpart in carPart:GetDescendants() do
if not bpart:IsA("BasePart") or not bpart:IsA("MeshPart") then continue end
for propertyName, value in whatToChange do
bpart[propertyName] = value
end
end
else
for propertyName, value in whatToChange do
selectedPart[propertyName] = value
end
end
end
moneyValue.Value -= amount
end)
local function FindFirstSimilarChild(haystack, needle)
local wordsTable = string.split(needle, " ")
for _, car in haystack:GetChildren() do
local similarities = 0
local carWordsTable = string.split(car.Name, " ")
for _, word in carWordsTable do
if table.find(wordsTable, word) then
similarities += 1
end
end
if similarities > 1 then
return car
end
similarities = 0
end
return nil
end
game.Players.PlayerAdded:Connect(function(player)
local playerCarInventory = purchasedCarsFolder:WaitForChild(player.Name)
local playerUserId = "Player_"..player.UserId
local dataToLoad = {}
local success, errorMessage = pcall(function()
dataToLoad = carCustomizationsData:GetAsync(playerUserId)
end)
if success and dataToLoad then
for carName, carParts in dataToLoad do
local carToModify = playerCarInventory:FindFirstChild(carName)
if not carToModify then warn("The car that was saved last time doesnt exist in player's inventory no more") continue end
print(carName)
for carPartName, properties in carParts do
for _, carPart in carToModify:GetDescendants() do
if carPartName ~= carPart then continue end
print(carPart.Name)
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for propertyName, propertyValue in properties do
carPart[propertyName] = propertyValue
print("Changed Property of: "..carPart.Name..", and the property was: "..propertyName.." to the ".. propertyValue)
end
elseif carPart:IsA("Model") then
for _, otherCarPart in carPart:GetChildren() do
if not otherCarPart:IsA("BasePart") and not otherCarPart:IsA("MeshPart") then continue end
for propertyName, propertyValue in properties do
otherCarPart[propertyName] = propertyValue
end
end
end
end
end
end
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local playerCarInventory = purchasedCarsFolder:WaitForChild(player.Name)
local playerUserId = "Player_"..player.UserId
local dataToSave = {}
for _, car in playerCarInventory:GetChildren() do
dataToSave[car.Name] = {}
for _, carPart in car:GetDescendants() do
if dataToSave[car.Name][carPart.Name] or not string.find(string.lower(carPart.Name), "paint") then continue end
dataToSave[car.Name][carPart.Name] = {}
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for _, propertyName in gameData.ChangableProperties do
dataToSave[car.Name][carPart.Name][propertyName] = carPart[propertyName] -- the value of the property
end
elseif carPart:IsA("Model") then
for _, otherCarPart in carPart:GetChildren() do
if otherCarPart:IsA("MeshPart") or otherCarPart:IsA("BasePart") then
for _, propertyName in gameData.ChangableProperties do
dataToSave[car.Name][carPart.Name][propertyName] = otherCarPart[propertyName] -- the value of the property
end
end
break
end
end
end
end
print(dataToSave)
pcall(function()
carCustomizationsData:SetAsync(playerUserId, dataToSave)
end)
end)
saveCarEvent.OnServerInvoke = function(player, carToSave, exitTpPart)
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local playerCarInventory = purchasedCarsFolder:FindFirstChild(player.Name)
if not playerCarInventory then warn(`Inventory for {player.Name} in purchasedCars doesn't exist.`) return end
local carToUpdate = FindFirstSimilarChild(playerCarInventory, carToSave:FindFirstChild("CarName").Value)
if not carToUpdate then warn(`Couldn't find {carToSave.Name} in player's inventory`) return end
local updatedParts = {}
for _, carPart in carToUpdate:GetDescendants() do
if not string.find(string.lower(carPart.Name), "paint") or table.find(updatedParts, carPart) then continue end
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for _, carPartOld in carToSave:GetDescendants() do
if carPartOld.Name ~= carPart.Name then continue end
if carPartOld:IsA("BasePart") or carPartOld:IsA("MeshPart") then
carPart.Color = carPartOld.Color
carPart.Transparency = carPartOld.Transparency
carPart.Reflectance = carPartOld.Reflectance
elseif carPartOld:IsA("Model") then
for _, otherCarPart in carPartOld:GetChildren() do
if not carPartOld:IsA("BasePart") or not carPartOld:IsA("MeshPart") then continue end
carPart.Color = carPartOld.Color
carPart.Transparency = carPartOld.Transparency
carPart.Reflectance = carPartOld.Reflectance
end
end
end
elseif carPart:IsA("Model") then
for _, moreOtherCarPart in carPart:GetChildren() do
for _, carPartOld in carToSave:GetDescendants() do
if carPartOld.Name ~= moreOtherCarPart.Name then continue end
if carPartOld:IsA("BasePart") or carPartOld:IsA("MeshPart") then
moreOtherCarPart.Color = carPartOld.Color
moreOtherCarPart.Transparency = carPartOld.Transparency
moreOtherCarPart.Reflectance = carPartOld.Reflectance
elseif carPartOld:IsA("Model") then
for _, otherCarPart in carPartOld:GetChildren() do
if not carPartOld:IsA("BasePart") or not carPartOld:IsA("MeshPart") then continue end
moreOtherCarPart.Color = carPartOld.Color
moreOtherCarPart.Transparency = carPartOld.Transparency
moreOtherCarPart.Reflectance = carPartOld.Reflectance
end
end
end
end
end
end
player:LoadCharacter()
carToSave:Destroy()
player.CharacterAppearanceLoaded:Wait()
character.HumanoidRootPart.CFrame = exitTpPart.CFrame
end
Have you tried printing out the data to save or seeing if there is an error when saving?
Use a BindToClose()
function. This ensures the game has enough time to save.
locak runService = game:GetService("RunService")
game:BindToClose(function()
if runService:IsStudio() then task.wait(5) return end
for _, player in pairs(game.Players:GetPlayers() do
--save
end
task.wait(5)
end)
It’s also worth putting your save and load functions as seperate functions so they can be called more easily from the closing function.
local function save(player:Player)
end
local function load(player:Player)
end
game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
if runService:IsStudio() then task.wait(5) return end
for _, player in pairs(game.Players:GetPlayers()) do
save(player)
end
end)
i did, there are no errors during :SetAsync function
And what does the data to save variable print out?
it prints out everything correctly, here is the picture:
the first two messages are from playerAdded function
could you match it with my script please
Like I said above, you need a BindToClose()
function. No errors and no save data sounds like the game shuts down before it has time to write the data into the store.
When you say the player leaves and it collects their data correctly, that makes sense to me. But what do you mean by the GetAsync method from PlayerAdded returns nil? Have you printed the data and it returns nil?
Also maybe let me know real quick all of the things you’ve tried so we can figure out what else the problem may be.
Also a few questions:
- Have you tried printing the data retrieved from playeradded to see if it loaded all the data
- Have you tested in studio only? Studio may close too fast for a PlayerRemoved function to run everything.
i tried printing the error message and the data gotten from getAsync()
and i have tried testing in the actual game too. it does the same thing
still returns nil.
current script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local carCustomizationsData = DataStoreService:GetDataStore("CarCustomizationsData")
local events = ReplicatedStorage:WaitForChild("Events")
local gameData = require(ReplicatedStorage:WaitForChild("GameData"))
local saveCarEvent = events.SaveCar
local purchasedCarsFolder = ServerStorage.PurchasedCars
events.BuyCarUpgrade.OnServerEvent:Connect(function(player, amount, selectedPart, car, whatToChange)
local moneyValue = player:WaitForChild("leaderstats"):WaitForChild("$")
for _, carPart in car:GetDescendants() do
if carPart.Name ~= selectedPart then continue end
if carPart:IsA("Model") then
for _, bpart in carPart:GetDescendants() do
if not bpart:IsA("BasePart") or not bpart:IsA("MeshPart") then continue end
for propertyName, value in whatToChange do
bpart[propertyName] = value
end
end
else
for propertyName, value in whatToChange do
selectedPart[propertyName] = value
end
end
end
moneyValue.Value -= amount
end)
local function FindFirstSimilarChild(haystack, needle)
local wordsTable = string.split(needle, " ")
for _, car in haystack:GetChildren() do
local similarities = 0
local carWordsTable = string.split(car.Name, " ")
for _, word in carWordsTable do
if table.find(wordsTable, word) then
similarities += 1
end
end
if similarities > 1 then
return car
end
similarities = 0
end
return nil
end
local function save(player)
local playerCarInventory = purchasedCarsFolder:WaitForChild(player.Name)
local playerUserId = "Player_"..player.UserId
local dataToSave = {}
for _, car in playerCarInventory:GetChildren() do
dataToSave[car.Name] = {}
for _, carPart in car:GetDescendants() do
if dataToSave[car.Name][carPart.Name] or not string.find(string.lower(carPart.Name), "paint") then continue end
dataToSave[car.Name][carPart.Name] = {}
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for _, propertyName in gameData.ChangableProperties do
dataToSave[car.Name][carPart.Name][propertyName] = carPart[propertyName] -- the value of the property
end
elseif carPart:IsA("Model") then
for _, otherCarPart in carPart:GetChildren() do
if otherCarPart:IsA("MeshPart") or otherCarPart:IsA("BasePart") then
for _, propertyName in gameData.ChangableProperties do
dataToSave[car.Name][carPart.Name][propertyName] = otherCarPart[propertyName] -- the value of the property
end
end
break
end
end
end
end
print(dataToSave)
pcall(function()
carCustomizationsData:SetAsync(playerUserId, dataToSave)
end)
end
local function load(player)
local playerCarInventory = purchasedCarsFolder:WaitForChild(player.Name)
local playerUserId = "Player_"..player.UserId
local dataToLoad = {}
local success, errorMessage = pcall(function()
dataToLoad = carCustomizationsData:GetAsync(playerUserId)
end)
warn("Error message: "..tostring(errorMessage))
print(dataToLoad)
if success and dataToLoad then
for carName, carParts in dataToLoad do
local carToModify = playerCarInventory:FindFirstChild(carName)
if not carToModify then warn("The car that was saved last time doesnt exist in player's inventory no more") continue end
print(carName)
for carPartName, properties in carParts do
for _, carPart in carToModify:GetDescendants() do
if carPartName ~= carPart then continue end
print(carPart.Name)
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for propertyName, propertyValue in properties do
carPart[propertyName] = propertyValue
print("Changed Property of: "..carPart.Name..", and the property was: "..propertyName.." to the ".. propertyValue)
end
elseif carPart:IsA("Model") then
for _, otherCarPart in carPart:GetChildren() do
if not otherCarPart:IsA("BasePart") and not otherCarPart:IsA("MeshPart") then continue end
for propertyName, propertyValue in properties do
otherCarPart[propertyName] = propertyValue
end
end
end
end
end
end
end
end
game.Players.PlayerAdded:Connect(load)
game.Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
if RunService:IsStudio() then task.wait(5) return end
for _, player in pairs(game.Players:GetPlayers()) do
save(player)
end
end)
saveCarEvent.OnServerInvoke = function(player, carToSave, exitTpPart)
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local playerCarInventory = purchasedCarsFolder:FindFirstChild(player.Name)
if not playerCarInventory then warn(`Inventory for {player.Name} in purchasedCars doesn't exist.`) return end
local carToUpdate = FindFirstSimilarChild(playerCarInventory, carToSave:FindFirstChild("CarName").Value)
if not carToUpdate then warn(`Couldn't find {carToSave.Name} in player's inventory`) return end
local updatedParts = {}
for _, carPart in carToUpdate:GetDescendants() do
if not string.find(string.lower(carPart.Name), "paint") or table.find(updatedParts, carPart) then continue end
if carPart:IsA("BasePart") or carPart:IsA("MeshPart") then
for _, carPartOld in carToSave:GetDescendants() do
if carPartOld.Name ~= carPart.Name then continue end
if carPartOld:IsA("BasePart") or carPartOld:IsA("MeshPart") then
carPart.Color = carPartOld.Color
carPart.Transparency = carPartOld.Transparency
carPart.Reflectance = carPartOld.Reflectance
elseif carPartOld:IsA("Model") then
for _, otherCarPart in carPartOld:GetChildren() do
if not carPartOld:IsA("BasePart") or not carPartOld:IsA("MeshPart") then continue end
carPart.Color = carPartOld.Color
carPart.Transparency = carPartOld.Transparency
carPart.Reflectance = carPartOld.Reflectance
end
end
end
elseif carPart:IsA("Model") then
for _, moreOtherCarPart in carPart:GetChildren() do
for _, carPartOld in carToSave:GetDescendants() do
if carPartOld.Name ~= moreOtherCarPart.Name then continue end
if carPartOld:IsA("BasePart") or carPartOld:IsA("MeshPart") then
moreOtherCarPart.Color = carPartOld.Color
moreOtherCarPart.Transparency = carPartOld.Transparency
moreOtherCarPart.Reflectance = carPartOld.Reflectance
elseif carPartOld:IsA("Model") then
for _, otherCarPart in carPartOld:GetChildren() do
if not carPartOld:IsA("BasePart") or not carPartOld:IsA("MeshPart") then continue end
moreOtherCarPart.Color = carPartOld.Color
moreOtherCarPart.Transparency = carPartOld.Transparency
moreOtherCarPart.Reflectance = carPartOld.Reflectance
end
end
end
end
end
end
player:LoadCharacter()
carToSave:Destroy()
player.CharacterAppearanceLoaded:Wait()
character.HumanoidRootPart.CFrame = exitTpPart.CFrame
end
Instead of just a basic pcall()
, try using that to check for an error.
local success, err = pcall(function()
--code here
end)
if success then
print("it worked")
elseif not success and err then
warn(err)
warn("Failed")
end
Sometimes I find that internal server errors don’t display.
Let me know on what the output is.
Oh, I know the issue. The DataStore
does accept dictionaries, but they can only contain numbers, strings, or booleans. Check if you are trying to save any instances or anything else that isn’t one of those things.
It might be the colour. Are you trying to save a Color3
value?
you are right. i am trying to store color3. my friend recommended me to convert it into a table
Yeah, that’s the problem. I’d suggest saving each value of the Color3
in a string (then concatenate it all into one string with spaces between the colour values), saving that, and loading it back on join.
Say you had a string of the colours (RGB example):
local colourString = "24 56 79"
you can split it to reconfigure the colour:
local splitted = colourString:Split(" ")
local c1 = tonumber(splitted[1])
local c2 = tonumber(splitted[2])
local c3 = tonumber(splitted[3])
local newColour = Color3.fromRGB(c1, c2, c3)
I’m pretty sure you could do the same thing with your decimal numbers, but you might just need to do Color3.new()