ProfileService - Need help with diagnosing an issue within my Load Cars System

  1. What do you want to achieve? Keep it simple and clear!
    I want to create a system that loads the cars from the cars table at the beginning and puts them into the player designated folder for these cars to be used and saved later on. I can handle the saving part, but the loading I just can’t seem to get to work.

  2. What is the issue? Include screenshots / videos if possible!
    No matter how I do it, I just can’t seem to get it to work. Refer to the script below. I think the script for some reason just downright ignores the “For” loop under the “LoadCars” function with no immediately obvious reason, after a couple days of trying to diagnose said issue.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve followed many ProfileService tutorials and had a look at similar posts, yet none have helped sadly. Others seem to have the same problem with “For” loops being ignored within ProfileService, but no solutions to this problem have been found yet that suits what I’m doing.

See code here

local ProfileTemplate = {
	Cash = 3500000;
	Level = 1;
	XP = 0;
	Laps = 0;
	LogInTimes = 0;
	Cars = {
		
		"DeltaElise"
		
	}
}

----- Loaded Modules -----

local ProfileService = require(game.ServerScriptService.Libs.ProfileService)

----- Private Variables -----

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")

local CarsStorage = ServerStorage.Cars

local ProfileStore = ProfileService.GetProfileStore(
	"PlayerData",
	ProfileTemplate
)

local Profiles = {} -- [player] = profile

----- Private Functions -----

function SearchTable(Table, directory)
	local Int = 0;
	while Int < #directory do
		Table = Table[directory[Int + 1]];
		Int += 1;
	end;

	return Table;
end;

function RetrieveData(Player, directory)
	local ReturnData = SearchTable(Profiles[Player].Data, directory);

	if ReturnData ~= nil then
		return ReturnData;
	else
		warn("Data not found for "..Player.Name..".");
		return nil;
	end;
end;

local function GiveLeaderstats(player, profile, amount)
	-- Create the Leaderstats folder:
	local leaderstats = Instance.new("Folder")
	leaderstats.Parent = player
	leaderstats.Name = "leaderstats"

	-- Create the stats themselves, XP and LogInTimes will not be shown however:
	local CashStat = Instance.new("NumberValue")
	CashStat.Parent = leaderstats
	CashStat.Name = "Cash"
	
	local LapsStat = Instance.new("IntValue")
	LapsStat.Parent = leaderstats
	LapsStat.Name = "Laps"
	
	local LevelStat = Instance.new("IntValue")
	LevelStat.Parent = leaderstats
	LevelStat.Name = "Level"
	
	print("Player Stats initialised for player: "..player.Name..".")
	
	-- If "Cash" was not defined in the ProfileTemplate at game launch,
	--   you will have to perform the following:
	if profile.Data.Cash == nil then
		profile.Data.Cash = 3500000
	end
	-- Add on the Join Bonus for XP:
	profile.Data.XP = profile.Data.XP + profile.Data.Level * amount
	
	-- Assign the stats to the values:
	CashStat.Value = profile.Data.Cash
	LapsStat.Value = profile.Data.Laps
	LevelStat.Value = profile.Data.Level
	
	-- Other stats will be loaded here anyway since ProfileService automatically
	--	does this.
end

local function LoadCars(player: Player, profile)
	-- Load the player folder:
	local carsFolder = Instance.new("Folder")
	carsFolder.Parent = ServerStorage.PlayerData
	carsFolder.Name = player.Name
	wait(1)
	
	-- Give the player their cars:
	local SavedCars = RetrieveData(player, {profile.Cars})
	
	print(SavedCars[1])
	
	for i = 1, #SavedCars do
		local Car = CarsStorage:FindFirstChild("CarName"):Clone()
		Car.Parent = carsFolder
		print(player.Name.."'s "..Car.Name.." has been loaded.")
	end
	
	print("Cars Given to ".. player.Name.."!")
