Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

What could be wrong with my "save file" improvisation?

Asked by
Sindrotex -41
4 years ago
Edited 4 years ago

I'm trying to make some kind of save file. Here's how I'm trying to do that: first I get 1 data store with a dictionary having the default values like money, then a 2nd data store to know if you already got the default one so it won't erase your progress. I have the dictionary data store go into a module (playerInfo) that I will modify and eventually save, only when you leave, so I don't use SetAsync or UpdateAsync too much. Once I enter, the default data store is successfully set and prints it in the output, but when I leave it doesn't set the new version of it. No errors in the output.

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerSaveFile = DataStoreService:GetDataStore("playerSaveFile")
local playerFirstJoined = DataStoreService:GetDataStore("playerFirstJoined")

Players.PlayerAdded:Connect(function(player)
    playerFirstJoined:SetAsync(player.UserId, "new")
end)

local playerDefaultStatus = {nothing = "here", pls = "move on"}

Players.PlayerAdded:Connect(function(player)
    if playerFirstJoined:GetAsync(player.UserId) == "new" then
(here goes another part that doesn't affect in any way the next, it works so I won't include it pls no cancel)

Players.PlayerRemoving:Connect(function(player)
    playerFirstJoined:SetAsync(player.UserId, "old")
    local success, err = pcall(function()
        playerSaveFile:UpdateAsync(player.UserId, function(oldValue)
            local playerInfo = require(workspace.playerInfo)
            local newValue = playerInfo.playerModuleSF or oldValue
            return newValue
        end)
    end)
    if success then
        print(player.Name.."'s save file was updated.")
    end
end)

Modulescript:

local PlayerInfo = {}
Players = game:GetService("Players")
function PlayerInfo.playerModule (player)
    local playerModuleSF = game:GetService("DataStoreService"):GetDataStore("playerSaveFile"):GetAsync(player.UserId)
    return playerModuleSF
end
Players.PlayerAdded:Connect(PlayerInfo.playerModule)
return PlayerInfo

1 answer

Log in to vote
0
Answered by 4 years ago

The immediate problem is this code here, where you're saving the player as new (and then immediately checking if they're new, even though you've just assigned them to new.) I suspect you're overriding the player's data with the default data within there

Players.PlayerAdded:Connect(function(player)
    playerFirstJoined:SetAsync(player.UserId, "new")
end)

Players.PlayerAdded:Connect(function(player)
    if playerFirstJoined:GetAsync(player.UserId) == "new" then
        ...
    end
end)

And the most immediate solution is to instead check if the data is nil (since that's the default value if nothing's been saved) and to assign some other value once they're leaving.

Players.PlayerAdded:Connect(function(player)
    if playerFirstJoined:GetAsync(player.UserId) == nil then
        ...
    end
end)

Players.PlayerRemoving:Connect(function(player)
    playerFirstJoined:SetAsync(player.UserId, true)
end)

Now I'm calling these immediate since they're the most direct solution, however, there's some bad design in your code

The problem is that you trust datastores a bit too much. They're prone to erroring if you make set/get requests fast, or just because it feels like it lol. Specifically, you're using another datastore to check if they're new when instead you should take advantage that all their data would be nil if they were new, and also you're making some unnecessary calls to the datastore. A solution would instead to cache the data in the module, which could be saved and retrieved very quickly without worrying about making too many calls to the datastore. Once the player leaves, the cached data can be saved

Players.PlayerAdded:Connect(function(player)
    local data
    local success, err = pcall(function()
        data = playerSaveFile:GetAsync(player.UserId)
    end)
    if not success then warn(err) end

    playerInfo.SaveData(player, data or defaultValue) --Taking advantage of how the or operator evaluates to the second operand if the first is nil (or false.)
end)

Players.PlayerRemoving:Connect(function(player)
    local success, err = pcall(function()
        playerSaveFile:UpdateAsync(player.UserId, function(oldValue)
            local newValue = playerInfo.GetData(player) or oldValue
            return newValue
        end)
    end)
    if success then
        print(player.Name.."'s save file was updated.")
    end
end)

Module Script:

local PlayerInfo = {}

local cachedData = {} --Holds player data instead of making calls to the datastore. You could use this to periodically save every players' data every few minutes or so

function PlayerInfo.SaveData(player, data)
    cachedData[player] = data
end

function PlayerInfo.GetData(player)
    return cachedData[player]
end

Players.PlayerRemoving:Connect(function(player)
    --Cleanup
    cachedData[player] = nil
end)

return PlayerInfo
0
Ah, I see now. Thank you for everything! I didn't reaize they'd have no data and could've just used that instead of the data store, kinda new into scripting. Sindrotex -41 — 4y
Ad

Answer this question