Best way to handle timed powerups?

local function onTimeChanged(newTime)
	local currentTime = math.max(0, newTime)
	local minutes = math.floor(currentTime / 60)
	local seconds = math.floor(currentTime) % 60
	return string.format("%02d:%02d", minutes, seconds)
end

for _, allPotions in pairs(potions:GetChildren()) do
	if allPotions:IsA('ImageLabel') then
		allPotions.Gems.Activated:Connect(function()
			if debounce then return end
			
			debounce = true
			
			if purchasePotion:InvokeServer(allPotions.Name, 'Gems') then
				allPotions.Gems.Visible = false
				allPotions.Gold.Visible = false
				
				allPotions.Time.Visible = true
				allPotions.Desc.Visible = true
			end
			
			debounce = false
		end)
		
		allPotions.Gold.Activated:Connect(function()
			if debounce then return end
			
			debounce = true
			
			if purchasePotion:InvokeServer(allPotions.Name, 'Gold') then
				allPotions.Gems.Visible = false
				allPotions.Gold.Visible = false
				
				allPotions.Time.Visible = true
				allPotions.Desc.Visible = true
				
				spawn(function()
					for i = 3600, 0, -1 do
						allPotions.Time.Text = onTimeChanged(i)
						wait(1)	
					end
				end)
			end
			
			debounce = false
		end)
	end
end

Currently got this. Basic run down, when you click to buy a potion, it checks the server to make you got the required amount for the set Potion, server handles giving you the powers, etc. Now main question I have is how to handle the countdown? Currently I just have the countdown inside the here, running in a spawn() function as to not stop the script from sitting there for an hour doing nothing. The countdown works, I can buy multiple potions, each one with there own countdown clock ticking down.

Question is. should I be doing this countdown timer inside the server? Only reason Iā€™m afraid of doing it in the server is how Iā€™d manage several countdowns at once (As I donā€™t want to have multiple Events for each potion)

Could I just keep the countdown where it is now, and then when itā€™s done fire an Event to say to the server that the potion has run out, take away there powers? I feel this would definitely be the easiest solution but is it the safest? I donā€™t see how players could edit the countdown timer in anyway, but then again, I donā€™t know how to do all that fancy client hacking stuff XD I just donā€™t want players either giving themselves the potion effects without buying it, or editing the timer, giving them an infinite time

2 Likes

If you want everything to be kept on the server, Iā€™d say that you could utilize Dictionaries and tables. For example,

local players = {
    [12345] = { --userid of player here
        ["Potion1"] = 3600,
        ["Potion2"] = 3600
    }
}

Where you could add the dictionary of potions after a player joins and initiate a countdown using the tables. Not sure if I set up the table correctly but I think you get the general idea :stuck_out_tongue:

If you want to continue on the client and instead use RemoteEvents, I think itā€™d be possible provided that you put in the usual security measures. The safest option I feel is if you fire the event when it starts, have the server record when timestamp, then fire again when it ends and have the server compare the two timestamps. This way, the client canā€™t pass in parameters that might be used to exploit it although Iā€™m not sure how efficient this would be. Ultimately, the safer way is still having the server control all the operations.

1 Like

The problem is more focused on how to get the client to show the countdown. If I have the countdown going on in the server, theres no real way to get it to show on the Client unless I fired a RemoteEvent, but not sure how firing a RemoteEvent every second for an hour would go, especially if say a player has purchased all 6 purchases, itā€™d be going nuts. And then if numbers overlap or whatever

You should probably have a timer on client which syncs with server every minute or so.

Having it sync too much is unnecessary and will result in lag.

And definitely send all data via one request, doing multiple requests for something like this is pure waste of network.

1 Like

Is there anyway that a player could use their hacking ways to ā€˜breakā€™ my current system though? :sweat_smile:

Definitely not.

Client has access to time, not to functionality.
As long as server knows true data and you donā€™t do anything stupid networking-wise, its safe.

So they:

  1. Canā€™t get the potion for free
  2. Change the timer to give them infinite time

No, definitely not.

As I said before, as long as you donā€™t do anything stupid networking-wise, itā€™s safe.
Anything stupid in this case would be allowing client to send data instead of just being able to read it.

Think of it as ā€œpermissionsā€;
In this case, client should only have read permission.

1 Like

As long as the server is validating what they are sending, they canā€™t. They are completely capable of changing the timer, but if your server is keeping itā€™s own timer than thereā€™s no use. Itā€™s the same with the potion, they can always request a potion but the server should invalidate the request.

But atm the server ainā€™t keeping track of the timer? Itā€™s purely the client setting the timer?

What do you mean? I would follow what Legoracer said:

If this is happening, the server is keeping track of the timer and it isnā€™t purely on the client. Unless you have another setup right now?

The timer loop is done on the client, that way the countdown label shows how long it has left. The reason I wanted to avoid server checking was because I wasnt sure how itā€™d work if I have 6 timers all running at the same time, firing the same event every second, 6 times.

It shouldnā€™t matter all that much as long as you arenā€™t syncing 24/7. A few remote calls every minute or two shouldnā€™t be too big on performance. Definitely donā€™t fire them every second, youā€™re right that it would become problematic.

To be honest, you can sync powerups when player joins the game and never sync them again unless player buys a new powerup.

Syncing every (few) minutes is there for potential time errors and for validation.

(wrong reply, sorry)

1 Like

To simplify this a lot you can have a table of when each power-up ends, so for eample if you have a certain power-up for 5 minutes then you would save tick() + 300. Then on the server you can loop through all the values every 30 seconds or every minute (or even every second if you wanted) and remove the ones that have expired.

On the client you just ask the server for the end-time value which was originally saved and then the client can caculate locally how much time is remaining and show that on the timer.

4 Likes