I’m learning to code even more and i have got to the stage where i want to learn to script with data and get data saved so that it saves players coins and other kind of data.
I’ve looked at some types and all i seem to be getting is Roblox’s own datastore service and Profile Service. But what i want to know is which is better.
I’m just making small projects to start with so anything from Basic to Advanced will do.
You should use data stores for this. Profile service is a module that builds on this and may be easier but I’ve never used it. Here is an example that I use:
locks = {} is not absolutely necessary but I use it for some safety checks elsewhere.
local dataStores = game:GetService("DataStoreService")
local httpService = game:GetService("HttpService")
local statsStore = dataStores:GetDataStore("PlayerStats")
local stats = {}
local locks = {}
local startingStats = {Crumbs = 10000, Shleen = 10}
players.PlayerAdded:Connect(function(player)
--Initialize save or load stats
--Lock player initially
locks[player] = true
--Load stats here, probably async
local statsJson = statsStore:GetAsync(tostring(player.UserId))
if statsJson == nil or statsJson == "" then
print("Initializing new player stats for " ..player.Name)
stats[player] = table.clone(startingStats)
else
local playerStats = httpService:JSONDecode(statsJson)
stats[player] = playerStats
print("Loaded stats for " ..player.Name)
end
--Don't unlock the player's stats until they have loaded
locks[player] = false
end)
players.PlayerRemoving:Connect(function(player : Player)
--SerializeStats
local statsJson = httpService:JSONEncode(stats[player])
if statsJson == nil or statsJson == "" then
warn("Failed to JSONEncode save stats for " ..player.Name)
return
end
--Save stats
statsStore:SetAsync(tostring(player.UserId), statsJson)
print("Saved stats for " ..player.Name)
end)
I have a script that handles “stats” that are used as currency. The way its set up its possible for multiple transactions to launch at once and there is no guarantee on their order, so when making a purchase I lock out other transactions until its completed.
local function LockPlayer(player : Player)
if locks[player] == true then
warn(player.Name.. " is already in a transaction.")
return false
end
locks[player] = true
return true
end
local function UnlockPlayer(player : Player)
locks[player] = false
end
--Request a purchase, returns true if the transaction goes through
function remotesLocation.Purchase.OnInvoke(player : Player, currencies)
--Lock this player's stats during transaction
if not LockPlayer(player) then
return false
end
--Perform transaction
local canAfford = true
for currencyType, currencyAmount in pairs(currencies) do
local currentAmt = stats[player][currencyType]
if currentAmt == nil or currentAmt < currencyAmount then
canAfford = false
break
end
end
if canAfford then
--Allow purchase
for currencyType, currencyAmount in pairs(currencies) do
stats[player][currencyType] -= currencyAmount
end
--Grant purchase
UnlockPlayer(player)
return true
else
warn(player.Name.. " is too broke to purchase that!")
UnlockPlayer(player)
return false
end
end
This is also just a temporary thing I did and it doesn’t stop most kinds of dupes. You need to put the lock into a MemoryStore or DataStore for that. Also its important that the Purchase function does not error between when it locks and unlocks. It should probably use pcall().