Problem with while wait() loop

Hey! So I gogt this code:

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("Level2")
local rep = game:FindFirstChild("ReplicatedStorage")
local mps = game:GetService("MarketplaceService")

game.Players.PlayerAdded:Connect(function(player)
	if player.UserId == 1430026986 or player.UserId == 1071071938 or player.UserId == 3119824160 then
		local changepart = rep:FindFirstChild("ChangeEmployeePart"):Clone()
		changepart.Parent = player.PlayerGui
	end
	---DATA STUFF
	--acount age req
	--if player.AccountAge < 7 then player:Kick("Your account is not old enough to play this game. Required account age (days): 7, current account age(days): " ..player.AccountAge) end
	
	local PlayerData = game.ServerStorage.PlayerData:Clone()
	PlayerData.Parent = player
	
	local leaderstats = game.ServerStorage.leaderstats:Clone()
	leaderstats.Parent = player
	task.wait(1)
	coroutine.wrap(function()		
		local  Success, data = pcall(function()
			return DataStore:GetAsync(player.UserId)
		end)
		
		if Success then
			if data then----IF DATA----IF DATA----IF DATA----IF DATA----IF DATA----IF DATA----IF DATA
				--print(data)

				--UPDATE DATA TO THE VALUES
				if data.Playtime then PlayerData.Playtime.Value = data.Playtime end
				
				if data.Level then PlayerData.Level.Value = data.Level leaderstats.Level.Value = data.Level end
				if data.XP then PlayerData.XP.Value = data.XP end
				
				local aprooval = Instance.new("BoolValue")
				aprooval.Name = "SaveAprooval"
				aprooval.Parent = PlayerData

			else----IF HAS NO DATA----IF HAS NO DATA----IF HAS NO DATA----IF HAS NO DATA----IF HAS NO DATA
				warn("Wasnt able to gather the data")
				task.wait(1)
				
				local aprooval = Instance.new("BoolValue")
				aprooval.Name = "SaveAprooval"
				aprooval.Parent = PlayerData
				PlayerData.Level.Value = 2
				PlayerData.XP.Value = 2
				task.wait(1)
				PlayerData.Level.Value = 1
				PlayerData.Level.Value = 1
			end

		else
			warn("Data filed to load")
			--player:Kick("Data failed to load, please rejoin the game.")
		end
	end)()
end)

--SAVING
local function Save(player)
	if not player:FindFirstChild("PlayerData") then warn("ATTEMPT TO SAVE DATA BUT DIDNT FIND DATA FOLDER") return end
	if not player.PlayerData:FindFirstChild("SaveAprooval") then print("ATTEMPT TO SAVE DATA BUT DIDNT FIND APPROOVAL")  return end
	local newData = {
		["Playtime"] = player.PlayerData.Playtime.Value,
		
		["Level"] = player.PlayerData.Level.Value,
		["XP"] = player.PlayerData.XP.Value,
	}
	local Success, data = pcall(function()
		return DataStore:GetAsync(player.UserId)
	end)

	--print(data)
	--print(newData)
	
	if data ~= nil then
		if data.Playtime ~= nil then
			if newData.Playtime < data.Playtime then
				print("ATTEMPT TO SAVE DATA BUT PLAYTIME WAS LOWER")
				return
			end
		end
	end
	--print("DATA SAVED")
	
	DataStore:SetAsync(player.UserId,newData --[[function(data) return newData end--]]) -- BEFORE UPDATE ASYNC
end

game.Players.PlayerRemoving:Connect(function(plr)
	coroutine.wrap(function()
		Save(plr)
	end)()
end)

game:BindToClose(function()
	for i, player in pairs(game.Players:GetChildren()) do
		Save(player)
	end
end)

local Counter = 0
while task.wait(15) do
	warn("Still running the task.wait 15")
	Counter += 15
	for i,v in pairs(game.Players:GetChildren()) do 
		if v:FindFirstChild("PlayerData") ~= nil and v:FindFirstChild("leaderstats") ~= nil then
			v.PlayerData.Playtime.Value += 15
			if Counter >= 90 then 
				if v.PlayerData:FindFirstChild("XP") ~= nil and v.PlayerData:FindFirstChild("Level") ~= nil then
					if mps:UserOwnsGamePassAsync(v.userId, 189517075) then
						if game.PrivateServerId ~= "" and game.PrivateServerOwnerId ~= 0 then else
							if v.MembershipType == Enum.MembershipType.Premium then
								v.Player.XP.Value += 600
							else
								v.PlayerData.XP.Value += 400
							end
						end
					else
						if game.PrivateServerId ~= "" and game.PrivateServerOwnerId ~= 0 then else
							if v.MembershipType == Enum.MembershipType.Premium then
								v.PlayerData.XP.Value += 300
							else
								v.PlayerData.XP.Value += 200
							end
						end
					end
					if v.PlayerData.XP.Value >= (v.PlayerData.Level.Value) * 100 then
						v.PlayerData.Level.Value += 1
						v.leaderstats.Level.Value = v.PlayerData.Level.Value
						if v.Character then
							if v.Character.Head:FindFirstChild("GroupRank") then
								if v:FindFirstChild("ResetChatTag") then else
									v.Character.Head.GroupRank.Level.Text = "<u>Level "..v.PlayerData.Level.Value.."</u>"
								end
							end
						end
						v.PlayerData.XP.Value = 0
					end
				end
			end
		end
	end
	if Counter >= 90 then Counter = 0 end
