CharacterAdded event doesn't fire

I’m making an anticheat system, everything is a module. I’m using ServerScript for events etc.

players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(char)
		local hum = char:WaitForChild("Humanoid")
		local torso = char:WaitForChild("Torso")
		
		char.DescendantRemoving:Connect(function()
			checkCharParts(plr)
		end)
		
		hum.Changed:Connect(function()
			humStateCheck(plr)
		end)
		
		torso:GetPropertyChangedSignal("Position"):Connect(function() --May cause overload
			print("ok")
			checkTPandFly(plr)
			wait()
		end)
	end)
end)

Only PayerAdded event fires. I tried removing CharacterAdded but other three don’t fire either. There are functions above this code so nothing causing delay (only one “wait()” and that’s because of one datastore)

CharacterAdded should have fired but I do see some things wrong here,

GetPropertyChangedSignal won’t work with properties that can easily fire many times like Position.

If your Changed event is to check the state of a Humanoid, you should use StateChanged instead.

1 Like

Sometimes the character is already present before you have bound the CharacterAdded event. You can check for this edge case:

local function charAdded(plr, char)
	local hum = char:WaitForChild("Humanoid")
	local torso = char:WaitForChild("Torso")
	
	char.DescendantRemoving:Connect(function()
		checkCharParts(plr)
	end)
	
	hum.Changed:Connect(function()
		humStateCheck(plr)
	end)
	
	torso:GetPropertyChangedSignal("Position"):Connect(function() --May cause overload
		print("ok")
		checkTPandFly(plr)
		wait()
	end)
end

players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function (char)
		charAdded(plr, plr.Character)
	end) do
		if plr.Character then
			charAdded(plr, plr.Character)
		end
	end
end)
1 Like

I forgot to change, thanks for reminding.

Didn’t work. I’m using breakpoints to test. It isn’t checking after PlayerAdded event.

Make sure that you put the PlayerAdded listener as high up in the script as possible. If you put it too low in the script, other things may execute first, taking time, and the player may join prior to the event’s connection.

3 Likes

A mini yield can make a difference, make sure PlayerAdded is fired too, try doing a print after PlayerAdded to know for sure.

players.PlayerAdded:Connect(function(plr)
	print("added")
	plr.CharacterAdded:Connect(function (char)
		print("added too")
		charAdded(plr, plr.Character)
	end) do
		if plr.Character then
			charAdded(plr, plr.Character)
		end
	end
end)

I tested and these prints aren’t in output.

It’s in the bottom because I needed to define some functions. Other than functions, I have this.

local module = require(script.AntiCheatModule)
wait()
local banned = module.getBanned()
if banned then
	print("ServerScript has received the banned list.")
else
	print("Banned list couldn't be loaded to the server.")
end

That wait is there so module can get the data before serverscript asks for it. Shall I remove? (These are the first lines of the script)

What you have written takes time; the player is joining before the event is connecting.
Do you need all of this in order to run the code in CharacterAdded or PlayerAdded?

Yes, I have a banCheck function which I forgot to put in event. So I need it loaded.

So no matter what you’re going to need to make sure PlayerAdded is the first thing you call in the script. This means that you will have to rewrite the way it works based on this requirement.

I would suggest that you put PlayerAdded at the top of the script (you can put it below variables as long as you don’t use WaitForChild) along with a null check within the PlayerAdded connection. For example, in your case:

game.Players.PlayerAdded:connect(function(player)
    if not banned then
        banned = module.getBanned()
        -- ...
    end
    -- ...
end)

If you are worried about two or more players joining at the same time and causing the banned variable to overwrite, you can alternatively just have it wait like this:

game.Players.PlayerAdded:connect(function(player)
    repeat
        wait()
    until banned
    -- ...
end)

local module = require(script.AntiCheatModule)
wait()
local banned = module.getBanned()
if banned then
    print("ServerScript has received the banned list.")
else
    print("Banned list couldn't be loaded to the server.")
end

The first option should be fine though unless if module.getBanned() is not immediate (i.e. takes time finish running). The reason why is because if checks on Player1 and Player2 (not banned) can turn out to true, leading two threads to write to banned which may give you undesirable results.

My getBanned function directly returns a table from module so it’s instant. I get the data on module.

If it’s instant then either method should work fine for you.

1 Like

I’ll get back when I find time to test.

@Tenal
I changed the script to this:

-- Services
local players = game:GetService("Players")
-- Event
local module = require(script.AntiCheatModule)
local banned
game.Players.PlayerAdded:Connect(function(plr)
	repeat wait() until banned
	local function banCheck(plr)
		-- Something (this will print a text if player isn't in the ban list)
	end
	banCheck(plr)
	plr.CharacterAdded:Connect(function(char)
		local function checkCharParts(plr)
			module.CheckChar(plr.Character)
		end 
		local function humStateCheck(plr)
			module.HumStateCheck(plr)
		end
		
		local function checkTPandFly(plr)
			module.checkTPandFly(plr)
		end
		
		local function humanoidJumpCheck(plr)
			module.humanoidJumpCheck(plr)
		end
		
		local function charAdded(plr, char)
			local hum = char:WaitForChild("Humanoid")
			local torso = char:WaitForChild("Torso")
			
			char.DescendantRemoving:Connect(function()
				checkCharParts(plr)
			end)
			
			hum.StateChanged:Connect(function()
				humStateCheck(plr)
			end)
			
			torso.Changed:Connect(function(prop) --May cause overload
				if prop == torso.Position then
					print("ok")
					checkTPandFly(plr)
					wait()
				end
			end)
		end
		charAdded(plr, char)
	end)
	plr:LoadCharacter()
end)

wait()
banned = module.getBanned()
if banned then
	print("ServerScript has received the banned list.")
else
	print("Banned list couldn't be loaded to the server.")
end

I’m not banned in my game but it doesn’t print that text, also I tested with breakpoints and still not working. I don’t think require will cause a delay.

It prints “ServerScript has received the banned list.”

The issue here is most likely that CharacterAdded is not the first thing you’re running here. It waits until banned becomes not nil and by the time that happens the character is already spawned.

I know, and after defining the event I’m running

code which’ll trigger it for first. Also, print in ban command won’t execute either.