Sword script very buggy

For some reason the code for my sword is very buggy and I can’t understand why?
Here’s the video that shows how buggy it is: 2022-12-17 17-28-16

and here’s the server script in serverscriptservice:

--Services
local rs = game:GetService("ReplicatedStorage")
local ds = game:GetService("Debris")
local mps = game:GetService("MarketplaceService")
local swordswingRE = rs:WaitForChild("SwordEvents"):WaitForChild("SwordSwingRE")
local sworddamageRE = rs:WaitForChild("SwordEvents"):WaitForChild("SwordDamageRE")

--Configuration
local deadcheck = false

function SwordSwing(player, sound)
	
	sound:Play()
end

function SwordDamage(player, hit, effect, tool, strength, damage, hitsound, CanDamage)
	if hit.Parent:FindFirstChild("Humanoid") then
		local Humanoid = hit.Parent:FindFirstChild("Humanoid")
		local char = hit.Parent
		if CanDamage == true and hit.Parent:FindFirstChild("Humanoid").Health >= 0 then
			
			local HumanoidRP = hit.Parent:FindFirstChild("HumanoidRootPart")
			local UpperTorso = hit.Parent:FindFirstChild("UpperTorso")

			--gamepass x2 money

			local userId = player.UserId
			local gamepass = 85869838


			--Clone effects
			local effectsclone = effect:Clone()
			local bloodeffectclone = rs:WaitForChild("SwordEffects"):WaitForChild("BloodParticles"):Clone()
			local sparkeffectclone = rs:WaitForChild("SwordEffects"):WaitForChild("SparksParticles"):Clone()
			effectsclone.Parent = UpperTorso
			local weldeffects1 = Instance.new("Weld", effectsclone)
			weldeffects1.Part0 = UpperTorso
			weldeffects1.Part1 = effectsclone
			bloodeffectclone.Parent = UpperTorso
			local weldeffects2 = Instance.new("Weld", bloodeffectclone)
			weldeffects2.Part0 = UpperTorso
			weldeffects2.Part1 = bloodeffectclone
			sparkeffectclone.Parent = UpperTorso
			local weldeffects3 = Instance.new("Weld", sparkeffectclone)
			weldeffects3.Part0 = UpperTorso
			weldeffects3.Part1 = sparkeffectclone

			--knockback
			local bv = Instance.new("BodyVelocity")
			bv.P = 2500
			bv.MaxForce = Vector3.new(100000,100000,100000)
			bv.Velocity = CFrame.new(tool.Parent:FindFirstChild("HumanoidRootPart").Position, HumanoidRP.Position).lookVector * (strength/2)

			bv.Parent = char:FindFirstChild("HumanoidRootPart")
			ds:AddItem(bv, 0.2)


			Humanoid:TakeDamage(damage)
			local findcombogui = player.PlayerGui:FindFirstChild('ComboGui')

			if findcombogui then
				if mps:UserOwnsGamePassAsync(userId, gamepass) then
					player.PrivateStats.Money.Value += 2
				else
					player.PrivateStats.Money.Value += 1
				end
				Humanoid.Died:Connect(function()
					if deadcheck == false then
						deadcheck = true
						player.leaderstats.Kills.Value += 1
						if mps:UserOwnsGamePassAsync(userId, gamepass) then
							player.PrivateStats.Money.Value += 10
						else
							player.PrivateStats.Money.Value += 5
						end
					end
				end)
				findcombogui.Combo.Value = findcombogui.Combo.Value + 1
				findcombogui.ShowCombo.Despawn.Disabled = true
				findcombogui.ShowCombo.Despawn.Disabled = false

			else
				local comboGui = game:GetService("ServerStorage").ComboGui:Clone()
				comboGui.Parent = player.PlayerGui
			end
			hitsound:Play()
			CanDamage = false
		else
			return
		end
	else
		return
	end
	deadcheck = false
end

sworddamageRE.OnServerEvent:Connect(SwordDamage)
swordswingRE.OnServerEvent:Connect(SwordSwing)

and here’s the local script in the sword:

--Services
local rs = game:GetService("ReplicatedStorage")
local swingswordRE = rs:WaitForChild("SwordEvents"):WaitForChild("SwordSwingRE")
local sworddamageRE = rs:WaitForChild("SwordEvents"):WaitForChild("SwordDamageRE")

--Configuration
local player = game:GetService("Players").LocalPlayer
local tool = script.Parent
local CanDamage = tool.CanDamage.Value
local CoolDown = tool.Cooldown.Value
local dmg = tool.dmg.Value
local strength = tool.knockbackstrength.Value
local turn = 1
local SecondsCoolDown = 0.03
local hiteffect = rs:WaitForChild("SwordEffects"):WaitForChild("HitEffects")
local track

