Upcoming Changes to Destroy()

I’ve written a few quick scripts in the past that did; I always expected them to eventually break without notification. The fact that we’ve gotten two announcements about this surprises me. Strange caveats such as these make the engine unintuitive, and are precisely the reason why concerns of memory leakage are so common.

3 Likes

@SubtotalAnt8185

All instances that are descendants of the Player's .Character property (yep, all) can be deleted by them and the deletion will replicate to the server (for some reason). I’m still very much so not sure why this is actually the case, it doesn’t really even make sense from a backwards compatibility standpoint, but this is basically the premise behind “FE god mode”…

An exploiter will locally delete, then replace their Humanoid, and because there is no Humanoid, the player can’t die.

Last time I checked this actually applies to every descendant of the character. Joints, parts, Humanoids, the Humanoid’s animator, scripts, local scripts, tools, and even things in those tools. It’s actually quite obnoxious behavior and I’m hoping that it eventually changes.

Network ownership and this are entirely unrelated, it’s simply a very questionable quirk for player characters, which means it’s not usually a good idea to be putting any essential stuff into a player’s character (or into tools which is especially limiting :slightly_frowning_face:)

P.s. this has been an issue for multiple years, it’s always existed as long as FE has been around as far as I am aware.

7 Likes

This is actually intentional for whatever reason. I knew this existed ever since I actually messed around with it, and it’s quite a good feature. This also applies to BaseParts with the NetworkOwner set to the player.

1 Like

You could make a script check when a child is removed from a player’s character, and kill them if it is

This is a lazy example and it will cause memory leaks because I don’t disconnect the connections if the player leaves or dies so use an event handler PLEASe

local Cooldown = {}
local bannedObjects = {"BasePart","Script","Humanoid","Folder"}

local function isBanned(object)--please tell me there is a function that automatically does this
	for i,v in next, bannedObjects do
		if object:IsA(v) then
			return true
		end
	end
	return false
end

local playerService = game:GetService("Players")
playerService.PlayerAdded:Connect(function(Player)
	local Name = Player.Name
	Player.CharacterAdded:Connect(function(Character)
		Character.ChildRemoved:Connect(function(Child)
			if not Cooldown[Name] and isBanned(Child) then
				Cooldown[Name]=true
				Character:BreakJoints()
				Player.CharacterAppearanceLoaded:Wait()
				Cooldown[Name] = nil
			end
		end)
	end)
end)
playerService.PlayerRemoving:Connect(function(Player)
	local Name = Player.Name
	Cooldown[Name] = nil
end)

2 Likes

Odd enough we can’t delete the clothing haha. They could do the same for other Instances under character, but whatever. The best solution right now is to not put anything important under a character.

It does not apply to BaseParts with the network owner set, that’s entirely separate. A part’s network owner is simply who is simulating the physics, it has nothing to do with anything beyond physics replication (and things like .Changed events for CFrame don’t replicate directly because no property changes replicate, they just replicate as physics to the server).

The behaviour shouldn’t exist. While maybe at one point it was intended, it isn’t really a “feature” persay, it’s not something you want to rely on. It’s probably either a bandaid fix for some old issue that FE at one point had (and probably no longer has), or its an oversight, but, in any case, it’s a security flaw and an annoyance, and it eventually will have to go. You definitely shouldn’t be relying on it at all, or your game might break if and when it eventually is removed.

@uwuCulturist The problem with this is you might still delete some things server-side, and, things like FallenPartsDestroyHeight will delete parts in the player. It’s probably likely that the Parent property won’t fire a .Changed event so you could try filtering server-side changes by GetPropertyChangedSignal("Parent") and I’m betting a .Destroying event won’t replicate either, but I’m just speculating on that, that’s my assumption based on how other similar things work in the engine. In any case you could probably test which events fire and if there is an event that won’t fire server-sided by the client deleting the descendant, but will by the server deleting it, that is a way to differentiate on the server between a client deleting a character descendant and the server doing it.

That’s also a way you can filter out server-side teleports when doing anti-cheat, since .CFrame and .Position won’t fire changed events (the player can only teleport themselves because they have network ownership and thus have authority over their character’s physics, which isn’t replicated through .Changed events so they don’t fire on the server unless server-side code is setting them)

7 Likes

I actually just made a post about this recently.

Almost seems as if Roblox took a pretty nasty design implementation and swept it under a rug, for who knows how long.

1 Like

Yep, if I remember correctly, for some reason something about how accessories replicate in general changed about 1-3 years ago (don’t really remember when), which I recall being around when HumanoidDescriptions were added. This effects other things too, for example (this is probably an unintentional side effect actually) clients can no longer drop accessories even though there used to be a feature where pressing = would drop your accessories.

I believe this hat dropping behaviour even still exists in the engine because I’ve seen it replicated in some Roblox games under specific circumstances (ones with their own methods of giving players accessories, like the bloxy awards event from two or three years ago) but it doesn’t work on vanilla Roblox avatars because of that weird change (whatever it is that makes accessories special)

My speculation was that the client and server have two different accessory instances, but, that’s just speculation. In any case accessories do seem to have inconsistent replication compared to other instances.

P.s. tool dropping is similar and is still something the client can do (even if CanBeDropped is off), if you have a tool, and you move it to the workspace or the player’s backpack on the client, it will replicate, but anywhere else and it won’t. And because of the descendant thing, you can still delete tools client-side if they’re held by the player and it will replicate (last time I checked, obviously things change so that might not be true anymore but probably is).

3 Likes

It’s been known about and discussed for a while but it’s relevant enough to this change people are talking about it more I guess but yeah. I hope that people’s sudden interest here gets it fixed :smile:

1 Like

Unexperienced scripters
Prolly the same people who dont use task.wait

Try setting the player’s parent to nil, or destroying it manually.

You can check if the parent is nil

THANK YOU!
if all goes to plan… the lag problem may be solved

Player’s also do not get properly destroyed on leave which is extremely bizarre and basically means every game using .PlayerAdded is leaking memory.

That can’t be true right? Keeping players in memory after they leave would cause memory leaks whether the game uses PlayerAdded or not. I rely on garbage collection to automatically remove player data stored in a hashmap where the key is the player instance. I’ve never had issues with this, indicating the player is removed (at least at a high level I guess).

If having events bound to player instances causes issues with removing them I might have to start disconnecting all player events when they leave, which should already be handled by the engine. I’ll investigate it tomorrow and let you know what I find.

1 Like

Sadly yeah, neither the Player nor its character gets destroyed.

When a player dies and you have connections made into any of the descendants of the character is better to disconnect all of it once it parents to nil or just destroy it manually (have in mind that you gotta check if the Humanoid is dead first as the character is parented to nil when CharacterAdded triggers). The same applies to the Player instance, they don’t get destroyed and you have no permission to destroy it either.

I would appreciate it if Roblox had a function like DisconnectAll for a player at least, cuz else you will have to save all connections made into a table and iterate through it when they leave.

You gotta read all first:

When you create a new instance, it will be parented to nil and this doesn’t mean is destroyed for example.

1 Like

if instance then ¯_(ツ)_/¯

1 Like

Well I guess you could use attributes, but I get your point and it actually makes sense lol

I have not been having issues and I have it set to Default, but curious to know what this change would break.

This shouldn’t break anything; it just calls Destroy on an Instance on the client when it’s Destroyed on the server. Previously, it would just set its parent to nil

2 Likes