So, recently I’ve started to use DataStoreService for the first time. Everything works well and all, right?
This all comes to an end when for some reason when I’m playtesting, all my data is lost
I’m unsure if this occurs when a user plays the game on the public client. This happens on all my data stores. Am I leaving and joining playtest too quickly? Is this normal?
This mostly sounds like an issue with your implementation of DataStoring than DataStores themselves. Providing the code with a brief description of what you’re attempting to achieve alongside any potential known issues such as errors would be a good starting point for anyone here to direct you into the right direction with correcting this behavior.
Yes sure! Here’s one of my datastores (not going to send all for the sake of the message being too long)
local DataStoreService = game:GetService("DataStoreService")
local FOVREMOTE = game:GetService("ReplicatedStorage").RemoteEvents.Slider.FOV
local IGMREMOTE = game:GetService("ReplicatedStorage").RemoteEvents.Slider.IGM
local FOVslider = DataStoreService:GetDataStore("SliderValues", "FOV")
local IGMslider = DataStoreService:GetDataStore("SliderValues", "IGM")
game.Players.PlayerAdded:Connect(function(Player)
-- FIELD OF VIEW
local FOV = Instance.new("IntValue")
local FOVdefaultValue = 50
FOV.Name = "FOV_VALUE"
FOV.Parent = Player:WaitForChild("leaderstats")
FOV.Value = FOVdefaultValue -- Default Value
FOVREMOTE:FireClient(Player, FOV.Value) -- Default Value
local FOVData = FOVslider:GetAsync(Player.UserId)
if FOVData == nil then
print("Oh! You must be new! We're setting you up...")
print("Welcome to Miles by the way. :)")
print(" ")
FOVData = FOVdefaultValue
warn("FOV set!")
else if FOV ~= nil then
print("Welcome back to Miles! :)")
end
end
FOV.Value = FOVData
FOVREMOTE:FireClient(Player, FOVData)
FOVREMOTE.OnServerEvent:Connect(function(Player, newFOV)
FOV.Value = newFOV
end)
-- IN GAME MUSIC
local IGM = Instance.new("NumberValue")
local IGMdefaultValue = 0.8
IGM.Name = "IGM_VALUE"
IGM.Parent = Player:WaitForChild("leaderstats")
IGM.Value = IGMdefaultValue -- Default Value
IGMREMOTE:FireClient(Player, IGM.Value) -- Default Value
local IGMData = IGMslider:GetAsync(Player.UserId)
if IGMData == nil then
IGMData = IGMdefaultValue
warn("IGM set!")
end
IGM.Value = IGMData
IGMREMOTE:FireClient(Player, IGMData)
IGMREMOTE.OnServerEvent:Connect(function(Player, newIGM)
IGM.Value = newIGM
end)
end)
game.Players.PlayerRemoving:Connect(function(Player)
local success, errorMessage = pcall(function()
local FOVData = FOVslider:GetAsync(Player.UserId)
FOVslider:SetAsync(Player.UserId, Player.leaderstats.FOV_VALUE.Value)
local IGMData = IGMslider:GetAsync(Player.UserId)
IGMslider:SetAsync(Player.UserId, Player.leaderstats.IGM_VALUE.Value)
end)
if not success then
print(errorMessage)
end
end)
This is my newest data store.
Its purpose is to save the settings’ slider values, depending on how the user has set them.
The script communicates by RemoteEvents with 2 LocalScripts. One for the FOV and the other for music. Since the sliders are in a local script in a UI, and the data store is a script saved in ServerScriptService, the only solution I could think of was RemoteEvents.
The whole thing works really well, it’s just that weird problem I’ve mentioned before
Edit:
This happens in all of my data stores as I mentioned before. It’s nothing specific. I tried my best to use the Roblox documentation to construct all my data stores.
Why do you get the data when the player is removed in the first place? It seems like its never used. Also, try implementing autosave, that might fix the issue. Maybe try testing in a team test server as in studio, PlayerRemoving will sometimes fail to fire.
As seen here, I do request the data when the player is added, not when they are removed. At least, I’m hoping that GetAsync is to retrieve data. As for autosave, that would be a good idea! As I said before, I’m a complete rookie in the whole DataStoreService space, so I’m still really green about the whole thing. Though, I will try to implement it anyways!
Is it okay if you tell me how this will differ in results? I may have forgotten to mention that this game is single-player as of now, I am planning to add a multi-player mode sometime.
(I had to repost, for some reason DevForum made me reply to myself)
Edit:
I just realized that I’m requesting data when the person left aswell. My bad!
First, I just want to mention that whenever you get and save data async, you should write it inside of a pcall. Also, since you’re saving the values of the slider from leaderstats, you could make sure the leaderstats folder is actually created. An easy way to know is to make sure the leaderboard actually says the values. If not, you’d have to manually create it and I’d recommend creating it inside of this script.
Yes, the autosave feature is quite simple, firstly you should separate your saving into a function, and call it every 5 minutes or so, as for the studio results. The game shuts down before it can fire the PlayerRemoved event. This is because doing a studio test actually runs it on your computer, and because of this differing code, it causes the server to shut down too early. This could also have been implemented to save time while you are unloading your tests.
I can confirm that the leaderstats folder is created by another script before the values are inside of it (not mentioned in this post). As for the pcall, I did use it in the PlayerRemoving function, unless you mean that I should do it for PlayerAdded as well.
So, if I’m understanding correctly, what I should do is separate:
local success, errorMessage = pcall(function()
local FOVData = FOVslider:GetAsync(Player.UserId)
FOVslider:SetAsync(Player.UserId, Player.leaderstats.FOV_VALUE.Value)
local IGMData = IGMslider:GetAsync(Player.UserId)
IGMslider:SetAsync(Player.UserId, Player.leaderstats.IGM_VALUE.Value)
end)
if not success then
print(errorMessage)
end
end)
into 2, one for IGMData and the other for FOVData inside functions (per say, SaveFOV() and SaveIGM(), then I should create a loop so that every 5 seconds, it executes those functions. Correct?
No, every 5 minutes. Doing an auto save every 5 seconds would exhaust the Data store API. Also, just put the entirety of the code you run on Player Added inside of a function, then just run that on startup and save all players data every 5 minutes.
local DataStoreService = game:GetService("DataStoreService")
local FOVREMOTE = game:GetService("ReplicatedStorage").RemoteEvents.Slider.FOV
local IGMREMOTE = game:GetService("ReplicatedStorage").RemoteEvents.Slider.IGM
local FOVslider = DataStoreService:GetDataStore("SliderValues", "FOV")
local IGMslider = DataStoreService:GetDataStore("SliderValues", "IGM")
game.Players.PlayerAdded:Connect(function(Player)
local function AutoSave()
-- FIELD OF VIEW
local FOV = Instance.new("IntValue")
local FOVdefaultValue = 50
FOV.Name = "FOV_VALUE"
FOV.Parent = Player:WaitForChild("leaderstats")
FOV.Value = FOVdefaultValue -- Default Value
FOVREMOTE:FireClient(Player, FOV.Value) -- Default Value
pcall(function()
local FOVData = FOVslider:GetAsync(Player.UserId)
if FOVData == nil then
print("Oh! You must be new! We're setting you up...")
print("Welcome to Miles by the way. :)")
print(" ")
FOVData = FOVdefaultValue
warn("FOV set!")
else if FOV ~= nil then
print("Welcome back to Miles! :)")
end
end
FOV.Value = FOVData
FOVREMOTE:FireClient(Player, FOVData)
FOVREMOTE.OnServerEvent:Connect(function(Player, newFOV)
FOV.Value = newFOV
end)
end)
-- IN GAME MUSIC
local IGM = Instance.new("NumberValue")
local IGMdefaultValue = 0.8
IGM.Name = "IGM_VALUE"
IGM.Parent = Player:WaitForChild("leaderstats")
IGM.Value = IGMdefaultValue -- Default Value
IGMREMOTE:FireClient(Player, IGM.Value) -- Default Value
pcall(function()
local IGMData = IGMslider:GetAsync(Player.UserId)
if IGMData == nil then
IGMData = IGMdefaultValue
warn("IGM set!")
end
IGM.Value = IGMData
IGMREMOTE:FireClient(Player, IGMData)
IGMREMOTE.OnServerEvent:Connect(function(Player, newIGM)
IGM.Value = newIGM
end)
end)
end
while true do
AutoSave()
task.wait(300)
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
local success, errorMessage = pcall(function()
FOVslider:SetAsync(Player.UserId, Player.leaderstats.FOV_VALUE.Value)
IGMslider:SetAsync(Player.UserId, Player.leaderstats.IGM_VALUE.Value)
end)
if not success then
print(errorMessage)
end
end)