How do i stop numbers from going into negatives?

I made a rebirthing system but if the player clicks the button too fast it rebirths them multiple times and puts them into negatives

I have tried adding a debounce but that still doesnt help

here is a video as an example

here are the scripts

local script:

script.Parent.ConfirmRebirth.Activated:Connect(function()
    local db = false
    if not db then
        if Power.Value >= requiredAmount then
            Remotes.Rebirth:FireServer(requiredAmount)
            db = true
            task.wait(5)
            db = false
        end
    end
end)

server script

Remotes.Rebirth.OnServerEvent:Connect(function(player, amount)
    local clientProfile = Manager.Profiles[player]
    clientProfile.Data.Wins -= math.max(0, amount)
    clientProfile.Data.Power -= math.max(0, amount)
    clientProfile.Data.Rebirths = clientProfile.Data.Rebirths + 1

    player.leaderstats.Power.Value = clientProfile.Data.Power
    player.Wins.Value = clientProfile.Data.Wins
    player.Rebirths.Value = clientProfile.Data.Rebirths
    Remotes.SendNotification:FireClient(player, "Successfully Rebirthed")
end)
1 Like

Well, as a start, don’t set db to false upon activation, set it to false outside of that function and that should fix your problem

2 Likes

as for the second script, you don’t need to use the math.max function as the amount should always be greater than 0.

1 Like

Use math.clamp() to ensure the final value remains above 0:

Example:

local Data = clientProfile.Data

-- 0 defines the lowest value it can be and math.huge defines the highest value
Data.Wins = math.clamp(Data.Wins - amount, 0, math.huge)
Data.Power = math.clamp(Data.Power - amount, 0, math.huge)
2 Likes

Move the requirement check and the cooldown to the server-side. The client is faster, which is the issue here. Since the server takes time to complete requests, people can rebirth again because the data is not set by the server yet. The client is always faster.

2 Likes

I did not know that the client was always faster than the server

thanks for teaching me something new!

Unless I’m misunderstanding your point, the main issue in the code from the original post is not necessarily that the client is faster. The primary issue was highlighted by @Verbolten_Jason, which is that the debounce was being initialized within the function itself.

Because of this, every time the function runs, the debounce is immediately being set to false, which disregards the 5 second wait that was included at the end of the function as soon as the function is run again.

-- LocalScript code from original post
script.Parent.ConfirmRebirth.Activated:Connect(function() -- Function activated on button activation
    local db = false -- Sets the debounce to false immediately
    if not db then --[[ Because debounce was set to false within the function,
this condition will ALWAYS be met --]]

        if Power.Value >= requiredAmount then
            Remotes.Rebirth:FireServer(requiredAmount)
            db = true -- Even though debounce is set back to true
            task.wait(5) -- And then it waits 5 seconds
            db = false --[[ Setting the debounce back to false here wouldn't do
anything for the next time the function is run because the debounce is
immediately set to false at the start of the function.

You can test this by adding print statements before the task.wait(5) and then
after the task.wait(5), and if you rapidly activate the function while
meeting the prior conditional statements, it'll print the first statements
right away and then the second statements would appear 5 seconds out from
the times that the function was run for each of the previous activations --]]
        end
    end
end)

Consequently, the solution that would help make sure that players could not repetitively fire the RemoteEvent is to initialize the debounce variable before the function starts so that its current value is not immediately overridden.

Example Revision

local debounce = false --[[ Sets the initial value of debounce to false before
the function starts to ensure that its current value is not overridden when
the player activates the button.
--]]

script.Parent.ConfirmRebirth.Activated:Connect(function()
    if not debounce then -- Checking immediately if debounce is not true

        debounce = true --[[ If so, then we set debounce to true so that if the
player decides to activate the button again, the first condition will not be
met until debounce has been set back to false after 5 seconds
at the end of the function.
--]]

        if Power.Value >= requiredAmount then
            Remotes.Rebirth:FireServer(requiredAmount)
        end

        task.wait(5) --[[ Separating this from the conditional statement above
ensures that it will always wait 5 seconds before setting debounce to false,
whether or not the player's Power.Value exceeded that of requiredAmount --]]
        debounce = false
    end
end)

However, I do agree that it is a good idea to add the debounce and the sanity checks to the serverside, too. Ideally, you have it on both sides:

  • It’s there on the client-side to provide immediate feedback (such as having an indicator appear to let the player know that they need to wait a certain amount of time before activating the button again if they try to press the button when debounce is still set to true)

  • It’s there on the server-side to ensure it’s not being abused by exploiters who have circumnavigated the cooldown and sanity checks on the client-side. If you (*the original poster of the thread) take anything away from this, it’s to make sure to always sanity check on the server side, because it’s not guaranteed that the client is telling the truth!!


And although that solves the primary issue that could enable players to get into the situation where they may accidentally cause their Wins / Power leaderstats to decrease into the negatives, one way to be 100% sure that the updated values cannot go below 0 would be to

Combined, those solutions prevent players from being able to activate the RemoteEvent too quickly and ensures that any edge cases where the server script could deduct their Wins / Powers below 0 won’t actually happen (but also make sure to check if they have reached the requiredAmount on the server before deducting from their Wins / Power).


And I want to clarify that @ShaShxa is correct with the idea that the client is faster than the server, because the inputs that the client makes would need to be communicated with the server, and then the changes that the server makes need to be communicated back to the client.

However, in this particular case, the issue described in the original post cannot be completely attributed to the sheer speed of the client, because:

  • The debounce was not set up correctly
  • There was nothing being done on the server-side to:
    • Verify that the player had enough Wins / Power
    • Ensure that the new values for the player’s Wins / Power would not go below 0.

Hope that I was able to provide some more insight into the suggested solutions and ideas during this thread :grin: If I missed anything or was mistaken about something I mentioned, please let me know!

1 Like

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