I want the NPC’s in my game to be unable to be tampered with by exploiters. I don’t use the humanoid’s health, I just use it for animations and movement. The health is saved to a script, so it can’t actually be affected by a client. The problem is, if the NPC dies client-side, it does server-side too, which makes doing things like boss fights impossible since the boss can’t play animations or move around to aim abilities.
I tested a few different ways that an exploiter could easily mess with the NPC’s. Setting the health to 0, deleting the humanoid, and breaking the joints of the model. Each got replicated from the client to the server as if the server was doing it. The only thing it didn’t work on was the players’ characters. I was thinking of just having no NPC server-side and have the client make all the humanoids, but that requires me to know if the humanoid is colliding with another humanoid and calculating if it’s jumping or on top of something. I think I overcomplicated it, so I’m asking for help here.
If anyone knows a simpler way or how to do this, help is greatly appreciated.
Setting the humanoid’s health to infinite, giving it a forcefield, and setting BreakJointsOnDeath to false does not work. If the client breaks the joints of the NPC client-side then it replicates server-side, basically killing the NPC.
You can make their health infinite, it should get the job done, but not the best solution either.
Another thing you could do is use a loop (maybe a heartbeat with runservice) to repeatedly set its health back to 100.
I mean there’s no way to really “detect” exploits the way you mentioned the only way would be sanity checks on the server but one way to detect most skids is to add a local script that detects when humanoids are killed etc. Although against experienced exploiters this will be useless
I’m keeping the NPC’s health separate from the humanoid. I just need the humanoid so the NPC can walk around and do animations. The problem is that exploiters can easily kill the NPC since it replicates to the server for some reason.
Changing the humanoids name to something like ‘fajuerjafajer’ would prevent exploiters from killing it by just using NPC.Humanoid but they could still kill it using FindFirstChildWhichIsA("Humanoid")
Setting Humanoid.BreakJointsOnDeath to false, setting it’s health display distance to 0 wouldn’t make it unkillable, but would mean that it’s still possible for it to move etc. without looking dead.
Kicking the exploiter if the humanoid is dead. Pretty straightforwards, put a localScript into serverStorage and clone it under the players clients every minute to check if they’ve killed the humanoid and kicking them if they have.
I’m not sure if any of these helped because I don’t know what your NPC’s are meant to do, but I hope it at least helps someone in the future!
The second way almost worked, it stopped the NPC from actually dying, but if the client breaks the joints of the model then it replicates to the server too.
Ok. Perhaps simple recreating all the Joints using Model:MakeJoints() would work. I couldn’t find anything about :BreakJoints replicating, so I’m not sure if there’s any way to prevent it or detect which client fired it. Your final option could be to make the NPC’s meshes or parts and make them move on their own.
All of these solutions above will do nothing to solve your problem; let me explain what is actually going on:
Humanoids that are not owned by a character (i.e. your character humanoid) are Physics objects similar to any other. Roblox uses a system of network ownership to handle the complicated physical calculations that you have to do without putting it all on the server (which would be really resource intensive!)
What Roblox do is they find the nearest Player to that physics object, and they give them “ownership” so that player has to do all of the physics calculations for that object (and any attached objects). This has the benefit of efficiency (distributing the calculation burden from the server to a mix of the server and different clients), but the downside of security.
Since these players have “network ownership” of these parts, they can change their position and certain other things. For example, they can break the joints on welds which is what they’re doing here. They aren’t actually changing the Humanoid health to 0 on the server, but the effect is the same.
SOLUTION - Just set the network ownership of the humanoid to “nil” (so to the server)
local Character = workspace:WaitForChild("CharacterModel")
for _, Item in pairs(Character:GetDescendants()) do
if Item:IsA("BasePart") and not Item.Anchored then
pcall(Item.SetNetworkOwner, Item, nil)
-- equivalent of Item:SetNetworkOwner(nil)
end
end
Thanks a lot, I was about to make a whole new humanoid every time the other one died and replace it lol. That also explains why it doesn’t effect other player’s characters too.