What do you want to achieve?
I want my script to save and load the player’s data 100% of the time, if possible. (Probably not)
What is the issue?
The Data Store script I wrote is only working 50% of the time, according to my players. It either doesn’t save or load the player’s data properly, they start losing their data when they continue to play the game.
What solutions have you tried so far?
I’ve tried to scour all over the DevForum, but I couldn’t find a problem similar to mine. If there is a topic that is similar please tell me, I’m desperate here.
By the way, all of the data is being stored within Replicated Storage. Also my game is single player, so if that helps the solution please help me.
Server Script in ServerScriptService
--Data Store
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData")
local players = game:GetService("Players")
local function saveData(player)
local playerData = {
game.ReplicatedStorage.PlayerData.GotFlashDrive.Value;
game.ReplicatedStorage.PlayerData.GotWeaponParts.Value;
game.ReplicatedStorage.PlayerData.GotArmor.Value;
game.ReplicatedStorage.PlayerData.P9Ammo.Value;
game.ReplicatedStorage.PlayerData.P9MaxAmmo.Value;
game.ReplicatedStorage.PlayerData.MaleFlag.Value;
game.ReplicatedStorage.PlayerData.FemaleFlag.Value;
game.ReplicatedStorage.PlayerData.GotAshley.Value;
game.ReplicatedStorage.PlayerData.GotCrowbar.Value;
game.ReplicatedStorage.PlayerData.SavedM4A1Ammo.Value;
game.ReplicatedStorage.PlayerData.SavedM4A1MaxAmmo.Value;
game.ReplicatedStorage.PlayerData.Saved870Ammo.Value;
game.ReplicatedStorage.PlayerData.Saved870MaxAmmo.Value;
game.ReplicatedStorage.PlayerData.GotM4A1.Value;
game.ReplicatedStorage.PlayerData.GotShotgun.Value
}
print("The player has probably saved data!")
return playerData
end
local function setUp(player)
local userID = player.UserId
local key = "Player_"..userID
local flashDrive = game.ReplicatedStorage.PlayerData.GotFlashDrive
local weaponParts = game.ReplicatedStorage.PlayerData.GotWeaponParts
local gotArmor = game.ReplicatedStorage.PlayerData.GotArmor
local P9Ammo = game.ReplicatedStorage.PlayerData.P9Ammo
local P9MaxAmmo = game.ReplicatedStorage.PlayerData.P9MaxAmmo
local male = game.ReplicatedStorage.PlayerData.MaleFlag
local female = game.ReplicatedStorage.PlayerData.FemaleFlag
local gotAshley = game.ReplicatedStorage.PlayerData.GotAshley
local gotCrowbar = game.ReplicatedStorage.PlayerData.GotCrowbar
local M4A1Ammo = game.ReplicatedStorage.PlayerData.SavedM4A1Ammo
local M4A1MaxAmmo = game.ReplicatedStorage.PlayerData.SavedM4A1MaxAmmo
local remingtonAmmo = game.ReplicatedStorage.PlayerData.Saved870Ammo
local remingtonMaxAmmo = game.ReplicatedStorage.PlayerData.Saved870MaxAmmo
local gotM4A1 = game.ReplicatedStorage.PlayerData.GotM4A1
local gotRemington = game.ReplicatedStorage.PlayerData.GotShotgun
local data
local success, err = pcall(function()
data = PlayerDataStore:GetAsync(key)
end)
if success and data then
print("The player had a success, right? ",success)
flashDrive.Value = data[1]
weaponParts.Value = data[2]
gotArmor.Value = data[3]
P9Ammo.Value = data[4]
P9MaxAmmo.Value = data[5]
male.Value = data[6]
female.Value = data[7]
gotAshley.Value = data[8]
gotCrowbar.Value = data[9]
M4A1Ammo.Value = data[10]
M4A1MaxAmmo.Value = data[11]
remingtonAmmo.Value = data[12]
remingtonMaxAmmo.Value = data[13]
gotM4A1.Value = data[14]
gotRemington.Value = data[15]
else
print("Uh oh... Player didnt get the data.")
print(err)
end
end
players.PlayerAdded:Connect(setUp)
players.PlayerRemoving:Connect(function(player)
task.wait(2)
local success, err = pcall(function()
return PlayerDataStore:UpdateAsync(player.UserId, saveData)
end)
if success then
print("Saved players data?")
else
warn("Player Removing, ", err)
end
task.wait(2)
end)
game:BindToClose(function(player)
task.wait(2)
local success, err = pcall(function()
return PlayerDataStore:UpdateAsync(player.UserId, saveData)
end)
if success then
print("Saved players data?")
else
warn("Bind To Close ", err)
end
task.wait(2)
end)
i think this is the issue, if the datastore fails to load it overwrites the save data when the player leaves as it doesnt store whether the data successfully loaded or not
If you do this though, you need to make sure new players with nil save data dont get marked as failure to load
you should add retries and sanity checks
Can I ask why you’re storing data in replicated storage? It just seems really strange…
Also even if you need to keep the data on the server for some reason, why? You stated it’s a single player game so the server is only going to be up while they are in the server so it’s not like you need to keep the data for other players that could join
As the person above said, why are you storing the values in Replicated Storage, it is unnecessary.
Store the players data in a table.
If you need to get the players data in another script, there are many ways to do so without having to make value instances, for example you can use _G or shared, or BindableFunctions.
Here is a script that uses _G to store the data so you can access it from other scripts.
-- # Services
local Players = game:GetService('Players')
local DataStoreService = game:GetService('DataStoreService')
-- # Data Store
local DataStore = DataStoreService:GetDataStore('UserData')
-- # Data Template
local DataTemplate = {
['GotFlashDrive'] = false;
['GotWeaponParts'] = false;
['GotArmor'] = false;
['P9Ammo'] = 0;
['P9MaxAmmo'] = 0;
['MaleFlag'] = '';
['FemaleFlag'] = '';
['GotAshley'] = false;
['GotCrowbar'] = false;
['SavedM4A1Ammo'] = 0;
['SavedM4A1MaxAmmo'] = 0;
['Saved870Ammo'] = 0;
['Saved870MaxAmmo'] = 0;
['GotM4A1'] = false;
['GotShotgun'] = false;
}
-- # Profiles
_G.Profiles = {}
-- # Functions
local function PlayerAdded(player: Player)
local UserId: number = player.UserId
local Succ, Data = pcall(function()
return DataStore:GetAsync(tostring(UserId))
end)
if Succ and typeof(Data) == 'table' then
_G.Profiles[player] = Data
else
_G.Profiles[player] = DataTemplate
end
end
local function PlayerRemoving(player: Player)
local UserId: number = player.UserId
local Attempts = 0
while true do
local Succ, err = pcall(function()
DataStore:SetAsync(tostring(UserId), _G.Profiles[player])
end)
Attempts += 1
if Succ == true then
break
else
if Attempts >= 10 then
break
end
end
task.wait(3)
end
_G.Profiles[player] = nil
end
-- # Connections
for _, v in ipairs(Players:GetPlayers()) do
PlayerAdded(v)
end
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)
game:BindToClose(function()
for _, v in ipairs(Players:GetPlayers()) do
PlayerRemoving(v)
end
end)
Some other script:
-- # Services
local Players = game:GetService('Players')
-- # Functions
local function PlayerAdded(player: Player)
task.wait(5)
-- # Get Players Data
local Profile = _G.Profiles[player]
print(Profile)
-- # Set Player Data
_G.Profiles[player]['P9Ammo'] = 50
end
-- # Connections
for _, v in pairs(Players:GetPlayers()) do
PlayerAdded(v)
end
Players.PlayerAdded:Connect(PlayerAdded)
I put the values in replicated storage because I didn’t know how to reference those values for in game. Back then I just thought it was easier to do this, so I went with it. I was also too lazy to change it because I was afraid that if I did, I would lose everyone’s data. Plus I didn’t think much of it because I just thought that if it works, it works because I’m only saving one person’s data.
TLDR: (I don’t have much experience in data stores… At all.)