end
local function DoSomethingWithALoadedProfile(player, profile)
	profile.Data.LogInTimes = profile.Data.LogInTimes + 1
	
	-- Log the Stats earned here and increment XP for join bonus:
	print(player.Name .. " has logged in " .. tostring(profile.Data.LogInTimes)
		.. " time" .. ((profile.Data.LogInTimes > 1) and "s" or ""))
	GiveLeaderstats(player, profile, 500)
	print(player.Name .. " owns " .. tostring(profile.Data.Cash) .. " Cash now!")
	print(player.Name .. " is Level" .. tostring(profile.Data.Level) .. " now!")
	print(player.Name .. " has " .. tostring(profile.Data.XP) .. " XP now!")
	print(player.Name .. " has " .. tostring(profile.Data.Laps) .. " Laps now!")
	
	-- Load player's cars here:
	LoadCars(player, profile)
end

local function PlayerAdded(player)
	
	local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
	if profile ~= nil then
		profile:AddUserId(player.UserId) -- GDPR compliance
		profile:Reconcile() -- Fill in missing variables from ProfileTemplate (optional)
		profile:ListenToRelease(function()
			Profiles[player] = nil
			-- The profile could've been loaded on another Roblox server:
			player:Kick()
		end)
		if player:IsDescendantOf(Players) == true then
			Profiles[player] = profile
			-- A profile has been successfully loaded:
			DoSomethingWithALoadedProfile(player, profile)
		else
			-- Player left before the profile loaded:
			profile:Release()
		end
	else
		-- The profile couldn't be loaded possibly due to other
		--   Roblox servers trying to load this profile at the same time:
		player:Kick() 
	end
end

----- Initialize -----

-- In case Players have joined the server earlier than this script ran:
for _, player in ipairs(Players:GetPlayers()) do
	task.spawn(PlayerAdded, player)
end

----- Connections -----

Players.PlayerAdded:Connect(PlayerAdded)

Players.PlayerRemoving:Connect(function(player)
	local profile = Profiles[player]
	if profile ~= nil then
		profile:Release()
	end
end)

Of course, I’m not asking for someone to write the entire script, just help identify where I’ve gone wrong.

1 Like

When writing code, you are expected to actually read the output window. If you had done so, you would have 100% immediately caught the error here, in the exact loop you mention:

local Car = CarsStorage:FindFirstChild("CarName"):Clone()

You’re looking for a car called “CarName”, and completely disregard the saved cars.
Fixed loop (also please just use ipairs):

	for _, savedCarName in ipairs(SavedCars) do
		local Car = CarsStorage:FindFirstChild(savedCarName):Clone()
                           -->>>               ~~~~~~~~~~~~
 
		Car.Parent = carsFolder
		print(player.Name.."'s "..Car.Name.." has been loaded.")
	end

Thanks, and I have read the output window, if you read closely, giving absolutely nothing at all.

This also has not solved my problem since Line 101 keeps returning nil, and the car doesn’t go into the player folder because the car was nil which was the intended function.

Since you might have gotten confused, I’ll go over the problem again:

The loop in the LoadCars function kept getting skipped for no apparent reason, not even showing up in the output console, it’s just downright skipped and goes to the line after the whole loop.

With your solution, this loop is still skipped for no apparent reason, not even showing up in the output console. Nil is still being returned and the car doesn’t go to the player’s folder.

I see a problem with line 101. I think you can just have local SavedCars = profile.Data.Cars (it’s definitely not supposed to be profile.Cars).

It looks like you got RetrieveData from somewhere else; I’m not sure if you actually need it anywhere, but it looks like it’s meant to be used like this:

local SavedCars = RetrieveData(player, {"Cars"})
-- or, imagine if you had profile.Data.Preferences.MuteAudio:
local MuteAudio = RetrieveData(player, {"Preferences", "MuteAudio"})

Also, note that this section is obsolete – the profile:Reconcile() already handles this:

	-- If "Cash" was not defined in the ProfileTemplate at game launch,
	--   you will have to perform the following:
	if profile.Data.Cash == nil then
		profile.Data.Cash = 3500000
	end