--Sounds
local hitsound = tool.Handle.HitSound
local swing1 = tool.Handle.Swing1Sound
local swing2 = tool.Handle.Swing2Sound

--Animations
local attack1 = tool.Attack1
local attack2 = tool.Attack2
local idle = tool.Idle


--Functions

tool.Equipped:Connect(function()
	track = tool.Parent.Humanoid:LoadAnimation(idle)
	track.Priority = Enum.AnimationPriority.Action
	track:Play()
end)
tool.Unequipped:Connect(function()
	if track then
		track:Stop()
	end
end)

tool.Destroying:Connect(function()
	if track then
		track:Stop()
	end
end)

tool.Activated:Connect(function()
	if CoolDown == false then
		CoolDown = true

		local Humanoid = tool.Parent.Humanoid
		local Anim1 = Humanoid:LoadAnimation(attack1)
		local Anim2 = Humanoid:LoadAnimation(attack2)

		if track then
			track:Stop()
		end

		if turn == 1 then
			Anim1:Play()
			wait(0.1)
			CanDamage = true
			swingswordRE:FireServer(swing1)
			turn = 2

			Anim1.Stopped:wait(SecondsCoolDown)
			CanDamage = false
			CoolDown = false

		elseif turn == 2 then
			Anim2:Play()
			wait(0.1)
			CanDamage = true
			swingswordRE:FireServer(swing2)
			turn = 1

			Anim2.Stopped:Wait(SecondsCoolDown)
			CanDamage = false
			CoolDown = false
		end
		wait()
		track:Play()
	else
		return
	end
end)

tool.Handle.Touched:Connect(function(Hit)
	
	sworddamageRE:FireServer(Hit, hiteffect, tool, strength, dmg, hitsound, CanDamage)
	
end)

If you guys also have any tips on how I could optimize these scripts I would be very glad!

Hey there,

I’m not quite sure what you mean by “code being buggy”, if it’s the error throwing part or the code not doing what you intended to be doing.

However,
the reason behind the error is probably the parent of the hit. You’re never checking whether the hit or it’s parent even exists (== nil). That’s why when you try to call :FindFirstChild() it would throw an error.

For the optimisation part, there is a lot of repeated code so try to use DRY (Don’t repeat yourself) rule and check if some of the same code could be squeezed into 1 with use of variables.
For the effect part and creating instances on the fly, you could prepare the BodyVelocity and the effect instances before and just use clone on the whole effect handler / BodyVelocity and parent it to desired parent.

Hope I helped,
Sougood.

well by buggy I mean that the effects get cloned like a thousand times and if you watch the combo gui it does a ton of hits, which is not normal. And for the findfirstchild solution should I do if not hit.Parent:FindFirstChild("Humanoid") == nil then? And for the optimisation part are you saying that I should put all of the variables at the start?

Not at all,

if (hit ~= nil) and (hit.Parent ~= nil) then ... end
For the variables, I meant that there’s only difference between some of the arguments getting passed through the functions, so you could make that into the variable and use the code once instead of if, elseif, else branches.
The spamming of hits and stuff could be because you don’t check for repeated use and if you do then by a little amount. Not quite sure what the issue is, I’d firstly go for optimisation and then fixing bugs, because it might lead to creating another bug.

Ok I see, I’m not that sure how I could check for repeated use should I use a debounce?

Here is an overworked and optimized version of the Server Code.

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local MarketplaceService = game:GetService("MarketplaceService")
local SwordSwingRE = ReplicatedStorage.SwordEvents.SwordSwingRE
local SwordDamageRE = ReplicatedStorage.SwordEvents.SwordDamageRE

-- Configuration
local deadcheck = false

function SwordSwing(player, sound)
  sound:Play()
end

