Help needed with databases

I’ve recently made a XP system but every time that I leave and rejoin back it always resets my level to 2 even though I may be a level 50.

This is the script for the server script as the other local scripts in the GUI just use the data and do everything but this is where I store and save all the data

local level = 1
local exp = 0
local axp = 20
 
local InStudio = game:GetService("RunService"):IsStudio()
 

if not InStudio then
    level = game:GetService("DataStoreService"):GetDataStore("Levels")
    exp = game:GetService("DataStoreService"):GetDataStore("EXP")
    axp = game:GetService("DataStoreService"):GetDataStore("AXP")
end
 
function savedata(dataname, playerid, value)
    if InStudio then return end
    dataname:SetAsync(playerid, value)
end
 
game.Players.PlayerAdded:connect(function(player)
    local levelz = Instance.new("IntValue")
    levelz.Name = "Level"
    local xpz = Instance.new("NumberValue")
    xpz.Name = "Exp"
    local xpn = Instance.new("IntValue")
    xpn.Name = "ExpNeeded"
	
	xpn.Parent = player
	xpz.Parent = player
	levelz.Parent = player
    
    if not InStudio then
        xpn.Value = axp:GetAsync(tostring(player.userId)) or 20
        xpz.Value = exp:GetAsync(tostring(player.userId)) or 0
        levelz.Value = level:GetAsync(tostring(player.userId)) or 1
    else
        xpn.Value = axp
        xpz.Value = exp
        levelz.Value = level
    end
    
    
    xpz.Changed:connect(function()
        if player:WaitForChild("Exp").Value >=player:WaitForChild("ExpNeeded").Value then
            levelz.Value = levelz.Value + 1
            
            
            xpn.Value = math.floor(xpn.Value * 2)
            xpz.Value = 0   
            
            savedata(level, player.userId, levelz.Value)
            savedata(exp, player.userId, xpz.Value)
            savedata(axp, player.userId, xpn.Value)
        else
            savedata(level, player.userId, levelz.Value)
            savedata(exp, player.userId, xpz.Value)
            savedata(axp, player.userId, xpn.Value)
        end
        savedata(level, player.userId, levelz.Value)
        savedata(exp, player.userId, xpz.Value)
        savedata(axp, player.userId, xpn.Value)
    end)
end)
 
game.Players.PlayerRemoving:connect(function(player)
    savedata(level, player.userId, player.Level.Value)
    savedata(exp, player.userId, player.Exp.Value)
    savedata(axp, player.userId, player.ExpNeeded.Value)
end)
1 Like

Try this

local bindableEvent = Instance.new("BindableEvent")
local playersLeft = 0

Players.PlayerAdded:Connect(function (player)
	
	playersLeft = playersLeft + 1
	-- Method for getting data
	
end)

Players.PlayerRemoving:Connect(function (player)
	
	pcall(function ()
		-- Method for getting data
		
		playersLeft = playersLeft - 1
		bindableEvent:Fire()
	end)
	
end)

game:BindToClose(function ()
	while playersLeft > 0 do
		bindableEvent.Event:Wait()
	end
end)

This code was directly ripped from one of @Alvin_Blox’s data saving tutorials. Can’t remember what video, but I’ll edit my post once I have it.

alright I’ll see if this works but thing is it still saves the data just not fully

1 Like

A likely cause to your issue could be that you are hitting your data store limits causing your data store to throttle then making your data not save. This can been seen in your xpz.Changed function because you are saving data whenever it changes and not taking into account data store limits. This can be extremely hazardous because your Values could change very quickly.

Another, seemingly unlikely, cause to your problem could be that you are updating your Values client sided causing the server not to register the changes because of FilteringEnabled. Instead you should always handle any changes to data on the server that way the server will then pick up the changes.

Better Practices
It looks like you are only using SetAsync() to updates players data. This can be very hazardous because SetAsync() forces a save on that key without taking into account the previous value. Then also the Developers Hub advises against using SetAsync() for the exact reasons I just explained. Instead, the advised way to update data is by using UpdateAsync().

Another thing that you should be doing is wrapping all your data store calls in a pcall because they sometimes fail. Using pcall will allow you to catch the error.

Last but not least you shouldn’t be saving the players data when they leave the game without first checking if their data has been loaded. The reason why this causes data loss is because the player could leave before their data has been loaded causing their data to be overridden.

Yeah I fixed it when I looked into it

hi, i have the save problem but i heard if the player dont have any saved data u cant use UpdateAsync()?

The general rule is to always use UpdateAsync() instead of SetAsync() when saving your data because SetAsync() can be hazardous. However there are some developers that use SetAsync() to save there data. DataStore2 is a great example of this and I think the reason why it does this is because it is never overriding and previous saved data. I will need some clarification on that though.

SetAsync() doesn’t take into account any previous saved data and should only be used when you need to force data. From my understanding it is fine to use SetAsync() when you don’t have any saved data for the player because you are not overriding any previous saved data.

You can use UpdateAsync() even when you don’t have any saved data. This is because it returns the current saved value and then you can check if the current value is nil and then return default data. Here is a tuturial on why you should be using UpdateAsync: Stop using SetAsync() to save player data. Then here is some horrible code that I just made to show how you can use UpdateAsync() even when you don’t have any saved data:

local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("Test")

local DefultValue = 20

game.Players.PlayerAdded:Connect(function(Player)
	local Success, Error = pcall(function()
		DataStore:UpdateAsync(tostring(Player.UserId), function(CurrentValue)
			if CurrentValue == nil then
				print("No data exists")
				return DefultValue
			else
				print("Data Exists")
				return CurrentValue + 4
			end
		end)
	end)
	
	if not Success then
		warn(Error)
	end
end)

Please don’t use this code as it is because it is missing a lot of stuff from it. For example it doesn’t first check if the player doesn’t have any saved data.

1 Like