Raycast hitboxes and exploits

This is an incredibly vague suggestion. How do you mean exactly?

1 Like

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.
  • Profit.
3 Likes

I’m a typically very straight forward guy, and if I’m being straight forward and honest, you’ve got straight up terrible advice.

  1. 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.

  2. 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.

  3. 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.

Anyways, @amadeupworld2 I suggest reading up on this resource post since it’s a genuinely helpful article when you’re pondering security. Guide to proper Anti Exploits

2 Likes

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.

1 Like

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.

2 Likes

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.

2 Likes

“Often”?

It’s impact is reduced by;

, 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.

1 Like

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

1 Like

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.

I’m willing to modify the module, it’s just I’m clueless at where to even begin.
I’m specifically confused about the wording of this bit.

Could you elaborate on what you mean?

1 Like
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?

1 Like

It wasn’t for me.

No, actually.

Unfortunately, I don’t feel like I can give you all the details on how to implement this whole thing in one reply. I’ll try and make a post about it.

1 Like

So what exactly did you do that allowed the script to run smoothly?

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.

There are a few optimisations you could make to make it run better:

  • instead of outright cloning the character, only clone the BaseParts and put those in a new model.
  • instead of iterating through the workspace every frame, iterate through players (if you only want pvp combat) or use tag every model with a humanoid and then iterate over CollectionService:GetTagged("name of humanoid tag").
  • Instead of using a different WorldModel for each character put all the characters in the same WorldModel for each frame.
  • if you want you could also also make a new WorldModel every couple milliseconds instead of every frame (this depends on how much accuracy you want to have as opposed to performance)
  • if you put all the character clones in the same WorldModel, having the character name as part of the name of the WorldModel would be redundant, so you could just name it the tick() it was created on, which means you also don’t have to split the string each frame.

So you’re already raycasting between the players on the server side but didn’t think to just use the raycast as the actual hit detection itself?

Also, you are literally giving the exploiters the ability to headshot on every shot on a silver platter and you still can’t tell what’s going on.