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

How come this save shop items and stats script not work?

Asked by 6 years ago

Script Location : ServerScriptService Script Type : ModuleScript

-- My scripter and I have been stuck on it for hours, help would be nice! We have no idea why it doesn't work! --

-- Setup table that we will return to scripts that require the ModuleScript.
local PlayerStatManager = {}

-- Create variable for the DataStore.
local DataStoreService = game:GetService('DataStoreService')
local Events = workspace:WaitForChild("Events", 30)
local playerData = DataStoreService:GetDataStore('PlayerData')

-- Create variable to configure how often the game autosaves the player data.
local AUTOSAVE_INTERVAL = 30

-- Number of times we can retry accessing a DataStore before we give up and create
-- an error.
local DATASTORE_RETRIES = 3

-- Table to hold all of the player information for the current session.
local sessionData = {}

-- Function the other scripts in our game can call to change a player's stats. This
-- function is stored in the returned table so external scripts can use it.
function PlayerStatManager:ChangeStat(player, statName, changeValue)
    sessionData[player][statName] = changeValue
end

function UpdateData(player)
    local playerleaderstats = player:WaitForChild("leaderstats", 30)
    local playerWins = playerleaderstats:WaitForChild("Wins", 30)
    local playerLevel = playerleaderstats:WaitForChild("Level", 30)
    local playerCoins = playerleaderstats:WaitForChild("Coins", 30)
    local playerBoughtItems = player:WaitForChild("BoughtItems", 30)
    local playerTimesVisited = player:WaitForChild("TimesVisited", 30)

    local boughtitemst = {}

    for i, v in pairs(playerBoughtItems:GetChildren()) do
        boughtitemst[i] = v.Name
    end

    sessionData[player] = {
        Wins = playerWins.Value, 
        Level = playerLevel.Value,
        Coins = playerCoins.Value,
        BoughtItems = boughtitemst,
        TimesVisited = playerTimesVisited.Value
    }
end

-- Function to retry the passed in function several times. If the passed in function
-- is unable to be run then this function returns false and creates an error.
local function dataStoreRetry(dataStoreFunction)
    local tries = 0 
    local success = true
    local data = nil
    repeat
        tries = tries + 1
        success = pcall(function() data = dataStoreFunction() end)
        if not success then wait(1) end
    until tries == DATASTORE_RETRIES or success
    if not success then
        warn('Could not access DataStore! Warn players that their data might not get saved!')
    end
    return success, data
end

-- Function to retrieve player's data from the DataStore.
local function getPlayerData(player)
    Events:WaitForChild("DataIconEvent", 30):FireClient(player, "In Progress", "Getting progress...", true)
    return dataStoreRetry(function()
        Events:WaitForChild("DataIconEvent", 30):FireClient(player, "Success", "Progress loaded!", true)
        return playerData:GetAsync(player.UserId)
    end)
end

-- Function to save player's data to the DataStore.
local function savePlayerData(player)
    if sessionData[player] then
        Events:WaitForChild("DataIconEvent", 30):FireClient(player, "In Progress", "Saving progress...", false)
        return dataStoreRetry(function()
            Events:WaitForChild("DataIconEvent", 30):FireClient(player, "Success", "Progress saved!", false)
            print("Saved")
            return playerData:SetAsync(player.UserId, sessionData[player])
        end)
    end
end

-- Function to add player to the sessionData table. First check if the player has
-- data in the DataStore. If so, we'll use that. If not, we'll add the player to
-- the DataStore.
local function setupPlayerData(player)
    local success, data = getPlayerData(player)
    if not success then
        -- Could not access DataStore, set session data for player to false.
        sessionData[player] = false
        Events:WaitForChild("DataIconEvent", 30):FireClient(player, "Fail", "Something went wrong...", true)
    else
        if not data then
            -- DataStores are working, but no data for this player
            sessionData[player] = {
                Wins = 0,
                Level = 1,
                Coins = 10,
                BoughtItems = {},
                TimesVisited = 1
            }
            savePlayerData(player)
        else
            -- DataStores are working and we got data for this player
            sessionData[player] = data

            local playerleaderstats = player:WaitForChild("leaderstats", 30)
            local playerWins = playerleaderstats:WaitForChild("Wins", 30)
            local playerLevel = playerleaderstats:WaitForChild("Level", 30)
            local playerLvlUpExp = playerLevel:WaitForChild("LvlUpExp", 30)
            local playerCoins = playerleaderstats:WaitForChild("Coins", 30)
            local playerBoughtItems = player:WaitForChild("BoughtItems", 30)
            local playerTimesVisited = player:WaitForChild("TimesVisited", 30)

            local CoinsMultiplier = player:WaitForChild("CoinsMultiplier", 30)
            local ExpMultiplier = player:WaitForChild("ExpMultiplier", 30)

            playerWins.Value = sessionData[player].Wins
            playerLevel.Value = sessionData[player].Level
            playerLvlUpExp.Value = ((playerLevel.Value * 3) / ExpMultiplier.Value)
            playerCoins.Value = sessionData[player].Coins
            for i, v in pairs(sessionData[player].BoughtItems) do
                local boughtitem = Instance.new("BoolValue", playerBoughtItems)
                boughtitem.Name = v
                boughtitem.Value = true
            end
            playerTimesVisited.Value = sessionData[player].TimesVisited

        end
    end 
end

-- Function to run in the background to periodically save player's data.
local function autosave()
    while wait(AUTOSAVE_INTERVAL) do
        for player, data in pairs(sessionData) do
            --UpdateData(player)
            savePlayerData(player)
            print("Autosaving...")
        end
    end
end

-- Bind setupPlayerData to PlayerAdded to call it when player joins.
game.Players.PlayerAdded:connect(setupPlayerData)

-- Call savePlayerData on PlayerRemoving to save player data when they leave.
-- Also delete the player from the sessionData, as the player isn't in-game anymore.
game.Players.PlayerRemoving:connect(function(player)
    --UpdateData(player)
    savePlayerData(player)
    sessionData[player] = nil
end)

-- Start running autosave function in the background.
spawn(autosave)

-- Return the PlayerStatManager table to external scripts can access it.
return PlayerStatManager

If you do end up fixing it my scripter and I will add you in credits! Thanks!

1 answer

Log in to vote
0
Answered by
Tomstah 401 Moderation Voter
6 years ago

On lines 85-87 you can see you're running your first function after binding it to PlayerAdded. Unto which the lines are:

local function setupPlayerData(player)
    local success, data = getPlayerData(player)
    if not success then

We can then proceed to getPlayerData(player) to which we then see:

local function getPlayerData(player)
    Events:WaitForChild("DataIconEvent", 30):FireClient(player, "In Progress", "Getting progress...", true)
    return dataStoreRetry(function()
        Events:WaitForChild("DataIconEvent", 30):FireClient(player, "Success", "Progress loaded!", true)
        return playerData:GetAsync(player.UserId)
    end)
end

Here's the problem, you're returning getPlayerData as a GetAsync, but, there's no Success value! So your GetAsync gets assigned to Success and it is "truthy" so it passes most tests. Which is where your problems start.

Ad

Answer this question