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.
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 )
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.
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.
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)
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)
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.
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).
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
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.
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.
if instance then
¯_(ツ)_/¯
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