Script takes too long to run through

Basically, my client script runs all of the four menu buttons and is taking way too long to complete.
The script will allow for buttons to be made based on a few modules. It’s taking around 30-60 seconds to fully complete.

I apologize in advance for the long code but I’m just confused on how this is taking so long. There are no wait() to slow it down. (only waits are in some functions which don’t run unless called)

I’m not quite sure if this counts as code review so I’ll leave it in scripting support unless someone can confirm.


local player = game:GetService('Players').LocalPlayer
--Services
local Rep = game:GetService("ReplicatedStorage")
local PlayerGui = player:WaitForChild("PlayerGui")
local MPS = game:GetService("MarketplaceService")
local Teams = game:GetService("Teams")
--Variables
local Modules = Rep:FindFirstChild("Modules")
local Menu = PlayerGui:WaitForChild("Menu")
	local AnimationsFrame = Menu:FindFirstChild("Animations")
	local GamepassesFrame = Menu:FindFirstChild("Gamepasses")
	local SubMenuFrame = Menu:FindFirstChild("Menu")
		local SubMenuFrameButtons = SubMenuFrame:FindFirstChild("Buttons")
	local TeamsFrame = Menu:FindFirstChild("Teams")
	local UniformsFrame = Menu:FindFirstChild("Uniforms")
local Remotes = Rep:FindFirstChild("Remotes")
	local R_Event = Remotes:FindFirstChild("MenuEvent")

local AccessorieRemove = UniformsFrame:FindFirstChild("Frame"):FindFirstChild('AccessoriesDelete')
local udim = UDim2.new
local CanToggleMenu = true
local AnimationsFolder = script:FindFirstChild("Animations")
local CurrentPlayingAnimation
local CanAnimate = true
--Modules
local PurchaseableMod = require(Modules.PurchaseableItems)
local UniformsMod = require(Modules.Uniforms)
local GamepassesMod = require(Modules.Gamepasses)
local AccessoriesMod = require(Modules.Accessories)
local TeamsMod = require(Modules:WaitForChild("Teams"))

wait()

local SaveOutfit = UniformsFrame:FindFirstChild('Frame'):FindFirstChild('OutfitSave')
local PlayerValues = Rep:WaitForChild('PlayerValues')
local myValue = PlayerValues:WaitForChild("uid_"..player.UserId)
local EnableCustom = myValue:WaitForChild('EnableCustom')
--Tables

warn('Main Client..')
Menu.Gamepasses.Visible = true

