Keep your pcalls in the same place, but eliminate some of the dependencies in your code (such as upvalues) and make use of what pcalls return. This allows you to do error handling as well.
-- Simplified pcall example, you may not understand the direct-wrap method
local success, data = pcall(function ()
return DataStoreWWE:GetAsync(player.userId.."-Wins")
end)
This allows you to handle cases of
Custom error handling
Data store failures
Actions based on returned values
Validation
Checking if returned data is nil or updated
Performing updates based on returns
if not success then
warn("DataStore: Failure to perform GetAsync request:", data)
else
if data then
-- Overwrite current values with saved ones
else
-- Handle the case of no data being found
end
end
Most importantly, before you think about what to do with pcalls, you need to rewrite your DataStore structure to use only a single DataStore with all the values to be saved in a table rather than as individual DataStores. The fundamental flaw to this structure is the way youâve set up your DataStores; once that has been corrected, you can think about the rest of your code.
If your game isnât public yet and no one has data saved to those DataStores yet, you can make the change fairly invisible by announcing a data wipe as the gameâs development progresses further. If your game already has data in it, then youâre in a pinch. You will need to set up a system where players can merge old data over to the new system.
As far as mergers go, I suggest a one-use merger option that incorporates UpdateAsync. Here is a reference template, though you will need to pursue further discussion on Scripting Support if you want to implement this (a topic such as âHow do I merge data from old DataStores to a new one?â would do - try specifying without DataStore2âs merge, otherwise most of your responses will just be âDataStore2â).
When the request is processed, prevent any further requests from that player altogether.
Perform a GetAsync request on all your DataStores.
You have around 6 GetAsync requests to call per player.
Keep in mind DataStore Limits. The lucky part is that you fall just under the limits. Youâll need about 7 requests per player - 6 to get old data, 1 for the UpdateAsync call.
Increment playerâs stats accordingly. Do not set, as this is a merger situation.
A note: if a player has nil data for all 6 of those GetAsync requests, drop the request. You can use an eighth GetAsync request at the start to check if players already have data saved, but this is pushing the limits literally.
This harkens back to my cache strategy where you donât use values directly under the player as data values, only as display values. Actual data should be in values under ServerStorage or cached in a session data tracking ModuleScript.
Call RemoveAsync on all those 6 DataStores to clear the playerâs data from the old stores.
Again, lucky you fall under limits. You need 7 write requests - 6 for RemoveAsync, 1 for UpdateAsync when the merge completes.
When the merge is complete, push the combined data to UpdateAsync to update player data. Make sure the new data is in a table format. After that, you should be good.
The above is my go-to, but obviously itâs not something that should be followed down to the word. Work around your inefficiency as needed.
Why would i want to remove the data that already exists? Also would it look like this for the pcall?
Also would remove the these?
local player_data,player_data1,player_dataElim,player_dataXP
local weaponsData
local equippedData
local success, data = pcall(function ()
return DataStoreWWE:GetAsync(player.userId.."-Wins")
return DataStoreBuxs:GetAsync(player.userId.."-Buxs")
return DataStoreElim:GetAsync(player.UserId.."-Kills")
return DataStoreXP:GetAsync(player.UserId.."-XP")
end)
end)
if not success then
warn("DataStore: Failure to perform GetAsync request:", data)
else
if data then -- Would i do SetAsync then? or Get Async
-- Overwrite current values with saved ones
else -- Would i use SetAsync instead of doing the default values?
DataStoreWWE:SetAsync(player.UserId..("-Buxs", player.leaderstats.Buxs.Value = 0)
end
end
No, because the call would terminate at the first return value and return only the data retrieved from DataStoreWWE. Each DataStore needs to be wrapped in a pcall. What I provided is sample code, so you shouldnât try bruteforcing it into your current code by copy-pasting it.
As well, again, the fundamental flaw in your DataStore system is that youâre using multiple DataStores.
You canât do this in a SetAsync call. You can only pass the value thatâs to be saved to the key. This would throw an error as well due to the way youâve written it, which is incorrect.
local success, data = pcall(function()
return DataStoreWWE:GetAsync(player.UserId.."Wins")
end)
local success1, data = pcall(function()
return DataStoreElim:GetAsync(player.UserId.."Kills")
end)
but since your saying at max i should have 2 DataStores, Could it be like this?
local DataStore = game:GetService("DataStoreService") -- This is for making it shorter (obviously)
local StatsStore = DataStore:GetDataStore('MainStats')
local EquippedData = DataStore:GetDataStore('Equipped')
then im having trouble with this part: How Could i make all the local player_data,player_data1, Ect. to local Player_data for all the MainStats?
local player_data,player_data1,player_data2,player_data3
local weaponsData
local equippedData
pcall(function()
player_data = StatsStore:GetAsync(player.UserId.."-Wins")
player_data1 = StatsStore:GetAsync(player.UserId.."-Buxs")-- Ex. iSkeptical,22939,-Buxs
player_data2 = StatsStore:GetAsync(player.UserId.."-Kills")
player_data3 = StatsStore:GetAsync(player.UserId.."-XP")
end)
pcall(function()
weaponsData = OwnedEquippedData:GetAsync(player.UserId.."-Weps")
end)
pcall(function()
equippedData = OwnedEquippedData:GetAsync(player.UserId.."-EquippedValue")
end)
if player_data ~= nil then
--player has saved data, load it in
wins.Value = player_data
buxs.Value = player_data1
kills.Value = player_data2
xp.Value = player_data3
print("loaded data for "..player.Name.."!")
else
--[New Player]--
wins.Value = defaultwins
buxs.Value = defaultbuxs
kills.Value = defaultelim
xp.Value = defaultxp
print("loading data baseline stats for "..player.Name.."")
end
If youâre only using normal data stores, then 1 data store should be enough.
Realistically you only need multiple datastores if youâre either over the limit of how much data you can store (which almost never happens), or youâre using OrderedDataStores.
You can store all the players info in a table, without having to use multiple keys in a datastore or using multiple datastores.
local DataStoreService = game:GetService"DataStoreService"
local MainDataStore = DataStoreService:GetDataStore"Main"
Using multiple keys is essentially as bad as using multiple datastores.
local success,playerdata = pcall(MainDataStore.GetAsync,MainDataStore,player.UserId)
if success then
playerdata = playerdata or {--[[include the defaults here]]}
--do what you want with the data
else
--data failed to load, might want to do something (ex: notify user, stop data from saving)
end
So i could use 2 keys then. One for the stats and for equipped and weapons owns.
I dont understand the (MainDataStore.GetAsync,MainDataStore,player.UserId)
what does that even do? Is it the same as the local StatsStore or is it what its suppose to be?
Instead of using multiple keys, simply use one, this way youâre only using one GetAsync call instead of multiple. (you arenât using OrderedDataStores, so its pointless to use multiple keys)
I used a different name for the datastore.
It gets the data from the datastore associated with the UserId. (wrapped in pcall)
If you donât understand why it works, here is an explanation.
pcall accepts multiple arguments, the first argument is the function, and the others are the arguments to be passed onto that function.
ex:
pcall(print,5,2)
--> 5 2
So MainDataStore, and the playerâs ID are passed through to MainDataStore.GetAsync
MainDataStore is passed to tell it to get data from that DataStore
UserId is passed to tell what key to get info from