function SwordDamage(player, hit, effect, tool, strength, damage, hitsound, CanDamage)
  local CanDamage = CanDamage or false
  local char = hit.Parent
  local Humanoid = char:FindFirstChild("Humanoid")
  
  if not Humanoid then return end
  
  if not CanDamage or Humanoid.Health < 0 then return end
  
  local HumanoidRP = char:FindFirstChild("HumanoidRootPart")
  local UpperTorso = char:FindFirstChild("UpperTorso")
  
  -- Clone effects
  local effectsclone = effect:Clone()
  local bloodeffectclone = ReplicatedStorage.SwordEffects.BloodParticles:Clone()
  local sparkeffectclone = ReplicatedStorage.SwordEffects.SparksParticles:Clone()
  effectsclone.Parent = UpperTorso
  bloodeffectclone.Parent = UpperTorso
  sparkeffectclone.Parent = UpperTorso
  local weldeffects1 = Instance.new("Weld", effectsclone)
  weldeffects1.Part0 = UpperTorso
  weldeffects1.Part1 = effectsclone
  local weldeffects2 = Instance.new("Weld", bloodeffectclone)
  weldeffects2.Part0 = UpperTorso
  weldeffects2.Part1 = bloodeffectclone
  local weldeffects3 = Instance.new("Weld", sparkeffectclone)
  weldeffects3.Part0 = UpperTorso
  weldeffects3.Part1 = sparkeffectclone
  
  -- Knockback
  local bv = Instance.new("BodyVelocity")
  bv.P = 2500
  bv.MaxForce = Vector3.new(100000, 100000, 100000)
  bv.Velocity = CFrame.new(tool.Parent:FindFirstChild("HumanoidRootPart").Position, HumanoidRP.Position).lookVector * (strength / 2)
  bv.Parent = char:FindFirstChild("HumanoidRootPart")
  Debris:AddItem(bv, 0.2)
  
  Humanoid:TakeDamage(damage)
  local ComboGui = player.PlayerGui:FindFirstChild("ComboGui")
  local userId = player.UserId
  local gamepass = 85869838
  
  if ComboGui then
    if MarketplaceService:UserOwnsGamePassAsync(userId, gamepass) then
      player.PrivateStats.Money.Value += 2
    else
      player.PrivateStats.Money.Value += 1
    end
  end
  
  Humanoid.Died:Connect(function()
    if deadcheck == false then
      deadcheck = true
      player.leaderstats.Kills.Value += 1
      if MarketplaceService:UserOwnsGamePassAsync(userId, gamepass) then
        player.PrivateStats.Money.Value += 10
      else
        player.PrivateStats.Money.Value += 5
      end
    end
  end)
end

SwordSwingRE.OnServerEvent:Connect(function(player, sound)
  SwordSwing(player, sound)
end)

SwordDamageRE.OnServerEvent:Connect(function(player, hit, effect, tool, strength, damage, hitsound, CanDamage)
  SwordDamage(player, hit, effect, tool, strength, damage, hitsound, CanDamage)
end)

Here is the revised client code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SwordSwingRE = ReplicatedStorage.SwordEvents.SwordSwingRE
local SwordDamageRE = ReplicatedStorage.SwordEvents.SwordDamageRE

local player = game:GetService("Players").LocalPlayer
local tool = script.Parent
local CanDamage = tool.CanDamage.Value
local CoolDown = tool.Cooldown.Value
local dmg = tool.dmg.Value
local strength = tool.knockbackstrength.Value
local turn = 1
local hiteffect = ReplicatedStorage.SwordEffects.HitEffects
local track

local hitsound = tool.Handle.HitSound
local swing1 = tool.Handle.Swing1Sound
local swing2 = tool.Handle.Swing2Sound

local attack1 = tool.Attack1
local attack2 = tool.Attack2
local idle = tool.Idle

tool.Equipped:Connect(function()
  track = tool.Parent.Humanoid:LoadAnimation(idle)
  track.Priority = Enum.AnimationPriority.Action
  track:Play()
end)

tool.Unequipped:Connect(function()
  if track then
    track:Stop()
  end
end)

tool.Destroying:Connect(function()
  if track then
    track:Stop()
  end
end)

tool.Activated:Connect(function()
  if CoolDown then return end
  CoolDown = true

  local Humanoid = tool.Parent.Humanoid
  local Anim1 = Humanoid:LoadAnimation(attack1)
  local Anim2 = Humanoid:LoadAnimation(attack2)

  if track then
    track:Stop()
  end

  if turn == 1 then
    Anim1:Play()
    CanDamage = true
    SwordSwingRE:FireServer(swing1)
    turn = 2

    Anim1.Stopped:Connect(function()
      CanDamage = false
      CoolDown = false
      track:Play()
    end)
  elseif turn == 2 then
    Anim2:Play()
    CanDamage = true
    SwordSwingRE:FireServer(swing2)
    turn = 1

    Anim2.Stopped:Connect(function()
      CanDamage = false
      CoolDown = false
      turn = 1
      track:Play()
    end)
  end
end)

tool.Handle.Touched:Connect(function(Hit)
  SwordDamageRE:FireServer(Hit, hiteffect, tool, strength, dmg, hitsound, CanDamage)
end)

I changed it on different times I honestly forgot what was changed but here you go this should work I guess.