local TweenFrames = {
	{
		Frame = SubMenuFrame,
		ToggleButton = SubMenuFrame.Open,
		ClosedTween = udim(-.1,0,.356,0),
		OpenTween = udim(.005,0,.356,0),
		TweenDirection = Enum.EasingDirection.InOut,
		TweenStyle = Enum.EasingStyle.Linear,
		Time = .2,
	},
	{
		Frame = AnimationsFrame,
		ToggleButton = SubMenuFrameButtons.AnimationPadding.Animations,
		CloseButton = AnimationsFrame.Close,
		ClosedTween = udim(-.4,0,.7,0),
		OpenTween = udim(0,10,.7,0),
		TweenDirection = Enum.EasingDirection.InOut,
		TweenStyle = Enum.EasingStyle.Linear,
		Time = .2,
	},
	{
		Frame = GamepassesFrame,
		ToggleButton = SubMenuFrameButtons.GamepassesPadding.Gamepasses,
		CloseButton = GamepassesFrame.Close,
		ClosedTween = udim(-.4,0,.25,0),
		OpenTween = udim(.325,0,.25,0),
		TweenDirection = Enum.EasingDirection.InOut,
		TweenStyle = Enum.EasingStyle.Linear,
		Time = .2,
		FramesToClose = {TeamsFrame,UniformsFrame}
	},
	{
		Frame = TeamsFrame,
		ToggleButton = SubMenuFrameButtons.TeamPadding.Teams,
		CloseButton = TeamsFrame.Close,
		ClosedTween = udim(-.4,0,.25,0),
		OpenTween = udim(.3,0,0.044,0),
		TweenDirection = Enum.EasingDirection.InOut,
		TweenStyle = Enum.EasingStyle.Linear,
		Time = .2,
		FramesToClose = {GamepassesFrame,UniformsFrame}
	},
	{
		Frame = UniformsFrame,
		ToggleButton = SubMenuFrameButtons.UniformsPadding.Uniforms,
		CloseButton = UniformsFrame.Close,
		ClosedTween = udim(-.6,0,.25,0),
		OpenTween = udim(0.235, 0,0.206, 0),
		TweenDirection = Enum.EasingDirection.InOut,
		TweenStyle = Enum.EasingStyle.Linear,
		Time = .2,
		FramesToClose = {GamepassesFrame,TeamsFrame}
	},
}
local MainFrames = {
	AnimationsFrame,
	GamepassesFrame,
	TeamsFrame,
	UniformsFrame,
}
local Buttons = {
	{Button = GamepassesFrame.Buttons.DevProducts, ActionFrame = GamepassesFrame.DevProducts, Type = "Open", FramesToClose = {GamepassesFrame.Gamepasses}},
	{Button = GamepassesFrame.Buttons.Gamepasses, ActionFrame = GamepassesFrame.Gamepasses, Type = "Open", FramesToClose = {GamepassesFrame.DevProducts}},
	{Button = UniformsFrame.Buttons.Accessories, ActionFrame = UniformsFrame.Accessories, Type = "Open", FramesToClose = {UniformsFrame.Allied,UniformsFrame.Army,UniformsFrame.Covers,UniformsFrame.Faces,UniformsFrame.Intelligence}},
	{Button = UniformsFrame.Buttons.Allied, ActionFrame = UniformsFrame.Allied, Type = "Open", FramesToClose = {UniformsFrame.Accessories,UniformsFrame.Army,UniformsFrame.Covers,UniformsFrame.Faces,UniformsFrame.Intelligence}},
	{Button = UniformsFrame.Buttons.Army, ActionFrame = UniformsFrame.Army, Type = "Open", FramesToClose = {UniformsFrame.Accessories,UniformsFrame.Allied,UniformsFrame.Covers,UniformsFrame.Faces,UniformsFrame.Intelligence}},
	{Button = UniformsFrame.Buttons.Covers, ActionFrame = UniformsFrame.Covers, Type = "Open", FramesToClose = {UniformsFrame.Accessories,UniformsFrame.Allied,UniformsFrame.Army,UniformsFrame.Faces,UniformsFrame.Intelligence}},
	{Button = UniformsFrame.Buttons.Faces, ActionFrame = UniformsFrame.Faces, Type = "Open", FramesToClose = {UniformsFrame.Accessories,UniformsFrame.Allied,UniformsFrame.Army,UniformsFrame.Covers,UniformsFrame.Intelligence}},
	{Button = UniformsFrame.Buttons.Intelligence, ActionFrame = UniformsFrame.Intelligence, Type = "Open", FramesToClose = {UniformsFrame.Accessories,UniformsFrame.Allied,UniformsFrame.Army,UniformsFrame.Covers,UniformsFrame.Faces}},
}
local Animations = {
	["Salute1"] = AnimationsFolder.Salute1,
	["Salute2"] = AnimationsFolder.Salute2,
	["At-Ease1"] = AnimationsFolder.AtEase1,
	["At-Ease2"] = AnimationsFolder.AtEase2,
	["Push-ups"] = AnimationsFolder.Pushups,
	["Salute1Hold"] = AnimationsFolder.Salute1Hold,
	["At-Ease1Hold"] = AnimationsFolder.AtEaseHold,
}
local LoadedAnimations = {}
local ConnectedAnimations = {
	["Salute"] = {[1] = "Salute1",[2] = "Salute2"},
	["At-Ease"] = {[1] = "At-Ease1",[2] = "At-Ease2"}
}
local GamepassCache = {}
--Pre-initialization
for i,v in pairs(Animations) do
	LoadedAnimations[tostring(i)] = {nil}
end
--Functions



local function Fire(action,args)
	R_Event:FireServer(action,args)
	print('fioreeeeeeeee')
