How to get Character from Players.PlayerRemoving

I’m trying to get the Player.Character inside the Players.PlayerRemoving to get the value of an instance that is parented to the Character and save the data to a DataStore.

However, the Players.PlayerRemoving only returns the Player instance, but not the Player.Character

(The following code is in the same server-side script)

Players.PlayerAdded:Connect(function(Player)
	-- detect when a player join and load his data
end)

Players.PlayerRemoving:Connect(function(Player)
	-- here I need to get the Character to save the Value of..
	-- ..an Instance parented to it
	print(Player) -- returns the Player Instance
	print(Player.Character) -- returns nil
end)

I tried using Player.CharacterRemoving, but it don’t work inside the Players.PlayerRemoving (this is expected, nothing abnormal)

Players.PlayerRemoving:Connect(function(Player)
	local Char = nil

	Player.CharacterRemoving:Connect(function(Character)
		-- this never executes
		print(Character)
		Char = Character
	end)

	print(Char) -- returns nil
end)

I need to get the Character only when the player is leaving the game, not on all times the Character loads. How can I achieve that?

Edit: I also need to get the Character position when leaving.

By the time Players.PlayerRemoving fires, the character has already been destroyed, so you can’t access it at all, unless you have a previous reference to it. Try either parenting the value to the player and modifying it through there, or just listening for CharacterRemoving in a separate connection.

3 Likes

Thank you for the reply. Parenting the value to the Player would be a solution to the first problem.

However, I also need to get the Character.HumanoidRootPart.Position to check if there are players on a certain team near him when he leaves. So I need the Character instance to get the HumanoidRootPart.Position.

If I listen to CharacterRemoving on a separate connection, I would need to detect if the Player is acctually leaving or if the Charater is just being loaded (respawned). If this is the best solution, how can I do this?

i assume you wanna do anti-combat-logging?

if so, i guess you could set an attribute of the player called “Fighting” to true, and then check its value in the .PlayerRemoving event

if you are not doing anti-combat-logging, i am sorry

1 Like
local LastPosition = {};

game:GetService('Players').PlayerAdded:Connect(function(Player)
	Player.CharacterRemoving:Connect(function(Char)
		LastPosition[Player] = Char.HumanoidRootPart.Position;
	end)
end)

game:GetService('Players').PlayerRemoving:Connect(function(Player)
	local lastCharacterPosition = LastPosition[Player];
end)

Edit: Unsure of the exact order of events, so may be worth checking to see if Player.Character exists first (and then using that value directly) before resorting to ‘LastPosition’, as if the PlayerRemoving is called first then the last position will be wherever the player died in their previous life. You could also just make it really simple and add a task.wait() or debounce before retrieving LastPosition[Player] to ensure that any sort of delay in the CharacterRemoving process doesn’t cause it to execute after PlayerRemoving.

1 Like
Player.CharacterRemoving:Connect(function()
    task.wait(10)
    if (not workspace:FindFirstChild(Player.Name)) then
        print("Player left the game.")
    end
end)

Since the character gets loaded on the server, this should work for lag as well. Otherwise, you can set CharacterAutoLoads to false and load the character manually on Humanoid.Died event.

As for logging the player’s previous position pretty much all use cases for that could be superseded by attributes. What is your case?

1 Like

Yes, exactly. I’m working on a type of anti-combat-logging. However, I also need to get the player position, not only the value (that could be stored in the Player Instance). So I need the Character to get its position on the workspace before it leaves.

1 Like

ermmmm

aren’t players stored in the Players service? :grin:

yeah but characters are in the workspace and we are just checking for the character

i am stupid :sob:

never let me cook again

As for logging the player’s previous position pretty much all use cases for that could be superseded by attributes. What is your case?

My case is: I need to check if there was a cop (players on the Police team) near the leaving player to check if he is trying to avoid arrest by leaving the game before he get cuffed by the cop near him.

Code (click to open)
if Player.leaderstats.WantedLevel.Value > 0 then
	local IsDetained = Player:FindFirstChild('IsDetained')
	
	if IsDetained then
		-- mark player as escapee (left the game as detained)
	else
		for _, Plr in pairs(Players:GetChildren()) do
			if Plr.Team == Teams["Police"] or Plr.Team == Teams["Sheriff"] then
				-- here I need to get the Leaving Character position
				local LeavingPos = Character.HumanoidRootPart.Position
				local CurrentPlrPos = Plr.Character.HumanoidRootPart.Position
				if (LeavingPos - CurrentPlrPos).magnitude <= 15 then
					--mark player as escapee (left the game while there was a cop near him)
				end
			end
		end
	end
end

What do you mean by “pretty much all use cases for that could be superseded by attributes”? Thanks.

Thank you, this might solve the problem, Additionally, @1234koip reply add a task.wait(10) to remove the character from the table and avoid lag and optimize the code.

Ill just wait the answer from him on my new reply and maybe mark this as a solution.

I was trying to think of ways to better optimise the whole system, sorry i just do that sometimes XD.

@darkelementallord would be the best option for this when sticking with your current setup.

1 Like