my main worry about my punch system is the hitbox because it is made on server and checking for touch on server too
this is the input local script which handles inputs and animation and fire a remote event
local function Punch(ActionName, inputState)
if ActionName == "punch" and inputState == Enum.UserInputState.Begin then
Holding = true
if inloop then return end
inloop = true
task.spawn(function()
while Holding do
if not CanPunch or StatesFolder.Dashing.Value == true then
task.wait(0.1)
continue
end
ComboCount += 1
CanPunch = false
local track: AnimationTrack = punchAnimation[ComboCount]
track:Play()
if CurrentConnection then
CurrentConnection:Disconnect()
CurrentConnection = nil
end
CurrentConnection = track:GetMarkerReachedSignal("Hit"):Connect(function()
PunchEvent:FireServer()
end)
if ComboCount >= PunchesPerCombo then
CanPunch = false
task.wait(EndTime)
CanPunch = true
ComboCount = 0
end
task.wait(0.6)
CanPunch = true
end
inloop = false
end)
elseif inputState == Enum.UserInputState.End then
Holding = false
end
end
this is the server script and it require the hitbox module the hitbox module creates a part and connect it to a touched event to do damage and also i weld it becasue i want it to follow the player for a very short time becasue it better
local Remote = game.ReplicatedStorage.Events.PunchEvent
local HitboxModule = require(game.ReplicatedStorage.Modules.HitboxModule)
Remote.OnServerEvent:Connect(function(player)
local character = player.Character
if character then
local humanoidrootpart = character.HumanoidRootPart
HitboxModule.CreateHitboxWithWeld(character, humanoidrootpart.CFrame * CFrame.new(0,-0.5,-3), Vector3.new(4,5,4), 10, 0.05, 0.2)
end
end)
Your code is well-structured and functional in terms of a basic punch and hitbox system in Roblox. You’ve done a good job separating input logic (client-side) from hitbox creation (server-side), which is a solid design choice. However, there are two critical areas that need improvement:
What’s Good:
Use of RemoteEvent: Correct use of RemoteEvent to send punch signals to the server.
Modular hitbox creation: Having a hitbox module keeps your server code clean and reusable.
Animation marker sync: Firing the server event on "Hit" animation marker makes the punch timing more accurate.
What Needs Improvement:
Server Trusting Client Too Much (Exploit Risk):
Right now, the server fully trusts the client to decide when a punch should happen. Exploiters can take advantage of this by firing the event manually or more frequently than allowed.
Recommendation: Add server-side validation. For example:
Check the player’s proximity to targets before applying damage.
Enforce server-side cooldowns to prevent spamming attacks even if the client is tampered with.
Hitbox on Server (Good, But Watch for Accuracy):
Creating the hitbox server-side is the right choice for security. However, since .Touched can be unreliable in fast or short-lived collisions, consider alternatives like using Region3 or GetTouchingParts during the short hitbox duration to improve hit detection accuracy (optional improvement).
Conclusion:
Your code is very good in terms of structure, but you must validate everything the client sends. Never trust the client fully in a combat system. With these improvements, your punch system will be more secure and reliable.
1. “Check the player’s proximity to targets before applying damage”
What it means:
This means the server should check if the target is close enough before applying any damage. This prevents players from cheating and damaging players across the map or out of range.
Practical example:
Before applying damage inside your HitboxModule, add something like this:
local maxDistance = 5 -- maximum punch range
for _, target in ipairs(workspace:GetChildren()) do
if target:IsA("Model") and target ~= player.Character then
local humanoid = target:FindFirstChildOfClass("Humanoid")
local hrp = target:FindFirstChild("HumanoidRootPart")
if humanoid and hrp then
local distance = (hrp.Position - player.Character.HumanoidRootPart.Position).Magnitude
if distance <= maxDistance then
humanoid:TakeDamage(10) -- Apply damage
end
end
end
end
This ensures the punch only damages enemies within a valid distance, even if the client tries to cheat.
2. “Enforce server-side cooldowns to prevent spamming attacks”
What it means:
Even if your client respects the punch cooldown, an exploiter could modify the script and send the event many times per second. So the server must also enforce its own cooldown timer.
Practical example:
In your Remote.OnServerEvent, keep track of each player’s last punch:
local lastPunchTimestamps = {}
Remote.OnServerEvent:Connect(function(player)
local now = tick()
local lastPunch = lastPunchTimestamps[player] or 0
local cooldown = 0.5 -- half a second between punches
if now - lastPunch < cooldown then
return -- still on cooldown, ignore
end
lastPunchTimestamps[player] = now
-- Create the hitbox here
end)
Now, even if a cheater tries to spam punches, the server only accepts valid punches that respect the cooldown.
Conclusion:
These two practices are essential to prevent exploiters and make your combat system more secure. The client can still trigger the animation and effects, but only the server decides if the attack is allowed to deal damage.
What I just explained is simply an example of how you can implement this logic in your system and in other similar situations. The idea is that the client makes a request to the server based on a specific need. However, to emphasize an important point: the server should never fully trust the client.