end
function InteractAnim(action)
	if action == "Stop" then
		if CurrentPlayingAnimation ~= nil and LoadedAnimations[CurrentPlayingAnimation][1] ~= nil then
			LoadedAnimations[CurrentPlayingAnimation][1]:Stop()
			CurrentPlayingAnimation = nil
		end
	elseif action == "Play" then
		if player and player.Character and player.Character:FindFirstChild("Humanoid") then
			if LoadedAnimations[CurrentPlayingAnimation][1] == nil then
				 LoadedAnimations[CurrentPlayingAnimation][1] = player.Character.Humanoid:LoadAnimation(Animations[CurrentPlayingAnimation])
			end
			if LoadedAnimations[CurrentPlayingAnimation][1] ~= nil then
				LoadedAnimations[CurrentPlayingAnimation][1]:Play()
				if CurrentPlayingAnimation == "Salute1" or CurrentPlayingAnimation == "At-Ease1" then
					wait(.25)
					local newAnimName = CurrentPlayingAnimation.."Hold"
					InteractAnim("Stop")
					CurrentPlayingAnimation = newAnimName
					InteractAnim("Play")
				end
				if CurrentPlayingAnimation == "Salute2" or CurrentPlayingAnimation == "At-Ease2" then
					wait(.25)
					CurrentPlayingAnimation = nil
					InteractAnim("Stop")
				end
			end
		end
	end
