Sword is doing FireServer depending on the amount of people in the game from local script when it should only do it once

  1. What do you want to achieve?

I’m making a Sword which fires a Raycast every time the tool is activated from a local script to do damage to an object, it fires the event on the server via a FireServer event and then there is a ‘ToolHandler’ script in the ServerScriptService which deducts the damage from the part.

  1. What is the issue?

So far it works fine when one player is in the game, if I hit an object first when I’m the only player in the game it will do the right amount of damage. But when the second player joins it will do double the damage for them but the correct damage for me. If I don’t use the Sword and wait until the 2nd player has joined it will do double the damage for both of us - I haven’t tried it with three but I assume it would then do three times the damage.

  1. What solutions have you tried so far?

I’ve tried adding a debounce to the FireServer event and the OnServerEvent in the ServerScriptService but that hasn’t worked. I’ve tried checking if the player name in the Server Script from the FireServer event is equal to the name of that coming from the Local Script but when I check the output in the game it comes up twice if there are two players in the game.

Client Script:

local tool = script.Parent
local plrNm = game.Players.LocalPlayer.Name

tool.Activated:Connect(function()
		local raycast = workspace:Raycast(tool.Handle.Position, tool.Hitbox.CFrame.LookVector * 100)
			if raycast then
				if raycast.Instance then
					print(raycast.Instance.Name)
					if raycast.Instance.Name == "Full" or raycast.Instance.Name == "Half1" or raycast.Instance.Name == "Half2" then
						local hit = raycast.Instance
						local damage = script.Parent.Damage.Value
						game.ReplicatedStorage.FireTool:FireServer(hit, script.Parent.Name, damage, plrNm)
						print("FIRING RAYCAST TOOL EVENT PLR: "..tostring(game.Players.LocalPlayer.UserId))
					end
				end
			end
end)

Server Script:

game.ReplicatedStorage.FireTool.OnServerEvent:Connect(function(plr, hit, toolName, damage, name)	
		print("TOOL BEING HANDLED BY SERVER")
		if plr.Name == name then
			print("PLR NAME EQUALS NAME")
			local objOg = hit
			if toolName then
				print(tostring(hit.Name))
				if hit.Name == "Full" or hit.Name == h1 or hit.Name == h2 then
					if hit.Parent:FindFirstChild("Dummy") then
						dummy = true
						print("Dummy!")
					else
						dummy = false
						print("Not dummy!")
					end
						local group = hit.Parent
					
						if playing == true then 
							local healthVal = hit.Parent:WaitForChild("HealthVal")
							
							local sum = healthVal.Value - damage
							if sum <= 0 then
								healthVal.Value = 0
							else
								healthVal.Value = healthVal.Value - damage
							end
							
						
							print(healthVal.Value)
						
						local tweenInfo = TweenInfo.new(0.25, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
						
						if hit.Name == "Full" and dummy == false then
							local x = hit.Size.X + 0.5
							local y = hit.Size.Y + 0.5
							local z = hit.Size.Z + 0.5

							local tweenOut = tweenService:Create(hit, tweenInfo, {Size = Vector3.new(x, y, z)})
							tweenOut:Play()
							wait(0.25)
							local x2 = hit.Size.X - 0.5
							local y2 = hit.Size.Y - 0.5
							local z2 = hit.Size.Z - 0.5

							local tweenIn = tweenService:Create(hit, tweenInfo, {Size = Vector3.new(x2, y2, z2)})
							tweenIn:Play()
						end
							
							local grpName = group.Name
						
							
							if group.CutGame.Value == true then
								
								local passCoins = hit.Parent.CoinsVal.Value
								local passXp = hit.Parent.XPVal.Value
								
								if healthVal.Value <= 0 then
									if gameRan.Value == false then
										print("Fired")
										gameRan.Value = true
										game.ReplicatedStorage.CutGame.GenerateGreen:FireClient(plr)
										game.ReplicatedStorage.CutGame.ShowGame:FireClient(plr)
										checkPasses(plr)
										wait(0.5)
										game.ReplicatedStorage.CutGame.ActivateGame:FireClient(plr, passCoins, passXp, doubleCoins, doubleXP, objOg, group)
										
									end
								end
								
								
								game.ReplicatedStorage.CutGame.Success.OnServerEvent:Connect(function(plr, obj, grp)
									
									print(script.Parent.Name.."equals")
								
									if plr then
										successGame(plr, obj, grp)
									end
								end)
								
								game.ReplicatedStorage.CutGame.Fail.OnServerEvent:Connect(function(plr, obj, grp)
								
									print(script.Parent.Name.."equals")
									
									if plr then
										failGame(plr, obj, grp)
									end
								end)
								
							else
							
								if healthVal.Value >= 50 and healthVal.Value <= 100 and dummy == false then
									if hit.Name == "Full" then
								
										if run == false then
											hit.Parent.Full:Destroy()
											run = true
										end
									
										local half1 = group[h1]
										local half2 = group[h2]		
												
										half1.Anchored = false
										half2.Anchored = false
										half1.CanCollide = true
										half2.CanCollide = true
										half1.CanTouch = true
										half2.CanTouch = true 
										half1.CanQuery = true
										half2.CanQuery = true
										
									end
											
								elseif healthVal.Value == 0 then
									local coins = hit.Parent.CoinsVal.Value 
									local xp = hit.Parent.XPVal.Value
									giveRewards(coins, xp)
									
									if dummy == false then
										hit.Parent.Health:Destroy()
										local tweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
										local tweenHalf1 = tweenService:Create(hit.Parent[h1], tweenInfo, {Size = Vector3.new(0,0,0)})
									    local tweenHalf2 = tweenService:Create(hit.Parent[h2], tweenInfo, {Size = Vector3.new(0,0,0)})
										tweenHalf1:Play()
										tweenHalf2:Play()
										wait(1.5)
										
										local pos = group:GetPivot().Position
										local name = group.Name
										objRemoved:Fire(name, pos)
										
										group.Full:Destroy()
										hit.Parent:Destroy()
										run = false
									
									end
								end	
								
							end
								
						end		
				end
			end
		end
end)

It looks like the reason your sword is dealing double/triple damage when more players join is because of how you’re connecting events inside your FireTool.OnServerEvent callback. Every time a player fires the tool, you’re creating new connections for CutGame.Success and CutGame.Fail. This causes multiple listeners to trigger simultaneously, multiplying the damage.

How to fix:

Move event connections out of the FireTool handler

Connect CutGame.Success and CutGame.Fail once globally in your server script, not every time the tool fires:

-- Place this at the top of your server script, outside of any OnServerEvent
game.ReplicatedStorage.CutGame.Success.OnServerEvent:Connect(function(plr, obj, grp)
    successGame(plr, obj, grp)
end)

game.ReplicatedStorage.CutGame.Fail.OnServerEvent:Connect(function(plr, obj, grp)
    failGame(plr, obj, grp)
end)

Add per-player debouncing for the sword damage (This is optional, like a fireevent anti-spam)

local playerDebounce = {}

game.ReplicatedStorage.FireTool.OnServerEvent:Connect(function(plr, hit, toolName, damage, name)
    -- prevent multiple triggers from same player at the same time
    if playerDebounce[plr] then return end
    playerDebounce[plr] = true

    -- some damage handling logic here
    -- e.g., reduce hit.Parent.HealthVal by damage

    task.delay(0.2, function()
        playerDebounce[plr] = nil
    end)
end)

Also, adjust the delay to match the tool’s activation speed.

Please mark this as a solution if it did. And if didn’t, you can ask me questions.

1 Like

Thank you so much, adding the debounce worked!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.