Going through your tutorial, it’s pretty well-made mate! I can probably see the amount of work you put into this. Though, could you tell me the theme you use for VSC? It looks very soft. But other than that, amazing job!
Thanks.
I use the One Monokai Theme which is available as extension in VSC and ColdCode to take screenshot excerpts from my code.
i have a question for you, why are you using a bindable Event in the onShutdown function
?
Question, for Berezaa’s Method, is there a way to save multiple values? Thank you!
I would put all the values into a table.
You probably shouldn’t use it anymore though, since Roblox added Versioning to Data Stores which you can use to achieve the same goal.
Once again I remind everyone that if you want a safe Data Store, you should use a module like ProfileService instead, I only created this tutorial to show some methods that can be applied to make datastoring safer.
The part where you call the save function (in the onShutdown part of your tutorial) you never passed through that second argument. I’m just confused on why you didn’t do that when in the previous steps above you mentioned a dontWait parameter in the function for situations where you need everything to save all at once.
Just checking but could you do this?
Local leaderstats = Instance.new("Folder", player)
and
local cash = Instance.new("IntValue", leaderstats)
You can, but you should not. Read this announcement for more information:
Sorry for bumping, but for some reason Bez’s method refuses to work and ret
is always nil.
local __ISVIP = game:GetService("ReplicatedStorage"):FindFirstChild("__ISVIP")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local function waitForRequestBudget(requestType)
local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
while currentBudget < 1 do
currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
task.wait(5)
end
end
local function safeCall(playerName, func, self, requestType, ...)
local success, ret
repeat
if requestType then
waitForRequestBudget(requestType)
end
success, ret = pcall(func, self, ...)
if not success then
print("Error: " .. ret)
if string.find(ret, "501") or string.find(ret, "504") then
return
end
end
until (success) or (playerName and not Players:FindFirstChild(playerName))
return success, ret
end
local function setUp(player)
local name = player.Name
local userId = player.UserId
local key = "Player_" .. userId
local str = Instance.new("StringValue")
str.Name = "Codes"
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
local TIX = Instance.new("IntValue")
TIX.Name = "TIX"
local dataStore = DataStoreService:GetDataStore(key)
local orderedDataStore = DataStoreService:GetOrderedDataStore(key)
local _, pages = safeCall(name, orderedDataStore.GetSortedAsync, orderedDataStore, Enum.DataStoreRequestType.GetSortedAsync, false, 100)
local currentPage = pages:GetCurrentPage()
if #currentPage > 0 then
for _, dataStoreKey in ipairs(currentPage) do
if not Players:FindFirstChild(name) then return end
dataStoreKey = dataStoreKey.value
local success, ret = safeCall(name, dataStore.GetAsync, dataStore, Enum.DataStoreRequestType.GetAsync, dataStoreKey)
if success then
str.Value = ret
TIX.Value = ret
TIX.Parent = leaderstats
str.Parent = player
leaderstats.Parent = player
break
end
end
else
str.Value = ""
str.Parent = player
TIX.Value = 100
TIX.Parent = leaderstats
leaderstats.Parent = player
end
end
local function save(player, dontWait)
if not __ISVIP.Value then
local userId = player.UserId
local key = "Player_" .. userId
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local cashValue = leaderstats.TIX.Value
local strValue = player.Codes.Value
local dataStore = DataStoreService:GetDataStore(key)
local orderedDataStore = DataStoreService:GetOrderedDataStore(key)
local _, pages = safeCall(nil, orderedDataStore.GetSortedAsync, orderedDataStore, Enum.DataStoreRequestType.GetSortedAsync, false, 1)
local latest = pages:GetCurrentPage()[1] or 0
local should = (type(latest) == "table" and latest.value or 0) + 1
safeCall(nil, orderedDataStore.UpdateAsync, orderedDataStore, (not dontWait and Enum.DataStoreRequestType.UpdateAsync), should, function()
return should
end)
safeCall(nil, dataStore.UpdateAsync, dataStore, (not dontWait and Enum.DataStoreRequestType.UpdateAsync), should, function()
return cashValue,strValue
end)
end
end
end
local function onShutdown()
if __ISVIP.Value then return end
if RunService:IsStudio() then
task.wait(2)
else
local finished = Instance.new("BindableEvent")
local allPlayers = Players:GetPlayers()
local leftPlayers = #allPlayers
for _,player in ipairs(allPlayers) do
coroutine.wrap(function()
save(player, true)
leftPlayers -= 1
if leftPlayers == 0 then
finished:Fire()
end
end)()
end
finished.Event:Wait()
end
end
Players.PlayerAdded:Connect(setUp)
Players.PlayerRemoving:Connect(save)
game:BindToClose(onShutdown)
for _, player in Players:GetPlayers() do
coroutine.wrap(setUp)(player)
end
while true do
task.wait(60)
for _, player in Players:GetPlayers() do
coroutine.wrap(save)(player)
end
end
Im confused about “.GetAsync” in pcalls and requesting budgets. is it a function call or what?
idk nothing aboir=t datastire and i only know whats the basics. I dont understand the budgettype thin and the getordereddatastored. What does it mean?
I was trying to understand it.
But I tried everything for it to work with boolvalues but yea still does not work…
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local dataStore = DataStoreService:GetDataStore("PlayerLocker")
local function setUp(player)
local userId = player.UserId
local key = userId.."_RadioEquipped"
local FolderOwned = Instance.new("Folder")
FolderOwned.Name = "ItemsOwned"
FolderOwned.Parent = player
local RadioOwned = Instance.new("BoolValue")
RadioOwned.Name = "RadioOwned"
RadioOwned.Parent = FolderOwned
local FolderEquipped = Instance.new("Folder")
FolderEquipped.Name = "ItemsEquipped"
FolderEquipped.Parent = player
local RadioEquipped = Instance.new("BoolValue")
RadioEquipped.Name = "RadioEquipped"
RadioEquipped.Parent = FolderEquipped
local data = dataStore:GetAsync(key)
RadioEquipped.Value = data or false
end
local function save(player)
local userId = player.UserId
local key = userId.."_RadioEquipped"
local ItemsEquipped = player:FindFirstChild("ItemsEquipped")
if ItemsEquipped then
local RadioEquippedvalue = ItemsEquipped.RadioEquipped.Value
dataStore:SetAsync(key, RadioEquippedvalue)
end
end
local function onShutDown()
task.wait(1)
end
game:BindToClose(onShutDown)
Players.PlayerAdded:Connect(setUp)
You didn’t add the Players.PlayerRemoving
event. Also, your BindToClose
is incomplete.
Sorry, I don’t understand the PCall part for the three parameters. Can someone please explain in more detail for that part?
pcall has 2 arguments, the function and the arguments you want to pass in (optional)
pcall(dataStore.GetAsync, dataStore, key)
; its just the same as
pcall(function()
return dataStore:GetAsync(key)
end)
if you got confused with, why pass in the dataStore
? any method in a table/object has its functional part, when you do dataStore:GetAsync(key)
, dataStore
is being passed in as the first parameter even tho you don’t see it, which is equal to dataStore.GetAsync(dataStore, key)
Ahh I see thank you for telling me!
im going to try and understand the code, so i can implement something like this in future projects
thanks for the help (:
i dont get making a datastore, or get async
elaborate on what you don’t get. “making a datastore” is just fetching it, or if its not found, then create the datastore. get async takes a key argument, it fetches the value in the datastore, with the provided key.
{
datastore1 = {
hello = 'world'
}
}
in this example, if you want to get the hello value, first use :GetDataStore(), then use :GetAsync(“hello”) on the datastore
Is this safe for ordered datastores? also what all would change if we were to use ordered datastore