How to stop purchase limits resetting when players rejoin
Weekly stock and daily caps kept in a script table reset every time a player rejoins. How to save per-player limits in the profile instead.
What it looks like
The game caps how much one player can buy or earn: a shop with three of each item per player, a weekly merchant, a daily cap on a reward, limited stock bought with a paid restock. The count of what each player has used is kept in a script table on the server and thrown away when they leave, so the cap starts again whenever they rejoin or move to another server.
local boughtThisWeek: { [Player]: number } = {} Players.PlayerRemoving:Connect(function(player) boughtThisWeek[player] = nil end)
What an exploiter could do
They hit the limit, rejoin or hop to another server, and buy or earn the full amount again. Limited items stop being limited, weekly stock becomes endless, and a paid restock is pointless because leaving does the same thing for free.
How to fix it
- Save the count in the player's profile with the period it belongs to, such as the week number, and reset it on the server when the period changes.
- Check and update the saved count in the same step that grants the item.
- Keep short cooldowns in memory. Only limits meant to outlast a session need saving.
Vulnerable example
local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local PlayerData = require(script.Parent.PlayerData) local price = 900 local dailyCap = 5 local opened: { [Player]: number } = {} ReplicatedStorage.Remotes.BuyMysteryBox.OnServerEvent:Connect(function(player: Player) local profile = PlayerData.get(player) local count = opened[player] or 0 if not profile or count >= dailyCap or profile.Coins < price then return end opened[player] = count + 1 profile.Coins -= price table.insert(profile.Inventory, "MysteryBox") end) Players.PlayerRemoving:Connect(function(player) opened[player] = nil end)
Fixed example
local ReplicatedStorage = game:GetService("ReplicatedStorage") local PlayerData = require(script.Parent.PlayerData) local price = 900 local dailyCap = 5 ReplicatedStorage.Remotes.BuyMysteryBox.OnServerEvent:Connect(function(player: Player) local profile = PlayerData.get(player) if not profile then return end local today = os.time() // 86400 if profile.Progress.MysteryBoxDay ~= today then profile.Progress.MysteryBoxDay = today profile.Progress.MysteryBoxes = 0 end local count = profile.Progress.MysteryBoxes or 0 if count >= dailyCap or profile.Coins < price then return end profile.Progress.MysteryBoxes = count + 1 profile.Coins -= price table.insert(profile.Inventory, "MysteryBox") end)
How to spot this in your own scripts, and the cases that only look like it, are part of the Luaudit check your AI runs.