GetAttributeChangedSignal running for every instance?

I am currently making a simple tree cutting simulator in the old classic roblox style but i am encountering the weirdest issue i have seen yet.

You will be able to have many axes in the game, so i decided to duplicate an axe and change the axe stats to test my dynamic tool stats system.

For example, a starter axe will do 5 damage to the tree changing it from 15 to 20, However if i have two or more axes (same or not) it will add up all the damage for every axe and when i try to hit the tree with one axe will deal that damage, causing it to break instantly

Here is the main script that seems to run for every axe you have: (MainTreeManager)

local TreesServerModules = script.Parent.Modules

local collectionService = game:GetService("CollectionService")

local treeEffectsModule = require(TreesServerModules.TreeEffectsModule)
local destroyTreeModule = require(TreesServerModules.DestroyTreeModule)
local checkHealthModule = require(TreesServerModules.CheckHealthModule)
local treesTable = collectionService:GetTagged("Tree") 
	
for i, tree in pairs(treesTable) do
	print("this is run every tree")
	local maxTreeHealth = tree:GetAttribute("MaxHealth")
	local healthGUI = game.ReplicatedStorage.TreeStorage.HealthGUI:Clone()
	
	healthGUI.Parent = tree.PrimaryPart
	
	tree:GetAttributeChangedSignal("Health"):Connect(function()
		print("health has been changed")
		local health = tree:GetAttribute("Health")
	
		if checkHealthModule.checkHealth(maxTreeHealth, health) then
			destroyTreeModule.destroyTree(tree)
		else
			treeEffectsModule.emitHitEffect(tree)
		end
	end)
end

this script only checks for the health, but it prints the print("health has been changed") for the amount of axes you have, which gave me the idea this was the problem. But, i dont see how it could possibly run more than once?

I have checked these two client and server scripts and debugged all the code to check for any chances it might run more than once, but it doesnt. However, feel free to check if you want.

These scripts are present in every tool (named ToolServer and ToolClient):

Client:

local player = game.Players.LocalPlayer
local tool = script.Parent
local toolPart = tool.ToolPart
local handle = tool.Handle
local swingSFX = tool.ToolPart.SwingSound

local cooldownTime = tool:GetAttribute("CooldownTime")
local swingAnimation = tool:GetAttribute("SwingAnimation")
local toolDamage = tool:GetAttribute("Damage")

local character = player.Character
local debounce = false

local damageTreeEvent = game.ReplicatedStorage.TreeEvents.DamageTreeEvent

tool.Activated:Connect(function ()

	
	local playersMouse = player:GetMouse()
	local mouseTarget = playersMouse.Target

	if not debounce and mouseTarget then
		debounce = true

		local animation = Instance.new("Animation")
		local humanoid = character:FindFirstChild("Humanoid")

		if humanoid then
			animation.AnimationId = swingAnimation
			animation.Parent = humanoid
			animation.Name = "ToolSwingAnimation"

			local animationTrack = humanoid:LoadAnimation(animation)
			animationTrack:Play()
			swingSFX:Play()
			print(tool.Name .. " activated")
		end

		local targetTree = mouseTarget.Parent
		if targetTree and targetTree:HasTag("Tree") then
			damageTreeEvent:FireServer(targetTree, toolDamage, tool)
			print("fired tool event to server")
		else
			targetTree = mouseTarget.Parent and mouseTarget.Parent.Parent
			if targetTree and targetTree:HasTag("Tree") then
				damageTreeEvent:FireServer(targetTree, toolDamage, tool)
				print("fired tool event to server")
			end
		end

		wait(cooldownTime)

		debounce = false

		local swingAnim = character.Humanoid:FindFirstChild("ToolSwingAnimation")
		if swingAnim then
			swingAnim:Destroy()
		end
	end
end)

Server:

local damageTreeEvent = game.ReplicatedStorage.TreeEvents.DamageTreeEvent

damageTreeEvent.OnServerEvent:Connect(function (player, targetTree, axeDamage, axe)
	print("tool event has been sent to server")
	local hitSFX = axe.ToolPart.HitSound

	local character = player.Character

	local hrp = character:FindFirstChild("HumanoidRootPart")

	if hrp then
		local distance = (targetTree:GetPivot().Position - hrp.Position).Magnitude
	
		if distance <= 10 then
			wait(.2)
			hitSFX:Play()
			print("close to " .. targetTree.Name)
			-- Ensure that only one axe damage is applied per hit
			local currentHealth = targetTree:GetAttribute("Health")
			if currentHealth then
				targetTree:SetAttribute("Health", currentHealth - axeDamage)
				print("damaged " .. targetTree.Name .. " by " .. tostring(axeDamage))
			end
		end
	end
end)

This video below may be able to help you understand the problem easier.

As you can see all of the axes in the toolbar do 5 damage. However, at the start of the video it does 10 damage as there are two axes. When i add more axes it breaks the tree straight away.

1 Like

since you have the server script in every tool and the remote event in RS, the event code is running in every Script with that event listener. You could fix this by adding a seperate remote event in each tool and firing that instead

1 Like

i was litteraly thinking of that but i didnt know if that would cause it, i think youre 100 percent right, let me try this

Its probably better to have a single server script in ServerScriptService handling the remote event and a single remote in RS, so that the code is centrally managed and you dont need to change the code in every tool script when you want to make changes

2 Likes

thank you, i feel stupid to not realise that was the issue, i appreciate the help.

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