end

Randomly, this whole loop simply breaks. So, we are getting reports from our player base that XP randomly “freeze” till a new server is being created. I joined such server and checked the server logs and it’s not pringing the “Still running the task.wait 15” meaning, the loop must break but I can’t find why. Anyone who could help me with this?

1 Like

I would guess something in the loop is causing an error.
I think this is most likely the loop being unable to find the player’s character.Head as it is a direct reference without a fallback should it not be there, it’s also the most likely part to be reset or removed as a player dies or leaves the server. So it seems pretty random as it’s just bad luck with the timing.

You could try using individual coroutines for each player and using os.time() if they need to be synchronised.

Hope it helps.

Can you tell if there are any errors in console?

Heyy! There are at all no errors within the logs. It might be that the head not found error is appearing when I am not in the server but will the loop be then penetrante broken because of one error? Wouldn’t it then continue with the next player??

Hey! I will see what I can do with this but wouldn’t 50 coros drag the performance of the server a bit down?

The loop can only really hang in 2 ways, an async call never returns (that would be an engine bug, unlikely in this case), or you’re getting an error you’re missing (doesn’t appear to be silenced here).

You have way too much repeated code, here is a possible issue.

if v.MembershipType == Enum.MembershipType.Premium then
	v.Player.XP.Value += 600 -- wrong
else
	v.PlayerData.XP.Value += 400 -- judging by the other uses, correct
end

Quick and dirty cleanup trying to bring the branching under control, check my work. Do more (think about making variables out of FFC and what not.) You could also just break it up into functions, which may make more sense because this is quite a long loop anyways.

local Counter = 0
while task.wait(15) do
	warn("Still running the task.wait 15")
	Counter += 15
	for i,v in pairs(game.Players:GetChildren()) do 

		if not (v:FindFirstChild("PlayerData") and v:FindFirstChild("leaderstats")) then
			continue
		end

		v.PlayerData.Playtime.Value += 15

		if Counter < 90 then 
			continue
		end

		if not (v.PlayerData:FindFirstChild("XP") and v.PlayerData:FindFirstChild("Level")) then
			continue
		end

		if (game.PrivateServerId ~= "" and game.PrivateServerOwnerId ~= 0) then
			local baseXP = (if (v.MembershipType == Enum.MembershipType.Premium) then 300 else 200)
			local passMult = (if mps:UserOwnsGamePassAsync(v.userId, 189517075) then 2 else 1)
			v.PlayerData.XP.Value += (baseXP * passMult)
		end

		if v.PlayerData.XP.Value < (v.PlayerData.Level.Value) * 100 then
			continue
		end

		v.PlayerData.Level.Value += 1
		v.leaderstats.Level.Value = v.PlayerData.Level.Value
		local character = v.Character

		if (character and character.Head:FindFirstChild("GroupRank") and v:FindFirstChild("ResetChatTag")) then
			v.Character.Head.GroupRank.Level.Text = "<u>Level "..v.PlayerData.Level.Value.."</u>"
		end

		v.PlayerData.XP.Value = 0

	end

	if Counter >= 90 then Counter = 0 end
	
end
1 Like

Alright, thank you. I will see what I will do about this.

As @Wigglyaa already mentioned, you search for the characters head, this probably causes the problem.
When the Humanoid of a Character falls on 0 HP or below, the whole model of your character will get “Destroyed” and a new one will be put in the server, looking alike. If in this time gap, your code runs, no head can be found, not even the character model at all. To prevent this I would seperate the script.

You seem to have some HeadTag which displays a GroupRank or similar. I would put a script in the TextLabel object and just set the text of it there, because this script will run as soon as the TextLabel is loaded and will ensure that it exists because without it, the script can’t run.

Everything regarding your character model should just be seperated, your player values are constantly available to the script in Players so that should be good.

1 Like

Heyy! Seperating this code did not resolve the issue sadly. When I look up in the new server it still does not print the (“still running…”) however, in studio it works…

Possibly, but most of the time they would be waiting rather than actually doing anything. If they are running at different intervals then it may be actually beneficial to spread the load, it would also insulate the other players from an error caused on one… Unless it’s something else common to all of them of course…

So you want me to seperate the script and make a coroutine for example for every player every 15 seconds? Doesn’t that efficient can’t lie…

One coroutine per player containing a while loop.

Outline

OnPlayerAdded create new coroutine and add to a table.

Coroutine contains a while loop to run the code every 15s include a check in the loop that the player is still in the game.

When the round/game/player loaded etc starts for the player resume the coroutine

Coroutine will see when player leaves (due to the check) and exit the loop putting it into a dead state, you may just need to clean up the table every so often to ensure the coroutines are gc’d.

1 Like

Hey! Your code appears to have fixed the issue. Thank you soooooo much!

The issue have been fixed but thank you still for your help you have dedicated into my issue!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.