Help with a value that changes a lot

I am trying to make a bar that fills up when clicking a tool by increasing a Value, while the bar is draining when Value > 0.


As can be seen in the video attached, when clicking with the tool the bar fills and starts to drain.
The draining part was done by using RunService Heartbeat

	RunService.Heartbeat:Connect(function(DeltaTime)
		if value > 0 then
			value = value - DrainRate * DeltaTime
			player.Data.Value.Value = value
		else
			return
		end
	end)

my problem is that when clicking the tool while Value > 0 the bar doesn’t fill any further and I think the problem might be that the value is changing too fast

I have tried stopping the value from draining when changing and it didn’t go well…


--This is the value that I have been talking about
	local Stam = Instance.new("NumberValue",stats)
	Stam.Value = 0
	Stam.Name = "Value"


--[[ Everytime the value changes it fires the server script 
which runs the Heartbeat RunService that does the draining part.--]]
data:WaitForChild("Value").Changed:Connect(function()
	updateBar()
	
	if value.Value > 0 and value.Value < maxValue.Value then
		remote:FireServer(value.Value)
	end
	if value.Value > maxValue.Value then
		value.Value = maxValue.Value
	end
end)

-- If you have been wondering this is how I add Value when clicking
tool.Equipped:Connect(function()
	holding = true
	UIS.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 and holding == true then
			player.Data.Value.Value += 5
			print("clicking")
		end
	end)
end)

If you have any idea on how to fix my problem or something I have done is wrong please leave it down here, thanks!

The problem is probably related to the value object’s value being changed on both client and server.

I believe something like this is happening:
When you click, you update the value on the client. Then your function connected to its changed event sends the new value to the server. However, it does not reach the server instantly. The server drains the old value before than the new value sent by the client reaches the server. The object’s value will then soon be updated to the drained old value on the client, too. This means that the function connected to changed event will run again and send this now outdated value to the server. When the new increased value sent by the client reaches the server, the server may set it as the object’s value for a very short time, but soon it will receive the outdated value from the client, and set that as the value.

I’m not sure if that’s what’s happening, but I believe so. I’d recommend only changing the value object’s value on either the client or the server, because changing it on both can cause a new value to be overwritten by an old value. So you should use a remote event when the player clicks if you want to change the value object’s value on the server.

Sadly this is not it.
The code I showed is very narrowed, to make it more convenient to read.
In my original code, the value is being changed only on the server.

What does the server do when the client fires the remote event in the function that is connected to the changed event? Does it update the server side variable value?

it starts to drain the Value.

local rp = game:GetService("ReplicatedStorage")
local remote = rp:WaitForChild("RemoteEvent")

local RunService = game:GetService("RunService")

local DrainRate = 0.5

remote.OnServerEvent:Connect(function(player, value)
	RunService.Heartbeat:Connect(function(DeltaTime)
		if value > 0 then
			value = value - DrainRate * DeltaTime
			player.Data.Value.Value = value
		else
			return
		end
	end)
end)

I don’t understand why you send the value from the client to the server every time it changes. If only the server is setting it, then it always knows the new value and doesn’t need it to be sent from the client. Because it takes time for the value changes to be detected by the client and the values sent back to the server, the values that the server receives are a little outdated. Your current code also seems to create new heartbeat connections without disconnecting old ones which can cause multiple value updates being done every frame and overwriting each other.

You could try disabling the line that fires the remote event in the function connected to changed and try using this code on the server instead of your current code.

local rp = game:GetService("ReplicatedStorage")
local remote = rp:WaitForChild("RemoteEvent")

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local DrainRate = 0.5

local function drain(DeltaTime)
	for i, plr in ipairs(Players:GetPlayers()) do
		local valObj = plr.Data.Value
		if valObj.Value > 0 then
			valObj.Value -= DrainRate * DeltaTime
		end
	end
end

remote.OnServerEvent:Connect(function(player)
	player.Data.Value.Value += 5
end)

RunService.Heartbeat:Connect(drain)

I have edited this code a few times now. I had forgotten some things.

1 Like

It works.
Thank you so much for your help!

1 Like