TL;DR: How can I implement sanity checks on the server to prevent constant headshots
Currently I’m using the raycast hitbox module for this combat system I’ve been making. In this system, different parts will affect the player health by different amounts, so a blow to the head will do more damage.
When a player is hit, the server receives two pieces of information from the client through a remote event. The tool used to hit the other player, and the body part that had been hit.
I’ve already added sanity checks to the server such as:
Server sided cooldowns to prevent remote spamming
Verifying that both players are in close enough proximity to be able to hit each other
Raycasting on the server to ensure there’s nothing between the two players
But even so, the player’s head is supposed to be hard to hit, but this can be bypassed by exploiters firing the remote event and specifying another players head, like so: PlayerHit:FireServer(workspace.Player1.ToolUsed, workspace.Player2.Head)
So how can I implement sanity checks on the server to prevent this?
You could handle the hitboxes on the player you hit. And they won’t be able to disable it if you add a script preventing the player by using the .Changed event.
You can also protect your remote event by constantly changing it’s name to gibberish. Just add a “fake” remote event after getting the real remote event and make the fake one change the name too. You can also make the fake remote ban or kick the player since the remote will only be fired if the exploiter makes a mistake.
Great suggestion if I am thinking about what you are thinking, server-side hit registration.
Horrible suggestion that will barely do anything except make programming slightly harder for exploiters and you.
On the topic of server-side hit registration, it’s a pretty big thing to cover in one reply, so I’ll summarize how you’d go about doing it;
Every frame, the server copies player avatars from workspace (which preserves their position) into a “WorldModel”, names it with the server’s current tick and deletes any world model more than a second old.
The client still does it’s own raycasts on the workspace so that player’s get visual feedback, i.e. bullet tracers etc
Client fires a remote event with look at direction.
The server gets a world model by looking at one with a name closest to serverTick - playerPing (you may have to divide playerPing by 2) and calls :Raycast on that.
I’m a typically very straight forward guy, and if I’m being straight forward and honest, you’ve got straight up terrible advice.
Exploits can disable and disconnect events easily. In fact, most exploiters—I’m willing to bet—have an Anti-afk (anti idle kick for 20 mins of inactivity) that disconnects Player.Idled Connections.
Changing the names of the remote constantly will do you no good, all it takes it one exploiter who knows roughly how to google for code on sites like V3rmillion to find out that if you use Remote Spy, find what script calls the remote, and then use registry/garbage collector skimming to grab the proper remote.
Fake Remotes? The people who fall for those—and don’t come back with an alt completely ready to dump your games codebase—weren’t going to find out how to do what the OP is concerned about anyways.
I’ve read through your linked post, and while it is very helpful to me in a general sense, I’m wondering if you could provide a more specific suggestion regarding the original problem.
You could do what I suggested, maybe I’ll make a tutorial on how to implement it;
The only reason I’m re-stating is because you didn’t reply to my original comment so I don’t think you even realized I edited it with more information.
I’m probably not the most ideal for this specific situation. But I’ll try to give some advice.
Continuing on with what @Judgy_Oreo is suggesting, server-side hit registration sounds like it’d be most ideal for the level of security you want.
…But it’s also gonna cost you.
Server-sided hit registration is often taxing. And, in some cases, has noticeable delays between visuals on the client.
Since registration is handled on the server (followed by replicating that again to all the clients,) it’s dependent heavily on the server and client’s ping.
Depending on the scale/extent of the calculations you end up performing/requiring, the server may slow down, further increasing strain on ping and degrading most, if not all, smooth gameplay.
But, it’s still the most ideal in this scenario since the server is the safest haven for our games with how powerful exploits truly are on the client.
, but stuff like damage numbers will have to be delayed since they are a more direct interaction.
Unless your ping is higher than one second (configurable) or your ping is extremely unstable to the point that it’s visually visible (and where you should hardly expect a good experience anyway), then this shouldn’t really be a problem.
I’m actually pretty sure it won’t be that expensive, raycasts themselves are extremely optimized and non-rendered, non-physically simulated parts should carry little performance cost. Of course, there’s probably a memory cost (but may be negligible with the correct optimizations like never cloning the map into individual WorldModels), and I can’t really say it won’t affect performance at all with complete certainty, since I’ve never actually fully finished my own implementation.
I’m gonna just be honest, I’m way too tired to even conceptualize writing a client-server modal outline for a combat system right now; much less give advice on one. I’ll give you the cookie this time since I should just drink the milk and hit the sack. Still not gonna go to sleep though, I’m so unreasonably bored that it’s turned into insomnia
I should have probably highlighted the fact that I was using the raycast hitbox module for client sided hit detection for melee weapons.
From your post, I’m sensing that your talking about server-sided hit registration for projectile weapons, so how viable would it be for melee weapons in my case? And I’m assuming I would have to create my own hit registration system? I don’t quite understand, most of this is beyond me.
No, it’ll work with anything that uses raycasts, not physics (though you could technically make a custom physics simulator with raycasts and do so as well), and,
Of course, I’m saying all of this considering you are willing to modify this module for the purpose of making it, on it’s own, completely secure from exploits.
local WorldModels = ServerStorage.WorldModels -- where all the worldmodels are stored
RemoteEvents.PlayerSwingMelee.OnServerEvent(function(Player, Direction)
local PlayerServerTime = workspace.DistributedGameTime - Player:GetPing() -- what point in time the player swung their melee weapon (as it will have taken time for the message to reach the server)
local BestWorldModel
local BestDifference = math.huge -- math.huge will always make the first world model checked get set to "BestWorldModel" in case there's only one
for _, WorldModel in WorldModels:GetChildren() do
local Time = tonumber(WorldModel.Name) -- upon creation, worldmodel.Name is set to workspace.DistributedGameTime
local Difference = math.abs(Time - PlayerServerTime) -- math.abs will always give a positive value
if Difference < BestDifference then -- try and find a world model that gets as close as possible to the point in time that the player swung their melee
BestWorldModel = WorldModel
BestDifference = Difference
end
end
-- do raycast, deal damage, check if head, etc
local Hit = BestWorldModel:Raycast(Player.Character.Head.Position, Direction, RayInfo)
...
end)
That’s just a rough idea of what it could look like, I’m sure there’s some central function inside of the melee raycast module that actually handles checking the collisions which you can easily modify.
Basically, the server keeps a record of where everyone was (called a “snapshot”), and we try and find the snapshot where everyone was when the player swung their melee on their screen.
Now that I think about it, would it make much difference if I simply just moved it so that the rays were cast on the server instead? Why would I need to copy the player avatar into a worldmodel every frame?
Because of ping. Everybody will have moved around by the time the remote event fires for the server, and so the server needs to know where everybody was.
So I’ve tried copying avatars into a worldmodel as you said. And everything works fine, except it is extremely performance intensive.
local function AddModels()
for _, Characters in pairs(workspace:GetChildren()) do
if Characters:FindFirstChildWhichIsA("Humanoid") then
local WorldModel = Instance.new("WorldModel", ServerStorage.WorldModels) --ServerStorage.WorldModels
WorldModel.Name = Characters.Name.."_"..tostring(tick())
Characters.Archivable = true
local CharModel = Characters:Clone()
CharModel.Parent = WorldModel
CharModel.PrimaryPart.Anchored = true
end
end
end
local function RemoveOldModels()
for _, WorldModel in pairs(ServerStorage.WorldModels:GetChildren()) do
local split = WorldModel.Name:split("_")
local PrevTick = tonumber(split[2])
if tick() - PrevTick > 1 then
WorldModel:Destroy()
end
end
end
local timeConsumed = 0
RunService.Heartbeat:Connect(function(dt)
AddModels()
timeConsumed += dt
if (timeConsumed >= 1) then
RemoveOldModels()
timeConsumed = 0
end
end)
Adding onto this, in your other post, you suggested to fire a remote event with look at direction. I’m sure you already know how raycasting works in TeamSwordphin’s hitbox module, so how I would get the raycasting to work on the server in this case?
A server-sided hitbox would be a good solution but I’ve worked with server-sided hitboxes and they all have the same problem. When you hit someone with a weapon it has a huge delay or doesn’t hit at all because on the client you hit the player but on the server, you didn’t. You should if you haven’t already check the distance between the players in the server script. That’s one thing you can do. You can also make a flag system in which if you hit the head like 10 times in a row, a moderator will look into it. (If you don’t have people moderating your game, don’t add this since false positives can be annoying.)
If you have a moderation team, add a reporting system if you haven’t already.