How Do I Properly Implement a Global Points Doubler System?

I created a “double points” game pass in order to do you know what, but I ran into a little problem. I wanted to avoid disturbing the pre-existing API I had in place for my game pertaining to point awards and I decided to detect whenever a point value was updated, and I would take the difference of the old and new point value and double the difference, and then apply it to the old value. However, I ran into a problem.

I used the Point value’s .Changed event as it seemed to be the most efficient way to go about implementing this Double Points system and it turned out to be a recursive function. When I applied the “doubling” changes to the points, my script then doubled that change, and on and on.

game.Players.PlayerAdded:Connect(function(plr)
        local Points = plr:WaitForChild("Points")

        if not userHasPass(g_ID) then return end -- if user doesn't have gamepass then no doubling

        local old = Points.Value
        Points.Changed:Connect(function()

                local difference = Points.Value - old
                local double = difference * 2

                Points.Value = old + double

        end)
end)

How can I stop this from happening? I tried adding a very quick debounce but of course that is way too hacky and inefficient.

Ignore the small mistakes, I simplified it on purpose

edit: misread question so redid my answer

You can use PromptGamePassPurchaseFinished to detect when the gamepass has been bought, and then double their points once! (For buying in-game)

If you’re looking to double the points when you add them it would be easier to just double it when you’re adding it instead of listening to the .Changed event and then doubling it again?

local function change(player, amount)
    if ownsPass(player) then
        points = points + amount*2)
    else
        points = points + amount
    end
end

This would honestly be the simplest way to do this instead of listening for the value to change and then working out the difference etc. Which is possible, but just doesn’t seem efficient and is probably more likely to go wrong. If you make use of a function to add points then you shouldnt need to change lots of code if you ever change your mind again :slight_smile:

Doing that would be harder because then I’d have to go to every area where I increase points and add that(horrible system i know) - is that the only way?

But once you do that once you shouldn’t need to do it ever again, which is why I think it would be easier in the long-run.

The problem with the other method is that when you change the value again it fires the connection again. You could solve it with this:

game.Players.PlayerAdded:Connect(function(plr)
        local Points = plr:WaitForChild("Points")

        if not userHasPass(g_ID) then return end -- if user doesn't have gamepass then no doubling

        local old = Points.Value
        local changing = false
        Points.Changed:Connect(function(newValue)
                if changing = false then -- are we changing the value again?
                    if newValue > old then -- probably dont want to have 2x the loss as well
                        local difference = newValue - old
                        local double = difference * 2
                        local finalVal = old + double
                        
                        changing = true -- set a flag
                        Points.Value = finalVal 
                        old = finalVal  -- make sure you change the old value!
                    end
               else
                   changing = false
               end
        end)
end)
-- hope this works

But this is SO hacky and really inefficient. I really recommend that you just go through the code and change it all to a function. You’ll save time in the future! :smiley:

1 Like

I agree with you @mario118118 , I made a big mistake back then but now I know what to do! I have one last question - if I was to set up a modulescript in replicated storage which acts as a global function for points changes and add the anti-exploit checks there, will that system be secure?

Also, thank you for the help!

I hate to be the guy that answers questions with other questions, but why are you handling points in ReplicationStorage??

I’ll be honest here - I’ve used ModuleScripts like twice in my entire history on Roblox (sorry elite devs), and am not familiar with them at all (take what I say with a pinch of salt). I think that the client and server have access to two different versions of the module script which will have different data saved inside of them if required from each. But I may be wrong so if anyone wants to elaborate on this or prove me wrong, feel free! :stuck_out_tongue:

I’m dumb, my bad. There’s no reason for a module script like that to be accessed per local script. For a local script point change, I’ll just send the change command to a remote event which then relays the command to the doubler function in a module script in server storage w/ all of the anti-exploit checks.

PS my entire game system is broken lol

1 Like