end
local function AnimatePlayer(animationName)
	if CanAnimate then
		CanAnimate = false
		if LoadedAnimations[animationName] and LoadedAnimations[animationName] ~= nil then
			if CurrentPlayingAnimation == animationName then
				InteractAnim("Stop")
			else
				CurrentPlayingAnimation = animationName
				InteractAnim("Play")
			end
		else
			for i,v in pairs(ConnectedAnimations) do
				if i == animationName then
					for x,d in pairs(v) do
						if CurrentPlayingAnimation ~= nil and string.sub(CurrentPlayingAnimation,1,#i) == i then
							if d == string.sub(CurrentPlayingAnimation,1,#d) then
								InteractAnim("Stop")
								if #v >= x+1 then
									CurrentPlayingAnimation = v[x+1]
									InteractAnim("Play")
								end
								break
							end
						else
							InteractAnim("Stop")
							CurrentPlayingAnimation = v[1]
							InteractAnim("Play")
							break
						end
					end
					break
				end
			end
		end
		wait(1)
		CanAnimate = true
	end
end
local function CreateNewTemplate(template,parent)
	local template = template:Clone()
	template.Parent = parent
	return template
end
local function Purchase(id,Type)
	Fire("PromptPurchase",{Id = id, Type = Type})
end
local function TweenOut(frame)
	for i,v in pairs(TweenFrames) do
		if v.Frame == frame then
			CanToggleMenu = false
			frame:TweenPosition(v.ClosedTween,v.TweenDirection,v.TweenStyle,v.Time)
			wait(v.Time)
			CanToggleMenu = true
			return
		end
	end
	return false
end
--//INITIALIZATION\\

warn('INITIALIZATION..')

for i,v in pairs(GamepassesMod) do
	for x,d in pairs(v) do
		local id = d
		local t = CreateNewTemplate(GamepassesFrame.Template,GamepassesFrame[i])
		local itemType
		if i == "Gamepasses" then
			itemType = 2
		elseif i == "DevProducts" then
			itemType = 1
		end
		local productinfo = MPS:GetProductInfo(id,itemType)
		local imageid,price = productinfo.IconImageAssetId,productinfo.PriceInRobux
		t:WaitForChild('ImageFrame').ImageLabel.Image = "rbxassetid://"..imageid
		t.TextFrame.Title.Text = x .. " - R$" .. price
		t.TextFrame.Purchase.MouseButton1Down:connect(function()
	
			Purchase(id,i)
				
				
		end)
		t.Visible = true
	end
	end
	
for i,v in pairs(TeamsMod) do
	local t = CreateNewTemplate(TeamsFrame.Template,TeamsFrame.ScrollingFrame)
	t.Frame.TextLabel.Text = i
	t.Visible = true
	t.Frame.TextButton.MouseButton1Down:connect(function()
		
			
			if player.Team.Name ~= "Visitors" and i == "Raiders" then
				-- no
			else
				Fire("ChangeTeam",{TeamName = i})
			end
			
			

		
	end)
end

warn('INT1A')
for i,v in pairs(PurchaseableMod) do
	local t = CreateNewTemplate(UniformsFrame.Template,UniformsFrame.Faces)
	local id = v.id
	local productinfo = MPS:GetProductInfo(id,2)
	local imageid,price = productinfo.IconImageAssetId,productinfo.PriceInRobux
	t.ImageFrame.ImageLabel.Image = "rbxassetid://"..v.decalID
	t.TextFrame.TextLabel.Text = i .. " - R$" .. price
	GamepassCache[id] = t
	if not MPS:UserOwnsGamePassAsync(player.UserId,id) then
		t.TextFrame.TextButton.Text = "Purchase"
	end
	
	t.TextFrame.TextButton.MouseButton1Down:connect(function()
		
			if not MPS:UserOwnsGamePassAsync(player.UserId,id) then
				Purchase(id,"Gamepasses")
			else
				Fire("Equip", {Type = "Face",Id = id})
			end
			
			
	end)
	t.Visible = true
end


warn('INITIALIZATION2..')

for i,v in pairs(UniformsMod) do
	for x,d in ipairs(v.Items) do
		if d.shirt ~= nil then
			local t = CreateNewTemplate(UniformsFrame.Template,UniformsFrame[i])
			t.TextFrame.TextLabel.Text = d.name
			t.ImageFrame.ImageLabel.Image = "rbxassetid://"..d.guiImage
				
			t.TextFrame.TextButton.MouseButton1Down:connect(function()
				
					Fire("Equip", {Type = "Uniform",Group = i,Name = d.name})
						
					
			end)
			t.Visible = true
		end
		
		if #d.helmet >= 1 then
			for int,obj in pairs(d.helmet) do
				local t = CreateNewTemplate(UniformsFrame.Template,UniformsFrame.Covers)
				t.TextFrame.TextLabel.Text = d.helmet[1].Name
				t.ImageFrame.ImageLabel.Image = "rbxassetid://"..d.helmetImage
				t.TextFrame.TextButton.MouseButton1Down:connect(function()
						Fire("Equip", {Type = "Cover",Group = i,Name = d.helmet[1].Name})
					
					
				end)
				
				t.Visible = true
			end
		end
	end
end


for i,v in pairs(AccessoriesMod) do
	
	local t = CreateNewTemplate(UniformsFrame.Template,UniformsFrame["Accessories"])
	t.TextFrame.TextLabel.Text = i
	
	local itemInfo = MPS:GetProductInfo(v.GPId, Enum.InfoType.GamePass)
	
	t.ImageFrame.ImageLabel.Image = "rbxassetid://"..itemInfo.IconImageAssetId
	if MPS:UserOwnsGamePassAsync(player.UserId,v.GPId) then
		t.TextFrame.TextButton.Text = "Equip"
	else
		t.TextFrame.TextButton.Text = "Purchase"
	end
	t.Visible = true
	
	t.TextFrame.TextButton.MouseButton1Down:connect(function()
		
			if not MPS:UserOwnsGamePassAsync(player.UserId,v.GPId) then
				Purchase(v.GPId,"Gamepasses")
			else
				Fire("Equip", {Type = "Accessory",Name = i})
			end
			
	end)
	GamepassCache[v.GPId] = t
	
end


warn('INITIALIZATION3..')
for i,v in pairs(TweenFrames) do
	--v.Frame.Position = v.ClosedTween
	v.ToggleButton.MouseButton1Down:connect(function()
		if CanToggleMenu == true then
			CanToggleMenu = false
			local EaseType
			if v.Frame.Position == v.ClosedTween then
				EaseType = "OpenTween"
			else
				EaseType = "ClosedTween"
			end
			if v.FramesToClose then
				for x,d in pairs(v.FramesToClose) do
					local tween = TweenOut(d)
					if tween == false then
						d.Visible = false
					end
				end
			end
			v.Frame:TweenPosition(v[EaseType],v.TweenDirection,v.TweenStyle,v.Time)
			wait(v.Time)
			CanToggleMenu = true
			if v.CloseButton then
				v.CloseButton.MouseButton1Down:connect(function()
					TweenOut(v.Frame)
				end)
			end
		end
	end)
end
--Events
R_Event.OnClientEvent:connect(function(action,args)
	if action == "NewChar" then
		CurrentPlayingAnimation = nil
		for i,v in pairs(LoadedAnimations) do
			v[1] = nil
		end
	end
end)

warn('INITIALIZATION4..')
MPS.PromptGamePassPurchaseFinished:connect(function(plr,id,purchased)
	for i,v in pairs(AccessoriesMod) do
		if id == v.GPId then
			local frame = GamepassCache[id]
			if frame and frame ~= nil then
				frame.TextFrame.TextButton.Text = "Equip"
			end
			break
		end
	end
	for i,v in pairs(PurchaseableMod) do
		if v.id == id then
			local frame = GamepassCache[id]
			if frame and frame ~= nil then
				frame.TextFrame.TextButton.Text = "Equip"
			end
			break
		end
	end
end)
--Misc
for i,v in pairs(Buttons) do
	v.Button.MouseButton1Down:connect(function()
		for i,v in pairs(v.FramesToClose) do
			v.Visible = false
		end
		if v.Type == "Toggle" then
			v.ActionFrame.Visible = not v.ActionFrame.Visible
		elseif v.Type == "Close" then
			v.ActionFrame.Visible = false
		elseif v.Type == "Open" then
			v.ActionFrame.Visible = true
		end
	end)
end
for i,v in pairs(AnimationsFrame.ScrollingFrame:GetChildren()) do
	if v:IsA("Frame") then
		v.Frame.TextButton.MouseButton1Down:connect(function()
			AnimatePlayer(v.Frame.TextButton.Text)
		end)
	end
end


AccessorieRemove.MouseButton1Down:Connect(function()
	Fire("AccessorieDelete", {Type = "All"})
end)

SaveOutfit.MouseButton1Down:Connect(function()
	Fire('SaveOutfit', {Type = "All"})
end)

if EnableCustom.Value == true then
	SaveOutfit.Text = "SAVE OUTFIT (TRUE)"
else
	SaveOutfit.Text = "SAVE OUTFIT (FALSE)"
end

EnableCustom.Changed:Connect(function()
	if EnableCustom.Value == true then
		SaveOutfit.Text = "SAVE OUTFIT (TRUE)"
	else
		SaveOutfit.Text = "SAVE OUTFIT (FALSE)"
	end
end)

I really can’t see why it’s taking this long to run through.

EDIT: By using prints it seems that the delay is coming heavily from the for i,v in pairs(PurchaseableMod) do

1 Like

That is way too giant a code block. The fact that your script is this big sets off flags in my head in regards to organisation and maintainability. Furthermore, it seems that you have a lot of unnecessary waits and yield method implementations in your code - I dare say even some useless variables.

I’d assume that your code hang has to do with one of those yield methods or a loop being improperly handled.

4 Likes

MarketplaceService:GetProductInfo and MarketplaceService:UserOwnsGamePassAsync request information from an external server and yield until the information is got or an error is thrown. It might be a good idea to handle these in a separate coroutine. Here’s a quick (but somewhat ugly) replacement of the mentioned for loop you can try:

for i,v in pairs(PurchaseableMod) do
	coroutine.wrap(function()
		local t = CreateNewTemplate(UniformsFrame.Template,UniformsFrame.Faces)
		local id = v.id
		local productinfo = MPS:GetProductInfo(id,2)
		local imageid,price = productinfo.IconImageAssetId,productinfo.PriceInRobux
		t.ImageFrame.ImageLabel.Image = "rbxassetid://"..v.decalID
		t.TextFrame.TextLabel.Text = i .. " - R$" .. price
		GamepassCache[id] = t
		if not MPS:UserOwnsGamePassAsync(player.UserId,id) then
			t.TextFrame.TextButton.Text = "Purchase"
		end
		t.TextFrame.TextButton.MouseButton1Down:Connect(function()
			if not MPS:UserOwnsGamePassAsync(player.UserId,id) then
				Purchase(id,"Gamepasses")
			else
				Fire("Equip", {Type = "Face",Id = id})
			end
		end)
		t.Visible = true
	end)()
end
1 Like

Thank you. I’ll get this sorted!

In the future, instead of posting a gigantic code block you should use your print statements mixed with tick() to figure out roughly where your script is yielding or simply taking forever to load. I agree with colbert2677 that the code block is simply way too big. This not only discourages viewers but also gives off a disorganized vibe.

1 Like

Will do in the future. At the time I wasn’t too sure where it was coming from and I’m not too sure how to use tick() but I’ll have a look on the wiki. I completely agree with both of you and I apologise for that.

tick() is very useful anytime you want to time how long something takes. For example:

local now = tick()
do
	-- some code here
end
print("Time taken:", tick() - now)

You could place the print statement in several places in your code to figure out how long certain loops and calculations are taking.

3 Likes

Ok, thank you. I appreciate it.

1 Like