Can you find a logic error when saving this data

I’m currently in the process of setting up developer products so players can buy ‘Cash’. To prepare for potential data loss or for the worst case scenario where I am forced to reset all player data, I have created a second datastore to record the amount of Robux spent on developer products. This means if ever have to, refunding players will be possible.

Because this is such a vital feature, I was wondering if other developers would be willing to proofread to code in case of any logic errors:

In simple, the system:

  1. Finds the price of the product the player purchased
  2. Adds this information to a dictionary, using the player’s ID
  3. Every 10 seconds, this information is saved to the datastore, and the information of the player in the dictionary is removed

Thanks.

1 Like

Saving data to the DataStore every 10 seconds is excessive and you are risking running into the per-place DataStore request limits.

Also, rather than running a spawn function, I would suggest switching to using RunService.Stepped like so:

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

local lastCashDataUpdate = tick()
local intervalBetweenCashDataUpdates = 10 -- In seconds
local function onStepped()
    local t = tick()
    if t - lastCashDataUpdate < intervalBetweenCashDataUpdates then return end
    lastCashDataUpdate = t
    -- Now your for loop, which looked like it would work just fine.
end

RunService.Stepped:Connect(onStepped)
1 Like

Could you explain why you would recommend using Stepped + logic over a simple while loop? Just curious.

I recommend using the event-driven system for two reasons. One is that I find it much cleaner than having an infinite while loop, and the other is that it ties your recurrent systems into RunService, which is meant for that purpose, and steers you away from infinitely running code.

Data isn’t being saved to the datastore every 10 seconds - it’s only saved when there is data needing to be saving, and that only happens when a player purchases cash. I chose 10 seconds over 60, for example, because if someone purchases cash right before a server shutsdown, then that should be enough time for it to be saved.

The loop should be infinite though?

So, yes, it is good to make sure you save data before the server shuts down - but that’s sort of what game.OnClose is for.

And when you really think about it, no, the loop shouldn’t be infinite. Once the RunService stops, once the game stops, then so should your updates. Now, yes, you’d be right in saying that the server handles that for you. But I would argue it is better to always design your code such that the server isn’t shutting it down mid-execution, which would be the case for an infinite loop.

Also getting back to the original question, is there any reason for the method you’re using? Why not just save the players data every time they purchase more cash?

I agree that I should also save data when the game closes, thanks.

Regarding RunService, I don’t have a huge understanding of it, but why would it matter if your code keeps running when RunService ends? The game will close eventually, and no one will be able to join that server, so why would it be a problem?

It can be a problem, rarely, because you don’t have any assurances as to when the code stops. At least with connecting to RunService events, you know that the last iteration of your code will happen when the game stops running.

As far as I know, an infinite loop doesn’t cause any actual technical problems. I just suggest avoiding them for cleaner code and to give yourself more assurances.

1 Like

:UpdateAsync has a ‘cooldown’ of 6 seconds. If a player was to buy 2 lots of cash within 6 seconds, then the request would be throttled. Making data save every 10 seconds prevents this, and is also less intensive on the datastore

1 Like

Ok thanks, I think I understand now! I’ll consider this for the code and future code.

And is there any reason to do this over something like

while RunService:IsRunning() do

wait(10)
end

It feels much less clean to me to be manually counting up on every Lua update as opposed to just letting the thread sleep and resume every 10 seconds

I mean, you could do that, I would not. wait(...) does not guarantee any actual amount of time, it just guarantees a minimum amount of time. Honestly my problem with infinite loops is wait(...)–I avoid that function whenever possible.

game:BindToClose()* :wink:

Also just a tip, @ForeverHD, you can put your code into a code block on here by pasting it in with one indentation to the right, or by doing ``` to start and end the code.

1 Like

Good call, thanks

1 Like