Touched event for punch tool works for me, but not for other players

Hello,
This is my first post so correct me if I’m doing something wrong.
I have a punch tool, which you can use to damage and kill players. The tool works fine for me in game and in studio, however when someone else except me uses the tool, the touched event doesn’t seem to work. I have got no idea why. The code is below, “Handtouched” and “Hit” isn’t printing for all players, except me. The rest prints. This is a normal script and a child of the tool (starterpack).

local tool = script.Parent
local waitTime = 1 -- set this to the time between each damagehit
local damageAmount = 10 -- set this to the amount of damage each damagehit does
local canDamage = tool.CanDamage
local clickGoing = false
local TouchConnection     -- touch event for the right hand
local TouchConnectionLeft -- touch event for the left  hand
print(canDamage)
local player = tool.Parent.Parent
print (player.Name)
local character = player.Character
if not character or not character.Parent then -- check if character loaded
    character = player.CharacterAdded:wait()
end
local RightHand = character:WaitForChild("RightHand")
local LeftHand = character:WaitForChild("LeftHand")

local function HandTouched(hit)
	print("Handtouched")
	print(canDamage.Value)
	if hit.Parent:FindFirstChild("Humanoid") and canDamage.Value == true then
		print("hit")
		canDamage.Value = false
		local humanoid = hit.Parent.Humanoid
		humanoid.Health = humanoid.Health - damageAmount
	end
end

tool.Activated:Connect(function()
	if clickGoing == false then
		print (player.Name)
		print(RightHand.Name)
		print(LeftHand.Name)
		TouchConnection = RightHand.Touched:Connect(HandTouched)
		TouchConnectionLeft = LeftHand.Touched:Connect(HandTouched)
		print("epic")
		if clickGoing == false then
			clickGoing = true
			wait(waitTime)
			TouchConnection:Disconnect()
			TouchConnectionLeft:Disconnect()
			canDamage.Value = true
			clickGoing = false
			print("You can damage again")
		end
	end
end)

Thank you for helping

1 Like

When you say that the HandTouched function isn’t working for other players, do you mean that when you do it, they can’t see it happening and “Handtouched” only prints for you? Or do you mean that if they have the tool, they can’t use it?

They see the animation work (Which is in a localscript), but they don’t do any damage. In the server output I only see “Handtouched” print when I click, not when other players click.

It makes sense that you don’t see “Handtouched” printed when others use it because it is in a local function. Try removing local from the function HandTouched(hit).

Removing local doesn’t make any difference. Still the same output.

Animations are replicated to all other clients, which is why they can see the animation. However, in regards to damage, if you’re doing this in a LocalScript this will not replicate to other clients, as this is where FilteringEnabled comes into play.

You’re going to want to look into RemoteEvents which will allow a client to ‘tell the server’ to do something by using :FireServer() on that RemoteEvent, and on the server you’ll have code that will run .OnServerEvent on that RemoteEvent. Obviously, you’ll want to ensure there are some server side checks to make sure the player is allowed to actually damage the character instead of straight up damaging them as that can prove to be exploitable otherwise.

This damage script, which checks if the hand touches a player, is not a local script but a server side script. Only the animation is in a separate local script.

Local Function just means that the variable holding the function is local. It does not mean that anything won’t replicate.

4 Likes

When you say it doesn’t work for other players, how are you testing that? Can you explain the way you are testing the multiplayer functionality? It might help in solving this.

I’m not exactly sure what is wrong with your script, but I would suggest against using .Touched events to deal damage from an attack. I’ve tried using that event before for melee attacks, and it seems to be very unreliable at actually detecting touching parts.

What I would do is:

  1. Have a LocalScript specifically handle detection
  2. In this script, use Raycasting to fire a ray to where your fist or weapon is going
  3. Cast this ray on every frame the client sees, using game:GetService("RunService").Heartbeat, or any of the other similar events
  4. Send anything the rays hit to a normal Script
  5. Sanity check the hits; make sure the attacker didn’t punch someone from 100 studs away
  6. Have the serverscript disable/enable this localscript when you want to get input, and be sure to only use data from the client when the server has the localscript enabled.

