Are there any non laggy alternatives to wait loops?

This script is for progressive cash gain, you gain a certain amount of cash every 0.25 seconds, but me and some of my players noticed that the cash gain progressively gets slower the longer they play to the point where they could be waiting upwards of a minute for your cash to update. Rejoining the game fixes this issue, and I can only think of this being an issue stemming from the wait loop I use to give the player cash. I have a feeling its lag related but I have no clue how to fix this issue. Feel free to look at my code, the table of stats I know is unnecessary but it was used in the past and I never deleted it, keeping it in there because it could be an issue that I don’t know of.

game.Players.PlayerAdded:Connect(function(plr)
	local x = require(game.ReplicatedStorage.EternityNum)
	local s = plr:WaitForChild("Data"):WaitForChild("Stats")
	local r = plr:WaitForChild("Data"):WaitForChild("Runes")
	local u = plr:WaitForChild("Data"):WaitForChild("Upgrades")
	local money = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("Money")
	local multi = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("Multiplier")
	local reb = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("Rebirths")
	local sreb = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("SuperRebirth")
	local pres = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("Prestige")
	local spres = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("SuperPrestige")
	local lvl = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("Level")

	local com = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Common")
	local ucom = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Uncommon")
	local rare = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Rare")
	local epic = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Epic")
	local legend = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Legendary")
	local mythic = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Mythical")
	local divine = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Divine")

	local adv = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Advanced")
	local elite = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Elite")
	local hyper = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Hyper")

	local hyper = plr:WaitForChild("Data"):WaitForChild("Runes"):WaitForChild("Release")
	

	local start1 = plr:WaitForChild("Data"):WaitForChild("PlayerData"):WaitForChild("UpgradeTreeStart")
	local start2 = plr:WaitForChild("Data"):WaitForChild("Upgrades"):WaitForChild("UpgradeTreeStart")
	local lt = plr:WaitForChild("Data"):WaitForChild("Stats"):WaitForChild("LightTokens")



	local MoneyBoosts = {

	}

	local MoneyBoostsRunes = {
		{Value = "Common", Function = "Multiply", Number1 = {0.0001,0}},
		{Value = "Uncommon", Function = "Multiply", Number1 = {0.0003,0}},
		{Value = "Rare", Function = "Multiply", Number1 = {0.001,0}},
		{Value = "Epic", Function = "Multiply", Number1 = {0.005,0}},
		{Value = "Legendary", Function = "Multiply", Number1 = {0.01,0}},
		{Value = "Mythical", Function = "Multiply", Number1 = {1,0}},
		{Value = "Divine", Function = "Multiply", Number1 = {5,0}},

		{Value = "Advanced", Function = "Multiply", Number1 = {0.0002,0}},
		{Value = "Elite", Function = "Multiply", Number1 = {0.0006,0}},
		{Value = "Hyper", Function = "Multiply", Number1 = {0.003,0}},

		{Value = "Release", Function = "Multiply", Number1 = {0.5,0}},
		{Value = "Common1K", Function = "Multiply", Number1 = {0.000005,0}},
		{Value = "Divine1K", Function = "Multiply", Number1 = {1,0}},
		{Value = "RedGarnet", Function = "Multiply", Number1 = {1,0}},
	}

	local LightTokensBoosts = {
		{Value = "UpgradeTreeStart", Function = "Multiply", Number1 = {1,0}},
		{Value = "LightTokens1", Function = "Multiply", Number1 = {0.5,0}},
	}

	local function CalculateMultiplier(Element)
		local array = MoneyBoosts[Element]

		if array.Function == "Multiply" then
			return x.add(x.mul(x.convert(s[array.Value].Value), array.Number1), {1,0})
		elseif array.Function == "Power" then
			return x.add(x.pow(x.convert(s[array.Value].Value), array.Number1), {1,0})
		end
	end

	local function CalculateMultiplierRunes(Element2)
		local array = MoneyBoostsRunes[Element2]

		if array.Function == "Multiply" then
			return x.add(x.mul(x.convert(r[array.Value].Value), array.Number1), {1,0})
		elseif array.Function == "Power" then
			return x.add(x.pow(x.convert(r[array.Value].Value), array.Number1), {1,0})
		end
	end

	local function CalculateMultiplierLightTokens(Element)
		local array = LightTokensBoosts[Element]

		if array.Function == "Multiply" then
			return x.add(x.mul(x.convert(u[array.Value].Value), array.Number1), {1,0})
		elseif array.Function == "Power" then
			return x.add(x.pow(x.convert(u[array.Value].Value), array.Number1), {1,0})
		end
	end

	local function CalculateMoney()
		local val = x.convert(1)
		val = x.mul(val, x.convert(multi.Value))

		for i = 1, #MoneyBoosts do
			val = x.mul(val, CalculateMultiplier(i))
		end
		for i = 1, #MoneyBoostsRunes do
			val = x.mul(val, CalculateMultiplierRunes(i))
		end


		local svb = x.convert(money.Value)
		svb = x.add(svb,val)
		money.Value = x.bnumtostr(svb)

	end

	local function CalculateLightTokens()
		local val2 = x.convert(1)
		val2 = x.mul(val2, x.convert(start2.Value))

		for i = 1, #LightTokensBoosts do
			val2 = x.mul(val2, CalculateMultiplierLightTokens(i))
		end


		local svb = x.convert(lt.Value)
		svb = x.add(svb,val2)
		lt.Value = x.bnumtostr(svb)

	end

	local function CalculateLevel(TableOfStats, Outcome)

		for i, v in pairs(TableOfStats) do
			Outcome = x.add(Outcome, x.mul(x.log10(x.add(v.Stat, {1, 0})), v.MultiplicationValue))
		end
		return Outcome
	end


	local moneylevel = coroutine.wrap(function()
		while wait(0.25) do
			CalculateMoney(0.5) --This gives money and level at the same time.
			lvl.Value = x.bnumtostr(CalculateLevel({
				{Stat = x.convert(money.Value), MultiplicationValue = {2,0}},
				{Stat = x.convert(multi.Value), MultiplicationValue = {4,0}},
				{Stat = x.convert(reb.Value), MultiplicationValue = {8,0}},
				{Stat = x.convert(sreb.Value), MultiplicationValue = {16,0}},
				{Stat = x.convert(pres.Value), MultiplicationValue = {32,0}},
				{Stat = x.convert(spres.Value), MultiplicationValue = {64,0}},

			}, 0))
		end
	end)

	local lighttokens = coroutine.wrap(function()
		while wait() do
			if start1.Value == true then
				while wait(1) do
					CalculateLightTokens(1)
				end
			end
		end
	end)
	moneylevel()
	lighttokens()
end)

You can change wait() to task.wait()

You also shouldn’t add while loops inside while loops. It can make massive amounts of lag.

You can break the while loop once the player has left the game.

I’m not sure what is going on but it seems like these loops never stop running, even after the player leaves. Maybe its building up a memory leak.

you should add some print statements to figure out what it is doing

Why is there a while loop within a while loop? Seems redundant.

I see the big problem here, each player individually creates a while loop. That causes alot of trouble. You can make one while loop that goes through every player and awards them with cash every .25 seconds instead.

while task.wait(.25) do
	for i,v in pairs(game.Players:GetPlayers()) do
		--give them cash, everybody will get it.
	end
end

But i’ve notice that you have really complicated system here, so im not sure if it will make it any easier.

I have to do that so when the player obtains the stat they will start generating the secondary currency