1 Like

Yeah debouncing could definitely fix that altough I can see you already debounce, try increasing the debouncing time and see how that goes. Also for exploit protection, delete debouncing on the client and debounce on the server.

Ok I see I’ll try that out tomorrow and let you know!

Wow thank you so much, I’ll let you know if it works tomorrow! :pray:

@Dyzody
So I tried using your code and now this error pops up as well:
ServerScriptService.SwordServer:18: attempt to index nil with ‘FindFirstChild’

Plus the effects still seem to be weird and duplicated a thousand times and the damage that it does it much more than what I put

Ye just change the findfirstchild to waitforchild

im looking into it

If I put waitforchild it gives me:
Infinite yield possible on ‘Workspace.Sword dummys.UpperTorso:WaitForChild(“Humanoid”)’
it’s basically the same error but with waitforchild and after a bit it also gives me index nil with waitforchild

That is fine

This is a new revision of the function which does the following:
Change CanDamage instead of declaring another variable instead of the parameter;
Disconnect the Humanoid.Died Event after it is no longer needed;
Change FindFirstChild to WaitForChild with a timeout of 2 seconds.

function SwordDamage(player, hit, effect, tool, strength, damage, hitsound, CanDamage)
  CanDamage = CanDamage or false
  local char = hit.Parent
  local Humanoid = char:WaitForChild("Humanoid", 2)
  
  if Humanoid == nil then return end
  
  if not CanDamage or Humanoid.Health < 0 then return end
  
  local HumanoidRP = char:FindFirstChild("HumanoidRootPart")
  local UpperTorso = char:FindFirstChild("UpperTorso")
  
  -- Clone effects
  local effectsclone = effect:Clone()
  local bloodeffectclone = ReplicatedStorage.SwordEffects.BloodParticles:Clone()
  local sparkeffectclone = ReplicatedStorage.SwordEffects.SparksParticles:Clone()
  effectsclone.Parent = UpperTorso
  bloodeffectclone.Parent = UpperTorso
  sparkeffectclone.Parent = UpperTorso
  local weldeffects1 = Instance.new("Weld", effectsclone)
  weldeffects1.Part0 = UpperTorso
  weldeffects1.Part1 = effectsclone
  local weldeffects2 = Instance.new("Weld", bloodeffectclone)
  weldeffects2.Part0 = UpperTorso
  weldeffects2.Part1 = bloodeffectclone
  local weldeffects3 = Instance.new("Weld", sparkeffectclone)
  weldeffects3.Part0 = UpperTorso
  weldeffects3.Part1 = sparkeffectclone
  
  -- Knockback
  local bv = Instance.new("BodyVelocity")
  bv.P = 2500
  bv.MaxForce = Vector3.new(100000, 100000, 100000)
  bv.Velocity = CFrame.new(tool.Parent:FindFirstChild("HumanoidRootPart").Position, HumanoidRP.Position).lookVector * (strength / 2)
  bv.Parent = char:FindFirstChild("HumanoidRootPart")
  Debris:AddItem(bv, 0.2)
  
  Humanoid:TakeDamage(damage)
  local ComboGui = player.PlayerGui:FindFirstChild("ComboGui")
  local userId = player.UserId
  local gamepass = 85869838
  
  if ComboGui then
    if MarketplaceService:UserOwnsGamePassAsync(userId, gamepass) then
      player.PrivateStats.Money.Value += 2
    else
      player.PrivateStats.Money.Value += 1
    end
  end
  
  local function onDied()
    player.leaderstats.Kills.Value += 1
    if MarketplaceService:UserOwnsGamePassAsync(userId, gamepass) then
      player.PrivateStats.Money.Value += 10
    else
      player.PrivateStats.Money.Value += 5
    end
  end
  
local DiedConnection

  DiedConnection = Humanoid.Died:Connect(onDied)
  DiedConnection:Disconnect()
end

hmmm I no longer get errors for the waitforchild part, but now when you disconnect the died function at the end I get this error: Disconnect is not a valid member of RBXScriptSignal
And now it still does way to much damage and when I kill the player it gives me a ton of cash and kills.

I have just edited it again, I’m not good with disconnecting events but this should work

@Dyzody you still there?
I see what you’ve done, but now this error pops up and as you can see I no longer get cash or kills when I kill the player, also the effects still get cloned a gazillion times and the damage is really high. Video: 2022-12-18 13-55-56

I think I figured something out:
You should check if the char variable is not nil before creating the Humanoid variable, and if it is nil, set the Humanoid property to nil too

So I should do if char == nil then
Humanoid = nil
End?

1 Like

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