Having a localscript handle hitboxes has some good and bad aspects, though I would definitely say the pros outweight the cons. For one, since you are getting hitboxes from the client, this is exploitable. Someone could spoof what they hit to the server. This means you should do that sanity check I mentioned as step #5, however this means that there is no way to be 100% secure. On the bright side, the user attacking will always deal damage if they see their hit connect, and firing a ray for each frame has proven to be an extremely accurate method for me. Depending on your level of scripting experience, this might be a bit too advanced for you, but if you’re up for it, I would highly suggest using this method for melee-ish attacks.

2 Likes

I am just testing it in game, by joining a server with other players. When they hit me, they don’t deal any damage and “Handtouched” and “Hit” do not appear in the server output. When I hit them then I deal damage and “Handtouched” and “Hit” are printing in the server output.

If you are sticking with your script that you’ve made, here are some changes you need to/should do:

  1. There is a print(canDamage), make sure you change that to print(canDamage.Value), otherwise it will be printing an object and not a value
  2. Get rid of the second if clickGoing == false then, since it is redundant. This isn’t a bad thing though, just useless to do seeing as you already check it beforehand.
  3. You are setting canDamage to true AFTER you have disconnected the .Touched events to HandTouched. That may be the big issue that you are looking to solve. Move that line before the disconnecting and waiting.

Here’s your code, revised a bit and with the changes I mentioned above. I am not available at the moment to test this in studio, so I can’t say this will 100% work, but I’m pretty sure this’ll do.

local tool = script.Parent
local waitTime = 1
local damageAmount = 10
local canDamage = tool.CanDamage
local clickGoing = false
local TouchConnectionRight --Adding RIGHT to be more specific
local TouchConnectionLeft
print(canDamage.Value) --Be sure to use .VALUE for these, otherwise you're printing an object and not a value
local player = tool.Parent.Parent
print (player.Name)

local character = player.Character or player.CharacterAdded:Wait() --You can do this with one line

local RightHand = character:WaitForChild("RightHand")
local LeftHand = character:WaitForChild("LeftHand")

local function HandTouched(hit)
	print("Handtouched")
	print(canDamage.Value)
	if canDamage.Value then --Since canDamage.Value is either true or false, you don't have to use .Value in an IF statement. If canDamage is true, then it passes through the IF.
		-- I would suggest creating variables for the stuff you need when attacking someone
		local model = hit:FindFirstAncestorOfClass("Model") --This will try to get whatever "model" hit is under. If there is no model, then it will be nil
		local human
		if model then --If hit is part of a model...
			human = model:FindFirstChildOfClass("Humanoid") -- This will try to get a 'humanoid' instance directly under 'model'. If there is none, it will return nil
		end
		
		if human then --Check to see if a humanoid was found
			print("Hit a humanoid")
			human:TakeDamage(damageAmount) --I would suggest using TakeDamage instead of subtracting health, since TakeDamage understands what forcefields are, and won't hurt players that have just spawned.
			canDamage.Value = false
		end
	end
end

tool.Activated:Connect(function()
	if clickGoing == false then --You can also write it as "if not clickGoing then"
		clickGoing = true
		
		canDamage.Value = true
		TouchConnectionRight = RightHand.Touched:Connect(HandTouched)
		TouchConnectionLeft = LeftHand.Touched:Connect(HandTouched)
		
		wait(waitTime)

		canDamage.Value = false --Adding this to make sure canDamage gets set to false, even if the player misses and doesn't hit anything
		TouchConnectionRight:Disconnect()
		TouchConnectionLeft:Disconnect()
		clickGoing = false
		print("You can damage again")
	end
end)
1 Like

This script is better setted up, thank you, but it’s still not working for other players. Only player.Name, canDamage.Value and “You can damage again” are printing. When I hit a player then it works, but still not for others.

1 Like

No, they use R15 and no packages. (I have a script to remove packages).