How can I optimize this code?

Hello, I have an issue where multiple people join at the same time and the script doesnt work fast enough to make it through the entire script, is there a way to fix this and or optimzise this code?

	Player.CharacterAdded:Connect(function()	
		local Data = HttpService:JSONDecode(HttpService:GetAsync(URL)) 
		local pointsNum = nil

		leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player
		Miles = Instance.new("IntValue")
		Miles.Name = "Points"
		Miles.Parent = leaderstats
		Rank = Instance.new("StringValue")
		Rank.Parent = leaderstats
		Rank.Name = "Rank"

		task.wait()

		if Player:FindFirstChild("leaderstats"):FindFirstChild("Points") then

		else
			leaderstats = Instance.new("Folder")
			leaderstats.Name = "leaderstats"
			leaderstats.Parent = Player
			Miles = Instance.new("IntValue")
			Miles.Name = "Points"
			Miles.Parent = leaderstats
		end

		local Table = {
			[Player.UserId] =  {
				["Miles"] = 0
			}
		}

		if Data[tostring(Player.UserId)] then

			Miles.Value = Data[tostring(Player.UserId)].Miles
			pointsNum = Data[tostring(Player.UserId)].Miles
		else		print(Player.Name .. " is in the database.")
			print(Player.Name .. " is not in the database.")
			Miles.Value = 0
			local data = HttpService:RequestAsync(
				{
					Url = URL,  
					Method = "PATCH",
					Headers = {
						["Content-Type"] = "application/json"  
					},
					Body = HttpService:JSONEncode(Table)
				}
			)
			Miles.Value = 0
			print(HttpService:JSONEncode(Table))
		end


		local pRank = Player:GetRoleInGroup(tonumber(script.GroupId.Value))

		wait(1)
		local ui = script.Rank:Clone()
		ui.Enabled = true
		ui.Parent = Player.Character
		ui.Adornee = Player.Character.Head

		while not Player.Character.Humanoid do wait() end
		Player.Character.Humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
		local frame = ui.Frame
		local name = frame.name
		local role = frame.Rank	
		local Teir = frame.Teir
		local TeirImage = frame.TeirImage

		name.Text = Player.Name
		role.Text = pRank
		Rank.Value = pRank
		
		print(Player:FindFirstChild("leaderstats"):FindFirstChild("Points"))
		if 	tonumber(pointsNum) > 2279 then
			TeirImage.ImageColor3 = EmeraldTeirColor
			Teir.Text = "Oneworld \ Emerald"
			local Card = game.ReplicatedStorage.PointsSystem.Card["Finnair Plus Platinum"]:Clone()
			Card.Parent = Player.Backpack
		elseif tonumber(pointsNum) > 1379 then
			TeirImage.ImageColor3 = SapphireTeirColor
			Teir.Text = "Oneworld \ Sapphire"
			local Card = game.ReplicatedStorage.PointsSystem.Card["Finnair Plus Gold"]:Clone()
			Card.Parent = Player.Backpack
		elseif tonumber(pointsNum) > 599 then
			TeirImage.ImageColor3 = RubyTeirColor
			Teir.Text = "Oneworld \ Ruby"
			local Card = game.ReplicatedStorage.PointsSystem.Card["Finnair Plus Silver"]:Clone()
			Card.Parent = Player.Backpack
		else
			TeirImage.ImageColor3 = BasicTeirColor
			Teir.Text = "Oneworld \ Basic"
		end
	end)
end)
2 Likes

you should be able to move your local Data outside of the connection to remove a pretty big yeild right off the bat. CharacterAdded is whenever the player spawns so retrieving this server data can be stored in scripts opposed to the internet, try to retrieve it on PlayerAdded instead.

remove wait and task.waits. Player:GetRoleInGroup also yeilds, try to defer it so nothing is waiting on it to finish. I am not sure that your HttpService request is doing anything so I would remove it, or again defer it with task.spawn

Here is an example using task.spawn for GetRoleInGroup

		local humanoid = Player.Character:WaitForChild("Humanoid")
		humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
		local frame = ui.Frame
		local name = frame.name
		local role = frame.Rank	
		local Teir = frame.Teir
		local TeirImage = frame.TeirImage

		name.Text = Player.Name
		role.Text = "loading..."
		Rank.Value = "loading..."
		-- rest of the function isn't stuck waiting for group role, text will be "loading..." until then
		task.spawn(function()
			local pRank = Player:GetRoleInGroup(tonumber(script.GroupId.Value))
			role.Text = pRank
			Rank.Value = pRank
		end)

Thank you, I appreciate this is there possibly any other way to optimize this?

I think the biggest time waster in this script is how you use task.wait() or wait() in order to make sure that things load in, you should just use object:WaitForChild(), for example, instead of doing

task.wait()
if Player:FindFirstChild("leaderstats"):FindFirstChild("Points") then
--stuff
end

you should do

Player:WaitForChild("leaderstats"):WaitForChild("Points")
--stuff

You also seem to have this wait(1) in the middle of your script which is no doubt increasing the time it takes to run by orders of magnitude, removing these waits would be the biggest improvement. Probably.

2 Likes

The single major thing that slows scripts down is yeilding. There is a good amount of yeilding in your script and I feel most is unnecessary like the wait()s. I highly doubt the script is doing anything CPU hard, just waiting around for data from the internet. The only way to speed up waiting around for data from the internet is

  1. Not waiting for data from the internet (minimize it’s use)
  2. Caching data

Preferably stick with 1. like in my example instead of halting the whole script just put a temporary value “loading…” and defer the function so the rest can continue on.


To build on @Absolute_Decimation 's point using :WaitForChild instead of single waits will remove race conditions, with :WaitForChild you are guaranteed to get the value you want and with wait you are just hoping that it is there. It is still potentailly a long wait but you should strongly prefer :WaitForChild if that is why you have waits

Thank you all this has highly improved performance time. If anyone has any more suggestions please do let me know.

I seem to have an issue where theres a large lag spike when players join, I believe this is due to the fact that it has to retrieve the data from Firebase, is there any way I could minimize this lag?

there’s no need:if Player:FindFirstChild("leaderstats"):FindFirstChild("Points") then
since it is the source script that creates the leaderstats and always… but I tell you ALWAYS
It is advisable to make the database script separate from the one created by leaderstats, because if you plan to add something new to your game, tell me, are you going to modify everything again?

You know I understand why you wait for the player’s data to avoid data loss but I tell you that the script that creates the leaderstats can never be the one that manages the database because if many people enter your game quickly the server will be damaged Or if they leave quickly, it will be worse. do the scripts separately

Thank you, however, if I try the scripts separately, there could come an issue where if multiple players join the server quickly like you said it could skip over that player, due to the fact its waiting for the leader stats stuff to be updated