Infinite yield problem for tycoon kit

Hello, Devs! I am using a modified Zed Tycoon kit, by @TwinPlayzDev, I fixed most of the Issues with the scripts. However, there Is an Infinite yield problem that Is very annoying for me, I know It’s not an error or does not cause any problem but I want the output code to be as clean as possible, whenever I play the game, It runs soo many Infinite yield warnings, the console Is almost full with this annoying messages, If anyone knows anything on how to solve this problem. The problem Is this Line

if script.Parent.PurchasedObjects:WaitForChild(v.Dependency.Value) then

please let me know what I should do, I tried changing “WaitForChild” with “FindFIrstChild” but It didn’t help, (It fixed the Infinite yield problem, but broke the code functionality). I tried to add wait but It didn’t work either (It might fix some issues but I am not sure.)

Model:https://create.roblox.com/store/asset/6133699812/Twins-Tycoon-Kit-20?externalSource=www&assetType=Model

Full Code:

	--[[
		All configurations are located in the "Settings" Module script.
		Please don't edit this script unless you know what you're doing.
--]]

	local TweenS = game:GetService("TweenService")

    local r = Random.new()
    local PlayMusic = game.ReplicatedStorage:FindFirstChild("PlayMusic")

	local BUILDING_ANIMATION_POSITION_OFFSET_AMOUNT = 200
	local BUILDING_ANIMATION_PARTDELAY = 0.03

function hasProperty(instance, property)
	assert(typeof(instance) == "Instance")
	assert(typeof(property) == "string")

	local hasProperty = false

	pcall(function()
		local v = instance[property] 
		hasProperty = true -- This line only runs if the previous line didn't error
	end)

	return hasProperty
end

