Problem with while true do not stopping once value is false

I have an activity logger that tracks player activity and then subtracts minutes that they were AFK from the total value. The AFK script I have is this:

local function AFK(Player, Status)
	if Status == true then
		while true do
		wait(5)
		Player.AFKTime.Value += 1
			print("Player is not playing")
			end
	end
end

Once the player returns, the value of “Status” becomes false. However, the value-adding and the print continue even after the player is back and the value is false.

Any idea on why this is happening? I have also tried using while wait(5) do, which also doesn’t work.

1 Like

Your while loop runs forever because true is always true, if you want it to stop when Status is false simply replace it with:

while Status == true do

Despite that, Status will always stay the same in your script because there is no change of it.

Have also tried this, the same result.

Use a global variable for the player AFK status instead of being in the scope of one function where outside code cannot change it.

The code above can misbehave in a lot of ways, because everytime it runs it creates a new loop(and I assume it will only run once if threads aren’t used). I tried recreating the script above, but instead it uses a single loop for every “afk” player:

local Players = game:GetService("Players")

local afks = {}

local function AFK(Player, Status)
	if Status and not table.find(afks, Player) then 
		table.insert(afks, Player) 
	elseif not Status then 
		local index = table.find(afks, Player)
		if index then 
			table.remove(afks, index)
		end
	end
end

--loop should be at the bottom of the script or inside another thread, else it stops the code below it from running
while task.wait(5) do 
	for index, afk in pairs(afks) do 
		local t = afk.AFKTime 
		if Players:GetPlayerByUserId(afk.UserId) and t then 
			t.Value += 1
		else 
			--if they are not in game, remove them
			table.remove(afks, index)
		end
	end
end
1 Like

Okay, how would I incorporate that into my script? (Asking because this sends data to a webhook which I don’t want to break.)

Script:

local Webhook = "" -- Proxy Webhook
local HttpService = game:GetService("HttpService")

local Close = Instance.new("BindableEvent")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Remotes = ReplicatedStorage.Resources.RemoteEvents
local FocusSignal = Remotes.FocusSignal

local GroupId = 5874921
local MinRank = 110

local rankData = {}

game.Players.PlayerAdded:Connect(function(Player)
	rankData[Player.UserId] = {Rank = Player:GetRankInGroup(GroupId), Role = Player:GetRoleInGroup(GroupId)}
	if rankData[Player.UserId].Rank >=  MinRank then
		local Timer  = Instance.new("NumberValue",Player) Timer.Name = "PlayTime"
		local AFKTimer = Instance.new("NumberValue",Player) AFKTimer.Name = "AFKTime"
		
		while wait(5) do
			Timer.Value += 1
			print("Player is playing")
			end
	end

	end)

local function AFK(Player, Status)
	if Status == true then
		while true do
		wait(5)
		Player.AFKTime.Value += 1
			print("Player is not playing")
			end
	end
end


game.Players.PlayerRemoving:Connect(function(Player)
	if rankData[Player.UserId].Rank >= MinRank then
		local payload = HttpService:JSONEncode({
			['embeds'] = {{
				["title"] = "<:gochi:780528692006092810> New Activity Log",
				['color'] = 663399,
				["fields"] = {
					{
						["name"] = "Username",
						["value"] =  Player.Name,
						["inline"] = false
					},
					{
						["name"] = "Rank",
						["value"] =  rankData[Player.UserId].Role,
						["inline"] = false
					},
					{
						["name"] = "Logged Time",
						["value"] =  Player.PlayTime.Value.. " minute(s)",
						["inline"] = false
					},
					{
						["name"] = "AFK Time",
						["value"] =  Player.AFKTime.Value.." minute(s)",
						["inline"] = false
					},
					{
						["name"] = "Actual  Time",
						["value"] =  Player.PlayTime.Value - Player.AFKTime.Value.." minute(s)",
						["inline"] = false
					},
				}
			}}
		})

		HttpService:PostAsync(Webhook, payload)
		rankData[Player.UserId] = nil
		Close:Fire()
	end
end)

game:BindToClose(function()
	while #rankData > 0 do
		Close.Event:Wait()
	end
end)

FocusSignal.OnServerEvent:Connect(function(Player, Status)
	AFK(Player, Status)
end)

Hey the issue here is that when you call the function you basically set the variable Status to True so when you actually update status the function still has the old one.

Try this

local Players = game:GetService("Players")



Players.PlayerAdded:Connect(function(plr)
	local bool = Instance.new("BoolValue")
	bool.Parent = plr
	bool.Name = "AFK"	
	bool.Value = false -- Sets Player To Not AFK


	local function AFK(Player, Status)
		while wait(5) and Player:FindFirstChild('AFK').Value do -- Waits 5 Seconds then checks if player is afk
			print("Player is not playing")
		end
	end
	
	AFK(plr)
end)

By checking if the value is true with an actual bool it gets an updated value. Hopefully this gives perspective on the error and this was just an example or a way you could do it