function instanceListToPropertyDict(instances, propertyList)
	assert(typeof(instances) == "table")
	assert(typeof(propertyList) == "table")

  --[[Given a list of instances and a list of properties, construct a dictionary like so:
  dict = {
      [instance1] = {property1 = instance1.property1, property2 = instance1.property2, ...},
      [instance2] = {property1 = instance2.property1, property2 = instance2.property2, ...},
      ...
  }]]
	local dict = {}

	for _, instance in ipairs(instances) do
		local dictEntry = {}

		for _, property in pairs(propertyList) do
			assert(hasProperty(instance, property), string.format(
				[[Instance '%s' (a %s) doesn't have property '%s'.]], 
				tostring(instance), instance.ClassName, property)
			)
			dictEntry[property] = instance[property]
		end

		dict[instance] = dictEntry
	end

	return dict
end

function getDescendantsWhichAre(ancestor, className)
	assert(typeof(ancestor) == "Instance")
	assert(typeof(className) == "string")

	--[[Returns all descendants of ancestor which are of class className or a class that inherits from className]]
	local descendants = {}

	for _, descendant in pairs(ancestor:GetDescendants()) do
		if descendant:IsA(className) then
			table.insert(descendants, descendant)
		end
	end

	return descendants
end

function animateBuildingIn(buildingModel, tweenInfo)
	assert(typeof(buildingModel) == "Instance" and buildingModel.ClassName == "Model", string.format(
		"Invalid argument #1 to 'animateBuildingIn' (Model expected, got %s)", 
		typeof(buildingModel) == "Instance" and buildingModel.ClassName or typeof(buildingModel)
		))
	assert(typeof(tweenInfo) == "TweenInfo", string.format(
		"Invalid argument #1 to 'animateBuildingIn' (TweenInfo expected, got %s)",
		typeof(tweenInfo)
		))

	--Collect BaseParts and original properties
	local parts = getDescendantsWhichAre(buildingModel, "BasePart")
	local originalProperties = instanceListToPropertyDict(parts, {"Transparency", "CFrame", "Color", "Size", "CanCollide"})
	--local originalBasePartCFrame = buildingModel.PrimaryPart.CFrame

	--Make parts invisible and randomly move them
	for _, part in pairs(parts) do
		part.Transparency = 1
		part.CanCollide = false
		part.Color = Color3.fromRGB(255, 255, 255)
		--	part.CanCollide = false
		part.Size = Vector3.new()

		local positionOffset = Vector3.new(r:NextNumber(-1, 1), r:NextNumber(-0.25, 1.75), r:NextNumber(-1, 1)) * BUILDING_ANIMATION_POSITION_OFFSET_AMOUNT
		local rotationOffset = CFrame.Angles(r:NextNumber(-math.pi, math.pi), r:NextNumber(-math.pi, math.pi), r:NextNumber(-math.pi, math.pi))
		part.CFrame *= CFrame.new(positionOffset) * rotationOffset
	end

	--Tween them back to their original state, one at a time
	local lastTween --Return this so the caller can do animateBuilding(...):Wait() to wait for the animation to complete

	for _, part in pairs(parts) do
		local tween = TweenS:Create(part, tweenInfo, originalProperties[part])
		lastTween = tween
		tween.Completed:Connect(function(playbackState)
			part.CanCollide = false
			--Sometimes Tweens stop before reaching their goal properly.
			--  Make sure each Part is exactly how it was before.
			part.Transparency = originalProperties[part].Transparency
			part.CFrame = originalProperties[part].CFrame
		end)

		tween:Play()
		--		tween.Completed:Wait()
		wait(BUILDING_ANIMATION_PARTDELAY)
	end

	return lastTween.Completed
end

	local MarketplaceService = game:GetService("MarketplaceService")
 
	local Objects = {}
	local TeamColor = script.Parent.TeamColor.Value
	local Settings = require(script.Parent.Parent.Parent.Settings)
	local Money = script.Parent.CurrencyToCollect
	local Debris = game:GetService('Debris')
	local Stealing = Settings.StealSettings
	local CanSteal = true -- don't change or else you won't be able to steal currency
	local BuildAnimation = Settings.BuildAnimation
	
	script.Parent.Essentials.Spawn.TeamColor = TeamColor
	script.Parent.Essentials.Spawn.BrickColor = TeamColor
	
	
	--Parts that fall into the collector(s) get processed
	for i,v in pairs(script.Parent.Essentials:GetChildren()) do
		if v.Name == "PartCollector" then
			v.Touched:connect(function(Part)
				if Part:FindFirstChild('Cash') then
					Money.Value = Money.Value + Part.Cash.Value
					Debris:AddItem(Part,0.1)
				end
			end)
		end
	end
	
	--Player Touched Collector processor
	deb = false
	script.Parent.Essentials.Giver.Touched:connect(function(hit)
		local player = game.Players:GetPlayerFromCharacter(hit.Parent)
		if player ~= nil then
			if script.Parent.Owner.Value == player then
				if hit.Parent:FindFirstChild("Humanoid") then
					if hit.Parent.Humanoid.Health > 0 then
						if deb == false then
							deb = true
							script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Bright red")
							local Stats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
							if Stats ~= nil then 
							PlayMusic:FireClient(player, "Collect") 
							Stats.Value = Stats.Value + Money.Value
							Money.Value = 0
							wait(1)
							script.Parent.Essentials.Giver.BrickColor = BrickColor.new("Sea green")
							deb = false
							end
						end
					end
				end
			elseif Stealing.Stealing then -- if player isn't owner and stealing is on
				if CanSteal == true then
					CanSteal = false
					delay(Stealing.PlayerProtection, function()
						CanSteal = true
					end)
					if hit.Parent:FindFirstChild("Humanoid") then
						if hit.Parent.Humanoid.Health > 0 then
							local Stats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
							if Stats ~= nil then
								local Difference = math.floor(Money.Value * Stealing.StealPrecent)
							    PlayMusic:FireClient(player, "Collect") 
								Stats.Value = Stats.Value + Difference
								Money.Value = Money.Value - Difference
							end
						end
					end
				else
				PlayMusic:FireClient(player, "ErrorBuy") 
				end
			end
		end
	end)

	local chosenGamePassButton = nil
	
	script.Parent:WaitForChild("Buttons")
	for i,v in pairs(script.Parent.Buttons:GetChildren()) do
		spawn(function()
		if v:FindFirstChild("Head") then
			
			local ThingMade = script.Parent.Purchases:WaitForChild(v.Object.Value)
			if ThingMade ~= nil then
				--print("adding------------------> purchase ",ThingMade.Name)
				Objects[ThingMade.Name] = ThingMade:Clone()
				ThingMade:Destroy()
			else
				--//Button doesn't have object, remove it
				error('Object missing for button: '..v.Name..', button has been removed')
				v.Head.CanCollide = false
				v.Head.Transparency = 1
			end
									
			if v:FindFirstChild("Dependency") then --// if button needs something unlocked before it pops up
				v.Head.CanCollide = false
				v.Head.Transparency = 1
				coroutine.resume(coroutine.create(function()
					if script.Parent.PurchasedObjects:WaitForChild(v.Dependency.Value) then
						if Settings['ButtonsFadeIn'] then
							for i=1,20 do
								wait(Settings['FadeInTime']/20)
								v.Head.Transparency = v.Head.Transparency - 0.05
							end
						end
						v.Head.CanCollide = true
						v.Head.Transparency = 0
					end
				end))
			end
			
			v.Head.Touched:connect(function(hit)
				local player = game.Players:GetPlayerFromCharacter(hit.Parent)
				if v.Head.CanCollide == true then
					if player ~= nil then
						if script.Parent.Owner.Value == player then
							if hit.Parent:FindFirstChild("Humanoid") then
								if hit.Parent.Humanoid.Health > 0 then
									local PlayerStats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
									if PlayerStats ~= nil then
										if (v:FindFirstChild('Gamepass')) and (v.Gamepass.Value >= 1) then
											if game:GetService("MarketplaceService"):UserOwnsGamePassAsync(player.UserId,v.Gamepass.Value) then
												Purchase({[1] = v.Price.Value,[2] = v,[3] = PlayerStats})
											else
												chosenGamePassButton = v
												game:GetService('MarketplaceService'):PromptGamePassPurchase(player,v.Gamepass.Value)
											end
										elseif (v:FindFirstChild('DevProduct')) and (v.DevProduct.Value >= 1) then
											game:GetService('MarketplaceService'):PromptProductPurchase(player,v.DevProduct.Value)
										elseif PlayerStats.Value >= v.Price.Value then
											Purchase({[1] = v.Price.Value,[2] = v,[3] = PlayerStats})
											PlayMusic:FireClient(player, "Purchased") 
										else
											PlayMusic:FireClient(player, "ErrorBuy") 
										end
									end
								end
							end
						end
					end
				end
			end)
			end
		end)
	end


	local function onPromptGamePassPurchaseFinished(player, purchasedPassID, purchaseSuccess)
	 	local PlayerStats = game.ServerStorage.PlayerMoney:FindFirstChild(player.Name)
		if purchaseSuccess == true and chosenGamePassButton and purchasedPassID == chosenGamePassButton.Gamepass.Value then
			print(player.Name .. " purchased the game pass with ID " .. chosenGamePassButton.Gamepass.Value)
			Purchase({[1] = chosenGamePassButton.Price.Value,[2] = chosenGamePassButton,[3] = PlayerStats})
		end
	end
	
	MarketplaceService.PromptGamePassPurchaseFinished:Connect(onPromptGamePassPurchaseFinished)
		
	function Purchase(tbl)
		local cost = tbl[1]
		local item = tbl[2]
		local stats = tbl[3]
		stats.Value = stats.Value - cost
		Objects[item.Object.Value].Parent = script.Parent.PurchasedObjects
		if Settings['ButtonsFadeOut'] then
			item.Head.CanCollide = false
			coroutine.resume(coroutine.create(function()
				for i=1,20 do
					wait(Settings['FadeOutTime']/20)
					item.Head.Transparency = item.Head.Transparency + 0.05
				end
			end))
		else
			item.Head.CanCollide = false
			item.Head.Transparency = 1
		end
	end
	
	function Create(tab)
		local x = Instance.new('Model')
		Instance.new('NumberValue',x).Value = tab[1]
		x.Value.Name = "Cost"
		Instance.new('ObjectValue',x).Value = tab[2]
		x.Value.Name = "Button"
		local Obj = Instance.new('ObjectValue',x)
		Obj.Name = "Stats"
		Obj.Value = tab[3]
		x.Parent = script.Parent.BuyObject
	end
	
	--// This was very rushed and is inefficent; if you plan on making something like this don't use a child added listener.
	script.Parent:WaitForChild('BuyObject').ChildAdded:connect(function(child)
		local tab = {}
		tab[1] = child.Cost.Value
		tab[2] = child.Button.Value
		tab[3] = child.Stats.Value
		Purchase(tab)
		wait(10)
		child:Destroy()
	end)



script.Parent.PurchasedObjects.ChildAdded:Connect(function(add)
	if Settings['BuildAnimation'] then
		local buildwait = 2
		for i,v in pairs(add:GetDescendants()) do
			if v:IsA("BasePart") then
				v.CanCollide = false
			end
		end
		local result = animateBuildingIn(script.Parent.PurchasedObjects[add.Name], TweenInfo.new(buildwait, Enum.EasingStyle.Elastic, Enum.EasingDirection.Out)):Wait()
		wait(0.05)
		for i,v in pairs(add:GetDescendants()) do
			if v:IsA("BasePart") then
				if v.Name == "Touch" or v.Name == "Upgrader" or v.Name == "Drop" or v.Name == "Pipe" or v.Name == "LeftFoot" or v.Name == "RightLowerArm" or v.Name == "RightLowerLeg" or v.Name == "RightHand" or v.Name == "RightFoot" or v.Name == "LowerTorso" or v.Name == "LeftUpperLeg" or v.Name == "LeftUpperArm" or v.Name == "LeftLowerLeg" or v.Name == "LeftLowerArm" or v.Name == "LeftHand" or v.Name == "RightUpperArm" or v.Name =="RightUpperLeg" or v.Name == "UpperTorso" or v.Name == "Head" or v.Name == "MyPhones" or v.Name == "Right Leg" or v.Name == "Right Arm" or v.Name == "Left Leg" or v.Name == "Left Arm" then
					print(v.Name)
					v.CanCollide = false
				else
					v.CanCollide = true
				end
			end
		end
	end
end)

return Objects

1 Like

This warning occurs when WaitForChild has been waiting for more than 5 seconds with no timeout parameter specified.

To fix, add a timeout parameter to WaitForChild.